VirtualBox

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

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

Main: remove the evil Auto*Lock*::maybeEnter() function which is no longer used by the media task code now

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.6 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 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};
429
430////////////////////////////////////////////////////////////////////////////////
431//
432// AutoWriteLock
433//
434////////////////////////////////////////////////////////////////////////////////
435
436/**
437 * Automatic write lock. Use this with a RWLockHandle to request a read/write
438 * semaphore in write mode. There can only ever be one writer of a read/write
439 * semaphore: while the lock is held in write mode, no other writer or reader
440 * can request the semaphore and will block.
441 *
442 * If constructed with a RWLockHandle or an instance of Lockable (which in
443 * practice means any VirtualBoxBase derivative), it autoamtically requests
444 * the lock in write mode and releases the write lock in the destructor.
445 *
446 * When used with a WriteLockHandle, it requests the semaphore contained therein
447 * exclusively.
448 */
449class AutoWriteLock : public AutoWriteLockBase
450{
451public:
452
453 /**
454 * Constructs a null instance that does not manage any read/write
455 * semaphore.
456 *
457 * Note that all method calls on a null instance are no-ops. This allows to
458 * have the code where lock protection can be selected (or omitted) at
459 * runtime.
460 */
461 AutoWriteLock(LOCKVAL_SRC_POS_DECL)
462 : AutoWriteLockBase(1,
463 NULL
464 COMMA_LOCKVAL_SRC_POS_ARGS)
465 { }
466
467 /**
468 * Constructs a new instance that will start managing the given read/write
469 * semaphore by requesting a write lock.
470 */
471 AutoWriteLock(LockHandle *aHandle
472 COMMA_LOCKVAL_SRC_POS_DECL)
473 : AutoWriteLockBase(1,
474 aHandle
475 COMMA_LOCKVAL_SRC_POS_ARGS)
476 {
477 acquire();
478 }
479
480 /**
481 * Constructs a new instance that will start managing the given read/write
482 * semaphore by requesting a write lock.
483 */
484 AutoWriteLock(LockHandle &aHandle
485 COMMA_LOCKVAL_SRC_POS_DECL)
486 : AutoWriteLockBase(1,
487 &aHandle
488 COMMA_LOCKVAL_SRC_POS_ARGS)
489 {
490 acquire();
491 }
492
493 /**
494 * Constructs a new instance that will start managing the given read/write
495 * semaphore by requesting a write lock.
496 */
497 AutoWriteLock(const Lockable &aLockable
498 COMMA_LOCKVAL_SRC_POS_DECL)
499 : AutoWriteLockBase(1,
500 aLockable.lockHandle()
501 COMMA_LOCKVAL_SRC_POS_ARGS)
502 {
503 acquire();
504 }
505
506 /**
507 * Constructs a new instance that will start managing the given read/write
508 * semaphore by requesting a write lock.
509 */
510 AutoWriteLock(const Lockable *aLockable
511 COMMA_LOCKVAL_SRC_POS_DECL)
512 : AutoWriteLockBase(1,
513 aLockable ? aLockable->lockHandle() : NULL
514 COMMA_LOCKVAL_SRC_POS_ARGS)
515 {
516 acquire();
517 }
518
519 /**
520 * Release all write locks acquired by this instance through the #lock()
521 * call and destroys the instance.
522 *
523 * Note that if there there are nested #lock() calls without the
524 * corresponding number of #unlock() calls when the destructor is called, it
525 * will assert. This is because having an unbalanced number of nested locks
526 * is a program logic error which must be fixed.
527 */
528 virtual ~AutoWriteLock()
529 {
530 cleanup();
531 }
532
533 void attach(LockHandle *aHandle);
534
535 /** @see attach (LockHandle *) */
536 void attach(LockHandle &aHandle)
537 {
538 attach(&aHandle);
539 }
540
541 /** @see attach (LockHandle *) */
542 void attach(const Lockable &aLockable)
543 {
544 attach(aLockable.lockHandle());
545 }
546
547 /** @see attach (LockHandle *) */
548 void attach(const Lockable *aLockable)
549 {
550 attach(aLockable ? aLockable->lockHandle() : NULL);
551 }
552
553 bool isWriteLockOnCurrentThread() const;
554 uint32_t writeLockLevel() const;
555};
556
557////////////////////////////////////////////////////////////////////////////////
558//
559// AutoMultiWriteLock*
560//
561////////////////////////////////////////////////////////////////////////////////
562
563/**
564 * A multi-write-lock containing two other write locks.
565 *
566 */
567class AutoMultiWriteLock2 : public AutoWriteLockBase
568{
569public:
570 AutoMultiWriteLock2(Lockable *pl1,
571 Lockable *pl2
572 COMMA_LOCKVAL_SRC_POS_DECL);
573 AutoMultiWriteLock2(LockHandle *pl1,
574 LockHandle *pl2
575 COMMA_LOCKVAL_SRC_POS_DECL);
576
577 virtual ~AutoMultiWriteLock2()
578 {
579 cleanup();
580 }
581};
582
583/**
584 * A multi-write-lock containing three other write locks.
585 *
586 */
587class AutoMultiWriteLock3 : public AutoWriteLockBase
588{
589public:
590 AutoMultiWriteLock3(Lockable *pl1,
591 Lockable *pl2,
592 Lockable *pl3
593 COMMA_LOCKVAL_SRC_POS_DECL);
594 AutoMultiWriteLock3(LockHandle *pl1,
595 LockHandle *pl2,
596 LockHandle *pl3
597 COMMA_LOCKVAL_SRC_POS_DECL);
598
599 virtual ~AutoMultiWriteLock3()
600 {
601 cleanup();
602 }
603};
604
605} /* namespace util */
606
607#endif // ____H_AUTOLOCK
608
609/* 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