VirtualBox

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

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

Main/glue/AutoLock: add a wrapper for checking whether any lock of a class is held

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