VirtualBox

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

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

Main: remove unused and broken autolock code

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