Changeset 40257 in vbox for trunk/src/VBox/Main/glue/AutoLock.cpp
- Timestamp:
- Feb 27, 2012 9:25:12 AM (13 years ago)
- svn:sync-xref-src-repo-rev:
- 76471
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/glue/AutoLock.cpp
r38773 r40257 5 5 6 6 /* 7 * Copyright (C) 2006-201 1Oracle Corporation7 * Copyright (C) 2006-2012 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 71 71 { LOCKCLASS_MACHINEOBJECT, "5-MACHINEOBJECT" }, 72 72 { LOCKCLASS_SNAPSHOTOBJECT, "6-SNAPSHOTOBJECT" }, 73 { LOCKCLASS_ LISTOFMEDIA, "7-LISTOFMEDIA" },74 { LOCKCLASS_LISTOF OTHEROBJECTS, "8-LISTOFOTHEROBJECTS" },75 { LOCKCLASS_ MEDIUMQUERY, "9-MEDIUMQUERY" },73 { LOCKCLASS_MEDIUMQUERY, "7-MEDIUMQUERY" }, 74 { LOCKCLASS_LISTOFMEDIA, "8-LISTOFMEDIA" }, 75 { LOCKCLASS_LISTOFOTHEROBJECTS, "9-LISTOFOTHEROBJECTS" }, 76 76 { LOCKCLASS_OTHEROBJECT, "10-OTHEROBJECT" }, 77 77 { LOCKCLASS_USBLIST, "11-USBLIST" }, … … 303 303 304 304 typedef std::vector<LockHandle*> HandlesVector; 305 typedef std::vector<uint32_t> CountsVector;306 305 307 306 struct AutoLockBase::Data … … 315 314 ) 316 315 : fIsLocked(false), 317 aHandles(cHandles), // size of array 318 acUnlockedInLeave(cHandles) 316 aHandles(cHandles) // size of array 319 317 #ifdef VBOX_WITH_MAIN_LOCK_VALIDATION 320 318 , pcszFile(pcszFile_), … … 324 322 { 325 323 for (uint32_t i = 0; i < cHandles; ++i) 326 {327 acUnlockedInLeave[i] = 0;328 324 aHandles[i] = NULL; 329 }330 325 } 331 326 … … 335 330 // and AutoReadLock, there will only be one item on the list; with the 336 331 // AutoMulti* derivatives, there will be multiple 337 CountsVector acUnlockedInLeave; // for each lock handle, how many times the handle was unlocked in leave(); otherwise 0338 332 339 333 #ifdef VBOX_WITH_MAIN_LOCK_VALIDATION … … 415 409 * Destructor implementation that can also be called explicitly, if required. 416 410 * Restores the exact state before the AutoLock was created; that is, unlocks 417 * all contained semaphores and might actually lock them again if leave() 418 * was called during the AutoLock's lifetime. 411 * all contained semaphores. 419 412 */ 420 413 void AutoLockBase::cleanup() 421 414 { 422 bool fAnyUnlockedInLeave = false; 423 424 uint32_t i = 0; 425 for (HandlesVector::iterator it = m->aHandles.begin(); 426 it != m->aHandles.end(); 427 ++it) 428 { 429 LockHandle *pHandle = *it; 430 if (pHandle) 431 { 432 if (m->acUnlockedInLeave[i]) 433 { 434 // there was a leave() before the destruction: then restore the 435 // lock level that might have been set by locks other than our own 436 if (m->fIsLocked) 437 { 438 --m->acUnlockedInLeave[i]; 439 fAnyUnlockedInLeave = true; 440 } 441 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i]) 442 callLockImpl(*pHandle); 443 } 444 } 445 ++i; 446 } 447 448 if (m->fIsLocked && !fAnyUnlockedInLeave) 415 if (m->fIsLocked) 449 416 callUnlockOnAllHandles(); 450 417 } … … 553 520 { 554 521 l.unlockWrite(); 555 }556 557 /**558 * Causes the current thread to completely release the write lock to make559 * the managed semaphore immediately available for locking by other threads.560 *561 * This implies that all nested write locks on the semaphore will be562 * released, even those that were acquired through the calls to #lock()563 * methods of all other AutoWriteLock/AutoReadLock instances managing the564 * <b>same</b> read/write semaphore.565 *566 * After calling this method, the only method you are allowed to call is567 * #enter(). It will acquire the write lock again and restore the same568 * level of nesting as it had before calling #leave().569 *570 * If this instance is destroyed without calling #enter(), the destructor571 * will try to restore the write lock level that existed when #leave() was572 * called minus the number of nested #lock() calls made on this instance573 * itself. This is done to preserve lock levels of other574 * AutoWriteLock/AutoReadLock instances managing the same semaphore (if575 * any). Tiis also means that the destructor may indefinitely block if a576 * write or a read lock is owned by some other thread by that time.577 */578 void AutoWriteLockBase::leave()579 {580 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot leave()!"));581 582 // unlock in reverse order!583 uint32_t i = m->aHandles.size();584 for (HandlesVector::reverse_iterator it = m->aHandles.rbegin();585 it != m->aHandles.rend();586 ++it)587 {588 --i; // array index is zero based, decrement with every loop since we iterate backwards589 LockHandle *pHandle = *it;590 if (pHandle)591 {592 AssertMsg(m->acUnlockedInLeave[i] == 0, ("m->cUnlockedInLeave[%d] is %d, must be 0! Called leave() twice?", i, m->acUnlockedInLeave[i]));593 m->acUnlockedInLeave[i] = pHandle->writeLockLevel();594 AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i]));595 596 for (uint32_t left = m->acUnlockedInLeave[i];597 left;598 --left)599 callUnlockImpl(*pHandle);600 }601 }602 }603 604 /**605 * Causes the current thread to restore the write lock level after the606 * #leave() call. This call will indefinitely block if another thread has607 * successfully acquired a write or a read lock on the same semaphore in608 * between.609 */610 void AutoWriteLockBase::enter()611 {612 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot enter()!"));613 614 uint32_t i = 0;615 for (HandlesVector::iterator it = m->aHandles.begin();616 it != m->aHandles.end();617 ++it)618 {619 LockHandle *pHandle = *it;620 if (pHandle)621 {622 AssertMsg(m->acUnlockedInLeave[i] != 0, ("m->cUnlockedInLeave[%d] is 0! enter() without leave()?", i));623 624 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])625 callLockImpl(*pHandle);626 }627 ++i;628 }629 522 } 630 523
Note:
See TracChangeset
for help on using the changeset viewer.