VirtualBox

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

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

Main: remove separate snapshots tree lock, have snapshots list use machine lock instead

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