VirtualBox

source: vbox/trunk/include/VBox/com/AutoLock.h@ 25885

Last change on this file since 25885 was 25885, checked in by vboxsync, 15 years ago

filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.7 KB
Line 
1/** @file
2 *
3 * Automatic locks, implementation
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31#ifndef ____H_AUTOLOCK
32#define ____H_AUTOLOCK
33
34#include <iprt/types.h>
35
36// macros for automatic lock validation; these will amount to nothing
37// unless lock validation is enabled for the runtime
38#if defined(RT_LOCK_STRICT) && defined (DEBUG)
39#define VBOX_WITH_MAIN_LOCK_VALIDATION
40# define COMMA_LOCKVAL_SRC_POS , RT_SRC_POS
41# define LOCKVAL_SRC_POS_DECL RT_SRC_POS_DECL
42# define COMMA_LOCKVAL_SRC_POS_DECL , RT_SRC_POS_DECL
43# define LOCKVAL_SRC_POS_ARGS RT_SRC_POS_ARGS
44# define COMMA_LOCKVAL_SRC_POS_ARGS , RT_SRC_POS_ARGS
45#else
46# define COMMA_LOCKVAL_SRC_POS
47# define LOCKVAL_SRC_POS_DECL
48# define COMMA_LOCKVAL_SRC_POS_DECL
49# define LOCKVAL_SRC_POS_ARGS
50# define COMMA_LOCKVAL_SRC_POS_ARGS
51#endif
52
53namespace util
54{
55
56////////////////////////////////////////////////////////////////////////////////
57//
58// Order classes for lock validation
59//
60////////////////////////////////////////////////////////////////////////////////
61
62/**
63 * IPRT now has a sophisticated system of run-time locking classes to validate
64 * locking order. Since the Main code is handled by simpler minds, we want
65 * compile-time constants for simplicity, and we'll look up the run-time classes
66 * in AutoLock.cpp transparently. These are passed to the constructors of the
67 * LockHandle classes.
68 */
69enum VBoxLockingClass
70{
71 LOCKCLASS_NONE = 0,
72 LOCKCLASS_VIRTUALBOXOBJECT = 1, // highest order: VirtualBox object lock
73 LOCKCLASS_USBPROXYSERVICE = 2, // USB proxy service object lock
74 LOCKCLASS_HOSTOBJECT = 3, // Host object lock
75 LOCKCLASS_LISTOFMACHINES = 4, // list of machines in VirtualBox object
76 LOCKCLASS_MACHINEOBJECT = 5, // Machine object lock
77 LOCKCLASS_LISTOFSNAPSHOTS = 6, // list of snapshots in Machine object
78 LOCKCLASS_SNAPSHOTOBJECT = 7, // snapshot object locks (need to have lower order
79 // than both MACHINEOBJECT and LOCKCLASS_MACHINELIST since
80 // the list of snapshots in Machine is LOCKCLASS_MACHINELIST)
81 LOCKCLASS_LISTOFMEDIA = 8, // list of media (hard disks, DVDs, floppies) in VirtualBox object
82 LOCKCLASS_LISTOFOTHEROBJECTS = 9, // any other list of objects
83 LOCKCLASS_OTHEROBJECT = 10, // any regular object member variable lock
84 LOCKCLASS_USBLIST = 11, // temporary hack to avoid having to clean up the USB filters
85 // too much @todo r=dj get rid of this!
86 LOCKCLASS_PROGRESSLIST = 12, // list of progress objects in VirtualBox; no other object lock
87 // may be held after this!
88 LOCKCLASS_OBJECTSTATE = 13 // object state lock (handled by AutoCaller classes)
89};
90
91void InitAutoLockSystem();
92
93////////////////////////////////////////////////////////////////////////////////
94//
95// LockHandle and friends
96//
97////////////////////////////////////////////////////////////////////////////////
98
99/**
100 * Abstract base class for semaphore handles (RWLockHandle and WriteLockHandle).
101 * Don't use this directly, but this implements lock validation for them.
102 */
103class LockHandle
104{
105public:
106 LockHandle()
107 {}
108
109 virtual ~LockHandle()
110 {}
111
112 /**
113 * Returns @c true if the current thread holds a write lock on this
114 * read/write semaphore. Intended for debugging only.
115 */
116 virtual bool isWriteLockOnCurrentThread() const = 0;
117
118 /**
119 * Returns the current write lock level of this semaphore. The lock level
120 * determines the number of nested #lock() calls on the given semaphore
121 * handle.
122 *
123 * Note that this call is valid only when the current thread owns a write
124 * lock on the given semaphore handle and will assert otherwise.
125 */
126 virtual uint32_t writeLockLevel() const = 0;
127
128 virtual void lockWrite(LOCKVAL_SRC_POS_DECL) = 0;
129 virtual void unlockWrite() = 0;
130 virtual void lockRead(LOCKVAL_SRC_POS_DECL) = 0;
131 virtual void unlockRead() = 0;
132
133#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
134 virtual const char* describe() const = 0;
135#endif
136
137private:
138 // prohibit copy + assignment
139 LockHandle(const LockHandle&);
140 LockHandle& operator=(const LockHandle&);
141};
142
143/**
144 * Full-featured read/write semaphore handle implementation.
145 *
146 * This is an auxiliary base class for classes that need full-featured
147 * read/write locking as described in the AutoWriteLock class documentation.
148 * Instances of classes inherited from this class can be passed as arguments to
149 * the AutoWriteLock and AutoReadLock constructors.
150 */
151class RWLockHandle : public LockHandle
152{
153public:
154 RWLockHandle(VBoxLockingClass lockClass);
155 virtual ~RWLockHandle();
156
157 virtual bool isWriteLockOnCurrentThread() const;
158
159 virtual void lockWrite(LOCKVAL_SRC_POS_DECL);
160 virtual void unlockWrite();
161 virtual void lockRead(LOCKVAL_SRC_POS_DECL);
162 virtual void unlockRead();
163
164 virtual uint32_t writeLockLevel() const;
165
166#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
167 virtual const char* describe() const;
168#endif
169
170private:
171 struct Data;
172 Data *m;
173};
174
175/**
176 * Write-only semaphore handle implementation.
177 *
178 * This is an auxiliary base class for classes that need write-only (exclusive)
179 * locking and do not need read (shared) locking. This implementation uses a
180 * cheap and fast critical section for both lockWrite() and lockRead() methods
181 * which makes a lockRead() call fully equivalent to the lockWrite() call and
182 * therefore makes it pointless to use instahces of this class with
183 * AutoReadLock instances -- shared locking will not be possible anyway and
184 * any call to lock() will block if there are lock owners on other threads.
185 *
186 * Use with care only when absolutely sure that shared locks are not necessary.
187 */
188class WriteLockHandle : public LockHandle
189{
190public:
191 WriteLockHandle(VBoxLockingClass lockClass);
192 virtual ~WriteLockHandle();
193 virtual bool isWriteLockOnCurrentThread() const;
194
195 virtual void lockWrite(LOCKVAL_SRC_POS_DECL);
196 virtual void unlockWrite();
197 virtual void lockRead(LOCKVAL_SRC_POS_DECL);
198 virtual void unlockRead();
199 virtual uint32_t writeLockLevel() const;
200
201#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
202 virtual const char* describe() const;
203#endif
204
205private:
206 struct Data;
207 Data *m;
208};
209
210////////////////////////////////////////////////////////////////////////////////
211//
212// Lockable
213//
214////////////////////////////////////////////////////////////////////////////////
215
216/**
217 * Lockable interface.
218 *
219 * This is an abstract base for classes that need read/write locking. Unlike
220 * RWLockHandle and other classes that makes the read/write semaphore a part of
221 * class data, this class allows subclasses to decide which semaphore handle to
222 * use.
223 */
224class Lockable
225{
226public:
227
228 /**
229 * Returns a pointer to a LockHandle used by AutoWriteLock/AutoReadLock
230 * for locking. Subclasses are allowed to return @c NULL -- in this case,
231 * the AutoWriteLock/AutoReadLock object constructed using an instance of
232 * such subclass will simply turn into no-op.
233 */
234 virtual LockHandle *lockHandle() const = 0;
235
236 /**
237 * Equivalent to <tt>#lockHandle()->isWriteLockOnCurrentThread()</tt>.
238 * Returns @c false if lockHandle() returns @c NULL.
239 */
240 bool isWriteLockOnCurrentThread()
241 {
242 LockHandle *h = lockHandle();
243 return h ? h->isWriteLockOnCurrentThread() : false;
244 }
245};
246
247////////////////////////////////////////////////////////////////////////////////
248//
249// AutoLockBase
250//
251////////////////////////////////////////////////////////////////////////////////
252
253/**
254 * Abstract base class for all autolocks.
255 *
256 * This cannot be used directly. Use AutoReadLock or AutoWriteLock or AutoMultiWriteLock2/3
257 * which directly and indirectly derive from this.
258 *
259 * In the implementation, the instance data contains a list of lock handles.
260 * The class provides some utility functions to help locking and unlocking
261 * them.
262 */
263
264class AutoLockBase
265{
266protected:
267 AutoLockBase(uint32_t cHandles
268 COMMA_LOCKVAL_SRC_POS_DECL);
269 AutoLockBase(uint32_t cHandles,
270 LockHandle *pHandle
271 COMMA_LOCKVAL_SRC_POS_DECL);
272 virtual ~AutoLockBase();
273
274 struct Data;
275 Data *m;
276
277 virtual void callLockImpl(LockHandle &l) = 0;
278 virtual void callUnlockImpl(LockHandle &l) = 0;
279
280 void callLockOnAllHandles();
281 void callUnlockOnAllHandles();
282
283 void cleanup();
284
285public:
286 void acquire();
287 void release();
288
289private:
290 // prohibit copy + assignment
291 AutoLockBase(const AutoLockBase&);
292 AutoLockBase& operator=(const AutoLockBase&);
293};
294
295////////////////////////////////////////////////////////////////////////////////
296//
297// AutoReadLock
298//
299////////////////////////////////////////////////////////////////////////////////
300
301/**
302 * Automatic read lock. Use this with a RWLockHandle to request a read/write
303 * semaphore in read mode. You can also use this with a WriteLockHandle but
304 * that makes little sense since they treat read mode like write mode.
305 *
306 * If constructed with a RWLockHandle or an instance of Lockable (which in
307 * practice means any VirtualBoxBase derivative), it autoamtically requests
308 * the lock in read mode and releases the read lock in the destructor.
309 */
310class AutoReadLock : public AutoLockBase
311{
312public:
313
314 /**
315 * Constructs a null instance that does not manage any read/write
316 * semaphore.
317 *
318 * Note that all method calls on a null instance are no-ops. This allows to
319 * have the code where lock protection can be selected (or omitted) at
320 * runtime.
321 */
322 AutoReadLock(LOCKVAL_SRC_POS_DECL)
323 : AutoLockBase(1,
324 NULL
325 COMMA_LOCKVAL_SRC_POS_ARGS)
326 { }
327
328 /**
329 * Constructs a new instance that will start managing the given read/write
330 * semaphore by requesting a read lock.
331 */
332 AutoReadLock(LockHandle *aHandle
333 COMMA_LOCKVAL_SRC_POS_DECL)
334 : AutoLockBase(1,
335 aHandle
336 COMMA_LOCKVAL_SRC_POS_ARGS)
337 {
338 acquire();
339 }
340
341 /**
342 * Constructs a new instance that will start managing the given read/write
343 * semaphore by requesting a read lock.
344 */
345 AutoReadLock(LockHandle &aHandle
346 COMMA_LOCKVAL_SRC_POS_DECL)
347 : AutoLockBase(1,
348 &aHandle
349 COMMA_LOCKVAL_SRC_POS_ARGS)
350 {
351 acquire();
352 }
353
354 /**
355 * Constructs a new instance that will start managing the given read/write
356 * semaphore by requesting a read lock.
357 */
358 AutoReadLock(const Lockable &aLockable
359 COMMA_LOCKVAL_SRC_POS_DECL)
360 : AutoLockBase(1,
361 aLockable.lockHandle()
362 COMMA_LOCKVAL_SRC_POS_ARGS)
363 {
364 acquire();
365 }
366
367 /**
368 * Constructs a new instance that will start managing the given read/write
369 * semaphore by requesting a read lock.
370 */
371 AutoReadLock(const Lockable *aLockable
372 COMMA_LOCKVAL_SRC_POS_DECL)
373 : AutoLockBase(1,
374 aLockable ? aLockable->lockHandle() : NULL
375 COMMA_LOCKVAL_SRC_POS_ARGS)
376 {
377 acquire();
378 }
379
380 virtual ~AutoReadLock();
381
382 virtual void callLockImpl(LockHandle &l);
383 virtual void callUnlockImpl(LockHandle &l);
384};
385
386////////////////////////////////////////////////////////////////////////////////
387//
388// AutoWriteLockBase
389//
390////////////////////////////////////////////////////////////////////////////////
391
392/**
393 * Base class for all auto write locks.
394 *
395 * This cannot be used directly. Use AutoWriteLock or AutoMultiWriteLock2/3
396 * which derive from this.
397 *
398 * In addition to utility methods for subclasses, this implements the public
399 * leave/enter/maybeEnter methods, which are common to all
400 * write locks.
401 */
402class AutoWriteLockBase : public AutoLockBase
403{
404protected:
405 AutoWriteLockBase(uint32_t cHandles
406 COMMA_LOCKVAL_SRC_POS_DECL)
407 : AutoLockBase(cHandles
408 COMMA_LOCKVAL_SRC_POS_ARGS)
409 { }
410
411 AutoWriteLockBase(uint32_t cHandles,
412 LockHandle *pHandle
413 COMMA_LOCKVAL_SRC_POS_DECL)
414 : AutoLockBase(cHandles,
415 pHandle
416 COMMA_LOCKVAL_SRC_POS_ARGS)
417 { }
418
419 virtual ~AutoWriteLockBase()
420 { }
421
422 virtual void callLockImpl(LockHandle &l);
423 virtual void callUnlockImpl(LockHandle &l);
424
425public:
426 void leave();
427 void enter();
428 void maybeEnter();
429};
430
431////////////////////////////////////////////////////////////////////////////////
432//
433// AutoWriteLock
434//
435////////////////////////////////////////////////////////////////////////////////
436
437/**
438 * Automatic write lock. Use this with a RWLockHandle to request a read/write
439 * semaphore in write mode. There can only ever be one writer of a read/write
440 * semaphore: while the lock is held in write mode, no other writer or reader
441 * can request the semaphore and will block.
442 *
443 * If constructed with a RWLockHandle or an instance of Lockable (which in
444 * practice means any VirtualBoxBase derivative), it autoamtically requests
445 * the lock in write mode and releases the write lock in the destructor.
446 *
447 * When used with a WriteLockHandle, it requests the semaphore contained therein
448 * exclusively.
449 */
450class AutoWriteLock : public AutoWriteLockBase
451{
452public:
453
454 /**
455 * Constructs a null instance that does not manage any read/write
456 * semaphore.
457 *
458 * Note that all method calls on a null instance are no-ops. This allows to
459 * have the code where lock protection can be selected (or omitted) at
460 * runtime.
461 */
462 AutoWriteLock(LOCKVAL_SRC_POS_DECL)
463 : AutoWriteLockBase(1,
464 NULL
465 COMMA_LOCKVAL_SRC_POS_ARGS)
466 { }
467
468 /**
469 * Constructs a new instance that will start managing the given read/write
470 * semaphore by requesting a write lock.
471 */
472 AutoWriteLock(LockHandle *aHandle
473 COMMA_LOCKVAL_SRC_POS_DECL)
474 : AutoWriteLockBase(1,
475 aHandle
476 COMMA_LOCKVAL_SRC_POS_ARGS)
477 {
478 acquire();
479 }
480
481 /**
482 * Constructs a new instance that will start managing the given read/write
483 * semaphore by requesting a write lock.
484 */
485 AutoWriteLock(LockHandle &aHandle
486 COMMA_LOCKVAL_SRC_POS_DECL)
487 : AutoWriteLockBase(1,
488 &aHandle
489 COMMA_LOCKVAL_SRC_POS_ARGS)
490 {
491 acquire();
492 }
493
494 /**
495 * Constructs a new instance that will start managing the given read/write
496 * semaphore by requesting a write lock.
497 */
498 AutoWriteLock(const Lockable &aLockable
499 COMMA_LOCKVAL_SRC_POS_DECL)
500 : AutoWriteLockBase(1,
501 aLockable.lockHandle()
502 COMMA_LOCKVAL_SRC_POS_ARGS)
503 {
504 acquire();
505 }
506
507 /**
508 * Constructs a new instance that will start managing the given read/write
509 * semaphore by requesting a write lock.
510 */
511 AutoWriteLock(const Lockable *aLockable
512 COMMA_LOCKVAL_SRC_POS_DECL)
513 : AutoWriteLockBase(1,
514 aLockable ? aLockable->lockHandle() : NULL
515 COMMA_LOCKVAL_SRC_POS_ARGS)
516 {
517 acquire();
518 }
519
520 /**
521 * Release all write locks acquired by this instance through the #lock()
522 * call and destroys the instance.
523 *
524 * Note that if there there are nested #lock() calls without the
525 * corresponding number of #unlock() calls when the destructor is called, it
526 * will assert. This is because having an unbalanced number of nested locks
527 * is a program logic error which must be fixed.
528 */
529 virtual ~AutoWriteLock()
530 {
531 cleanup();
532 }
533
534 void attach(LockHandle *aHandle);
535
536 /** @see attach (LockHandle *) */
537 void attach(LockHandle &aHandle)
538 {
539 attach(&aHandle);
540 }
541
542 /** @see attach (LockHandle *) */
543 void attach(const Lockable &aLockable)
544 {
545 attach(aLockable.lockHandle());
546 }
547
548 /** @see attach (LockHandle *) */
549 void attach(const Lockable *aLockable)
550 {
551 attach(aLockable ? aLockable->lockHandle() : NULL);
552 }
553
554 bool isWriteLockOnCurrentThread() const;
555 uint32_t writeLockLevel() const;
556};
557
558////////////////////////////////////////////////////////////////////////////////
559//
560// AutoMultiWriteLock*
561//
562////////////////////////////////////////////////////////////////////////////////
563
564/**
565 * A multi-write-lock containing two other write locks.
566 *
567 */
568class AutoMultiWriteLock2 : public AutoWriteLockBase
569{
570public:
571 AutoMultiWriteLock2(Lockable *pl1,
572 Lockable *pl2
573 COMMA_LOCKVAL_SRC_POS_DECL);
574 AutoMultiWriteLock2(LockHandle *pl1,
575 LockHandle *pl2
576 COMMA_LOCKVAL_SRC_POS_DECL);
577
578 virtual ~AutoMultiWriteLock2()
579 {
580 cleanup();
581 }
582};
583
584/**
585 * A multi-write-lock containing three other write locks.
586 *
587 */
588class AutoMultiWriteLock3 : public AutoWriteLockBase
589{
590public:
591 AutoMultiWriteLock3(Lockable *pl1,
592 Lockable *pl2,
593 Lockable *pl3
594 COMMA_LOCKVAL_SRC_POS_DECL);
595 AutoMultiWriteLock3(LockHandle *pl1,
596 LockHandle *pl2,
597 LockHandle *pl3
598 COMMA_LOCKVAL_SRC_POS_DECL);
599
600 virtual ~AutoMultiWriteLock3()
601 {
602 cleanup();
603 }
604};
605
606} /* namespace util */
607
608#endif // ____H_AUTOLOCK
609
610/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette