VirtualBox

source: vbox/trunk/src/VBox/Main/glue/AutoLock.cpp@ 38717

Last change on this file since 38717 was 38717, checked in by vboxsync, 13 years ago

Main/Medium+Machine+AutoLock: Integrate the queryInfo semaphore into the AutoLock infrastructure with the appropriate lock class. Adjust the locking rules for queryInfo and start propagating them up to the callers. Needs more work, but this is comparably simple: just get the mediaTree lock in the caller if the assert triggers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.2 KB
Line 
1/** @file
2 *
3 * Automatic locks, implementation
4 */
5
6/*
7 * Copyright (C) 2006-2011 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
18#include <iprt/cdefs.h>
19#include <iprt/critsect.h>
20#include <iprt/thread.h>
21#include <iprt/semaphore.h>
22
23#include <iprt/err.h>
24#include <iprt/assert.h>
25
26#if defined(RT_LOCK_STRICT)
27# include <iprt/asm.h> // for ASMReturnAddress
28#endif
29
30#include <iprt/string.h>
31#include <iprt/path.h>
32#include <iprt/stream.h>
33
34#include "VBox/com/AutoLock.h"
35#include <VBox/com/string.h>
36
37#include <vector>
38#include <list>
39#include <map>
40
41namespace util
42{
43
44////////////////////////////////////////////////////////////////////////////////
45//
46// RuntimeLockClass
47//
48////////////////////////////////////////////////////////////////////////////////
49
50#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
51typedef std::map<VBoxLockingClass, RTLOCKVALCLASS> LockValidationClassesMap;
52LockValidationClassesMap g_mapLockValidationClasses;
53#endif
54
55/**
56 * Called from initterm.cpp on process initialization (on the main thread)
57 * to give us a chance to initialize lock validation runtime data.
58 */
59void InitAutoLockSystem()
60{
61#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
62 struct
63 {
64 VBoxLockingClass cls;
65 const char *pcszDescription;
66 } aClasses[] =
67 {
68 { LOCKCLASS_VIRTUALBOXOBJECT, "1-VIRTUALBOXOBJECT" },
69 { LOCKCLASS_HOSTOBJECT, "3-HOSTOBJECT" },
70 { LOCKCLASS_LISTOFMACHINES, "4-LISTOFMACHINES" },
71 { LOCKCLASS_MACHINEOBJECT, "5-MACHINEOBJECT" },
72 { LOCKCLASS_SNAPSHOTOBJECT, "6-SNAPSHOTOBJECT" },
73 { LOCKCLASS_LISTOFMEDIA, "7-LISTOFMEDIA" },
74 { LOCKCLASS_LISTOFOTHEROBJECTS, "8-LISTOFOTHEROBJECTS" },
75 { LOCKCLASS_MEDIUMQUERY, "9-MEDIUMQUERY" },
76 { LOCKCLASS_OTHEROBJECT, "10-OTHEROBJECT" },
77 { LOCKCLASS_USBLIST, "11-USBLIST" },
78 { LOCKCLASS_PROGRESSLIST, "12-PROGRESSLIST" },
79 { LOCKCLASS_OBJECTSTATE, "13-OBJECTSTATE" }
80 };
81
82 RTLOCKVALCLASS hClass;
83 int vrc;
84 for (unsigned i = 0; i < RT_ELEMENTS(aClasses); ++i)
85 {
86 vrc = RTLockValidatorClassCreate(&hClass,
87 true, /*fAutodidact*/
88 RT_SRC_POS,
89 aClasses[i].pcszDescription);
90 AssertRC(vrc);
91
92 // teach the new class that the classes created previously can be held
93 // while the new class is being acquired
94 for (LockValidationClassesMap::iterator it = g_mapLockValidationClasses.begin();
95 it != g_mapLockValidationClasses.end();
96 ++it)
97 {
98 RTLOCKVALCLASS &canBeHeld = it->second;
99 vrc = RTLockValidatorClassAddPriorClass(hClass,
100 canBeHeld);
101 AssertRC(vrc);
102 }
103
104 // and store the new class
105 g_mapLockValidationClasses[aClasses[i].cls] = hClass;
106 }
107
108/* WriteLockHandle critsect1(LOCKCLASS_VIRTUALBOXOBJECT);
109 WriteLockHandle critsect2(LOCKCLASS_VIRTUALBOXLIST);
110
111 AutoWriteLock lock1(critsect1 COMMA_LOCKVAL_SRC_POS);
112 AutoWriteLock lock2(critsect2 COMMA_LOCKVAL_SRC_POS);*/
113#endif
114}
115
116bool AutoLockHoldsLocksInClass(VBoxLockingClass lockClass)
117{
118#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
119 return RTLockValidatorHoldsLocksInClass(NIL_RTTHREAD,
120 g_mapLockValidationClasses[lockClass]);
121#else /* !VBOX_WITH_MAIN_LOCK_VALIDATION */
122 return false;
123#endif /* !VBOX_WITH_MAIN_LOCK_VALIDATION */
124}
125
126////////////////////////////////////////////////////////////////////////////////
127//
128// RWLockHandle
129//
130////////////////////////////////////////////////////////////////////////////////
131
132struct RWLockHandle::Data
133{
134 Data()
135 { }
136
137 RTSEMRW sem;
138 VBoxLockingClass lockClass;
139
140#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
141 com::Utf8Str strDescription;
142#endif
143};
144
145RWLockHandle::RWLockHandle(VBoxLockingClass lockClass)
146{
147 m = new Data();
148
149 m->lockClass = lockClass;
150
151#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
152 m->strDescription = com::Utf8StrFmt("r/w %RCv", this);
153 int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL);
154#else
155 int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL);
156#endif
157 AssertRC(vrc);
158}
159
160/*virtual*/ RWLockHandle::~RWLockHandle()
161{
162 RTSemRWDestroy(m->sem);
163 delete m;
164}
165
166/*virtual*/ bool RWLockHandle::isWriteLockOnCurrentThread() const
167{
168 return RTSemRWIsWriteOwner(m->sem);
169}
170
171/*virtual*/ void RWLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL)
172{
173#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
174 int vrc = RTSemRWRequestWriteDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
175#else
176 int vrc = RTSemRWRequestWrite(m->sem, RT_INDEFINITE_WAIT);
177#endif
178 AssertRC(vrc);
179}
180
181/*virtual*/ void RWLockHandle::unlockWrite()
182{
183 int vrc = RTSemRWReleaseWrite(m->sem);
184 AssertRC(vrc);
185
186}
187
188/*virtual*/ void RWLockHandle::lockRead(LOCKVAL_SRC_POS_DECL)
189{
190#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
191 int vrc = RTSemRWRequestReadDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
192#else
193 int vrc = RTSemRWRequestRead(m->sem, RT_INDEFINITE_WAIT);
194#endif
195 AssertRC(vrc);
196}
197
198/*virtual*/ void RWLockHandle::unlockRead()
199{
200 int vrc = RTSemRWReleaseRead(m->sem);
201 AssertRC(vrc);
202}
203
204/*virtual*/ uint32_t RWLockHandle::writeLockLevel() const
205{
206 /* Note! This does not include read recursions done by the writer! */
207 return RTSemRWGetWriteRecursion(m->sem);
208}
209
210#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
211/*virtual*/ const char* RWLockHandle::describe() const
212{
213 return m->strDescription.c_str();
214}
215#endif
216
217////////////////////////////////////////////////////////////////////////////////
218//
219// WriteLockHandle
220//
221////////////////////////////////////////////////////////////////////////////////
222
223struct WriteLockHandle::Data
224{
225 Data()
226 { }
227
228 mutable RTCRITSECT sem;
229 VBoxLockingClass lockClass;
230
231#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
232 com::Utf8Str strDescription;
233#endif
234};
235
236WriteLockHandle::WriteLockHandle(VBoxLockingClass lockClass)
237{
238 m = new Data;
239
240 m->lockClass = lockClass;
241
242#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
243 m->strDescription = com::Utf8StrFmt("crit %RCv", this);
244 int vrc = RTCritSectInitEx(&m->sem, 0/*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL);
245#else
246 int vrc = RTCritSectInitEx(&m->sem, 0/*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL);
247#endif
248 AssertRC(vrc);
249}
250
251WriteLockHandle::~WriteLockHandle()
252{
253 RTCritSectDelete(&m->sem);
254 delete m;
255}
256
257/*virtual*/ bool WriteLockHandle::isWriteLockOnCurrentThread() const
258{
259 return RTCritSectIsOwner(&m->sem);
260}
261
262/*virtual*/ void WriteLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL)
263{
264#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
265 RTCritSectEnterDebug(&m->sem, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
266#else
267 RTCritSectEnter(&m->sem);
268#endif
269}
270
271/*virtual*/ void WriteLockHandle::unlockWrite()
272{
273 RTCritSectLeave(&m->sem);
274}
275
276/*virtual*/ void WriteLockHandle::lockRead(LOCKVAL_SRC_POS_DECL)
277{
278 lockWrite(LOCKVAL_SRC_POS_ARGS);
279}
280
281/*virtual*/ void WriteLockHandle::unlockRead()
282{
283 unlockWrite();
284}
285
286/*virtual*/ uint32_t WriteLockHandle::writeLockLevel() const
287{
288 return RTCritSectGetRecursion(&m->sem);
289}
290
291#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
292/*virtual*/ const char* WriteLockHandle::describe() const
293{
294 return m->strDescription.c_str();
295}
296#endif
297
298////////////////////////////////////////////////////////////////////////////////
299//
300// AutoLockBase
301//
302////////////////////////////////////////////////////////////////////////////////
303
304typedef std::vector<LockHandle*> HandlesVector;
305typedef std::vector<uint32_t> CountsVector;
306
307struct AutoLockBase::Data
308{
309 Data(size_t cHandles
310#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
311 , const char *pcszFile_,
312 unsigned uLine_,
313 const char *pcszFunction_
314#endif
315 )
316 : fIsLocked(false),
317 aHandles(cHandles), // size of array
318 acUnlockedInLeave(cHandles)
319#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
320 , pcszFile(pcszFile_),
321 uLine(uLine_),
322 pcszFunction(pcszFunction_)
323#endif
324 {
325 for (uint32_t i = 0; i < cHandles; ++i)
326 {
327 acUnlockedInLeave[i] = 0;
328 aHandles[i] = NULL;
329 }
330 }
331
332 bool fIsLocked; // if true, then all items in aHandles are locked by this AutoLock and
333 // need to be unlocked in the destructor
334 HandlesVector aHandles; // array (vector) of LockHandle instances; in the case of AutoWriteLock
335 // and AutoReadLock, there will only be one item on the list; with the
336 // AutoMulti* derivatives, there will be multiple
337 CountsVector acUnlockedInLeave; // for each lock handle, how many times the handle was unlocked in leave(); otherwise 0
338
339#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
340 // information about where the lock occurred (passed down from the AutoLock classes)
341 const char *pcszFile;
342 unsigned uLine;
343 const char *pcszFunction;
344#endif
345};
346
347AutoLockBase::AutoLockBase(uint32_t cHandles
348 COMMA_LOCKVAL_SRC_POS_DECL)
349{
350 m = new Data(cHandles
351 COMMA_LOCKVAL_SRC_POS_ARGS);
352}
353
354AutoLockBase::AutoLockBase(uint32_t cHandles,
355 LockHandle *pHandle
356 COMMA_LOCKVAL_SRC_POS_DECL)
357{
358 Assert(cHandles == 1);
359 m = new Data(1
360 COMMA_LOCKVAL_SRC_POS_ARGS);
361 m->aHandles[0] = pHandle;
362}
363
364AutoLockBase::~AutoLockBase()
365{
366 delete m;
367}
368
369/**
370 * Requests ownership of all contained lock handles by calling
371 * the pure virtual callLockImpl() function on each of them,
372 * which must be implemented by the descendant class; in the
373 * implementation, AutoWriteLock will request a write lock
374 * whereas AutoReadLock will request a read lock.
375 *
376 * Does *not* modify the lock counts in the member variables.
377 */
378void AutoLockBase::callLockOnAllHandles()
379{
380 for (HandlesVector::iterator it = m->aHandles.begin();
381 it != m->aHandles.end();
382 ++it)
383 {
384 LockHandle *pHandle = *it;
385 if (pHandle)
386 // call virtual function implemented in AutoWriteLock or AutoReadLock
387 this->callLockImpl(*pHandle);
388 }
389}
390
391/**
392 * Releases ownership of all contained lock handles by calling
393 * the pure virtual callUnlockImpl() function on each of them,
394 * which must be implemented by the descendant class; in the
395 * implementation, AutoWriteLock will release a write lock
396 * whereas AutoReadLock will release a read lock.
397 *
398 * Does *not* modify the lock counts in the member variables.
399 */
400void AutoLockBase::callUnlockOnAllHandles()
401{
402 // unlock in reverse order!
403 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin();
404 it != m->aHandles.rend();
405 ++it)
406 {
407 LockHandle *pHandle = *it;
408 if (pHandle)
409 // call virtual function implemented in AutoWriteLock or AutoReadLock
410 this->callUnlockImpl(*pHandle);
411 }
412}
413
414/**
415 * Destructor implementation that can also be called explicitly, if required.
416 * Restores the exact state before the AutoLock was created; that is, unlocks
417 * all contained semaphores and might actually lock them again if leave()
418 * was called during the AutoLock's lifetime.
419 */
420void AutoLockBase::cleanup()
421{
422 bool fAnyUnlockedInLeave = false;
423
424 uint32_t i = 0;
425 for (HandlesVector::iterator it = m->aHandles.begin();
426 it != m->aHandles.end();
427 ++it)
428 {
429 LockHandle *pHandle = *it;
430 if (pHandle)
431 {
432 if (m->acUnlockedInLeave[i])
433 {
434 // there was a leave() before the destruction: then restore the
435 // lock level that might have been set by locks other than our own
436 if (m->fIsLocked)
437 {
438 --m->acUnlockedInLeave[i];
439 fAnyUnlockedInLeave = true;
440 }
441 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])
442 callLockImpl(*pHandle);
443 }
444 }
445 ++i;
446 }
447
448 if (m->fIsLocked && !fAnyUnlockedInLeave)
449 callUnlockOnAllHandles();
450}
451
452/**
453 * Requests ownership of all contained semaphores. Public method that can
454 * only be called once and that also gets called by the AutoLock constructors.
455 */
456void AutoLockBase::acquire()
457{
458 AssertMsg(!m->fIsLocked, ("m->fIsLocked is true, attempting to lock twice!"));
459 callLockOnAllHandles();
460 m->fIsLocked = true;
461}
462
463/**
464 * Releases ownership of all contained semaphores. Public method.
465 */
466void AutoLockBase::release()
467{
468 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot release!"));
469 callUnlockOnAllHandles();
470 m->fIsLocked = false;
471}
472
473////////////////////////////////////////////////////////////////////////////////
474//
475// AutoReadLock
476//
477////////////////////////////////////////////////////////////////////////////////
478
479/**
480 * Release all read locks acquired by this instance through the #lock()
481 * call and destroys the instance.
482 *
483 * Note that if there there are nested #lock() calls without the
484 * corresponding number of #unlock() calls when the destructor is called, it
485 * will assert. This is because having an unbalanced number of nested locks
486 * is a program logic error which must be fixed.
487 */
488/*virtual*/ AutoReadLock::~AutoReadLock()
489{
490 LockHandle *pHandle = m->aHandles[0];
491
492 if (pHandle)
493 {
494 if (m->fIsLocked)
495 callUnlockImpl(*pHandle);
496 }
497}
498
499/**
500 * Implementation of the pure virtual declared in AutoLockBase.
501 * This gets called by AutoLockBase.acquire() to actually request
502 * the semaphore; in the AutoReadLock implementation, we request
503 * the semaphore in read mode.
504 */
505/*virtual*/ void AutoReadLock::callLockImpl(LockHandle &l)
506{
507#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
508 l.lockRead(m->pcszFile, m->uLine, m->pcszFunction);
509#else
510 l.lockRead();
511#endif
512}
513
514/**
515 * Implementation of the pure virtual declared in AutoLockBase.
516 * This gets called by AutoLockBase.release() to actually release
517 * the semaphore; in the AutoReadLock implementation, we release
518 * the semaphore in read mode.
519 */
520/*virtual*/ void AutoReadLock::callUnlockImpl(LockHandle &l)
521{
522 l.unlockRead();
523}
524
525////////////////////////////////////////////////////////////////////////////////
526//
527// AutoWriteLockBase
528//
529////////////////////////////////////////////////////////////////////////////////
530
531/**
532 * Implementation of the pure virtual declared in AutoLockBase.
533 * This gets called by AutoLockBase.acquire() to actually request
534 * the semaphore; in the AutoWriteLock implementation, we request
535 * the semaphore in write mode.
536 */
537/*virtual*/ void AutoWriteLockBase::callLockImpl(LockHandle &l)
538{
539#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
540 l.lockWrite(m->pcszFile, m->uLine, m->pcszFunction);
541#else
542 l.lockWrite();
543#endif
544}
545
546/**
547 * Implementation of the pure virtual declared in AutoLockBase.
548 * This gets called by AutoLockBase.release() to actually release
549 * the semaphore; in the AutoWriteLock implementation, we release
550 * the semaphore in write mode.
551 */
552/*virtual*/ void AutoWriteLockBase::callUnlockImpl(LockHandle &l)
553{
554 l.unlockWrite();
555}
556
557/**
558 * Causes the current thread to completely release the write lock to make
559 * the managed semaphore immediately available for locking by other threads.
560 *
561 * This implies that all nested write locks on the semaphore will be
562 * released, even those that were acquired through the calls to #lock()
563 * methods of all other AutoWriteLock/AutoReadLock instances managing the
564 * <b>same</b> read/write semaphore.
565 *
566 * After calling this method, the only method you are allowed to call is
567 * #enter(). It will acquire the write lock again and restore the same
568 * level of nesting as it had before calling #leave().
569 *
570 * If this instance is destroyed without calling #enter(), the destructor
571 * will try to restore the write lock level that existed when #leave() was
572 * called minus the number of nested #lock() calls made on this instance
573 * itself. This is done to preserve lock levels of other
574 * AutoWriteLock/AutoReadLock instances managing the same semaphore (if
575 * any). Tiis also means that the destructor may indefinitely block if a
576 * write or a read lock is owned by some other thread by that time.
577 */
578void AutoWriteLockBase::leave()
579{
580 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot leave()!"));
581
582 // unlock in reverse order!
583 uint32_t i = m->aHandles.size();
584 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin();
585 it != m->aHandles.rend();
586 ++it)
587 {
588 --i; // array index is zero based, decrement with every loop since we iterate backwards
589 LockHandle *pHandle = *it;
590 if (pHandle)
591 {
592 AssertMsg(m->acUnlockedInLeave[i] == 0, ("m->cUnlockedInLeave[%d] is %d, must be 0! Called leave() twice?", i, m->acUnlockedInLeave[i]));
593 m->acUnlockedInLeave[i] = pHandle->writeLockLevel();
594 AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i]));
595
596 for (uint32_t left = m->acUnlockedInLeave[i];
597 left;
598 --left)
599 callUnlockImpl(*pHandle);
600 }
601 }
602}
603
604/**
605 * Causes the current thread to restore the write lock level after the
606 * #leave() call. This call will indefinitely block if another thread has
607 * successfully acquired a write or a read lock on the same semaphore in
608 * between.
609 */
610void AutoWriteLockBase::enter()
611{
612 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot enter()!"));
613
614 uint32_t i = 0;
615 for (HandlesVector::iterator it = m->aHandles.begin();
616 it != m->aHandles.end();
617 ++it)
618 {
619 LockHandle *pHandle = *it;
620 if (pHandle)
621 {
622 AssertMsg(m->acUnlockedInLeave[i] != 0, ("m->cUnlockedInLeave[%d] is 0! enter() without leave()?", i));
623
624 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])
625 callLockImpl(*pHandle);
626 }
627 ++i;
628 }
629}
630
631////////////////////////////////////////////////////////////////////////////////
632//
633// AutoWriteLock
634//
635////////////////////////////////////////////////////////////////////////////////
636
637/**
638 * Attaches another handle to this auto lock instance.
639 *
640 * The previous object's lock is completely released before the new one is
641 * acquired. The lock level of the new handle will be the same. This
642 * also means that if the lock was not acquired at all before #attach(), it
643 * will not be acquired on the new handle too.
644 *
645 * @param aHandle New handle to attach.
646 */
647void AutoWriteLock::attach(LockHandle *aHandle)
648{
649 LockHandle *pHandle = m->aHandles[0];
650
651 /* detect simple self-reattachment */
652 if (pHandle != aHandle)
653 {
654 bool fWasLocked = m->fIsLocked;
655
656 cleanup();
657
658 m->aHandles[0] = aHandle;
659 m->fIsLocked = fWasLocked;
660
661 if (aHandle)
662 if (fWasLocked)
663 callLockImpl(*aHandle);
664 }
665}
666
667/**
668 * Returns @c true if the current thread holds a write lock on the managed
669 * read/write semaphore. Returns @c false if the managed semaphore is @c
670 * NULL.
671 *
672 * @note Intended for debugging only.
673 */
674bool AutoWriteLock::isWriteLockOnCurrentThread() const
675{
676 return m->aHandles[0] ? m->aHandles[0]->isWriteLockOnCurrentThread() : false;
677}
678
679 /**
680 * Returns the current write lock level of the managed semaphore. The lock
681 * level determines the number of nested #lock() calls on the given
682 * semaphore handle. Returns @c 0 if the managed semaphore is @c
683 * NULL.
684 *
685 * Note that this call is valid only when the current thread owns a write
686 * lock on the given semaphore handle and will assert otherwise.
687 *
688 * @note Intended for debugging only.
689 */
690uint32_t AutoWriteLock::writeLockLevel() const
691{
692 return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0;
693}
694
695////////////////////////////////////////////////////////////////////////////////
696//
697// AutoMultiWriteLock*
698//
699////////////////////////////////////////////////////////////////////////////////
700
701AutoMultiWriteLock2::AutoMultiWriteLock2(Lockable *pl1,
702 Lockable *pl2
703 COMMA_LOCKVAL_SRC_POS_DECL)
704 : AutoWriteLockBase(2
705 COMMA_LOCKVAL_SRC_POS_ARGS)
706{
707 if (pl1)
708 m->aHandles[0] = pl1->lockHandle();
709 if (pl2)
710 m->aHandles[1] = pl2->lockHandle();
711 acquire();
712}
713
714AutoMultiWriteLock2::AutoMultiWriteLock2(LockHandle *pl1,
715 LockHandle *pl2
716 COMMA_LOCKVAL_SRC_POS_DECL)
717 : AutoWriteLockBase(2
718 COMMA_LOCKVAL_SRC_POS_ARGS)
719{
720 m->aHandles[0] = pl1;
721 m->aHandles[1] = pl2;
722 acquire();
723}
724
725AutoMultiWriteLock3::AutoMultiWriteLock3(Lockable *pl1,
726 Lockable *pl2,
727 Lockable *pl3
728 COMMA_LOCKVAL_SRC_POS_DECL)
729 : AutoWriteLockBase(3
730 COMMA_LOCKVAL_SRC_POS_ARGS)
731{
732 if (pl1)
733 m->aHandles[0] = pl1->lockHandle();
734 if (pl2)
735 m->aHandles[1] = pl2->lockHandle();
736 if (pl3)
737 m->aHandles[2] = pl3->lockHandle();
738 acquire();
739}
740
741AutoMultiWriteLock3::AutoMultiWriteLock3(LockHandle *pl1,
742 LockHandle *pl2,
743 LockHandle *pl3
744 COMMA_LOCKVAL_SRC_POS_DECL)
745 : AutoWriteLockBase(3
746 COMMA_LOCKVAL_SRC_POS_ARGS)
747{
748 m->aHandles[0] = pl1;
749 m->aHandles[1] = pl2;
750 m->aHandles[2] = pl3;
751 acquire();
752}
753
754} /* namespace util */
755/* 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