VirtualBox

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

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

Main: remove separate snapshots tree lock, have snapshots list use machine lock instead

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.0 KB
Line 
1/** @file
2 *
3 * Automatic locks, implementation
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include <iprt/cdefs.h>
23#include <iprt/critsect.h>
24#include <iprt/thread.h>
25#include <iprt/semaphore.h>
26
27#include <iprt/err.h>
28#include <iprt/assert.h>
29
30#if defined(RT_LOCK_STRICT)
31# include <iprt/asm.h> // for ASMReturnAddress
32#endif
33
34#include <iprt/string.h>
35#include <iprt/path.h>
36#include <iprt/stream.h>
37
38#include "VBox/com/AutoLock.h"
39#include <VBox/com/string.h>
40
41#include <vector>
42#include <list>
43#include <map>
44
45namespace util
46{
47
48////////////////////////////////////////////////////////////////////////////////
49//
50// RuntimeLockClass
51//
52////////////////////////////////////////////////////////////////////////////////
53
54#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
55typedef std::map<VBoxLockingClass, RTLOCKVALCLASS> LockValidationClassesMap;
56LockValidationClassesMap g_mapLockValidationClasses;
57#endif
58
59/**
60 * Called from initterm.cpp on process initialization (on the main thread)
61 * to give us a chance to initialize lock validation runtime data.
62 */
63void InitAutoLockSystem()
64{
65#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
66 struct
67 {
68 VBoxLockingClass cls;
69 const char *pcszDescription;
70 } aClasses[] =
71 {
72 { LOCKCLASS_VIRTUALBOXOBJECT, "1-VIRTUALBOXOBJECT" },
73 { LOCKCLASS_USBPROXYSERVICE, "2-USBPROXYSERVICE" },
74 { LOCKCLASS_HOSTOBJECT, "3-HOSTOBJECT" },
75 { LOCKCLASS_LISTOFMACHINES, "4-LISTOFMACHINES" },
76 { LOCKCLASS_MACHINEOBJECT, "5-MACHINEOBJECT" },
77 { LOCKCLASS_SNAPSHOTOBJECT, "6-SNAPSHOTOBJECT" },
78 { LOCKCLASS_LISTOFMEDIA, "7-LISTOFMEDIA" },
79 { LOCKCLASS_LISTOFOTHEROBJECTS, "8-LISTOFOTHEROBJECTS" },
80 { LOCKCLASS_OTHEROBJECT, "9-OTHEROBJECT" },
81 { LOCKCLASS_USBLIST, "10-USBLIST" },
82 { LOCKCLASS_PROGRESSLIST, "11-PROGRESSLIST" },
83 { LOCKCLASS_OBJECTSTATE, "12-OBJECTSTATE" }
84 };
85
86 RTLOCKVALCLASS hClass;
87 int vrc;
88 for (unsigned i = 0; i < RT_ELEMENTS(aClasses); ++i)
89 {
90 vrc = RTLockValidatorClassCreate(&hClass,
91 true, /*fAutodidact*/
92 RT_SRC_POS,
93 aClasses[i].pcszDescription);
94 AssertRC(vrc);
95
96 // teach the new class that the classes created previously can be held
97 // while the new class is being acquired
98 for (LockValidationClassesMap::iterator it = g_mapLockValidationClasses.begin();
99 it != g_mapLockValidationClasses.end();
100 ++it)
101 {
102 RTLOCKVALCLASS &canBeHeld = it->second;
103 vrc = RTLockValidatorClassAddPriorClass(hClass,
104 canBeHeld);
105 AssertRC(vrc);
106 }
107
108 // and store the new class
109 g_mapLockValidationClasses[aClasses[i].cls] = hClass;
110 }
111
112/* WriteLockHandle critsect1(LOCKCLASS_VIRTUALBOXOBJECT);
113 WriteLockHandle critsect2(LOCKCLASS_VIRTUALBOXLIST);
114
115 AutoWriteLock lock1(critsect1 COMMA_LOCKVAL_SRC_POS);
116 AutoWriteLock lock2(critsect2 COMMA_LOCKVAL_SRC_POS);*/
117#endif
118}
119
120////////////////////////////////////////////////////////////////////////////////
121//
122// RWLockHandle
123//
124////////////////////////////////////////////////////////////////////////////////
125
126struct RWLockHandle::Data
127{
128 Data()
129 { }
130
131 RTSEMRW sem;
132 VBoxLockingClass lockClass;
133
134#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
135 com::Utf8Str strDescription;
136#endif
137};
138
139RWLockHandle::RWLockHandle(VBoxLockingClass lockClass)
140{
141 m = new Data();
142
143 m->lockClass = lockClass;
144
145#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
146 m->strDescription = com::Utf8StrFmt("r/w %RCv", this);
147 int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL);
148#else
149 int vrc = RTSemRWCreateEx(&m->sem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL);
150#endif
151 AssertRC(vrc);
152}
153
154/*virtual*/ RWLockHandle::~RWLockHandle()
155{
156 RTSemRWDestroy(m->sem);
157 delete m;
158}
159
160/*virtual*/ bool RWLockHandle::isWriteLockOnCurrentThread() const
161{
162 return RTSemRWIsWriteOwner(m->sem);
163}
164
165/*virtual*/ void RWLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL)
166{
167#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
168 int vrc = RTSemRWRequestWriteDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
169#else
170 int vrc = RTSemRWRequestWrite(m->sem, RT_INDEFINITE_WAIT);
171#endif
172 AssertRC(vrc);
173}
174
175/*virtual*/ void RWLockHandle::unlockWrite()
176{
177 int vrc = RTSemRWReleaseWrite(m->sem);
178 AssertRC(vrc);
179
180}
181
182/*virtual*/ void RWLockHandle::lockRead(LOCKVAL_SRC_POS_DECL)
183{
184#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
185 int vrc = RTSemRWRequestReadDebug(m->sem, RT_INDEFINITE_WAIT, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
186#else
187 int vrc = RTSemRWRequestRead(m->sem, RT_INDEFINITE_WAIT);
188#endif
189 AssertRC(vrc);
190}
191
192/*virtual*/ void RWLockHandle::unlockRead()
193{
194 int vrc = RTSemRWReleaseRead(m->sem);
195 AssertRC(vrc);
196}
197
198/*virtual*/ uint32_t RWLockHandle::writeLockLevel() const
199{
200 /* Note! This does not include read recursions done by the writer! */
201 return RTSemRWGetWriteRecursion(m->sem);
202}
203
204#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
205/*virtual*/ const char* RWLockHandle::describe() const
206{
207 return m->strDescription.c_str();
208}
209#endif
210
211////////////////////////////////////////////////////////////////////////////////
212//
213// WriteLockHandle
214//
215////////////////////////////////////////////////////////////////////////////////
216
217struct WriteLockHandle::Data
218{
219 Data()
220 { }
221
222 mutable RTCRITSECT sem;
223 VBoxLockingClass lockClass;
224
225#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
226 com::Utf8Str strDescription;
227#endif
228};
229
230WriteLockHandle::WriteLockHandle(VBoxLockingClass lockClass)
231{
232 m = new Data;
233
234 m->lockClass = lockClass;
235
236#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
237 m->strDescription = com::Utf8StrFmt("crit %RCv", this);
238 int vrc = RTCritSectInitEx(&m->sem, 0/*fFlags*/, g_mapLockValidationClasses[lockClass], RTLOCKVAL_SUB_CLASS_ANY, NULL);
239#else
240 int vrc = RTCritSectInitEx(&m->sem, 0/*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, NULL);
241#endif
242 AssertRC(vrc);
243}
244
245WriteLockHandle::~WriteLockHandle()
246{
247 RTCritSectDelete(&m->sem);
248 delete m;
249}
250
251/*virtual*/ bool WriteLockHandle::isWriteLockOnCurrentThread() const
252{
253 return RTCritSectIsOwner(&m->sem);
254}
255
256/*virtual*/ void WriteLockHandle::lockWrite(LOCKVAL_SRC_POS_DECL)
257{
258#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
259 RTCritSectEnterDebug(&m->sem, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
260#else
261 RTCritSectEnter(&m->sem);
262#endif
263}
264
265/*virtual*/ void WriteLockHandle::unlockWrite()
266{
267 RTCritSectLeave(&m->sem);
268}
269
270/*virtual*/ void WriteLockHandle::lockRead(LOCKVAL_SRC_POS_DECL)
271{
272 lockWrite(LOCKVAL_SRC_POS_ARGS);
273}
274
275/*virtual*/ void WriteLockHandle::unlockRead()
276{
277 unlockWrite();
278}
279
280/*virtual*/ uint32_t WriteLockHandle::writeLockLevel() const
281{
282 return RTCritSectGetRecursion(&m->sem);
283}
284
285#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
286/*virtual*/ const char* WriteLockHandle::describe() const
287{
288 return m->strDescription.c_str();
289}
290#endif
291
292////////////////////////////////////////////////////////////////////////////////
293//
294// AutoLockBase
295//
296////////////////////////////////////////////////////////////////////////////////
297
298typedef std::vector<LockHandle*> HandlesVector;
299typedef std::vector<uint32_t> CountsVector;
300
301struct AutoLockBase::Data
302{
303 Data(size_t cHandles
304#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
305 , const char *pcszFile_,
306 unsigned uLine_,
307 const char *pcszFunction_
308#endif
309 )
310 : fIsLocked(false),
311 aHandles(cHandles), // size of array
312 acUnlockedInLeave(cHandles)
313#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
314 , pcszFile(pcszFile_),
315 uLine(uLine_),
316 pcszFunction(pcszFunction_)
317#endif
318 {
319 for (uint32_t i = 0; i < cHandles; ++i)
320 {
321 acUnlockedInLeave[i] = 0;
322 aHandles[i] = NULL;
323 }
324 }
325
326 bool fIsLocked; // if true, then all items in aHandles are locked by this AutoLock and
327 // need to be unlocked in the destructor
328 HandlesVector aHandles; // array (vector) of LockHandle instances; in the case of AutoWriteLock
329 // and AutoReadLock, there will only be one item on the list; with the
330 // AutoMulti* derivatives, there will be multiple
331 CountsVector acUnlockedInLeave; // for each lock handle, how many times the handle was unlocked in leave(); otherwise 0
332
333#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
334 // information about where the lock occured (passed down from the AutoLock classes)
335 const char *pcszFile;
336 unsigned uLine;
337 const char *pcszFunction;
338#endif
339};
340
341AutoLockBase::AutoLockBase(uint32_t cHandles
342 COMMA_LOCKVAL_SRC_POS_DECL)
343{
344 m = new Data(cHandles
345 COMMA_LOCKVAL_SRC_POS_ARGS);
346}
347
348AutoLockBase::AutoLockBase(uint32_t cHandles,
349 LockHandle *pHandle
350 COMMA_LOCKVAL_SRC_POS_DECL)
351{
352 Assert(cHandles == 1);
353 m = new Data(1
354 COMMA_LOCKVAL_SRC_POS_ARGS);
355 m->aHandles[0] = pHandle;
356}
357
358AutoLockBase::~AutoLockBase()
359{
360 delete m;
361}
362
363/**
364 * Requests ownership of all contained lock handles by calling
365 * the pure virtual callLockImpl() function on each of them,
366 * which must be implemented by the descendant class; in the
367 * implementation, AutoWriteLock will request a write lock
368 * whereas AutoReadLock will request a read lock.
369 *
370 * Does *not* modify the lock counts in the member variables.
371 */
372void AutoLockBase::callLockOnAllHandles()
373{
374 for (HandlesVector::iterator it = m->aHandles.begin();
375 it != m->aHandles.end();
376 ++it)
377 {
378 LockHandle *pHandle = *it;
379 if (pHandle)
380 // call virtual function implemented in AutoWriteLock or AutoReadLock
381 this->callLockImpl(*pHandle);
382 }
383}
384
385/**
386 * Releases ownership of all contained lock handles by calling
387 * the pure virtual callUnlockImpl() function on each of them,
388 * which must be implemented by the descendant class; in the
389 * implementation, AutoWriteLock will release a write lock
390 * whereas AutoReadLock will release a read lock.
391 *
392 * Does *not* modify the lock counts in the member variables.
393 */
394void AutoLockBase::callUnlockOnAllHandles()
395{
396 // unlock in reverse order!
397 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin();
398 it != m->aHandles.rend();
399 ++it)
400 {
401 LockHandle *pHandle = *it;
402 if (pHandle)
403 // call virtual function implemented in AutoWriteLock or AutoReadLock
404 this->callUnlockImpl(*pHandle);
405 }
406}
407
408/**
409 * Destructor implementation that can also be called explicitly, if required.
410 * Restores the exact state before the AutoLock was created; that is, unlocks
411 * all contained semaphores and might actually lock them again if leave()
412 * was called during the AutoLock's lifetime.
413 */
414void AutoLockBase::cleanup()
415{
416 bool fAnyUnlockedInLeave = false;
417
418 uint32_t i = 0;
419 for (HandlesVector::iterator it = m->aHandles.begin();
420 it != m->aHandles.end();
421 ++it)
422 {
423 LockHandle *pHandle = *it;
424 if (pHandle)
425 {
426 if (m->acUnlockedInLeave[i])
427 {
428 // there was a leave() before the destruction: then restore the
429 // lock level that might have been set by locks other than our own
430 if (m->fIsLocked)
431 {
432 --m->acUnlockedInLeave[i];
433 fAnyUnlockedInLeave = true;
434 }
435 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])
436 callLockImpl(*pHandle);
437 }
438 }
439 ++i;
440 }
441
442 if (m->fIsLocked && !fAnyUnlockedInLeave)
443 callUnlockOnAllHandles();
444}
445
446/**
447 * Requests ownership of all contained semaphores. Public method that can
448 * only be called once and that also gets called by the AutoLock constructors.
449 */
450void AutoLockBase::acquire()
451{
452 AssertMsg(!m->fIsLocked, ("m->fIsLocked is true, attempting to lock twice!"));
453 callLockOnAllHandles();
454 m->fIsLocked = true;
455}
456
457/**
458 * Releases ownership of all contained semaphores. Public method.
459 */
460void AutoLockBase::release()
461{
462 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot release!"));
463 callUnlockOnAllHandles();
464 m->fIsLocked = false;
465}
466
467////////////////////////////////////////////////////////////////////////////////
468//
469// AutoReadLock
470//
471////////////////////////////////////////////////////////////////////////////////
472
473/**
474 * Release all read locks acquired by this instance through the #lock()
475 * call and destroys the instance.
476 *
477 * Note that if there there are nested #lock() calls without the
478 * corresponding number of #unlock() calls when the destructor is called, it
479 * will assert. This is because having an unbalanced number of nested locks
480 * is a program logic error which must be fixed.
481 */
482/*virtual*/ AutoReadLock::~AutoReadLock()
483{
484 LockHandle *pHandle = m->aHandles[0];
485
486 if (pHandle)
487 {
488 if (m->fIsLocked)
489 callUnlockImpl(*pHandle);
490 }
491}
492
493/**
494 * Implementation of the pure virtual declared in AutoLockBase.
495 * This gets called by AutoLockBase.acquire() to actually request
496 * the semaphore; in the AutoReadLock implementation, we request
497 * the semaphore in read mode.
498 */
499/*virtual*/ void AutoReadLock::callLockImpl(LockHandle &l)
500{
501#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
502 l.lockRead(m->pcszFile, m->uLine, m->pcszFunction);
503#else
504 l.lockRead();
505#endif
506}
507
508/**
509 * Implementation of the pure virtual declared in AutoLockBase.
510 * This gets called by AutoLockBase.release() to actually release
511 * the semaphore; in the AutoReadLock implementation, we release
512 * the semaphore in read mode.
513 */
514/*virtual*/ void AutoReadLock::callUnlockImpl(LockHandle &l)
515{
516 l.unlockRead();
517}
518
519////////////////////////////////////////////////////////////////////////////////
520//
521// AutoWriteLockBase
522//
523////////////////////////////////////////////////////////////////////////////////
524
525/**
526 * Implementation of the pure virtual declared in AutoLockBase.
527 * This gets called by AutoLockBase.acquire() to actually request
528 * the semaphore; in the AutoWriteLock implementation, we request
529 * the semaphore in write mode.
530 */
531/*virtual*/ void AutoWriteLockBase::callLockImpl(LockHandle &l)
532{
533#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
534 l.lockWrite(m->pcszFile, m->uLine, m->pcszFunction);
535#else
536 l.lockWrite();
537#endif
538}
539
540/**
541 * Implementation of the pure virtual declared in AutoLockBase.
542 * This gets called by AutoLockBase.release() to actually release
543 * the semaphore; in the AutoWriteLock implementation, we release
544 * the semaphore in write mode.
545 */
546/*virtual*/ void AutoWriteLockBase::callUnlockImpl(LockHandle &l)
547{
548 l.unlockWrite();
549}
550
551/**
552 * Causes the current thread to completely release the write lock to make
553 * the managed semaphore immediately available for locking by other threads.
554 *
555 * This implies that all nested write locks on the semaphore will be
556 * released, even those that were acquired through the calls to #lock()
557 * methods of all other AutoWriteLock/AutoReadLock instances managing the
558 * <b>same</b> read/write semaphore.
559 *
560 * After calling this method, the only method you are allowed to call is
561 * #enter(). It will acquire the write lock again and restore the same
562 * level of nesting as it had before calling #leave().
563 *
564 * If this instance is destroyed without calling #enter(), the destructor
565 * will try to restore the write lock level that existed when #leave() was
566 * called minus the number of nested #lock() calls made on this instance
567 * itself. This is done to preserve lock levels of other
568 * AutoWriteLock/AutoReadLock instances managing the same semaphore (if
569 * any). Tiis also means that the destructor may indefinitely block if a
570 * write or a read lock is owned by some other thread by that time.
571 */
572void AutoWriteLockBase::leave()
573{
574 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot leave()!"));
575
576 // unlock in reverse order!
577 uint32_t i = m->aHandles.size();
578 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin();
579 it != m->aHandles.rend();
580 ++it)
581 {
582 --i; // array index is zero based, decrement with every loop since we iterate backwards
583 LockHandle *pHandle = *it;
584 if (pHandle)
585 {
586 AssertMsg(m->acUnlockedInLeave[i] == 0, ("m->cUnlockedInLeave[%d] is %d, must be 0! Called leave() twice?", i, m->acUnlockedInLeave[i]));
587 m->acUnlockedInLeave[i] = pHandle->writeLockLevel();
588 AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i]));
589
590 for (uint32_t left = m->acUnlockedInLeave[i];
591 left;
592 --left)
593 callUnlockImpl(*pHandle);
594 }
595 }
596}
597
598/**
599 * Causes the current thread to restore the write lock level after the
600 * #leave() call. This call will indefinitely block if another thread has
601 * successfully acquired a write or a read lock on the same semaphore in
602 * between.
603 */
604void AutoWriteLockBase::enter()
605{
606 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot enter()!"));
607
608 uint32_t i = 0;
609 for (HandlesVector::iterator it = m->aHandles.begin();
610 it != m->aHandles.end();
611 ++it)
612 {
613 LockHandle *pHandle = *it;
614 if (pHandle)
615 {
616 AssertMsg(m->acUnlockedInLeave[i] != 0, ("m->cUnlockedInLeave[%d] is 0! enter() without leave()?", i));
617
618 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])
619 callLockImpl(*pHandle);
620 }
621 ++i;
622 }
623}
624
625////////////////////////////////////////////////////////////////////////////////
626//
627// AutoWriteLock
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 smaphore. 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//
691// AutoMultiWriteLock*
692//
693////////////////////////////////////////////////////////////////////////////////
694
695AutoMultiWriteLock2::AutoMultiWriteLock2(Lockable *pl1,
696 Lockable *pl2
697 COMMA_LOCKVAL_SRC_POS_DECL)
698 : AutoWriteLockBase(2
699 COMMA_LOCKVAL_SRC_POS_ARGS)
700{
701 if (pl1)
702 m->aHandles[0] = pl1->lockHandle();
703 if (pl2)
704 m->aHandles[1] = pl2->lockHandle();
705 acquire();
706}
707
708AutoMultiWriteLock2::AutoMultiWriteLock2(LockHandle *pl1,
709 LockHandle *pl2
710 COMMA_LOCKVAL_SRC_POS_DECL)
711 : AutoWriteLockBase(2
712 COMMA_LOCKVAL_SRC_POS_ARGS)
713{
714 m->aHandles[0] = pl1;
715 m->aHandles[1] = pl2;
716 acquire();
717}
718
719AutoMultiWriteLock3::AutoMultiWriteLock3(Lockable *pl1,
720 Lockable *pl2,
721 Lockable *pl3
722 COMMA_LOCKVAL_SRC_POS_DECL)
723 : AutoWriteLockBase(3
724 COMMA_LOCKVAL_SRC_POS_ARGS)
725{
726 if (pl1)
727 m->aHandles[0] = pl1->lockHandle();
728 if (pl2)
729 m->aHandles[1] = pl2->lockHandle();
730 if (pl3)
731 m->aHandles[2] = pl3->lockHandle();
732 acquire();
733}
734
735AutoMultiWriteLock3::AutoMultiWriteLock3(LockHandle *pl1,
736 LockHandle *pl2,
737 LockHandle *pl3
738 COMMA_LOCKVAL_SRC_POS_DECL)
739 : AutoWriteLockBase(3
740 COMMA_LOCKVAL_SRC_POS_ARGS)
741{
742 m->aHandles[0] = pl1;
743 m->aHandles[1] = pl2;
744 m->aHandles[2] = pl3;
745 acquire();
746}
747
748} /* namespace util */
749/* 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