Changeset 25285 in vbox
- Timestamp:
- Dec 9, 2009 11:38:58 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 55832
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/AutoLock.cpp
r25284 r25285 96 96 97 97 typedef std::vector<LockHandle*> HandlesVector; 98 typedef std::vector<uint32_t> CountsVector; 98 99 99 100 struct AutoLockBase::Data 100 101 { 101 102 Data(size_t cHandles) 102 : aHandles(cHandles), // size of array 103 fIsLocked(false), 104 cUnlockedInLeave(0) 105 { } 106 103 : fIsLocked(false), 104 aHandles(cHandles), // size of array 105 acUnlockedInLeave(cHandles) 106 { 107 for (uint32_t i = 0; i < cHandles; ++i) 108 { 109 acUnlockedInLeave[i] = 0; 110 aHandles[i] = NULL; 111 } 112 } 113 114 bool fIsLocked; // if true, then all items in aHandles are locked by this AutoLock and 115 // need to be unlocked in the destructor 107 116 HandlesVector aHandles; // array (vector) of LockHandle instances; in the case of AutoWriteLock 108 117 // and AutoReadLock, there will only be one item on the list; with the 109 118 // AutoMulti* derivatives, there will be multiple 110 bool fIsLocked; // if true, then all items in aHandles are locked by this AutoLock and 111 // need to be unlocked in the destructor 112 uint32_t cUnlockedInLeave; // how many times the handle was unlocked in leave(); otherwise 0 119 CountsVector acUnlockedInLeave; // for each lock handle, how many times the handle was unlocked in leave(); otherwise 0 113 120 }; 114 121 115 AutoLockBase::AutoLockBase(LockHandle *pHandle) 116 { 122 AutoLockBase::AutoLockBase(uint32_t cHandles) 123 { 124 m = new Data(cHandles); 125 } 126 127 AutoLockBase::AutoLockBase(uint32_t cHandles, LockHandle *pHandle) 128 { 129 Assert(cHandles == 1); 117 130 m = new Data(1); 118 131 m->aHandles[0] = pHandle; … … 176 189 void AutoLockBase::cleanup() 177 190 { 178 if (m->cUnlockedInLeave) 179 { 180 // there was a leave() before the destruction: then restore the 181 // lock level that might have been set by locks other than our own 182 if (m->fIsLocked) 183 --m->cUnlockedInLeave; // no lock for our own 184 m->fIsLocked = false; 185 for (; m->cUnlockedInLeave; --m->cUnlockedInLeave) 186 callLockOnAllHandles(); 187 } 188 189 if (m->fIsLocked) 191 bool fAnyUnlockedInLeave = false; 192 193 uint32_t i = 0; 194 for (HandlesVector::iterator it = m->aHandles.begin(); 195 it != m->aHandles.end(); 196 ++it) 197 { 198 LockHandle *pHandle = *it; 199 if (pHandle) 200 { 201 if (m->acUnlockedInLeave[i]) 202 { 203 // there was a leave() before the destruction: then restore the 204 // lock level that might have been set by locks other than our own 205 if (m->fIsLocked) 206 { 207 --m->acUnlockedInLeave[i]; 208 fAnyUnlockedInLeave = true; 209 } 210 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i]) 211 callLockImpl(*pHandle); 212 } 213 } 214 ++i; 215 } 216 217 if (m->fIsLocked && !fAnyUnlockedInLeave) 190 218 callUnlockOnAllHandles(); 191 219 } … … 286 314 { 287 315 l.unlockWrite(); 288 }289 290 /**291 * Returns @c true if the current thread holds a write lock on the managed292 * read/write semaphore. Returns @c false if the managed semaphore is @c293 * NULL.294 *295 * @note Intended for debugging only.296 */297 bool AutoWriteLockBase::isWriteLockOnCurrentThread() const298 {299 return m->aHandles[0] ? m->aHandles[0]->isWriteLockOnCurrentThread() : false;300 }301 302 /**303 * Returns the current write lock level of the managed smaphore. The lock304 * level determines the number of nested #lock() calls on the given305 * semaphore handle. Returns @c 0 if the managed semaphore is @c306 * NULL.307 *308 * Note that this call is valid only when the current thread owns a write309 * lock on the given semaphore handle and will assert otherwise.310 *311 * @note Intended for debugging only.312 */313 uint32_t AutoWriteLockBase::writeLockLevel() const314 {315 return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0;316 316 } 317 317 … … 340 340 { 341 341 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot leave()!")); 342 AssertMsg(m->cUnlockedInLeave == 0, ("m->cUnlockedInLeave is %d, must be 0! Called leave() twice?", m->cUnlockedInLeave)); 343 342 343 uint32_t i = 0; 344 344 for (HandlesVector::iterator it = m->aHandles.begin(); 345 345 it != m->aHandles.end(); … … 349 349 if (pHandle) 350 350 { 351 m->cUnlockedInLeave = pHandle->writeLockLevel(); 352 AssertMsg(m->cUnlockedInLeave >= 1, ("m->cUnlockedInLeave is %d, must be >=1!", m->cUnlockedInLeave)); 353 354 for (uint32_t left = m->cUnlockedInLeave; 351 AssertMsg(m->acUnlockedInLeave[i] == 0, ("m->cUnlockedInLeave[%d] is %d, must be 0! Called leave() twice?", i, m->acUnlockedInLeave[i])); 352 m->acUnlockedInLeave[i] = pHandle->writeLockLevel(); 353 AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i])); 354 355 for (uint32_t left = m->acUnlockedInLeave[i]; 355 356 left; 356 357 --left) 357 358 pHandle->unlockWrite(); 358 359 } 360 ++i; 359 361 } 360 362 } … … 369 371 { 370 372 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot enter()!")); 371 AssertMsg(m->cUnlockedInLeave != 0, ("m->cUnlockedInLeave is 0! enter() without leave()?")); 372 373 374 uint32_t i = 0; 373 375 for (HandlesVector::iterator it = m->aHandles.begin(); 374 376 it != m->aHandles.end(); … … 378 380 if (pHandle) 379 381 { 380 for (; m->cUnlockedInLeave; --m->cUnlockedInLeave) 382 AssertMsg(m->acUnlockedInLeave[i] != 0, ("m->cUnlockedInLeave[%d] is 0! enter() without leave()?", i)); 383 384 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i]) 381 385 pHandle->lockWrite(); 382 386 } 387 ++i; 388 } 389 } 390 391 /** 392 * Same as #leave() but checks if the current thread actally owns the lock 393 * and only proceeds in this case. As a result, as opposed to #leave(), 394 * doesn't assert when called with no lock being held. 395 */ 396 void AutoWriteLockBase::maybeLeave() 397 { 398 uint32_t i = 0; 399 for (HandlesVector::iterator it = m->aHandles.begin(); 400 it != m->aHandles.end(); 401 ++it) 402 { 403 LockHandle *pHandle = *it; 404 if (pHandle) 405 { 406 if (pHandle->isWriteLockOnCurrentThread()) 407 { 408 m->acUnlockedInLeave[i] = pHandle->writeLockLevel(); 409 AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i])); 410 411 for (uint32_t left = m->acUnlockedInLeave[i]; 412 left; 413 --left) 414 pHandle->unlockWrite(); 415 } 416 } 417 ++i; 418 } 419 } 420 421 /** 422 * Same as #enter() but checks if the current thread actally owns the lock 423 * and only proceeds if not. As a result, as opposed to #enter(), doesn't 424 * assert when called with the lock already being held. 425 */ 426 void AutoWriteLockBase::maybeEnter() 427 { 428 uint32_t i = 0; 429 for (HandlesVector::iterator it = m->aHandles.begin(); 430 it != m->aHandles.end(); 431 ++it) 432 { 433 LockHandle *pHandle = *it; 434 if (pHandle) 435 { 436 if (!pHandle->isWriteLockOnCurrentThread()) 437 { 438 for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i]) 439 pHandle->lockWrite(); 440 } 441 } 442 ++i; 383 443 } 384 444 } … … 425 485 } 426 486 487 /** 488 * Returns @c true if the current thread holds a write lock on the managed 489 * read/write semaphore. Returns @c false if the managed semaphore is @c 490 * NULL. 491 * 492 * @note Intended for debugging only. 493 */ 494 bool AutoWriteLock::isWriteLockOnCurrentThread() const 495 { 496 return m->aHandles[0] ? m->aHandles[0]->isWriteLockOnCurrentThread() : false; 497 } 498 499 /** 500 * Returns the current write lock level of the managed smaphore. The lock 501 * level determines the number of nested #lock() calls on the given 502 * semaphore handle. Returns @c 0 if the managed semaphore is @c 503 * NULL. 504 * 505 * Note that this call is valid only when the current thread owns a write 506 * lock on the given semaphore handle and will assert otherwise. 507 * 508 * @note Intended for debugging only. 509 */ 510 uint32_t AutoWriteLock::writeLockLevel() const 511 { 512 return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0; 513 } 514 515 //////////////////////////////////////////////////////////////////////////////// 516 // 517 // AutoMultiWriteLock* 518 // 519 //////////////////////////////////////////////////////////////////////////////// 520 521 AutoMultiWriteLock2::AutoMultiWriteLock2(Lockable *pl1, Lockable *pl2) 522 : AutoWriteLockBase(2) 523 { 524 if (pl1) 525 m->aHandles[0] = pl1->lockHandle(); 526 if (pl2) 527 m->aHandles[1] = pl2->lockHandle(); 528 acquire(); 529 } 530 531 AutoMultiWriteLock2::AutoMultiWriteLock2(LockHandle *pl1, LockHandle *pl2) 532 : AutoWriteLockBase(2) 533 { 534 m->aHandles[0] = pl1; 535 m->aHandles[1] = pl2; 536 acquire(); 537 } 538 539 AutoMultiWriteLock3::AutoMultiWriteLock3(Lockable *pl1, Lockable *pl2, Lockable *pl3) 540 : AutoWriteLockBase(3) 541 { 542 if (pl1) 543 m->aHandles[0] = pl1->lockHandle(); 544 if (pl2) 545 m->aHandles[1] = pl2->lockHandle(); 546 if (pl3) 547 m->aHandles[2] = pl3->lockHandle(); 548 acquire(); 549 } 550 551 AutoMultiWriteLock3::AutoMultiWriteLock3(LockHandle *pl1, LockHandle *pl2, LockHandle *pl3) 552 : AutoWriteLockBase(3) 553 { 554 m->aHandles[0] = pl1; 555 m->aHandles[1] = pl2; 556 m->aHandles[2] = pl3; 557 acquire(); 558 } 559 427 560 } /* namespace util */ 428 561 /* vi: set tabstop=4 shiftwidth=4 expandtab: */ -
trunk/src/VBox/Main/include/AutoLock.h
r25284 r25285 318 318 { 319 319 protected: 320 AutoLockBase(LockHandle *pHandle); 320 AutoLockBase(uint32_t cHandles); 321 AutoLockBase(uint32_t cHandles, LockHandle *pHandle); 321 322 virtual ~AutoLockBase(); 322 323 … … 361 362 */ 362 363 AutoReadLock() 363 : AutoLockBase( NULL)364 : AutoLockBase(1, NULL) 364 365 { } 365 366 … … 369 370 */ 370 371 AutoReadLock(LockHandle *aHandle) 371 : AutoLockBase( aHandle)372 : AutoLockBase(1, aHandle) 372 373 { 373 374 acquire(); … … 379 380 */ 380 381 AutoReadLock(LockHandle &aHandle) 381 : AutoLockBase( &aHandle)382 : AutoLockBase(1, &aHandle) 382 383 { 383 384 acquire(); … … 389 390 */ 390 391 AutoReadLock(const Lockable &aLockable) 391 : AutoLockBase( aLockable.lockHandle())392 : AutoLockBase(1, aLockable.lockHandle()) 392 393 { 393 394 acquire(); … … 399 400 */ 400 401 AutoReadLock(const Lockable *aLockable) 401 : AutoLockBase( aLockable ? aLockable->lockHandle() : NULL)402 : AutoLockBase(1, aLockable ? aLockable->lockHandle() : NULL) 402 403 { 403 404 acquire(); … … 419 420 { 420 421 protected: 421 AutoWriteLockBase(LockHandle *pHandle) 422 : AutoLockBase(pHandle) 422 AutoWriteLockBase(uint32_t cHandles) 423 : AutoLockBase(cHandles) 424 { } 425 426 AutoWriteLockBase(uint32_t cHandles, LockHandle *pHandle) 427 : AutoLockBase(cHandles, pHandle) 423 428 { } 424 429 … … 430 435 431 436 public: 432 bool isWriteLockOnCurrentThread() const;433 uint32_t writeLockLevel() const;434 435 437 void leave(); 436 438 void enter(); 437 438 /** 439 * Same as #leave() but checks if the current thread actally owns the lock 440 * and only proceeds in this case. As a result, as opposed to #leave(), 441 * doesn't assert when called with no lock being held. 442 */ 443 void maybeLeave() 444 { 445 if (isWriteLockOnCurrentThread()) 446 leave(); 447 } 448 449 /** 450 * Same as #enter() but checks if the current thread actally owns the lock 451 * and only proceeds if not. As a result, as opposed to #enter(), doesn't 452 * assert when called with the lock already being held. 453 */ 454 void maybeEnter() 455 { 456 if (!isWriteLockOnCurrentThread()) 457 enter(); 458 } 459 439 void maybeLeave(); 440 void maybeEnter(); 460 441 }; 461 442 … … 479 460 */ 480 461 AutoWriteLock() 481 : AutoWriteLockBase( NULL)462 : AutoWriteLockBase(1, NULL) 482 463 { } 483 464 … … 487 468 */ 488 469 AutoWriteLock(LockHandle *aHandle) 489 : AutoWriteLockBase( aHandle)470 : AutoWriteLockBase(1, aHandle) 490 471 { 491 472 acquire(); … … 497 478 */ 498 479 AutoWriteLock(LockHandle &aHandle) 499 : AutoWriteLockBase( &aHandle)480 : AutoWriteLockBase(1, &aHandle) 500 481 { 501 482 acquire(); … … 507 488 */ 508 489 AutoWriteLock(const Lockable &aLockable) 509 : AutoWriteLockBase( aLockable.lockHandle())490 : AutoWriteLockBase(1, aLockable.lockHandle()) 510 491 { 511 492 acquire(); … … 517 498 */ 518 499 AutoWriteLock(const Lockable *aLockable) 519 : AutoWriteLockBase( aLockable ? aLockable->lockHandle() : NULL)500 : AutoWriteLockBase(1, aLockable ? aLockable->lockHandle() : NULL) 520 501 { 521 502 acquire(); … … 557 538 558 539 void attachRaw(LockHandle *ph); 559 }; 540 541 bool isWriteLockOnCurrentThread() const; 542 uint32_t writeLockLevel() const; 543 }; 544 545 //////////////////////////////////////////////////////////////////////////////// 546 // 547 // AutoMultiWriteLock* 548 // 549 //////////////////////////////////////////////////////////////////////////////// 550 551 class AutoMultiWriteLock2 : public AutoWriteLockBase 552 { 553 public: 554 AutoMultiWriteLock2(Lockable *pl1, Lockable *pl2); 555 AutoMultiWriteLock2(LockHandle *pl1, LockHandle *pl2); 556 557 virtual ~AutoMultiWriteLock2() 558 { 559 cleanup(); 560 } 561 }; 562 563 class AutoMultiWriteLock3 : public AutoWriteLockBase 564 { 565 public: 566 AutoMultiWriteLock3(Lockable *pl1, Lockable *pl2, Lockable *pl3); 567 AutoMultiWriteLock3(LockHandle *pl1, LockHandle *pl2, LockHandle *pl3); 568 569 virtual ~AutoMultiWriteLock3() 570 { 571 cleanup(); 572 } 573 }; 574 560 575 561 576 //////////////////////////////////////////////////////////////////////////////// … … 710 725 #undef A 711 726 712 ////////////////////////////////////////////////////////////////////////////////713 714 /**715 * Helper template class for AutoMultiWriteLockN classes.716 *717 * @param Cnt number of write semaphores to manage.718 */719 template <size_t Cnt>720 class AutoMultiWriteLockBase721 {722 723 public:724 /**725 * Calls AutoWriteLock::acquire() methods for all managed semaphore handles in726 * order they were passed to the constructor.727 */728 void acquire()729 {730 size_t i = 0;731 while (i < RT_ELEMENTS(mLocks))732 mLocks[i++].acquire();733 }734 735 /**736 * Calls AutoWriteLock::unlock() methods for all managed semaphore handles737 * in reverse to the order they were passed to the constructor.738 */739 void release()740 {741 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);742 size_t i = RT_ELEMENTS(mLocks);743 do744 mLocks[--i].release();745 while (i != 0);746 }747 748 /**749 * Calls AutoWriteLock::leave() methods for all managed semaphore handles in750 * reverse to the order they were passed to the constructor.751 */752 void leave()753 {754 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);755 size_t i = RT_ELEMENTS(mLocks);756 do757 mLocks[--i].leave();758 while (i != 0);759 }760 761 /**762 * Calls AutoWriteLock::maybeLeave() methods for all managed semaphore763 * handles in reverse to the order they were passed to the constructor.764 */765 void maybeLeave()766 {767 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);768 size_t i = RT_ELEMENTS(mLocks);769 do770 mLocks [-- i].maybeLeave();771 while (i != 0);772 }773 774 /**775 * Calls AutoWriteLock::maybeEnter() methods for all managed semaphore776 * handles in order they were passed to the constructor.777 */778 void maybeEnter()779 {780 size_t i = 0;781 while (i < RT_ELEMENTS(mLocks))782 mLocks[i++].maybeEnter();783 }784 785 /**786 * Calls AutoWriteLock::enter() methods for all managed semaphore handles in787 * order they were passed to the constructor.788 */789 void enter()790 {791 size_t i = 0;792 while (i < RT_ELEMENTS(mLocks))793 mLocks[i++].enter();794 }795 796 protected:797 798 AutoMultiWriteLockBase() {}799 800 void setLockHandle(size_t aIdx, LockHandle *aHandle)801 {802 mLocks[aIdx].attachRaw(aHandle);803 }804 805 private:806 807 AutoWriteLock mLocks[Cnt];808 809 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiWriteLockBase)810 DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiWriteLockBase)811 };812 813 /** AutoMultiWriteLockBase <0> is meaningless and forbidden. */814 template<>815 class AutoMultiWriteLockBase <0> { private : AutoMultiWriteLockBase(); };816 817 /** AutoMultiWriteLockBase <1> is meaningless and forbidden. */818 template<>819 class AutoMultiWriteLockBase <1> { private : AutoMultiWriteLockBase(); };820 821 ////////////////////////////////////////////////////////////////////////////////822 823 /* AutoMultiLockN class definitions */824 825 #define A(n) LockHandle *l##n826 #define B(n) setLockHandle (n, l##n)827 828 #define C(n) Lockable *l##n829 #define D(n) setLockHandle (n, l##n ? l##n->lockHandle() : NULL)830 831 /**832 * AutoMultiWriteLock for 2 locks.833 *834 * The AutoMultiWriteLockN family of classes provides a possibility to manage835 * several read/write semaphores at once. This is handy if all managed836 * semaphores need to be locked and unlocked synchronously and will also help to837 * avoid locking order errors.838 *839 * The functionality of the AutoMultiWriteLockN class family is similar to the840 * functionality of the AutoMultiLockN class family (see the AutoMultiLock2841 * class for details) with two important differences:842 * <ol>843 * <li>Instances of AutoMultiWriteLockN classes are constructed from a list844 * of LockHandle or Lockable arguments directly instead of getting845 * intermediate LockOps interface pointers.846 * </li>847 * <li>All locks are requested in <b>write</b> mode.848 * </li>849 * <li>Since all locks are requested in write mode, bulk850 * AutoMultiWriteLockBase::leave() and AutoMultiWriteLockBase::enter()851 * operations are also available, that will leave and enter all managed852 * semaphores at once in the proper order (similarly to853 * AutoMultiWriteLockBase::lock() and AutoMultiWriteLockBase::unlock()).854 * </li>855 * </ol>856 *857 * Here is a typical usage pattern:858 * <code>859 * ...860 * LockHandle data1, data2;861 * ...862 * {863 * AutoMultiWriteLock2 multiLock (&data1, &data2);864 * // both locks are held in write mode here865 * }866 * // both locks are released here867 * </code>868 */869 class AutoMultiWriteLock2 : public AutoMultiWriteLockBase <2>870 {871 public:872 AutoMultiWriteLock2 (A(0), A(1))873 { B(0); B(1); acquire(); }874 AutoMultiWriteLock2 (C(0), C(1))875 { D(0); D(1); acquire(); }876 };877 878 /** AutoMultiWriteLock for 3 locks. See AutoMultiWriteLock2 for more details. */879 class AutoMultiWriteLock3 : public AutoMultiWriteLockBase <3>880 {881 public:882 AutoMultiWriteLock3 (A(0), A(1), A(2))883 { B(0); B(1); B(2); acquire(); }884 AutoMultiWriteLock3 (C(0), C(1), C(2))885 { D(0); D(1); D(2); acquire(); }886 };887 888 /** AutoMultiWriteLock for 4 locks. See AutoMultiWriteLock2 for more details. */889 class AutoMultiWriteLock4 : public AutoMultiWriteLockBase <4>890 {891 public:892 AutoMultiWriteLock4 (A(0), A(1), A(2), A(3))893 { B(0); B(1); B(2); B(3); acquire(); }894 AutoMultiWriteLock4 (C(0), C(1), C(2), C(3))895 { D(0); D(1); D(2); D(3); acquire(); }896 };897 898 #undef D899 #undef C900 #undef B901 #undef A902 903 727 } /* namespace util */ 904 728
Note:
See TracChangeset
for help on using the changeset viewer.