VirtualBox

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

Last change on this file since 106077 was 106077, checked in by vboxsync, 3 months ago

Main: Name locks.

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