VirtualBox

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

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

Main: only add parent to the lock list if it isn't null

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.7 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
637AutoWriteLock::AutoWriteLock(uint32_t cHandles,
638 LockHandle** pHandles
639 COMMA_LOCKVAL_SRC_POS_DECL)
640 : AutoWriteLockBase(cHandles
641 COMMA_LOCKVAL_SRC_POS_ARGS)
642{
643 Assert(cHandles);
644 Assert(pHandles);
645
646 for (uint32_t i = 0; i < cHandles; ++i)
647 m->aHandles[i] = pHandles[i];
648
649 acquire();
650}
651
652
653
654/**
655 * Attaches another handle to this auto lock instance.
656 *
657 * The previous object's lock is completely released before the new one is
658 * acquired. The lock level of the new handle will be the same. This
659 * also means that if the lock was not acquired at all before #attach(), it
660 * will not be acquired on the new handle too.
661 *
662 * @param aHandle New handle to attach.
663 */
664void AutoWriteLock::attach(LockHandle *aHandle)
665{
666 LockHandle *pHandle = m->aHandles[0];
667
668 /* detect simple self-reattachment */
669 if (pHandle != aHandle)
670 {
671 bool fWasLocked = m->fIsLocked;
672
673 cleanup();
674
675 m->aHandles[0] = aHandle;
676 m->fIsLocked = fWasLocked;
677
678 if (aHandle)
679 if (fWasLocked)
680 callLockImpl(*aHandle);
681 }
682}
683
684/**
685 * Returns @c true if the current thread holds a write lock on the managed
686 * read/write semaphore. Returns @c false if the managed semaphore is @c
687 * NULL.
688 *
689 * @note Intended for debugging only.
690 */
691bool AutoWriteLock::isWriteLockOnCurrentThread() const
692{
693 return m->aHandles[0] ? m->aHandles[0]->isWriteLockOnCurrentThread() : false;
694}
695
696 /**
697 * Returns the current write lock level of the managed semaphore. The lock
698 * level determines the number of nested #lock() calls on the given
699 * semaphore handle. Returns @c 0 if the managed semaphore is @c
700 * NULL.
701 *
702 * Note that this call is valid only when the current thread owns a write
703 * lock on the given semaphore handle and will assert otherwise.
704 *
705 * @note Intended for debugging only.
706 */
707uint32_t AutoWriteLock::writeLockLevel() const
708{
709 return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0;
710}
711
712////////////////////////////////////////////////////////////////////////////////
713//
714// AutoMultiWriteLock*
715//
716////////////////////////////////////////////////////////////////////////////////
717
718AutoMultiWriteLock2::AutoMultiWriteLock2(Lockable *pl1,
719 Lockable *pl2
720 COMMA_LOCKVAL_SRC_POS_DECL)
721 : AutoWriteLockBase(2
722 COMMA_LOCKVAL_SRC_POS_ARGS)
723{
724 if (pl1)
725 m->aHandles[0] = pl1->lockHandle();
726 if (pl2)
727 m->aHandles[1] = pl2->lockHandle();
728 acquire();
729}
730
731AutoMultiWriteLock2::AutoMultiWriteLock2(LockHandle *pl1,
732 LockHandle *pl2
733 COMMA_LOCKVAL_SRC_POS_DECL)
734 : AutoWriteLockBase(2
735 COMMA_LOCKVAL_SRC_POS_ARGS)
736{
737 m->aHandles[0] = pl1;
738 m->aHandles[1] = pl2;
739 acquire();
740}
741
742AutoMultiWriteLock3::AutoMultiWriteLock3(Lockable *pl1,
743 Lockable *pl2,
744 Lockable *pl3
745 COMMA_LOCKVAL_SRC_POS_DECL)
746 : AutoWriteLockBase(3
747 COMMA_LOCKVAL_SRC_POS_ARGS)
748{
749 if (pl1)
750 m->aHandles[0] = pl1->lockHandle();
751 if (pl2)
752 m->aHandles[1] = pl2->lockHandle();
753 if (pl3)
754 m->aHandles[2] = pl3->lockHandle();
755 acquire();
756}
757
758AutoMultiWriteLock3::AutoMultiWriteLock3(LockHandle *pl1,
759 LockHandle *pl2,
760 LockHandle *pl3
761 COMMA_LOCKVAL_SRC_POS_DECL)
762 : AutoWriteLockBase(3
763 COMMA_LOCKVAL_SRC_POS_ARGS)
764{
765 m->aHandles[0] = pl1;
766 m->aHandles[1] = pl2;
767 m->aHandles[2] = pl3;
768 acquire();
769}
770
771AutoMultiWriteLock4::AutoMultiWriteLock4(Lockable *pl1,
772 Lockable *pl2,
773 Lockable *pl3,
774 Lockable *pl4
775 COMMA_LOCKVAL_SRC_POS_DECL)
776 : AutoWriteLockBase(4
777 COMMA_LOCKVAL_SRC_POS_ARGS)
778{
779 if (pl1)
780 m->aHandles[0] = pl1->lockHandle();
781 if (pl2)
782 m->aHandles[1] = pl2->lockHandle();
783 if (pl3)
784 m->aHandles[2] = pl3->lockHandle();
785 if (pl4)
786 m->aHandles[3] = pl4->lockHandle();
787 acquire();
788}
789
790AutoMultiWriteLock4::AutoMultiWriteLock4(LockHandle *pl1,
791 LockHandle *pl2,
792 LockHandle *pl3,
793 LockHandle *pl4
794 COMMA_LOCKVAL_SRC_POS_DECL)
795 : AutoWriteLockBase(4
796 COMMA_LOCKVAL_SRC_POS_ARGS)
797{
798 m->aHandles[0] = pl1;
799 m->aHandles[1] = pl2;
800 m->aHandles[2] = pl3;
801 m->aHandles[3] = pl4;
802 acquire();
803}
804
805} /* namespace util */
806/* 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