VirtualBox

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

Last change on this file since 52664 was 45126, checked in by vboxsync, 11 years ago

block fix.

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