VirtualBox

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

Last change on this file since 36254 was 30501, checked in by vboxsync, 14 years ago

webservice: add webservice locking class, use critsects instead of rwsems in session locks

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.7 KB
Line 
1/** @file
2 *
3 * Automatic locks, implementation
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
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
27#ifndef ____H_AUTOLOCK
28#define ____H_AUTOLOCK
29
30#include <iprt/types.h>
31
32// macros for automatic lock validation; these will amount to nothing
33// unless lock validation is enabled for the runtime
34#if defined(RT_LOCK_STRICT)
35# define VBOX_WITH_MAIN_LOCK_VALIDATION
36# define COMMA_LOCKVAL_SRC_POS , RT_SRC_POS
37# define LOCKVAL_SRC_POS_DECL RT_SRC_POS_DECL
38# define COMMA_LOCKVAL_SRC_POS_DECL , RT_SRC_POS_DECL
39# define LOCKVAL_SRC_POS_ARGS RT_SRC_POS_ARGS
40# define COMMA_LOCKVAL_SRC_POS_ARGS , RT_SRC_POS_ARGS
41#else
42# define COMMA_LOCKVAL_SRC_POS
43# define LOCKVAL_SRC_POS_DECL
44# define COMMA_LOCKVAL_SRC_POS_DECL
45# define LOCKVAL_SRC_POS_ARGS
46# define COMMA_LOCKVAL_SRC_POS_ARGS
47#endif
48
49namespace util
50{
51
52////////////////////////////////////////////////////////////////////////////////
53//
54// Order classes for lock validation
55//
56////////////////////////////////////////////////////////////////////////////////
57
58/**
59 * IPRT now has a sophisticated system of run-time locking classes to validate
60 * locking order. Since the Main code is handled by simpler minds, we want
61 * compile-time constants for simplicity, and we'll look up the run-time classes
62 * in AutoLock.cpp transparently. These are passed to the constructors of the
63 * LockHandle classes.
64 */
65enum VBoxLockingClass
66{
67 LOCKCLASS_NONE = 0,
68 LOCKCLASS_WEBSERVICE = 1, // highest order: webservice locks
69 LOCKCLASS_VIRTUALBOXOBJECT = 2, // highest order within Main itself: VirtualBox object lock
70 LOCKCLASS_HOSTOBJECT = 3, // Host object lock
71 LOCKCLASS_LISTOFMACHINES = 4, // list of machines in VirtualBox object
72 LOCKCLASS_MACHINEOBJECT = 5, // Machine object lock
73 LOCKCLASS_SNAPSHOTOBJECT = 6, // snapshot object locks
74 // (the snapshots tree, including the child pointers in Snapshot,
75 // is protected by the normal Machine object lock)
76 LOCKCLASS_LISTOFMEDIA = 7, // list of media (hard disks, DVDs, floppies) in VirtualBox object
77 LOCKCLASS_LISTOFOTHEROBJECTS = 8, // any other list of objects
78 LOCKCLASS_OTHEROBJECT = 9, // any regular object member variable lock
79 LOCKCLASS_USBLIST = 10, // temporary hack to avoid having to clean up the USB filters
80 // too much @todo r=dj get rid of this!
81 LOCKCLASS_PROGRESSLIST = 11, // list of progress objects in VirtualBox; no other object lock
82 // may be held after this!
83 LOCKCLASS_OBJECTSTATE = 12 // object state lock (handled by AutoCaller classes)
84};
85
86void InitAutoLockSystem();
87
88/**
89 * Check whether the current thread holds any locks in the given class
90 *
91 * @return true if any such locks are held, false otherwise. If the lock
92 * validator is not compiled in, always returns false.
93 * @param lockClass Which lock class to check.
94 */
95bool AutoLockHoldsLocksInClass(VBoxLockingClass lockClass);
96
97////////////////////////////////////////////////////////////////////////////////
98//
99// LockHandle and friends
100//
101////////////////////////////////////////////////////////////////////////////////
102
103/**
104 * Abstract base class for semaphore handles (RWLockHandle and WriteLockHandle).
105 * Don't use this directly, but this implements lock validation for them.
106 */
107class LockHandle
108{
109public:
110 LockHandle()
111 {}
112
113 virtual ~LockHandle()
114 {}
115
116 /**
117 * Returns @c true if the current thread holds a write lock on this
118 * read/write semaphore. Intended for debugging only.
119 */
120 virtual bool isWriteLockOnCurrentThread() const = 0;
121
122 /**
123 * Returns the current write lock level of this semaphore. The lock level
124 * determines the number of nested #lock() calls on the given semaphore
125 * handle.
126 *
127 * Note that this call is valid only when the current thread owns a write
128 * lock on the given semaphore handle and will assert otherwise.
129 */
130 virtual uint32_t writeLockLevel() const = 0;
131
132 virtual void lockWrite(LOCKVAL_SRC_POS_DECL) = 0;
133 virtual void unlockWrite() = 0;
134 virtual void lockRead(LOCKVAL_SRC_POS_DECL) = 0;
135 virtual void unlockRead() = 0;
136
137#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
138 virtual const char* describe() const = 0;
139#endif
140
141private:
142 // prohibit copy + assignment
143 LockHandle(const LockHandle&);
144 LockHandle& operator=(const LockHandle&);
145};
146
147/**
148 * Full-featured read/write semaphore handle implementation.
149 *
150 * This is an auxiliary base class for classes that need full-featured
151 * read/write locking as described in the AutoWriteLock class documentation.
152 * Instances of classes inherited from this class can be passed as arguments to
153 * the AutoWriteLock and AutoReadLock constructors.
154 */
155class RWLockHandle : public LockHandle
156{
157public:
158 RWLockHandle(VBoxLockingClass lockClass);
159 virtual ~RWLockHandle();
160
161 virtual bool isWriteLockOnCurrentThread() const;
162
163 virtual void lockWrite(LOCKVAL_SRC_POS_DECL);
164 virtual void unlockWrite();
165 virtual void lockRead(LOCKVAL_SRC_POS_DECL);
166 virtual void unlockRead();
167
168 virtual uint32_t writeLockLevel() const;
169
170#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
171 virtual const char* describe() const;
172#endif
173
174private:
175 struct Data;
176 Data *m;
177};
178
179/**
180 * Write-only semaphore handle implementation.
181 *
182 * This is an auxiliary base class for classes that need write-only (exclusive)
183 * locking and do not need read (shared) locking. This implementation uses a
184 * cheap and fast critical section for both lockWrite() and lockRead() methods
185 * which makes a lockRead() call fully equivalent to the lockWrite() call and
186 * therefore makes it pointless to use instahces of this class with
187 * AutoReadLock instances -- shared locking will not be possible anyway and
188 * any call to lock() will block if there are lock owners on other threads.
189 *
190 * Use with care only when absolutely sure that shared locks are not necessary.
191 */
192class WriteLockHandle : public LockHandle
193{
194public:
195 WriteLockHandle(VBoxLockingClass lockClass);
196 virtual ~WriteLockHandle();
197 virtual bool isWriteLockOnCurrentThread() const;
198
199 virtual void lockWrite(LOCKVAL_SRC_POS_DECL);
200 virtual void unlockWrite();
201 virtual void lockRead(LOCKVAL_SRC_POS_DECL);
202 virtual void unlockRead();
203 virtual uint32_t writeLockLevel() const;
204
205#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
206 virtual const char* describe() const;
207#endif
208
209private:
210 struct Data;
211 Data *m;
212};
213
214////////////////////////////////////////////////////////////////////////////////
215//
216// Lockable
217//
218////////////////////////////////////////////////////////////////////////////////
219
220/**
221 * Lockable interface.
222 *
223 * This is an abstract base for classes that need read/write locking. Unlike
224 * RWLockHandle and other classes that makes the read/write semaphore a part of
225 * class data, this class allows subclasses to decide which semaphore handle to
226 * use.
227 */
228class Lockable
229{
230public:
231
232 /**
233 * Returns a pointer to a LockHandle used by AutoWriteLock/AutoReadLock
234 * for locking. Subclasses are allowed to return @c NULL -- in this case,
235 * the AutoWriteLock/AutoReadLock object constructed using an instance of
236 * such subclass will simply turn into no-op.
237 */
238 virtual LockHandle *lockHandle() const = 0;
239
240 /**
241 * Equivalent to <tt>#lockHandle()->isWriteLockOnCurrentThread()</tt>.
242 * Returns @c false if lockHandle() returns @c NULL.
243 */
244 bool isWriteLockOnCurrentThread()
245 {
246 LockHandle *h = lockHandle();
247 return h ? h->isWriteLockOnCurrentThread() : false;
248 }
249};
250
251////////////////////////////////////////////////////////////////////////////////
252//
253// AutoLockBase
254//
255////////////////////////////////////////////////////////////////////////////////
256
257/**
258 * Abstract base class for all autolocks.
259 *
260 * This cannot be used directly. Use AutoReadLock or AutoWriteLock or AutoMultiWriteLock2/3
261 * which directly and indirectly derive from this.
262 *
263 * In the implementation, the instance data contains a list of lock handles.
264 * The class provides some utility functions to help locking and unlocking
265 * them.
266 */
267
268class AutoLockBase
269{
270protected:
271 AutoLockBase(uint32_t cHandles
272 COMMA_LOCKVAL_SRC_POS_DECL);
273 AutoLockBase(uint32_t cHandles,
274 LockHandle *pHandle
275 COMMA_LOCKVAL_SRC_POS_DECL);
276 virtual ~AutoLockBase();
277
278 struct Data;
279 Data *m;
280
281 virtual void callLockImpl(LockHandle &l) = 0;
282 virtual void callUnlockImpl(LockHandle &l) = 0;
283
284 void callLockOnAllHandles();
285 void callUnlockOnAllHandles();
286
287 void cleanup();
288
289public:
290 void acquire();
291 void release();
292
293private:
294 // prohibit copy + assignment
295 AutoLockBase(const AutoLockBase&);
296 AutoLockBase& operator=(const AutoLockBase&);
297};
298
299////////////////////////////////////////////////////////////////////////////////
300//
301// AutoReadLock
302//
303////////////////////////////////////////////////////////////////////////////////
304
305/**
306 * Automatic read lock. Use this with a RWLockHandle to request a read/write
307 * semaphore in read mode. You can also use this with a WriteLockHandle but
308 * that makes little sense since they treat read mode like write mode.
309 *
310 * If constructed with a RWLockHandle or an instance of Lockable (which in
311 * practice means any VirtualBoxBase derivative), it autoamtically requests
312 * the lock in read mode and releases the read lock in the destructor.
313 */
314class AutoReadLock : public AutoLockBase
315{
316public:
317
318 /**
319 * Constructs a null instance that does not manage any read/write
320 * semaphore.
321 *
322 * Note that all method calls on a null instance are no-ops. This allows to
323 * have the code where lock protection can be selected (or omitted) at
324 * runtime.
325 */
326 AutoReadLock(LOCKVAL_SRC_POS_DECL)
327 : AutoLockBase(1,
328 NULL
329 COMMA_LOCKVAL_SRC_POS_ARGS)
330 { }
331
332 /**
333 * Constructs a new instance that will start managing the given read/write
334 * semaphore by requesting a read lock.
335 */
336 AutoReadLock(LockHandle *aHandle
337 COMMA_LOCKVAL_SRC_POS_DECL)
338 : AutoLockBase(1,
339 aHandle
340 COMMA_LOCKVAL_SRC_POS_ARGS)
341 {
342 acquire();
343 }
344
345 /**
346 * Constructs a new instance that will start managing the given read/write
347 * semaphore by requesting a read lock.
348 */
349 AutoReadLock(LockHandle &aHandle
350 COMMA_LOCKVAL_SRC_POS_DECL)
351 : AutoLockBase(1,
352 &aHandle
353 COMMA_LOCKVAL_SRC_POS_ARGS)
354 {
355 acquire();
356 }
357
358 /**
359 * Constructs a new instance that will start managing the given read/write
360 * semaphore by requesting a read lock.
361 */
362 AutoReadLock(const Lockable &aLockable
363 COMMA_LOCKVAL_SRC_POS_DECL)
364 : AutoLockBase(1,
365 aLockable.lockHandle()
366 COMMA_LOCKVAL_SRC_POS_ARGS)
367 {
368 acquire();
369 }
370
371 /**
372 * Constructs a new instance that will start managing the given read/write
373 * semaphore by requesting a read lock.
374 */
375 AutoReadLock(const Lockable *aLockable
376 COMMA_LOCKVAL_SRC_POS_DECL)
377 : AutoLockBase(1,
378 aLockable ? aLockable->lockHandle() : NULL
379 COMMA_LOCKVAL_SRC_POS_ARGS)
380 {
381 acquire();
382 }
383
384 virtual ~AutoReadLock();
385
386 virtual void callLockImpl(LockHandle &l);
387 virtual void callUnlockImpl(LockHandle &l);
388};
389
390////////////////////////////////////////////////////////////////////////////////
391//
392// AutoWriteLockBase
393//
394////////////////////////////////////////////////////////////////////////////////
395
396/**
397 * Base class for all auto write locks.
398 *
399 * This cannot be used directly. Use AutoWriteLock or AutoMultiWriteLock2/3
400 * which derive from this.
401 *
402 * In addition to utility methods for subclasses, this implements the public
403 * leave/enter methods, which are common to all
404 * write locks.
405 */
406class AutoWriteLockBase : public AutoLockBase
407{
408protected:
409 AutoWriteLockBase(uint32_t cHandles
410 COMMA_LOCKVAL_SRC_POS_DECL)
411 : AutoLockBase(cHandles
412 COMMA_LOCKVAL_SRC_POS_ARGS)
413 { }
414
415 AutoWriteLockBase(uint32_t cHandles,
416 LockHandle *pHandle
417 COMMA_LOCKVAL_SRC_POS_DECL)
418 : AutoLockBase(cHandles,
419 pHandle
420 COMMA_LOCKVAL_SRC_POS_ARGS)
421 { }
422
423 virtual ~AutoWriteLockBase()
424 { }
425
426 virtual void callLockImpl(LockHandle &l);
427 virtual void callUnlockImpl(LockHandle &l);
428
429public:
430 void leave();
431 void enter();
432};
433
434////////////////////////////////////////////////////////////////////////////////
435//
436// AutoWriteLock
437//
438////////////////////////////////////////////////////////////////////////////////
439
440/**
441 * Automatic write lock. Use this with a RWLockHandle to request a read/write
442 * semaphore in write mode. There can only ever be one writer of a read/write
443 * semaphore: while the lock is held in write mode, no other writer or reader
444 * can request the semaphore and will block.
445 *
446 * If constructed with a RWLockHandle or an instance of Lockable (which in
447 * practice means any VirtualBoxBase derivative), it autoamtically requests
448 * the lock in write mode and releases the write lock in the destructor.
449 *
450 * When used with a WriteLockHandle, it requests the semaphore contained therein
451 * exclusively.
452 */
453class AutoWriteLock : public AutoWriteLockBase
454{
455public:
456
457 /**
458 * Constructs a null instance that does not manage any read/write
459 * semaphore.
460 *
461 * Note that all method calls on a null instance are no-ops. This allows to
462 * have the code where lock protection can be selected (or omitted) at
463 * runtime.
464 */
465 AutoWriteLock(LOCKVAL_SRC_POS_DECL)
466 : AutoWriteLockBase(1,
467 NULL
468 COMMA_LOCKVAL_SRC_POS_ARGS)
469 { }
470
471 /**
472 * Constructs a new instance that will start managing the given read/write
473 * semaphore by requesting a write lock.
474 */
475 AutoWriteLock(LockHandle *aHandle
476 COMMA_LOCKVAL_SRC_POS_DECL)
477 : AutoWriteLockBase(1,
478 aHandle
479 COMMA_LOCKVAL_SRC_POS_ARGS)
480 {
481 acquire();
482 }
483
484 /**
485 * Constructs a new instance that will start managing the given read/write
486 * semaphore by requesting a write lock.
487 */
488 AutoWriteLock(LockHandle &aHandle
489 COMMA_LOCKVAL_SRC_POS_DECL)
490 : AutoWriteLockBase(1,
491 &aHandle
492 COMMA_LOCKVAL_SRC_POS_ARGS)
493 {
494 acquire();
495 }
496
497 /**
498 * Constructs a new instance that will start managing the given read/write
499 * semaphore by requesting a write lock.
500 */
501 AutoWriteLock(const Lockable &aLockable
502 COMMA_LOCKVAL_SRC_POS_DECL)
503 : AutoWriteLockBase(1,
504 aLockable.lockHandle()
505 COMMA_LOCKVAL_SRC_POS_ARGS)
506 {
507 acquire();
508 }
509
510 /**
511 * Constructs a new instance that will start managing the given read/write
512 * semaphore by requesting a write lock.
513 */
514 AutoWriteLock(const Lockable *aLockable
515 COMMA_LOCKVAL_SRC_POS_DECL)
516 : AutoWriteLockBase(1,
517 aLockable ? aLockable->lockHandle() : NULL
518 COMMA_LOCKVAL_SRC_POS_ARGS)
519 {
520 acquire();
521 }
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} /* namespace util */
610
611#endif // ____H_AUTOLOCK
612
613/* 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