VirtualBox

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

Last change on this file since 63147 was 63147, checked in by vboxsync, 8 years ago

Main: warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.2 KB
Line 
1/** @file
2 * MS COM / XPCOM Abstraction Layer - Automatic locks, implementation.
3 */
4
5/*
6 * Copyright (C) 2006-2016 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
32/** @defgroup grp_com_autolock Automatic Locks
33 * @ingroup grp_com
34 * @{
35 */
36
37// macros for automatic lock validation; these will amount to nothing
38// unless lock validation is enabled for the runtime
39#if defined(RT_LOCK_STRICT)
40# define VBOX_WITH_MAIN_LOCK_VALIDATION
41# define COMMA_LOCKVAL_SRC_POS , RT_SRC_POS
42# define LOCKVAL_SRC_POS_DECL RT_SRC_POS_DECL
43# define COMMA_LOCKVAL_SRC_POS_DECL , RT_SRC_POS_DECL
44# define LOCKVAL_SRC_POS_ARGS RT_SRC_POS_ARGS
45# define COMMA_LOCKVAL_SRC_POS_ARGS , RT_SRC_POS_ARGS
46#else
47# define COMMA_LOCKVAL_SRC_POS
48# define LOCKVAL_SRC_POS_DECL
49# define COMMA_LOCKVAL_SRC_POS_DECL
50# define LOCKVAL_SRC_POS_ARGS
51# define COMMA_LOCKVAL_SRC_POS_ARGS
52#endif
53
54namespace util
55{
56
57////////////////////////////////////////////////////////////////////////////////
58//
59// Order classes for lock validation
60//
61////////////////////////////////////////////////////////////////////////////////
62
63/**
64 * IPRT now has a sophisticated system of run-time locking classes to validate
65 * locking order. Since the Main code is handled by simpler minds, we want
66 * compile-time constants for simplicity, and we'll look up the run-time classes
67 * in AutoLock.cpp transparently. These are passed to the constructors of the
68 * LockHandle classes.
69 */
70enum VBoxLockingClass
71{
72 LOCKCLASS_NONE = 0,
73 LOCKCLASS_WEBSERVICE = 1, // highest order: webservice locks
74 LOCKCLASS_VIRTUALBOXOBJECT = 2, // highest order within Main itself: VirtualBox object lock
75 LOCKCLASS_HOSTOBJECT = 3, // Host object lock
76 LOCKCLASS_LISTOFMACHINES = 4, // list of machines in VirtualBox object
77 LOCKCLASS_MACHINEOBJECT = 5, // Machine object lock
78 LOCKCLASS_SNAPSHOTOBJECT = 6, // snapshot object locks
79 // (the snapshots tree, including the child pointers in Snapshot,
80 // is protected by the normal Machine object lock)
81 LOCKCLASS_MEDIUMQUERY = 7, // lock used to protect Machine::queryInfo
82 LOCKCLASS_LISTOFMEDIA = 8, // list of media (hard disks, DVDs, floppies) in VirtualBox object
83 LOCKCLASS_LISTOFOTHEROBJECTS = 9, // any other list of objects
84 LOCKCLASS_OTHEROBJECT = 10, // any regular object member variable lock
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 * Check whether the current thread holds any locks in the given class
94 *
95 * @return true if any such locks are held, false otherwise. If the lock
96 * validator is not compiled in, always returns false.
97 * @param lockClass Which lock class to check.
98 */
99bool AutoLockHoldsLocksInClass(VBoxLockingClass lockClass);
100
101////////////////////////////////////////////////////////////////////////////////
102//
103// LockHandle and friends
104//
105////////////////////////////////////////////////////////////////////////////////
106
107/**
108 * Abstract base class for semaphore handles (RWLockHandle and WriteLockHandle).
109 * Don't use this directly, but this implements lock validation for them.
110 */
111class LockHandle
112{
113public:
114 LockHandle()
115 {}
116
117 virtual ~LockHandle()
118 {}
119
120 /**
121 * Returns @c true if the current thread holds a write lock on this
122 * read/write semaphore. Intended for debugging only.
123 */
124 virtual bool isWriteLockOnCurrentThread() const = 0;
125
126 /**
127 * Returns the current write lock level of this semaphore. The lock level
128 * determines the number of nested #lockWrite() calls on the given
129 * semaphore handle.
130 *
131 * Note that this call is valid only when the current thread owns a write
132 * lock on the given semaphore handle and will assert otherwise.
133 */
134 virtual uint32_t writeLockLevel() const = 0;
135
136 virtual void lockWrite(LOCKVAL_SRC_POS_DECL) = 0;
137 virtual void unlockWrite() = 0;
138 virtual void lockRead(LOCKVAL_SRC_POS_DECL) = 0;
139 virtual void unlockRead() = 0;
140
141#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
142 virtual const char* describe() const = 0;
143#endif
144
145private:
146 // prohibit copy + assignment
147 LockHandle(const LockHandle&);
148 LockHandle& operator=(const LockHandle&);
149};
150
151/**
152 * Full-featured read/write semaphore handle implementation.
153 *
154 * This is an auxiliary base class for classes that need full-featured
155 * read/write locking as described in the AutoWriteLock class documentation.
156 * Instances of classes inherited from this class can be passed as arguments to
157 * the AutoWriteLock and AutoReadLock constructors.
158 */
159class RWLockHandle : public LockHandle
160{
161public:
162 RWLockHandle(VBoxLockingClass lockClass);
163 virtual ~RWLockHandle();
164
165 virtual bool isWriteLockOnCurrentThread() const;
166
167 virtual void lockWrite(LOCKVAL_SRC_POS_DECL);
168 virtual void unlockWrite();
169 virtual void lockRead(LOCKVAL_SRC_POS_DECL);
170 virtual void unlockRead();
171
172 virtual uint32_t writeLockLevel() const;
173
174#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
175 virtual const char* describe() const;
176#endif
177
178private:
179 struct Data;
180 Data *m;
181
182 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(RWLockHandle); /* Shuts up MSC warning C4625. */
183};
184
185/**
186 * Write-only semaphore handle implementation.
187 *
188 * This is an auxiliary base class for classes that need write-only (exclusive)
189 * locking and do not need read (shared) locking. This implementation uses a
190 * cheap and fast critical section for both lockWrite() and lockRead() methods
191 * which makes a lockRead() call fully equivalent to the lockWrite() call and
192 * therefore makes it pointless to use instahces of this class with
193 * AutoReadLock instances -- shared locking will not be possible anyway and
194 * any call to lock() will block if there are lock owners on other threads.
195 *
196 * Use with care only when absolutely sure that shared locks are not necessary.
197 */
198class WriteLockHandle : public LockHandle
199{
200public:
201 WriteLockHandle(VBoxLockingClass lockClass);
202 virtual ~WriteLockHandle();
203 virtual bool isWriteLockOnCurrentThread() const;
204
205 virtual void lockWrite(LOCKVAL_SRC_POS_DECL);
206 virtual void unlockWrite();
207 virtual void lockRead(LOCKVAL_SRC_POS_DECL);
208 virtual void unlockRead();
209 virtual uint32_t writeLockLevel() const;
210
211#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
212 virtual const char* describe() const;
213#endif
214
215private:
216 struct Data;
217 Data *m;
218
219 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(WriteLockHandle); /* Shuts up MSC warning C4625. */
220};
221
222////////////////////////////////////////////////////////////////////////////////
223//
224// Lockable
225//
226////////////////////////////////////////////////////////////////////////////////
227
228/**
229 * Lockable interface.
230 *
231 * This is an abstract base for classes that need read/write locking. Unlike
232 * RWLockHandle and other classes that makes the read/write semaphore a part of
233 * class data, this class allows subclasses to decide which semaphore handle to
234 * use.
235 */
236class Lockable
237{
238public:
239
240 /**
241 * Returns a pointer to a LockHandle used by AutoWriteLock/AutoReadLock
242 * for locking. Subclasses are allowed to return @c NULL -- in this case,
243 * the AutoWriteLock/AutoReadLock object constructed using an instance of
244 * such subclass will simply turn into no-op.
245 */
246 virtual LockHandle *lockHandle() const = 0;
247
248 /**
249 * Equivalent to <tt>#lockHandle()->isWriteLockOnCurrentThread()</tt>.
250 * Returns @c false if lockHandle() returns @c NULL.
251 */
252 bool isWriteLockOnCurrentThread()
253 {
254 LockHandle *h = lockHandle();
255 return h ? h->isWriteLockOnCurrentThread() : false;
256 }
257};
258
259////////////////////////////////////////////////////////////////////////////////
260//
261// AutoLockBase
262//
263////////////////////////////////////////////////////////////////////////////////
264
265/**
266 * Abstract base class for all autolocks.
267 *
268 * This cannot be used directly. Use AutoReadLock or AutoWriteLock or AutoMultiWriteLock2/3
269 * which directly and indirectly derive from this.
270 *
271 * In the implementation, the instance data contains a list of lock handles.
272 * The class provides some utility functions to help locking and unlocking
273 * them.
274 */
275
276class AutoLockBase
277{
278protected:
279 AutoLockBase(uint32_t cHandles
280 COMMA_LOCKVAL_SRC_POS_DECL);
281 AutoLockBase(uint32_t cHandles,
282 LockHandle *pHandle
283 COMMA_LOCKVAL_SRC_POS_DECL);
284 virtual ~AutoLockBase();
285
286 struct Data;
287 Data *m;
288
289 virtual void callLockImpl(LockHandle &l) = 0;
290 virtual void callUnlockImpl(LockHandle &l) = 0;
291
292 void callLockOnAllHandles();
293 void callUnlockOnAllHandles();
294
295 void cleanup();
296
297public:
298 void acquire();
299 void release();
300
301private:
302 // prohibit copy + assignment
303 AutoLockBase(const AutoLockBase&);
304 AutoLockBase& operator=(const AutoLockBase&);
305};
306
307////////////////////////////////////////////////////////////////////////////////
308//
309// AutoReadLock
310//
311////////////////////////////////////////////////////////////////////////////////
312
313/**
314 * Automatic read lock. Use this with a RWLockHandle to request a read/write
315 * semaphore in read mode. You can also use this with a WriteLockHandle but
316 * that makes little sense since they treat read mode like write mode.
317 *
318 * If constructed with a RWLockHandle or an instance of Lockable (which in
319 * practice means any VirtualBoxBase derivative), it autoamtically requests
320 * the lock in read mode and releases the read lock in the destructor.
321 */
322class AutoReadLock : public AutoLockBase
323{
324public:
325
326 /**
327 * Constructs a null instance that does not manage any read/write
328 * semaphore.
329 *
330 * Note that all method calls on a null instance are no-ops. This allows to
331 * have the code where lock protection can be selected (or omitted) at
332 * runtime.
333 */
334 AutoReadLock(LOCKVAL_SRC_POS_DECL)
335 : AutoLockBase(1,
336 NULL
337 COMMA_LOCKVAL_SRC_POS_ARGS)
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(LockHandle &aHandle
358 COMMA_LOCKVAL_SRC_POS_DECL)
359 : AutoLockBase(1,
360 &aHandle
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.lockHandle()
374 COMMA_LOCKVAL_SRC_POS_ARGS)
375 {
376 acquire();
377 }
378
379 /**
380 * Constructs a new instance that will start managing the given read/write
381 * semaphore by requesting a read lock.
382 */
383 AutoReadLock(const Lockable *aLockable
384 COMMA_LOCKVAL_SRC_POS_DECL)
385 : AutoLockBase(1,
386 aLockable ? aLockable->lockHandle() : NULL
387 COMMA_LOCKVAL_SRC_POS_ARGS)
388 {
389 acquire();
390 }
391
392 virtual ~AutoReadLock();
393
394 virtual void callLockImpl(LockHandle &l);
395 virtual void callUnlockImpl(LockHandle &l);
396
397private:
398 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoReadLock); /* Shuts up MSC warning C4625. */
399};
400
401////////////////////////////////////////////////////////////////////////////////
402//
403// AutoWriteLockBase
404//
405////////////////////////////////////////////////////////////////////////////////
406
407/**
408 * Base class for all auto write locks.
409 *
410 * This cannot be used directly. Use AutoWriteLock or AutoMultiWriteLock2/3
411 * which derive from this.
412 *
413 * It has some utility methods for subclasses.
414 */
415class AutoWriteLockBase : public AutoLockBase
416{
417protected:
418 AutoWriteLockBase(uint32_t cHandles
419 COMMA_LOCKVAL_SRC_POS_DECL)
420 : AutoLockBase(cHandles
421 COMMA_LOCKVAL_SRC_POS_ARGS)
422 { }
423
424 AutoWriteLockBase(uint32_t cHandles,
425 LockHandle *pHandle
426 COMMA_LOCKVAL_SRC_POS_DECL)
427 : AutoLockBase(cHandles,
428 pHandle
429 COMMA_LOCKVAL_SRC_POS_ARGS)
430 { }
431
432 virtual ~AutoWriteLockBase()
433 { }
434
435 virtual void callLockImpl(LockHandle &l);
436 virtual void callUnlockImpl(LockHandle &l);
437
438private:
439 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoWriteLockBase); /* Shuts up MSC warning C4625. */
440};
441
442////////////////////////////////////////////////////////////////////////////////
443//
444// AutoWriteLock
445//
446////////////////////////////////////////////////////////////////////////////////
447
448/**
449 * Automatic write lock. Use this with a RWLockHandle to request a read/write
450 * semaphore in write mode. There can only ever be one writer of a read/write
451 * semaphore: while the lock is held in write mode, no other writer or reader
452 * can request the semaphore and will block.
453 *
454 * If constructed with a RWLockHandle or an instance of Lockable (which in
455 * practice means any VirtualBoxBase derivative), it autoamtically requests
456 * the lock in write mode and releases the write lock in the destructor.
457 *
458 * When used with a WriteLockHandle, it requests the semaphore contained therein
459 * exclusively.
460 */
461class AutoWriteLock : public AutoWriteLockBase
462{
463public:
464
465 /**
466 * Constructs a null instance that does not manage any read/write
467 * semaphore.
468 *
469 * Note that all method calls on a null instance are no-ops. This allows to
470 * have the code where lock protection can be selected (or omitted) at
471 * runtime.
472 */
473 AutoWriteLock(LOCKVAL_SRC_POS_DECL)
474 : AutoWriteLockBase(1,
475 NULL
476 COMMA_LOCKVAL_SRC_POS_ARGS)
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(LockHandle &aHandle
497 COMMA_LOCKVAL_SRC_POS_DECL)
498 : AutoWriteLockBase(1,
499 &aHandle
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.lockHandle()
513 COMMA_LOCKVAL_SRC_POS_ARGS)
514 {
515 acquire();
516 }
517
518 /**
519 * Constructs a new instance that will start managing the given read/write
520 * semaphore by requesting a write lock.
521 */
522 AutoWriteLock(const Lockable *aLockable
523 COMMA_LOCKVAL_SRC_POS_DECL)
524 : AutoWriteLockBase(1,
525 aLockable ? aLockable->lockHandle() : NULL
526 COMMA_LOCKVAL_SRC_POS_ARGS)
527 {
528 acquire();
529 }
530
531 /**
532 * Constructs a new instance that will start managing the given read/write
533 * semaphore by requesting a write lock.
534 */
535 AutoWriteLock(uint32_t cHandles,
536 LockHandle** pHandles
537 COMMA_LOCKVAL_SRC_POS_DECL);
538
539 /**
540 * Release all write locks acquired by this instance through the #acquire()
541 * call and destroys the instance.
542 *
543 * Note that if there there are nested #acquire() calls without the
544 * corresponding number of #release() calls when the destructor is called, it
545 * will assert. This is because having an unbalanced number of nested locks
546 * is a program logic error which must be fixed.
547 */
548 virtual ~AutoWriteLock()
549 {
550 cleanup();
551 }
552
553 void attach(LockHandle *aHandle);
554
555 /** @see attach (LockHandle *) */
556 void attach(LockHandle &aHandle)
557 {
558 attach(&aHandle);
559 }
560
561 /** @see attach (LockHandle *) */
562 void attach(const Lockable &aLockable)
563 {
564 attach(aLockable.lockHandle());
565 }
566
567 /** @see attach (LockHandle *) */
568 void attach(const Lockable *aLockable)
569 {
570 attach(aLockable ? aLockable->lockHandle() : NULL);
571 }
572
573 bool isWriteLockOnCurrentThread() const;
574 uint32_t writeLockLevel() const;
575
576private:
577 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoWriteLock); /* Shuts up MSC warning C4625. */
578};
579
580////////////////////////////////////////////////////////////////////////////////
581//
582// AutoMultiWriteLock*
583//
584////////////////////////////////////////////////////////////////////////////////
585
586/**
587 * A multi-write-lock containing two other write locks.
588 *
589 */
590class AutoMultiWriteLock2 : public AutoWriteLockBase
591{
592public:
593 AutoMultiWriteLock2(Lockable *pl1,
594 Lockable *pl2
595 COMMA_LOCKVAL_SRC_POS_DECL);
596 AutoMultiWriteLock2(LockHandle *pl1,
597 LockHandle *pl2
598 COMMA_LOCKVAL_SRC_POS_DECL);
599
600 virtual ~AutoMultiWriteLock2()
601 {
602 cleanup();
603 }
604
605private:
606 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock2); /* Shuts up MSC warning C4625. */
607};
608
609/**
610 * A multi-write-lock containing three other write locks.
611 *
612 */
613class AutoMultiWriteLock3 : public AutoWriteLockBase
614{
615public:
616 AutoMultiWriteLock3(Lockable *pl1,
617 Lockable *pl2,
618 Lockable *pl3
619 COMMA_LOCKVAL_SRC_POS_DECL);
620 AutoMultiWriteLock3(LockHandle *pl1,
621 LockHandle *pl2,
622 LockHandle *pl3
623 COMMA_LOCKVAL_SRC_POS_DECL);
624
625 virtual ~AutoMultiWriteLock3()
626 {
627 cleanup();
628 }
629
630private:
631 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock3); /* Shuts up MSC warning C4625. */
632};
633
634/**
635 * A multi-write-lock containing four other write locks.
636 *
637 */
638class AutoMultiWriteLock4 : public AutoWriteLockBase
639{
640public:
641 AutoMultiWriteLock4(Lockable *pl1,
642 Lockable *pl2,
643 Lockable *pl3,
644 Lockable *pl4
645 COMMA_LOCKVAL_SRC_POS_DECL);
646 AutoMultiWriteLock4(LockHandle *pl1,
647 LockHandle *pl2,
648 LockHandle *pl3,
649 LockHandle *pl4
650 COMMA_LOCKVAL_SRC_POS_DECL);
651
652 virtual ~AutoMultiWriteLock4()
653 {
654 cleanup();
655 }
656
657private:
658 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock4); /* Shuts up MSC warning C4625. */
659};
660
661} /* namespace util */
662
663/** @} */
664
665#endif
666
667/* 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