VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.8 KB
Line 
1/* $Id: AutoLock.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * Automatic locks, implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2023 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)
171{
172 m = new Data();
173
174 m->lockClass = lockClass;
175#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
176 m->strDescription.printf("r/w %RCv", this);
177#endif
178
179#ifdef GLUE_USE_CRITSECTRW
180# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
181 int vrc = RTCritSectRwInitEx(&m->CritSect, 0 /*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL);
182# else
183 int vrc = RTCritSectRwInitEx(&m->CritSect, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL);
184# endif
185#else
186# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
187 int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL);
188# else
189 int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL);
190# endif
191#endif
192 AssertRC(vrc);
193}
194
195/*virtual*/ RWLockHandle::~RWLockHandle()
196{
197#ifdef GLUE_USE_CRITSECTRW
198 RTCritSectRwDelete(&m->CritSect);
199#else
200 RTSemRWDestroy(m->sem);
201#endif
202 delete m;
203}
204
205/*virtual*/ bool RWLockHandle::isWriteLockOnCurrentThread() const
206{
207#ifdef GLUE_USE_CRITSECTRW
208 return RTCritSectRwIsWriteOwner(&m->CritSect);
209#else
210 return RTSemRWIsWriteOwner(m->sem);
211#endif
212}
213
214/*virtual*/ void RWLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL)
215{
216#ifdef GLUE_USE_CRITSECTRW
217# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
218 int vrc = RTCritSectRwEnterExclDebug(&m->CritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
219# else
220 int vrc = RTCritSectRwEnterExcl(&m->CritSect);
221# endif
222#else
223# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
224 int vrc = RTSemRWRequestWriteDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
225# else
226 int vrc = RTSemRWRequestWrite(m->sem, RT_INDEFINITE_WAIT);
227# endif
228#endif
229 AssertRC(vrc);
230}
231
232/*virtual*/ void RWLockHandle::unlockWrite()
233{
234#ifdef GLUE_USE_CRITSECTRW
235 int vrc = RTCritSectRwLeaveExcl(&m->CritSect);
236#else
237 int vrc = RTSemRWReleaseWrite(m->sem);
238#endif
239 AssertRC(vrc);
240
241}
242
243/*virtual*/ bool RWLockHandle::isReadLockedOnCurrentThread(bool fWannaHear) const
244{
245#ifdef GLUE_USE_CRITSECTRW
246 return RTCritSectRwIsReadOwner(&m->CritSect, fWannaHear);
247#else
248 return RTSemRWIsReadOwner(m->sem, fWannaHear);
249#endif
250}
251
252/*virtual*/ void RWLockHandle::lockRead(LOCKVAL_SRC_POS_DECL)
253{
254#ifdef GLUE_USE_CRITSECTRW
255# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
256 int vrc = RTCritSectRwEnterSharedDebug(&m->CritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
257# else
258 int vrc = RTCritSectRwEnterShared(&m->CritSect);
259# endif
260#else
261# ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
262 int vrc = RTSemRWRequestReadDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
263# else
264 int vrc = RTSemRWRequestRead(m->sem, RT_INDEFINITE_WAIT);
265# endif
266#endif
267 AssertRC(vrc);
268}
269
270/*virtual*/ void RWLockHandle::unlockRead()
271{
272#ifdef GLUE_USE_CRITSECTRW
273 int vrc = RTCritSectRwLeaveShared(&m->CritSect);
274#else
275 int vrc = RTSemRWReleaseRead(m->sem);
276#endif
277 AssertRC(vrc);
278}
279
280/*virtual*/ uint32_t RWLockHandle::writeLockLevel() const
281{
282 /* Note! This does not include read recursions done by the writer! */
283#ifdef GLUE_USE_CRITSECTRW
284 return RTCritSectRwGetWriteRecursion(&m->CritSect);
285#else
286 return RTSemRWGetWriteRecursion(m->sem);
287#endif
288}
289
290#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
291/*virtual*/ const char* RWLockHandle::describe() const
292{
293 return m->strDescription.c_str();
294}
295#endif
296
297////////////////////////////////////////////////////////////////////////////////
298//
299// WriteLockHandle
300//
301////////////////////////////////////////////////////////////////////////////////
302
303struct WriteLockHandle::Data
304{
305 Data()
306 { }
307
308 mutable RTCRITSECT sem;
309 VBoxLockingClass lockClass;
310
311#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
312 com::Utf8Str strDescription;
313#endif
314};
315
316WriteLockHandle::WriteLockHandle(VBoxLockingClass lockClass)
317{
318 m = new Data;
319
320 m->lockClass = lockClass;
321
322#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
323 m->strDescription = com::Utf8StrFmt("crit %RCv", this);
324 int vrc = RTCritSectInitEx(&m->sem, 0/*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL);
325#else
326 int vrc = RTCritSectInitEx(&m->sem, 0/*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL);
327#endif
328 AssertRC(vrc);
329}
330
331WriteLockHandle::~WriteLockHandle()
332{
333 RTCritSectDelete(&m->sem);
334 delete m;
335}
336
337/*virtual*/ bool WriteLockHandle::isWriteLockOnCurrentThread() const
338{
339 return RTCritSectIsOwner(&m->sem);
340}
341
342/*virtual*/ void WriteLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL)
343{
344#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
345 RTCritSectEnterDebug(&m->sem, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
346#else
347 RTCritSectEnter(&m->sem);
348#endif
349}
350
351/*virtual*/ bool WriteLockHandle::isReadLockedOnCurrentThread(bool fWannaHear) const
352{
353 RT_NOREF(fWannaHear);
354 return RTCritSectIsOwner(&m->sem);
355}
356
357/*virtual*/ void WriteLockHandle::unlockWrite()
358{
359 RTCritSectLeave(&m->sem);
360}
361
362/*virtual*/ void WriteLockHandle::lockRead(LOCKVAL_SRC_POS_DECL)
363{
364 lockWrite(LOCKVAL_SRC_POS_ARGS);
365}
366
367/*virtual*/ void WriteLockHandle::unlockRead()
368{
369 unlockWrite();
370}
371
372/*virtual*/ uint32_t WriteLockHandle::writeLockLevel() const
373{
374 return RTCritSectGetRecursion(&m->sem);
375}
376
377#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
378/*virtual*/ const char* WriteLockHandle::describe() const
379{
380 return m->strDescription.c_str();
381}
382#endif
383
384////////////////////////////////////////////////////////////////////////////////
385//
386// AutoLockBase
387//
388////////////////////////////////////////////////////////////////////////////////
389
390typedef std::vector<LockHandle*> HandlesVector;
391
392struct AutoLockBase::Data
393{
394 Data(size_t cHandles
395#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
396 , const char *pcszFile_,
397 unsigned uLine_,
398 const char *pcszFunction_
399#endif
400 )
401 : fIsLocked(false),
402 aHandles(cHandles) // size of array
403#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
404 , pcszFile(pcszFile_),
405 uLine(uLine_),
406 pcszFunction(pcszFunction_)
407#endif
408 {
409 for (uint32_t i = 0; i < cHandles; ++i)
410 aHandles[i] = NULL;
411 }
412
413 bool fIsLocked; // if true, then all items in aHandles are locked by this AutoLock and
414 // need to be unlocked in the destructor
415 HandlesVector aHandles; // array (vector) of LockHandle instances; in the case of AutoWriteLock
416 // and AutoReadLock, there will only be one item on the list; with the
417 // AutoMulti* derivatives, there will be multiple
418
419#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
420 // information about where the lock occurred (passed down from the AutoLock classes)
421 const char *pcszFile;
422 unsigned uLine;
423 const char *pcszFunction;
424#endif
425};
426
427AutoLockBase::AutoLockBase(uint32_t cHandles
428 COMMA_LOCKVAL_SRC_POS_DECL)
429{
430 m = new Data(cHandles COMMA_LOCKVAL_SRC_POS_ARGS);
431}
432
433AutoLockBase::AutoLockBase(uint32_t cHandles,
434 LockHandle *pHandle
435 COMMA_LOCKVAL_SRC_POS_DECL)
436{
437 Assert(cHandles == 1); NOREF(cHandles);
438 m = new Data(1 COMMA_LOCKVAL_SRC_POS_ARGS);
439 m->aHandles[0] = pHandle;
440}
441
442AutoLockBase::~AutoLockBase()
443{
444 delete m;
445}
446
447/**
448 * Requests ownership of all contained lock handles by calling
449 * the pure virtual callLockImpl() function on each of them,
450 * which must be implemented by the descendant class; in the
451 * implementation, AutoWriteLock will request a write lock
452 * whereas AutoReadLock will request a read lock.
453 *
454 * Does *not* modify the lock counts in the member variables.
455 */
456void AutoLockBase::callLockOnAllHandles()
457{
458 for (HandlesVector::iterator it = m->aHandles.begin();
459 it != m->aHandles.end();
460 ++it)
461 {
462 LockHandle *pHandle = *it;
463 if (pHandle)
464 // call virtual function implemented in AutoWriteLock or AutoReadLock
465 this->callLockImpl(*pHandle);
466 }
467}
468
469/**
470 * Releases ownership of all contained lock handles by calling
471 * the pure virtual callUnlockImpl() function on each of them,
472 * which must be implemented by the descendant class; in the
473 * implementation, AutoWriteLock will release a write lock
474 * whereas AutoReadLock will release a read lock.
475 *
476 * Does *not* modify the lock counts in the member variables.
477 */
478void AutoLockBase::callUnlockOnAllHandles()
479{
480 // unlock in reverse order!
481 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin();
482 it != m->aHandles.rend();
483 ++it)
484 {
485 LockHandle *pHandle = *it;
486 if (pHandle)
487 // call virtual function implemented in AutoWriteLock or AutoReadLock
488 this->callUnlockImpl(*pHandle);
489 }
490}
491
492/**
493 * Destructor implementation that can also be called explicitly, if required.
494 * Restores the exact state before the AutoLock was created; that is, unlocks
495 * all contained semaphores.
496 */
497void AutoLockBase::cleanup()
498{
499 if (m->fIsLocked)
500 callUnlockOnAllHandles();
501}
502
503/**
504 * Requests ownership of all contained semaphores. Public method that can
505 * only be called once and that also gets called by the AutoLock constructors.
506 */
507void AutoLockBase::acquire()
508{
509 AssertMsgReturnVoid(!m->fIsLocked, ("m->fIsLocked is true, attempting to lock twice!"));
510 callLockOnAllHandles();
511 m->fIsLocked = true;
512}
513
514/**
515 * Releases ownership of all contained semaphores. Public method.
516 */
517void AutoLockBase::release()
518{
519 AssertMsgReturnVoid(m->fIsLocked, ("m->fIsLocked is false, cannot release!"));
520 callUnlockOnAllHandles();
521 m->fIsLocked = false;
522}
523
524////////////////////////////////////////////////////////////////////////////////
525//
526// AutoReadLock
527//
528////////////////////////////////////////////////////////////////////////////////
529
530/**
531 * Release all read locks acquired by this instance through the #lock()
532 * call and destroys the instance.
533 *
534 * Note that if there there are nested #lock() calls without the
535 * corresponding number of #unlock() calls when the destructor is called, it
536 * will assert. This is because having an unbalanced number of nested locks
537 * is a program logic error which must be fixed.
538 */
539/*virtual*/ AutoReadLock::~AutoReadLock()
540{
541 LockHandle *pHandle = m->aHandles[0];
542
543 if (pHandle)
544 {
545 if (m->fIsLocked)
546 callUnlockImpl(*pHandle);
547 }
548}
549
550/**
551 * Implementation of the pure virtual declared in AutoLockBase.
552 * This gets called by AutoLockBase.acquire() to actually request
553 * the semaphore; in the AutoReadLock implementation, we request
554 * the semaphore in read mode.
555 */
556/*virtual*/ void AutoReadLock::callLockImpl(LockHandle &l)
557{
558#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
559 l.lockRead(m->pcszFile, m->uLine, m->pcszFunction);
560#else
561 l.lockRead();
562#endif
563}
564
565/**
566 * Implementation of the pure virtual declared in AutoLockBase.
567 * This gets called by AutoLockBase.release() to actually release
568 * the semaphore; in the AutoReadLock implementation, we release
569 * the semaphore in read mode.
570 */
571/*virtual*/ void AutoReadLock::callUnlockImpl(LockHandle &l)
572{
573 l.unlockRead();
574}
575
576////////////////////////////////////////////////////////////////////////////////
577//
578// AutoWriteLockBase
579//
580////////////////////////////////////////////////////////////////////////////////
581
582/**
583 * Implementation of the pure virtual declared in AutoLockBase.
584 * This gets called by AutoLockBase.acquire() to actually request
585 * the semaphore; in the AutoWriteLock implementation, we request
586 * the semaphore in write mode.
587 */
588/*virtual*/ void AutoWriteLockBase::callLockImpl(LockHandle &l)
589{
590#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
591 l.lockWrite(m->pcszFile, m->uLine, m->pcszFunction);
592#else
593 l.lockWrite();
594#endif
595}
596
597/**
598 * Implementation of the pure virtual declared in AutoLockBase.
599 * This gets called by AutoLockBase.release() to actually release
600 * the semaphore; in the AutoWriteLock implementation, we release
601 * the semaphore in write mode.
602 */
603/*virtual*/ void AutoWriteLockBase::callUnlockImpl(LockHandle &l)
604{
605 l.unlockWrite();
606}
607
608////////////////////////////////////////////////////////////////////////////////
609//
610// AutoWriteLock
611//
612////////////////////////////////////////////////////////////////////////////////
613
614AutoWriteLock::AutoWriteLock(uint32_t cHandles,
615 LockHandle** pHandles
616 COMMA_LOCKVAL_SRC_POS_DECL)
617 : AutoWriteLockBase(cHandles
618 COMMA_LOCKVAL_SRC_POS_ARGS)
619{
620 Assert(cHandles);
621 Assert(pHandles);
622
623 for (uint32_t i = 0; i < cHandles; ++i)
624 m->aHandles[i] = pHandles[i];
625
626 acquire();
627}
628
629
630
631/**
632 * Attaches another handle to this auto lock instance.
633 *
634 * The previous object's lock is completely released before the new one is
635 * acquired. The lock level of the new handle will be the same. This
636 * also means that if the lock was not acquired at all before #attach(), it
637 * will not be acquired on the new handle too.
638 *
639 * @param aHandle New handle to attach.
640 */
641void AutoWriteLock::attach(LockHandle *aHandle)
642{
643 LockHandle *pHandle = m->aHandles[0];
644
645 /* detect simple self-reattachment */
646 if (pHandle != aHandle)
647 {
648 bool fWasLocked = m->fIsLocked;
649
650 cleanup();
651
652 m->aHandles[0] = aHandle;
653 m->fIsLocked = fWasLocked;
654
655 if (aHandle)
656 if (fWasLocked)
657 callLockImpl(*aHandle);
658 }
659}
660
661/**
662 * Returns @c true if the current thread holds a write lock on the managed
663 * read/write semaphore. Returns @c false if the managed semaphore is @c
664 * NULL.
665 *
666 * @note Intended for debugging only.
667 */
668bool AutoWriteLock::isWriteLockOnCurrentThread() const
669{
670 return m->aHandles[0] ? m->aHandles[0]->isWriteLockOnCurrentThread() : false;
671}
672
673 /**
674 * Returns the current write lock level of the managed semaphore. The lock
675 * level determines the number of nested #lock() calls on the given
676 * semaphore handle. Returns @c 0 if the managed semaphore is @c
677 * NULL.
678 *
679 * Note that this call is valid only when the current thread owns a write
680 * lock on the given semaphore handle and will assert otherwise.
681 *
682 * @note Intended for debugging only.
683 */
684uint32_t AutoWriteLock::writeLockLevel() const
685{
686 return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0;
687}
688
689/**
690 * Returns @c true if the current thread holds a write lock on the managed
691 * read/write semaphore. Returns @c false if the managed semaphore is @c
692 * NULL.
693 *
694 * @note Intended for debugging only (esp. considering fWannaHear).
695 */
696bool AutoWriteLock::isReadLockedOnCurrentThread(bool fWannaHear) const
697{
698 return m->aHandles[0] ? m->aHandles[0]->isReadLockedOnCurrentThread(fWannaHear) : false;
699}
700
701////////////////////////////////////////////////////////////////////////////////
702//
703// AutoMultiWriteLock*
704//
705////////////////////////////////////////////////////////////////////////////////
706
707AutoMultiWriteLock2::AutoMultiWriteLock2(Lockable *pl1,
708 Lockable *pl2
709 COMMA_LOCKVAL_SRC_POS_DECL)
710 : AutoWriteLockBase(2
711 COMMA_LOCKVAL_SRC_POS_ARGS)
712{
713 if (pl1)
714 m->aHandles[0] = pl1->lockHandle();
715 if (pl2)
716 m->aHandles[1] = pl2->lockHandle();
717 acquire();
718}
719
720AutoMultiWriteLock2::AutoMultiWriteLock2(LockHandle *pl1,
721 LockHandle *pl2
722 COMMA_LOCKVAL_SRC_POS_DECL)
723 : AutoWriteLockBase(2
724 COMMA_LOCKVAL_SRC_POS_ARGS)
725{
726 m->aHandles[0] = pl1;
727 m->aHandles[1] = pl2;
728 acquire();
729}
730
731AutoMultiWriteLock3::AutoMultiWriteLock3(Lockable *pl1,
732 Lockable *pl2,
733 Lockable *pl3
734 COMMA_LOCKVAL_SRC_POS_DECL)
735 : AutoWriteLockBase(3
736 COMMA_LOCKVAL_SRC_POS_ARGS)
737{
738 if (pl1)
739 m->aHandles[0] = pl1->lockHandle();
740 if (pl2)
741 m->aHandles[1] = pl2->lockHandle();
742 if (pl3)
743 m->aHandles[2] = pl3->lockHandle();
744 acquire();
745}
746
747AutoMultiWriteLock3::AutoMultiWriteLock3(LockHandle *pl1,
748 LockHandle *pl2,
749 LockHandle *pl3
750 COMMA_LOCKVAL_SRC_POS_DECL)
751 : AutoWriteLockBase(3
752 COMMA_LOCKVAL_SRC_POS_ARGS)
753{
754 m->aHandles[0] = pl1;
755 m->aHandles[1] = pl2;
756 m->aHandles[2] = pl3;
757 acquire();
758}
759
760AutoMultiWriteLock4::AutoMultiWriteLock4(Lockable *pl1,
761 Lockable *pl2,
762 Lockable *pl3,
763 Lockable *pl4
764 COMMA_LOCKVAL_SRC_POS_DECL)
765 : AutoWriteLockBase(4
766 COMMA_LOCKVAL_SRC_POS_ARGS)
767{
768 if (pl1)
769 m->aHandles[0] = pl1->lockHandle();
770 if (pl2)
771 m->aHandles[1] = pl2->lockHandle();
772 if (pl3)
773 m->aHandles[2] = pl3->lockHandle();
774 if (pl4)
775 m->aHandles[3] = pl4->lockHandle();
776 acquire();
777}
778
779AutoMultiWriteLock4::AutoMultiWriteLock4(LockHandle *pl1,
780 LockHandle *pl2,
781 LockHandle *pl3,
782 LockHandle *pl4
783 COMMA_LOCKVAL_SRC_POS_DECL)
784 : AutoWriteLockBase(4
785 COMMA_LOCKVAL_SRC_POS_ARGS)
786{
787 m->aHandles[0] = pl1;
788 m->aHandles[1] = pl2;
789 m->aHandles[2] = pl3;
790 m->aHandles[3] = pl4;
791 acquire();
792}
793
794} /* namespace util */
795/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use