VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 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
RevLine 
[45127]1/* $Id: AutoLock.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
[7992]2/** @file
[45127]3 * Automatic locks, implementation.
[7992]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[7992]8 *
[96407]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
[7992]26 */
27
[45127]28
[57358]29/*********************************************************************************************************************************
30* Defined Constants And Macros *
31*********************************************************************************************************************************/
[45127]32#define GLUE_USE_CRITSECTRW
33
34
[57358]35/*********************************************************************************************************************************
36* Header Files *
37*********************************************************************************************************************************/
[25288]38#include <iprt/cdefs.h>
39#include <iprt/critsect.h>
40#include <iprt/thread.h>
41#include <iprt/semaphore.h>
42
[76474]43#include <iprt/errcore.h>
[25288]44#include <iprt/assert.h>
45
[25890]46#if defined(RT_LOCK_STRICT)
[25288]47# include <iprt/asm.h> // for ASMReturnAddress
48#endif
49
[8639]50#include <iprt/string.h>
[25310]51#include <iprt/path.h>
[25809]52#include <iprt/stream.h>
[8639]53
[25813]54#include "VBox/com/AutoLock.h"
[25408]55#include <VBox/com/string.h>
56
[25283]57#include <vector>
[25310]58#include <list>
[25834]59#include <map>
[8639]60
[45127]61
[7992]62namespace util
63{
64
[25279]65////////////////////////////////////////////////////////////////////////////////
66//
[25809]67// RuntimeLockClass
[25310]68//
69////////////////////////////////////////////////////////////////////////////////
70
[25834]71#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
72typedef std::map<VBoxLockingClass, RTLOCKVALCLASS> LockValidationClassesMap;
73LockValidationClassesMap g_mapLockValidationClasses;
74#endif
[25310]75
[25408]76/**
[25809]77 * Called from initterm.cpp on process initialization (on the main thread)
78 * to give us a chance to initialize lock validation runtime data.
[25408]79 */
[25809]80void InitAutoLockSystem()
[25310]81{
[25834]82#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
83 struct
84 {
85 VBoxLockingClass cls;
86 const char *pcszDescription;
87 } aClasses[] =
88 {
[41528]89 { LOCKCLASS_VIRTUALBOXOBJECT, "2-VIRTUALBOXOBJECT" },
[25880]90 { LOCKCLASS_HOSTOBJECT, "3-HOSTOBJECT" },
91 { LOCKCLASS_LISTOFMACHINES, "4-LISTOFMACHINES" },
92 { LOCKCLASS_MACHINEOBJECT, "5-MACHINEOBJECT" },
[25930]93 { LOCKCLASS_SNAPSHOTOBJECT, "6-SNAPSHOTOBJECT" },
[40257]94 { LOCKCLASS_MEDIUMQUERY, "7-MEDIUMQUERY" },
95 { LOCKCLASS_LISTOFMEDIA, "8-LISTOFMEDIA" },
96 { LOCKCLASS_LISTOFOTHEROBJECTS, "9-LISTOFOTHEROBJECTS" },
[38717]97 { LOCKCLASS_OTHEROBJECT, "10-OTHEROBJECT" },
[41528]98 { LOCKCLASS_PROGRESSLIST, "11-PROGRESSLIST" },
[92403]99 { LOCKCLASS_OBJECTSTATE, "12-OBJECTSTATE" },
100 { LOCKCLASS_TRANSLATOR, "13-TRANSLATOR" }
[25834]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
[25310]135}
[25408]136
[28270]137bool AutoLockHoldsLocksInClass(VBoxLockingClass lockClass)
138{
139#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[63147]140 return RTLockValidatorHoldsLocksInClass(NIL_RTTHREAD, g_mapLockValidationClasses[lockClass]);
141#else
142 RT_NOREF(lockClass);
[28270]143 return false;
[63147]144#endif
[28270]145}
146
[25310]147////////////////////////////////////////////////////////////////////////////////
148//
[25279]149// RWLockHandle
150//
151////////////////////////////////////////////////////////////////////////////////
152
[25288]153struct RWLockHandle::Data
154{
155 Data()
156 { }
157
[45127]158#ifdef GLUE_USE_CRITSECTRW
159 mutable RTCRITSECTRW CritSect;
160#else
161 RTSEMRW sem;
162#endif
163 VBoxLockingClass lockClass;
[25408]164
[25834]165#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[45127]166 com::Utf8Str strDescription;
[25408]167#endif
[25288]168};
169
[25834]170RWLockHandle::RWLockHandle(VBoxLockingClass lockClass)
[7992]171{
[25288]172 m = new Data();
[25736]173
[25809]174 m->lockClass = lockClass;
[25834]175#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[98087]176 m->strDescription.printf("r/w %RCv", this);
[45127]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
[25834]187 int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL);
[45127]188# else
[25834]189 int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL);
[45127]190# endif
[25408]191#endif
[25834]192 AssertRC(vrc);
[7992]193}
194
[25288]195/*virtual*/ RWLockHandle::~RWLockHandle()
[7992]196{
[45127]197#ifdef GLUE_USE_CRITSECTRW
198 RTCritSectRwDelete(&m->CritSect);
199#else
[25288]200 RTSemRWDestroy(m->sem);
[45127]201#endif
[25288]202 delete m;
[7992]203}
204
[25288]205/*virtual*/ bool RWLockHandle::isWriteLockOnCurrentThread() const
[7992]206{
[45127]207#ifdef GLUE_USE_CRITSECTRW
208 return RTCritSectRwIsWriteOwner(&m->CritSect);
209#else
[25288]210 return RTSemRWIsWriteOwner(m->sem);
[45127]211#endif
[7992]212}
213
[25310]214/*virtual*/ void RWLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL)
[7992]215{
[45127]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
[25736]224 int vrc = RTSemRWRequestWriteDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
[45127]225# else
[25288]226 int vrc = RTSemRWRequestWrite(m->sem, RT_INDEFINITE_WAIT);
[45127]227# endif
[25736]228#endif
[25288]229 AssertRC(vrc);
[7992]230}
231
[25288]232/*virtual*/ void RWLockHandle::unlockWrite()
[7992]233{
[45127]234#ifdef GLUE_USE_CRITSECTRW
235 int vrc = RTCritSectRwLeaveExcl(&m->CritSect);
236#else
[25288]237 int vrc = RTSemRWReleaseWrite(m->sem);
[45127]238#endif
[25288]239 AssertRC(vrc);
[25310]240
[7992]241}
242
[67721]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
[25310]252/*virtual*/ void RWLockHandle::lockRead(LOCKVAL_SRC_POS_DECL)
[7992]253{
[45127]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
[25736]262 int vrc = RTSemRWRequestReadDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
[45127]263# else
[25288]264 int vrc = RTSemRWRequestRead(m->sem, RT_INDEFINITE_WAIT);
[45127]265# endif
[25736]266#endif
[25288]267 AssertRC(vrc);
[7992]268}
269
[25288]270/*virtual*/ void RWLockHandle::unlockRead()
[7992]271{
[45127]272#ifdef GLUE_USE_CRITSECTRW
273 int vrc = RTCritSectRwLeaveShared(&m->CritSect);
274#else
[25288]275 int vrc = RTSemRWReleaseRead(m->sem);
[45127]276#endif
[25288]277 AssertRC(vrc);
[7992]278}
279
[25288]280/*virtual*/ uint32_t RWLockHandle::writeLockLevel() const
[7992]281{
[25736]282 /* Note! This does not include read recursions done by the writer! */
[45127]283#ifdef GLUE_USE_CRITSECTRW
284 return RTCritSectRwGetWriteRecursion(&m->CritSect);
285#else
[25288]286 return RTSemRWGetWriteRecursion(m->sem);
[45127]287#endif
[7992]288}
289
[25834]290#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[25408]291/*virtual*/ const char* RWLockHandle::describe() const
292{
293 return m->strDescription.c_str();
294}
295#endif
296
[25281]297////////////////////////////////////////////////////////////////////////////////
298//
[25287]299// WriteLockHandle
300//
301////////////////////////////////////////////////////////////////////////////////
302
[25288]303struct WriteLockHandle::Data
304{
305 Data()
306 { }
307
[25809]308 mutable RTCRITSECT sem;
[25834]309 VBoxLockingClass lockClass;
[25408]310
[25834]311#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[25809]312 com::Utf8Str strDescription;
[25408]313#endif
[25288]314};
315
[25834]316WriteLockHandle::WriteLockHandle(VBoxLockingClass lockClass)
[25287]317{
[25288]318 m = new Data;
[25809]319
320 m->lockClass = lockClass;
321
[25834]322#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[25408]323 m->strDescription = com::Utf8StrFmt("crit %RCv", this);
[25834]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);
[25408]327#endif
[25834]328 AssertRC(vrc);
[25287]329}
330
[25288]331WriteLockHandle::~WriteLockHandle()
[25287]332{
[25288]333 RTCritSectDelete(&m->sem);
334 delete m;
[25287]335}
336
337/*virtual*/ bool WriteLockHandle::isWriteLockOnCurrentThread() const
338{
[25288]339 return RTCritSectIsOwner(&m->sem);
[25287]340}
341
[25310]342/*virtual*/ void WriteLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL)
[25287]343{
[25834]344#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[25368]345 RTCritSectEnterDebug(&m->sem, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
[25287]346#else
[25288]347 RTCritSectEnter(&m->sem);
[25287]348#endif
349}
350
[67721]351/*virtual*/ bool WriteLockHandle::isReadLockedOnCurrentThread(bool fWannaHear) const
352{
353 RT_NOREF(fWannaHear);
354 return RTCritSectIsOwner(&m->sem);
355}
356
[25287]357/*virtual*/ void WriteLockHandle::unlockWrite()
358{
[25288]359 RTCritSectLeave(&m->sem);
[25287]360}
361
[25310]362/*virtual*/ void WriteLockHandle::lockRead(LOCKVAL_SRC_POS_DECL)
[25287]363{
[25310]364 lockWrite(LOCKVAL_SRC_POS_ARGS);
[25287]365}
366
367/*virtual*/ void WriteLockHandle::unlockRead()
368{
369 unlockWrite();
370}
371
372/*virtual*/ uint32_t WriteLockHandle::writeLockLevel() const
373{
[25288]374 return RTCritSectGetRecursion(&m->sem);
[25287]375}
376
[25834]377#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[25408]378/*virtual*/ const char* WriteLockHandle::describe() const
379{
380 return m->strDescription.c_str();
381}
382#endif
383
[25287]384////////////////////////////////////////////////////////////////////////////////
385//
[25281]386// AutoLockBase
387//
388////////////////////////////////////////////////////////////////////////////////
389
[25283]390typedef std::vector<LockHandle*> HandlesVector;
391
[25281]392struct AutoLockBase::Data
393{
[25310]394 Data(size_t cHandles
[25834]395#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[25310]396 , const char *pcszFile_,
397 unsigned uLine_,
398 const char *pcszFunction_
399#endif
400 )
[25285]401 : fIsLocked(false),
[40257]402 aHandles(cHandles) // size of array
[25834]403#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[25310]404 , pcszFile(pcszFile_),
405 uLine(uLine_),
406 pcszFunction(pcszFunction_)
407#endif
[25285]408 {
409 for (uint32_t i = 0; i < cHandles; ++i)
410 aHandles[i] = NULL;
411 }
[25281]412
[25285]413 bool fIsLocked; // if true, then all items in aHandles are locked by this AutoLock and
414 // need to be unlocked in the destructor
[25283]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
[25310]418
[25834]419#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[33540]420 // information about where the lock occurred (passed down from the AutoLock classes)
[25310]421 const char *pcszFile;
422 unsigned uLine;
423 const char *pcszFunction;
424#endif
[25281]425};
426
[25310]427AutoLockBase::AutoLockBase(uint32_t cHandles
428 COMMA_LOCKVAL_SRC_POS_DECL)
[25281]429{
[63147]430 m = new Data(cHandles COMMA_LOCKVAL_SRC_POS_ARGS);
[25285]431}
432
[25310]433AutoLockBase::AutoLockBase(uint32_t cHandles,
434 LockHandle *pHandle
435 COMMA_LOCKVAL_SRC_POS_DECL)
[25285]436{
[63147]437 Assert(cHandles == 1); NOREF(cHandles);
438 m = new Data(1 COMMA_LOCKVAL_SRC_POS_ARGS);
[25283]439 m->aHandles[0] = pHandle;
[25281]440}
441
442AutoLockBase::~AutoLockBase()
443{
444 delete m;
445}
446
[25282]447/**
448 * Requests ownership of all contained lock handles by calling
[25283]449 * the pure virtual callLockImpl() function on each of them,
[25282]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.
[25283]453 *
454 * Does *not* modify the lock counts in the member variables.
[25282]455 */
[25283]456void AutoLockBase::callLockOnAllHandles()
[25282]457{
[25283]458 for (HandlesVector::iterator it = m->aHandles.begin();
459 it != m->aHandles.end();
460 ++it)
[25282]461 {
[25283]462 LockHandle *pHandle = *it;
463 if (pHandle)
464 // call virtual function implemented in AutoWriteLock or AutoReadLock
465 this->callLockImpl(*pHandle);
[25282]466 }
467}
468
469/**
470 * Releases ownership of all contained lock handles by calling
[25283]471 * the pure virtual callUnlockImpl() function on each of them,
[25282]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.
[25283]475 *
476 * Does *not* modify the lock counts in the member variables.
[25282]477 */
[25283]478void AutoLockBase::callUnlockOnAllHandles()
[25282]479{
[25310]480 // unlock in reverse order!
481 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin();
482 it != m->aHandles.rend();
[25283]483 ++it)
[25282]484 {
[25283]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
[40257]495 * all contained semaphores.
[25283]496 */
497void AutoLockBase::cleanup()
498{
[40257]499 if (m->fIsLocked)
[25283]500 callUnlockOnAllHandles();
[25282]501}
502
[25283]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{
[40452]509 AssertMsgReturnVoid(!m->fIsLocked, ("m->fIsLocked is true, attempting to lock twice!"));
[25283]510 callLockOnAllHandles();
511 m->fIsLocked = true;
512}
513
514/**
515 * Releases ownership of all contained semaphores. Public method.
516 */
517void AutoLockBase::release()
518{
[40452]519 AssertMsgReturnVoid(m->fIsLocked, ("m->fIsLocked is false, cannot release!"));
[25283]520 callUnlockOnAllHandles();
521 m->fIsLocked = false;
522}
523
[25281]524////////////////////////////////////////////////////////////////////////////////
525//
[25284]526// AutoReadLock
[25281]527//
528////////////////////////////////////////////////////////////////////////////////
529
[25282]530/**
[25284]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)
[25310]546 callUnlockImpl(*pHandle);
[25284]547 }
548}
549
550/**
[25282]551 * Implementation of the pure virtual declared in AutoLockBase.
552 * This gets called by AutoLockBase.acquire() to actually request
[25284]553 * the semaphore; in the AutoReadLock implementation, we request
554 * the semaphore in read mode.
555 */
556/*virtual*/ void AutoReadLock::callLockImpl(LockHandle &l)
557{
[25834]558#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[25310]559 l.lockRead(m->pcszFile, m->uLine, m->pcszFunction);
560#else
[25284]561 l.lockRead();
[25310]562#endif
[25284]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
[25282]585 * the semaphore; in the AutoWriteLock implementation, we request
586 * the semaphore in write mode.
587 */
[25284]588/*virtual*/ void AutoWriteLockBase::callLockImpl(LockHandle &l)
[25281]589{
[25834]590#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
[25310]591 l.lockWrite(m->pcszFile, m->uLine, m->pcszFunction);
592#else
[25282]593 l.lockWrite();
[25310]594#endif
[25281]595}
596
[25282]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 */
[25284]603/*virtual*/ void AutoWriteLockBase::callUnlockImpl(LockHandle &l)
[25281]604{
[25282]605 l.unlockWrite();
[25281]606}
607
[25284]608////////////////////////////////////////////////////////////////////////////////
609//
610// AutoWriteLock
611//
612////////////////////////////////////////////////////////////////////////////////
613
[38773]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
[25281]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{
[25283]643 LockHandle *pHandle = m->aHandles[0];
644
[25281]645 /* detect simple self-reattachment */
[25283]646 if (pHandle != aHandle)
[25281]647 {
648 bool fWasLocked = m->fIsLocked;
649
650 cleanup();
651
[25283]652 m->aHandles[0] = aHandle;
[25281]653 m->fIsLocked = fWasLocked;
654
[25283]655 if (aHandle)
[25281]656 if (fWasLocked)
[25310]657 callLockImpl(*aHandle);
[25281]658 }
659}
660
[25285]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 /**
[33540]674 * Returns the current write lock level of the managed semaphore. The lock
[25285]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
[67721]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
[25285]701////////////////////////////////////////////////////////////////////////////////
702//
703// AutoMultiWriteLock*
704//
705////////////////////////////////////////////////////////////////////////////////
706
[25310]707AutoMultiWriteLock2::AutoMultiWriteLock2(Lockable *pl1,
708 Lockable *pl2
709 COMMA_LOCKVAL_SRC_POS_DECL)
710 : AutoWriteLockBase(2
711 COMMA_LOCKVAL_SRC_POS_ARGS)
[25285]712{
713 if (pl1)
714 m->aHandles[0] = pl1->lockHandle();
715 if (pl2)
716 m->aHandles[1] = pl2->lockHandle();
717 acquire();
718}
719
[25310]720AutoMultiWriteLock2::AutoMultiWriteLock2(LockHandle *pl1,
721 LockHandle *pl2
722 COMMA_LOCKVAL_SRC_POS_DECL)
723 : AutoWriteLockBase(2
724 COMMA_LOCKVAL_SRC_POS_ARGS)
[25285]725{
726 m->aHandles[0] = pl1;
727 m->aHandles[1] = pl2;
728 acquire();
729}
730
[25310]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)
[25285]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
[25310]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)
[25285]753{
754 m->aHandles[0] = pl1;
755 m->aHandles[1] = pl2;
756 m->aHandles[2] = pl3;
757 acquire();
758}
759
[38743]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
[7992]794} /* namespace util */
[14772]795/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use