VirtualBox

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

Last change on this file since 35105 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

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