VirtualBox

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

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

Autolock.h: Only test for RT_LOCK_STRICT because we want lock validation and lock details for main in strict builds and not only debug builds.

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

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