VirtualBox

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

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

AutoLock.cpp: Pass file and line number to RTCritSectEnterDebug.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.9 KB
Line 
1/** @file
2 *
3 * AutoWriteLock/AutoReadLock: smart R/W semaphore wrappers
4 */
5
6/*
7 * Copyright (C) 2006-2000 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 "AutoLock.h"
23
24#include "Logging.h"
25
26#include <iprt/cdefs.h>
27#include <iprt/critsect.h>
28#include <iprt/thread.h>
29#include <iprt/semaphore.h>
30
31#include <iprt/err.h>
32#include <iprt/assert.h>
33
34#if defined(DEBUG)
35# include <iprt/asm.h> // for ASMReturnAddress
36#endif
37
38#include <iprt/string.h>
39#include <iprt/path.h>
40
41#include <vector>
42#include <list>
43
44namespace util
45{
46
47////////////////////////////////////////////////////////////////////////////////
48//
49// Global variables
50//
51////////////////////////////////////////////////////////////////////////////////
52
53#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
54// index used for allocating thread-local storage for locking stack
55RTTLS LockHandle::s_lockingStackTlsIndex = NIL_RTTLS;
56
57/**
58 * One item on the LockingStack. One of these gets pushed on the
59 * stack for each lock operation and popped for each unlock.
60 */
61struct LockStackItem
62{
63 LockStackItem(LockHandle *pLock_,
64 const char *pcszFile_,
65 unsigned uLine_,
66 const char *pcszFunction_)
67 : pLock(pLock_),
68 pcszFile(pcszFile_),
69 uLine(uLine_),
70 pcszFunction(pcszFunction_)
71 {
72 pcszFile = RTPathFilename(pcszFile_);
73 }
74
75 LockHandle *pLock;
76
77 // information about where the lock occured (passed down from the AutoLock classes)
78 const char *pcszFile;
79 unsigned uLine;
80 const char *pcszFunction;
81};
82
83typedef std::list<LockStackItem> LockHandlesList;
84struct LockingStack
85{
86 LockingStack()
87 : threadSelf(RTThreadSelf()),
88 pcszThreadName(NULL),
89 c(0)
90 {
91 threadSelf = RTThreadSelf();
92 pcszThreadName = RTThreadGetName(threadSelf);
93 }
94
95 RTTHREAD threadSelf;
96 const char *pcszThreadName;
97
98 LockHandlesList ll;
99 size_t c;
100};
101
102LockingStack* getThreadLocalLockingStack()
103{
104 // very first call in this process: allocate the TLS variable
105 if (LockHandle::s_lockingStackTlsIndex == NIL_RTTLS)
106 {
107 LockHandle::s_lockingStackTlsIndex = RTTlsAlloc();
108 Assert(LockHandle::s_lockingStackTlsIndex != NIL_RTTLS);
109 }
110
111 // get pointer to thread-local locking stack
112 LockingStack *pStack = (LockingStack*)RTTlsGet(LockHandle::s_lockingStackTlsIndex);
113 if (!pStack)
114 {
115 // first call on this thread:
116 pStack = new LockingStack;
117 RTTlsSet(LockHandle::s_lockingStackTlsIndex, pStack);
118 }
119
120 return pStack;
121}
122#endif
123
124////////////////////////////////////////////////////////////////////////////////
125//
126// LockHandle
127//
128////////////////////////////////////////////////////////////////////////////////
129
130#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
131void LockHandle::validateLock(LOCKVAL_SRC_POS_DECL)
132{
133 // put "this" on locking stack
134 LockingStack *pStack = getThreadLocalLockingStack();
135 LockStackItem lsi(this, RT_SRC_POS_ARGS);
136 pStack->ll.push_back(lsi);
137 ++pStack->c;
138
139 LogFlow(("LOCKVAL: lock from %s (%s:%u), new count: %RI32\n", lsi.pcszFunction, lsi.pcszFile, lsi.uLine, (uint32_t)pStack->c));
140}
141
142void LockHandle::validateUnlock()
143{
144 // pop "this" from locking stack
145 LockingStack *pStack = getThreadLocalLockingStack();
146
147 LogFlow(("LOCKVAL: unlock, old count: %RI32\n", (uint32_t)pStack->c));
148
149 AssertMsg(pStack->c == pStack->ll.size(), ("Locking size mismatch"));
150 AssertMsg(pStack->c > 0, ("Locking stack is empty when it should have current LockHandle on top"));
151
152 // validate that "this" is the top item on the stack
153 LockStackItem &lsiTop = pStack->ll.back();
154 if (lsiTop.pLock != this)
155 {
156 // violation of unlocking order: "this" was not the last to be locked on this thread,
157 // see if it's somewhere deep under the locks
158 bool fFound;
159 uint32_t c = 0;
160 for (LockHandlesList::iterator it = pStack->ll.begin();
161 it != pStack->ll.end();
162 ++it, ++c)
163 {
164 LockStackItem &lsiThis = *it;
165 if (lsiThis.pLock == this)
166 {
167 AssertMsgFailed(("Unlocking order violation: unlock attempted for LockHandle which is %d items under the top item\n", c));
168 pStack->ll.erase(it);
169 fFound = true;
170 break;
171 }
172 }
173
174 if (!fFound)
175 AssertMsgFailed(("Locking stack does not contain current LockHandle at all\n"));
176 }
177 else
178 pStack->ll.pop_back();
179 --pStack->c;
180}
181#endif // VBOX_WITH_DEBUG_LOCK_VALIDATOR
182
183////////////////////////////////////////////////////////////////////////////////
184//
185// RWLockHandle
186//
187////////////////////////////////////////////////////////////////////////////////
188
189struct RWLockHandle::Data
190{
191 Data()
192 { }
193
194 RTSEMRW sem;
195};
196
197RWLockHandle::RWLockHandle()
198{
199 m = new Data();
200 int vrc = RTSemRWCreate(&m->sem);
201 AssertRC(vrc);
202}
203
204/*virtual*/ RWLockHandle::~RWLockHandle()
205{
206 RTSemRWDestroy(m->sem);
207 delete m;
208}
209
210/*virtual*/ bool RWLockHandle::isWriteLockOnCurrentThread() const
211{
212 return RTSemRWIsWriteOwner(m->sem);
213}
214
215/*virtual*/ void RWLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL)
216{
217#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
218 validateLock(LOCKVAL_SRC_POS_ARGS);
219#endif
220 int vrc = RTSemRWRequestWrite(m->sem, RT_INDEFINITE_WAIT);
221 AssertRC(vrc);
222}
223
224/*virtual*/ void RWLockHandle::unlockWrite()
225{
226#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
227 validateUnlock();
228#endif
229 int vrc = RTSemRWReleaseWrite(m->sem);
230 AssertRC(vrc);
231
232}
233
234/*virtual*/ void RWLockHandle::lockRead(LOCKVAL_SRC_POS_DECL)
235{
236#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
237 validateLock(LOCKVAL_SRC_POS_ARGS);
238#endif
239 int vrc = RTSemRWRequestRead(m->sem, RT_INDEFINITE_WAIT);
240 AssertRC(vrc);
241}
242
243/*virtual*/ void RWLockHandle::unlockRead()
244{
245#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
246 validateUnlock();
247#endif
248 int vrc = RTSemRWReleaseRead(m->sem);
249 AssertRC(vrc);
250}
251
252/*virtual*/ uint32_t RWLockHandle::writeLockLevel() const
253{
254 return RTSemRWGetWriteRecursion(m->sem);
255}
256
257////////////////////////////////////////////////////////////////////////////////
258//
259// WriteLockHandle
260//
261////////////////////////////////////////////////////////////////////////////////
262
263struct WriteLockHandle::Data
264{
265 Data()
266 { }
267
268 mutable RTCRITSECT sem;
269};
270
271WriteLockHandle::WriteLockHandle()
272{
273 m = new Data;
274 RTCritSectInit(&m->sem);
275}
276
277WriteLockHandle::~WriteLockHandle()
278{
279 RTCritSectDelete(&m->sem);
280 delete m;
281}
282
283/*virtual*/ bool WriteLockHandle::isWriteLockOnCurrentThread() const
284{
285 return RTCritSectIsOwner(&m->sem);
286}
287
288/*virtual*/ void WriteLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL)
289{
290#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
291 validateLock(LOCKVAL_SRC_POS_ARGS);
292#endif
293
294#if defined(DEBUG) && defined(VBOX_WITH_DEBUG_LOCK_VALIDATOR)
295 RTCritSectEnterDebug(&m->sem, pszFile, iLine, (uintptr_t)ASMReturnAddress());
296#elif defined(DEBUG)
297 RTCritSectEnterDebug(&m->sem,
298 "WriteLockHandle::lockWrite() return address >>>",
299 0, (RTUINTPTR)ASMReturnAddress());
300#else
301 RTCritSectEnter(&m->sem);
302#endif
303}
304
305/*virtual*/ void WriteLockHandle::unlockWrite()
306{
307#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
308 validateUnlock();
309#endif
310
311 RTCritSectLeave(&m->sem);
312}
313
314/*virtual*/ void WriteLockHandle::lockRead(LOCKVAL_SRC_POS_DECL)
315{
316 lockWrite(LOCKVAL_SRC_POS_ARGS);
317}
318
319/*virtual*/ void WriteLockHandle::unlockRead()
320{
321 unlockWrite();
322}
323
324/*virtual*/ uint32_t WriteLockHandle::writeLockLevel() const
325{
326 return RTCritSectGetRecursion(&m->sem);
327}
328
329////////////////////////////////////////////////////////////////////////////////
330//
331// AutoLockBase
332//
333////////////////////////////////////////////////////////////////////////////////
334
335typedef std::vector<LockHandle*> HandlesVector;
336typedef std::vector<uint32_t> CountsVector;
337
338struct AutoLockBase::Data
339{
340 Data(size_t cHandles
341#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
342 , const char *pcszFile_,
343 unsigned uLine_,
344 const char *pcszFunction_
345#endif
346 )
347 : fIsLocked(false),
348 aHandles(cHandles), // size of array
349 acUnlockedInLeave(cHandles)
350#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
351 , pcszFile(pcszFile_),
352 uLine(uLine_),
353 pcszFunction(pcszFunction_)
354#endif
355 {
356 for (uint32_t i = 0; i < cHandles; ++i)
357 {
358 acUnlockedInLeave[i] = 0;
359 aHandles[i] = NULL;
360 }
361 }
362
363 bool fIsLocked; // if true, then all items in aHandles are locked by this AutoLock and
364 // need to be unlocked in the destructor
365 HandlesVector aHandles; // array (vector) of LockHandle instances; in the case of AutoWriteLock
366 // and AutoReadLock, there will only be one item on the list; with the
367 // AutoMulti* derivatives, there will be multiple
368 CountsVector acUnlockedInLeave; // for each lock handle, how many times the handle was unlocked in leave(); otherwise 0
369
370#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
371 // information about where the lock occured (passed down from the AutoLock classes)
372 const char *pcszFile;
373 unsigned uLine;
374 const char *pcszFunction;
375#endif
376};
377
378AutoLockBase::AutoLockBase(uint32_t cHandles
379 COMMA_LOCKVAL_SRC_POS_DECL)
380{
381 m = new Data(cHandles
382 COMMA_LOCKVAL_SRC_POS_ARGS);
383}
384
385AutoLockBase::AutoLockBase(uint32_t cHandles,
386 LockHandle *pHandle
387 COMMA_LOCKVAL_SRC_POS_DECL)
388{
389 Assert(cHandles == 1);
390 m = new Data(1
391 COMMA_LOCKVAL_SRC_POS_ARGS);
392 m->aHandles[0] = pHandle;
393}
394
395AutoLockBase::~AutoLockBase()
396{
397 delete m;
398}
399
400/**
401 * Requests ownership of all contained lock handles by calling
402 * the pure virtual callLockImpl() function on each of them,
403 * which must be implemented by the descendant class; in the
404 * implementation, AutoWriteLock will request a write lock
405 * whereas AutoReadLock will request a read lock.
406 *
407 * Does *not* modify the lock counts in the member variables.
408 */
409void AutoLockBase::callLockOnAllHandles()
410{
411 for (HandlesVector::iterator it = m->aHandles.begin();
412 it != m->aHandles.end();
413 ++it)
414 {
415 LockHandle *pHandle = *it;
416 if (pHandle)
417 // call virtual function implemented in AutoWriteLock or AutoReadLock
418 this->callLockImpl(*pHandle);
419 }
420}
421
422/**
423 * Releases ownership of all contained lock handles by calling
424 * the pure virtual callUnlockImpl() function on each of them,
425 * which must be implemented by the descendant class; in the
426 * implementation, AutoWriteLock will release a write lock
427 * whereas AutoReadLock will release a read lock.
428 *
429 * Does *not* modify the lock counts in the member variables.
430 */
431void AutoLockBase::callUnlockOnAllHandles()
432{
433 // unlock in reverse order!
434 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin();
435 it != m->aHandles.rend();
436 ++it)
437 {
438 LockHandle *pHandle = *it;
439 if (pHandle)
440 // call virtual function implemented in AutoWriteLock or AutoReadLock
441 this->callUnlockImpl(*pHandle);
442 }
443}
444
445/**
446 * Destructor implementation that can also be called explicitly, if required.
447 * Restores the exact state before the AutoLock was created; that is, unlocks
448 * all contained semaphores and might actually lock them again if leave()
449 * was called during the AutoLock's lifetime.
450 */
451void AutoLockBase::cleanup()
452{
453 bool fAnyUnlockedInLeave = false;
454
455 uint32_t i = 0;
456 for (HandlesVector::iterator it = m->aHandles.begin();
457 it != m->aHandles.end();
458 ++it)
459 {
460 LockHandle *pHandle = *it;
461 if (pHandle)
462 {
463 if (m->acUnlockedInLeave[i])
464 {
465 // there was a leave() before the destruction: then restore the
466 // lock level that might have been set by locks other than our own
467 if (m->fIsLocked)
468 {
469 --m->acUnlockedInLeave[i];
470 fAnyUnlockedInLeave = true;
471 }
472 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])
473 callLockImpl(*pHandle);
474 }
475 }
476 ++i;
477 }
478
479 if (m->fIsLocked && !fAnyUnlockedInLeave)
480 callUnlockOnAllHandles();
481}
482
483/**
484 * Requests ownership of all contained semaphores. Public method that can
485 * only be called once and that also gets called by the AutoLock constructors.
486 */
487void AutoLockBase::acquire()
488{
489 AssertMsg(!m->fIsLocked, ("m->fIsLocked is true, attempting to lock twice!"));
490 callLockOnAllHandles();
491 m->fIsLocked = true;
492}
493
494/**
495 * Releases ownership of all contained semaphores. Public method.
496 */
497void AutoLockBase::release()
498{
499 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot release!"));
500 callUnlockOnAllHandles();
501 m->fIsLocked = false;
502}
503
504////////////////////////////////////////////////////////////////////////////////
505//
506// AutoReadLock
507//
508////////////////////////////////////////////////////////////////////////////////
509
510/**
511 * Release all read locks acquired by this instance through the #lock()
512 * call and destroys the instance.
513 *
514 * Note that if there there are nested #lock() calls without the
515 * corresponding number of #unlock() calls when the destructor is called, it
516 * will assert. This is because having an unbalanced number of nested locks
517 * is a program logic error which must be fixed.
518 */
519/*virtual*/ AutoReadLock::~AutoReadLock()
520{
521 LockHandle *pHandle = m->aHandles[0];
522
523 if (pHandle)
524 {
525 if (m->fIsLocked)
526 callUnlockImpl(*pHandle);
527 }
528}
529
530/**
531 * Implementation of the pure virtual declared in AutoLockBase.
532 * This gets called by AutoLockBase.acquire() to actually request
533 * the semaphore; in the AutoReadLock implementation, we request
534 * the semaphore in read mode.
535 */
536/*virtual*/ void AutoReadLock::callLockImpl(LockHandle &l)
537{
538#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
539 l.lockRead(m->pcszFile, m->uLine, m->pcszFunction);
540#else
541 l.lockRead();
542#endif
543}
544
545/**
546 * Implementation of the pure virtual declared in AutoLockBase.
547 * This gets called by AutoLockBase.release() to actually release
548 * the semaphore; in the AutoReadLock implementation, we release
549 * the semaphore in read mode.
550 */
551/*virtual*/ void AutoReadLock::callUnlockImpl(LockHandle &l)
552{
553 l.unlockRead();
554}
555
556////////////////////////////////////////////////////////////////////////////////
557//
558// AutoWriteLockBase
559//
560////////////////////////////////////////////////////////////////////////////////
561
562/**
563 * Implementation of the pure virtual declared in AutoLockBase.
564 * This gets called by AutoLockBase.acquire() to actually request
565 * the semaphore; in the AutoWriteLock implementation, we request
566 * the semaphore in write mode.
567 */
568/*virtual*/ void AutoWriteLockBase::callLockImpl(LockHandle &l)
569{
570#ifdef VBOX_WITH_DEBUG_LOCK_VALIDATOR
571 l.lockWrite(m->pcszFile, m->uLine, m->pcszFunction);
572#else
573 l.lockWrite();
574#endif
575}
576
577/**
578 * Implementation of the pure virtual declared in AutoLockBase.
579 * This gets called by AutoLockBase.release() to actually release
580 * the semaphore; in the AutoWriteLock implementation, we release
581 * the semaphore in write mode.
582 */
583/*virtual*/ void AutoWriteLockBase::callUnlockImpl(LockHandle &l)
584{
585 l.unlockWrite();
586}
587
588/**
589 * Causes the current thread to completely release the write lock to make
590 * the managed semaphore immediately available for locking by other threads.
591 *
592 * This implies that all nested write locks on the semaphore will be
593 * released, even those that were acquired through the calls to #lock()
594 * methods of all other AutoWriteLock/AutoReadLock instances managing the
595 * <b>same</b> read/write semaphore.
596 *
597 * After calling this method, the only method you are allowed to call is
598 * #enter(). It will acquire the write lock again and restore the same
599 * level of nesting as it had before calling #leave().
600 *
601 * If this instance is destroyed without calling #enter(), the destructor
602 * will try to restore the write lock level that existed when #leave() was
603 * called minus the number of nested #lock() calls made on this instance
604 * itself. This is done to preserve lock levels of other
605 * AutoWriteLock/AutoReadLock instances managing the same semaphore (if
606 * any). Tiis also means that the destructor may indefinitely block if a
607 * write or a read lock is owned by some other thread by that time.
608 */
609void AutoWriteLockBase::leave()
610{
611 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot leave()!"));
612
613 // unlock in reverse order!
614 uint32_t i = 0;
615 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin();
616 it != m->aHandles.rend();
617 ++it)
618 {
619 LockHandle *pHandle = *it;
620 if (pHandle)
621 {
622 AssertMsg(m->acUnlockedInLeave[i] == 0, ("m->cUnlockedInLeave[%d] is %d, must be 0! Called leave() twice?", i, m->acUnlockedInLeave[i]));
623 m->acUnlockedInLeave[i] = pHandle->writeLockLevel();
624 AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i]));
625
626 for (uint32_t left = m->acUnlockedInLeave[i];
627 left;
628 --left)
629 callUnlockImpl(*pHandle);
630 }
631 ++i;
632 }
633}
634
635/**
636 * Causes the current thread to restore the write lock level after the
637 * #leave() call. This call will indefinitely block if another thread has
638 * successfully acquired a write or a read lock on the same semaphore in
639 * between.
640 */
641void AutoWriteLockBase::enter()
642{
643 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot enter()!"));
644
645 uint32_t i = 0;
646 for (HandlesVector::iterator it = m->aHandles.begin();
647 it != m->aHandles.end();
648 ++it)
649 {
650 LockHandle *pHandle = *it;
651 if (pHandle)
652 {
653 AssertMsg(m->acUnlockedInLeave[i] != 0, ("m->cUnlockedInLeave[%d] is 0! enter() without leave()?", i));
654
655 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])
656 callLockImpl(*pHandle);
657 }
658 ++i;
659 }
660}
661
662/**
663 * Same as #leave() but checks if the current thread actally owns the lock
664 * and only proceeds in this case. As a result, as opposed to #leave(),
665 * doesn't assert when called with no lock being held.
666 */
667void AutoWriteLockBase::maybeLeave()
668{
669 // unlock in reverse order!
670 uint32_t i = 0;
671 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin();
672 it != m->aHandles.rend();
673 ++it)
674 {
675 LockHandle *pHandle = *it;
676 if (pHandle)
677 {
678 if (pHandle->isWriteLockOnCurrentThread())
679 {
680 m->acUnlockedInLeave[i] = pHandle->writeLockLevel();
681 AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i]));
682
683 for (uint32_t left = m->acUnlockedInLeave[i];
684 left;
685 --left)
686 callUnlockImpl(*pHandle);
687 }
688 }
689 ++i;
690 }
691}
692
693/**
694 * Same as #enter() but checks if the current thread actally owns the lock
695 * and only proceeds if not. As a result, as opposed to #enter(), doesn't
696 * assert when called with the lock already being held.
697 */
698void AutoWriteLockBase::maybeEnter()
699{
700 uint32_t i = 0;
701 for (HandlesVector::iterator it = m->aHandles.begin();
702 it != m->aHandles.end();
703 ++it)
704 {
705 LockHandle *pHandle = *it;
706 if (pHandle)
707 {
708 if (!pHandle->isWriteLockOnCurrentThread())
709 {
710 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])
711 callLockImpl(*pHandle);
712 }
713 }
714 ++i;
715 }
716}
717
718////////////////////////////////////////////////////////////////////////////////
719//
720// AutoWriteLock
721//
722////////////////////////////////////////////////////////////////////////////////
723
724/**
725 * Attaches another handle to this auto lock instance.
726 *
727 * The previous object's lock is completely released before the new one is
728 * acquired. The lock level of the new handle will be the same. This
729 * also means that if the lock was not acquired at all before #attach(), it
730 * will not be acquired on the new handle too.
731 *
732 * @param aHandle New handle to attach.
733 */
734void AutoWriteLock::attach(LockHandle *aHandle)
735{
736 LockHandle *pHandle = m->aHandles[0];
737
738 /* detect simple self-reattachment */
739 if (pHandle != aHandle)
740 {
741 bool fWasLocked = m->fIsLocked;
742
743 cleanup();
744
745 m->aHandles[0] = aHandle;
746 m->fIsLocked = fWasLocked;
747
748 if (aHandle)
749 if (fWasLocked)
750 callLockImpl(*aHandle);
751 }
752}
753
754/**
755 * Returns @c true if the current thread holds a write lock on the managed
756 * read/write semaphore. Returns @c false if the managed semaphore is @c
757 * NULL.
758 *
759 * @note Intended for debugging only.
760 */
761bool AutoWriteLock::isWriteLockOnCurrentThread() const
762{
763 return m->aHandles[0] ? m->aHandles[0]->isWriteLockOnCurrentThread() : false;
764}
765
766 /**
767 * Returns the current write lock level of the managed smaphore. The lock
768 * level determines the number of nested #lock() calls on the given
769 * semaphore handle. Returns @c 0 if the managed semaphore is @c
770 * NULL.
771 *
772 * Note that this call is valid only when the current thread owns a write
773 * lock on the given semaphore handle and will assert otherwise.
774 *
775 * @note Intended for debugging only.
776 */
777uint32_t AutoWriteLock::writeLockLevel() const
778{
779 return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0;
780}
781
782////////////////////////////////////////////////////////////////////////////////
783//
784// AutoMultiWriteLock*
785//
786////////////////////////////////////////////////////////////////////////////////
787
788AutoMultiWriteLock2::AutoMultiWriteLock2(Lockable *pl1,
789 Lockable *pl2
790 COMMA_LOCKVAL_SRC_POS_DECL)
791 : AutoWriteLockBase(2
792 COMMA_LOCKVAL_SRC_POS_ARGS)
793{
794 if (pl1)
795 m->aHandles[0] = pl1->lockHandle();
796 if (pl2)
797 m->aHandles[1] = pl2->lockHandle();
798 acquire();
799}
800
801AutoMultiWriteLock2::AutoMultiWriteLock2(LockHandle *pl1,
802 LockHandle *pl2
803 COMMA_LOCKVAL_SRC_POS_DECL)
804 : AutoWriteLockBase(2
805 COMMA_LOCKVAL_SRC_POS_ARGS)
806{
807 m->aHandles[0] = pl1;
808 m->aHandles[1] = pl2;
809 acquire();
810}
811
812AutoMultiWriteLock3::AutoMultiWriteLock3(Lockable *pl1,
813 Lockable *pl2,
814 Lockable *pl3
815 COMMA_LOCKVAL_SRC_POS_DECL)
816 : AutoWriteLockBase(3
817 COMMA_LOCKVAL_SRC_POS_ARGS)
818{
819 if (pl1)
820 m->aHandles[0] = pl1->lockHandle();
821 if (pl2)
822 m->aHandles[1] = pl2->lockHandle();
823 if (pl3)
824 m->aHandles[2] = pl3->lockHandle();
825 acquire();
826}
827
828AutoMultiWriteLock3::AutoMultiWriteLock3(LockHandle *pl1,
829 LockHandle *pl2,
830 LockHandle *pl3
831 COMMA_LOCKVAL_SRC_POS_DECL)
832 : AutoWriteLockBase(3
833 COMMA_LOCKVAL_SRC_POS_ARGS)
834{
835 m->aHandles[0] = pl1;
836 m->aHandles[1] = pl2;
837 m->aHandles[2] = pl3;
838 acquire();
839}
840
841} /* namespace util */
842/* 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