Changeset 25279 in vbox for trunk/src/VBox/Main
- Timestamp:
- Dec 9, 2009 5:50:26 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 55821
- Location:
- trunk/src/VBox/Main
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/ApplianceImpl.cpp
r25149 r25279 1037 1037 1038 1038 /* Unlock the appliance for the reading thread */ 1039 appLock. unlock();1039 appLock.release(); 1040 1040 /* Wait until the reading is done, but report the progress back to the 1041 1041 caller */ … … 1044 1044 1045 1045 /* Again lock the appliance for the next steps */ 1046 appLock. lock();1046 appLock.acquire(); 1047 1047 } 1048 1048 catch(HRESULT aRC) … … 2104 2104 2105 2105 /* Unlock the appliance for the fs import thread */ 2106 appLock. unlock();2106 appLock.release(); 2107 2107 /* Wait until the import is done, but report the progress back to the 2108 2108 caller */ … … 2111 2111 2112 2112 /* Again lock the appliance for the next steps */ 2113 appLock. lock();2113 appLock.acquire(); 2114 2114 } 2115 2115 catch(HRESULT aRC) … … 3126 3126 3127 3127 /* Unlock the appliance for the writing thread */ 3128 appLock. unlock();3128 appLock.release(); 3129 3129 /* Wait until the writing is done, but report the progress back to the 3130 3130 caller */ … … 3133 3133 3134 3134 /* Again lock the appliance for the next steps */ 3135 appLock. lock();3135 appLock.acquire(); 3136 3136 3137 3137 vrc = RTPathExists(strTmpOvf.c_str()); /* Paranoid check */ -
trunk/src/VBox/Main/AutoLock.cpp
r24000 r25279 29 29 namespace util 30 30 { 31 32 //////////////////////////////////////////////////////////////////////////////// 33 // 34 // RWLockHandle 35 // 36 //////////////////////////////////////////////////////////////////////////////// 31 37 32 38 RWLockHandle::RWLockHandle() -
trunk/src/VBox/Main/ConsoleImpl.cpp
r25149 r25279 3217 3217 described above. 3218 3218 */ 3219 alock. unlock();3219 alock.release(); 3220 3220 3221 3221 /* -
trunk/src/VBox/Main/HostImpl.cpp
r25200 r25279 1356 1356 1357 1357 /* save the global settings */ 1358 alock. unlock();1358 alock.release(); 1359 1359 return rc = m->pParent->saveSettings(); 1360 1360 #else … … 1411 1411 1412 1412 /* save the global settings */ 1413 alock. unlock();1413 alock.release(); 1414 1414 return rc = m->pParent->saveSettings(); 1415 1415 #else … … 1800 1800 1801 1801 // save the global settings... yeah, on every single filter property change 1802 alock. unlock();1802 alock.release(); 1803 1803 return m->pParent->saveSettings(); 1804 1804 } -
trunk/src/VBox/Main/MachineImpl.cpp
r25203 r25279 3489 3489 3490 3490 /* just be on the safe side when calling another process */ 3491 alock. unlock();3491 alock.release(); 3492 3492 3493 3493 /* fail if we were called after #OnSessionEnd() is called. This is a … … 3733 3733 3734 3734 /* just be on the safe side when calling another process */ 3735 alock. unlock();3735 alock.release(); 3736 3736 3737 3737 if (!directControl) … … 9296 9296 mHWData->mPropertyServiceActive = false; 9297 9297 9298 alock. unlock();9298 alock.release(); 9299 9299 SaveSettings(); 9300 9300 9301 9301 /* Restore the mRegistered flag. */ 9302 alock. lock();9302 alock.acquire(); 9303 9303 mData->mRegistered = TRUE; 9304 9304 -
trunk/src/VBox/Main/MediumImpl.cpp
r25184 r25279 3346 3346 // deleteStorageAndWait calls unregisterWithVirtualBox which gets 3347 3347 // a write tree lock, so don't deadlock 3348 treeLock. unlock();3349 alock. unlock();3348 treeLock.release(); 3349 alock.release(); 3350 3350 3351 3351 rc = deleteStorageAndWait(&aProgress); -
trunk/src/VBox/Main/NetworkAdapterImpl.cpp
r25149 r25279 227 227 228 228 /* leave the lock before informing callbacks */ 229 alock. unlock();229 alock.release(); 230 230 231 231 mParent->onNetworkAdapterChange (this, FALSE); … … 280 280 281 281 /* leave the lock before informing callbacks */ 282 alock. unlock();282 alock.release(); 283 283 284 284 mParent->onNetworkAdapterChange (this, FALSE); … … 376 376 { 377 377 /* leave the lock before informing callbacks */ 378 alock. unlock();378 alock.release(); 379 379 380 380 mParent->onNetworkAdapterChange (this, FALSE); … … 434 434 435 435 /* leave the lock before informing callbacks */ 436 alock. unlock();436 alock.release(); 437 437 438 438 mParent->onNetworkAdapterChange (this, FALSE); … … 482 482 483 483 /* leave the lock before informing callbacks */ 484 alock. unlock();484 alock.release(); 485 485 486 486 mParent->onNetworkAdapterChange (this, FALSE); … … 525 525 526 526 /* leave the lock before informing callbacks */ 527 alock. unlock();527 alock.release(); 528 528 529 529 mParent->onNetworkAdapterChange (this, FALSE); … … 564 564 565 565 /* leave the lock before informing callbacks */ 566 alock. unlock();566 alock.release(); 567 567 568 568 mParent->onNetworkAdapterChange (this, FALSE); … … 603 603 604 604 /* leave the lock before informing callbacks */ 605 alock. unlock();605 alock.release(); 606 606 607 607 mParent->onNetworkAdapterChange (this, FALSE); … … 641 641 642 642 /* leave the lock before informing callbacks */ 643 alock. unlock();643 alock.release(); 644 644 645 645 mParent->onNetworkAdapterChange (this, TRUE); … … 680 680 681 681 /* leave the lock before informing callbacks */ 682 alock. unlock();682 alock.release(); 683 683 684 684 mParent->onNetworkAdapterChange (this, FALSE); … … 713 713 714 714 /* leave the lock before informing callbacks */ 715 alock. unlock();715 alock.release(); 716 716 717 717 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE); … … 755 755 756 756 /* leave the lock before informing callbacks */ 757 alock. unlock();757 alock.release(); 758 758 759 759 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE); … … 805 805 806 806 /* leave the lock before informing callbacks */ 807 alock. unlock();807 alock.release(); 808 808 809 809 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE); … … 847 847 848 848 /* leave the lock before informing callbacks */ 849 alock. unlock();849 alock.release(); 850 850 851 851 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE); … … 883 883 884 884 /* leave the lock before informing callbacks */ 885 alock. unlock();885 alock.release(); 886 886 887 887 mParent->onNetworkAdapterChange (this, TRUE); -
trunk/src/VBox/Main/ParallelPortImpl.cpp
r25203 r25279 230 230 231 231 /* leave the lock before informing callbacks */ 232 alock. unlock();232 alock.release(); 233 233 234 234 m->pMachine->onParallelPortChange (this); … … 298 298 { 299 299 /* leave the lock before informing callbacks */ 300 alock. unlock();300 alock.release(); 301 301 302 302 m->pMachine->onParallelPortChange (this); … … 352 352 { 353 353 /* leave the lock before informing callbacks */ 354 alock. unlock();354 alock.release(); 355 355 356 356 m->pMachine->onParallelPortChange (this); … … 395 395 396 396 /* leave the lock before informing callbacks */ 397 alock. unlock();397 alock.release(); 398 398 399 399 return m->pMachine->onParallelPortChange(this); -
trunk/src/VBox/Main/SerialPortImpl.cpp
r25203 r25279 226 226 227 227 /* leave the lock before informing callbacks */ 228 alock. unlock();228 alock.release(); 229 229 230 230 m->pMachine->onSerialPortChange (this); … … 300 300 { 301 301 /* leave the lock before informing callbacks */ 302 alock. unlock();302 alock.release(); 303 303 304 304 m->pMachine->onSerialPortChange (this); … … 368 368 { 369 369 /* leave the lock before informing callbacks */ 370 alock. unlock();370 alock.release(); 371 371 372 372 m->pMachine->onSerialPortChange (this); … … 422 422 { 423 423 /* leave the lock before informing callbacks */ 424 alock. unlock();424 alock.release(); 425 425 426 426 m->pMachine->onSerialPortChange (this); … … 469 469 470 470 /* leave the lock before informing callbacks */ 471 alock. unlock();471 alock.release(); 472 472 473 473 return m->pMachine->onSerialPortChange(this); … … 508 508 509 509 /* leave the lock before informing callbacks */ 510 alock. unlock();510 alock.release(); 511 511 512 512 m->pMachine->onSerialPortChange (this); -
trunk/src/VBox/Main/SnapshotImpl.cpp
r25200 r25279 586 586 else 587 587 { 588 alock. unlock();588 alock.release(); 589 589 for (SnapshotsList::const_iterator it = m->llChildren.begin(); 590 590 it != m->llChildren.end(); … … 619 619 else 620 620 { 621 alock. unlock();621 alock.release(); 622 622 for (SnapshotsList::const_iterator it = m->llChildren.begin(); 623 623 it != m->llChildren.end(); … … 720 720 if (FAILED(rc)) return rc; 721 721 722 alock. unlock();722 alock.release(); 723 723 724 724 data.llChildSnapshots.clear(); … … 1670 1670 * provide an AutoWriteLock argument that lets create a non-locking 1671 1671 * instance */ 1672 vboxLock. unlock();1672 vboxLock.release(); 1673 1673 1674 1674 AutoWriteLock alock(this); … … 1719 1719 1720 1720 /* leave the locks before the potentially lengthy operation */ 1721 snapshotLock. unlock();1721 snapshotLock.release(); 1722 1722 alock.leave(); 1723 1723 … … 1729 1729 1730 1730 alock.enter(); 1731 snapshotLock. lock();1731 snapshotLock.acquire(); 1732 1732 1733 1733 /* Note: on success, current (old) hard disks will be … … 1755 1755 1756 1756 /* leave the lock before the potentially lengthy operation */ 1757 snapshotLock. unlock();1757 snapshotLock.release(); 1758 1758 alock.leave(); 1759 1759 … … 1766 1766 1767 1767 alock.enter(); 1768 snapshotLock. lock();1768 snapshotLock.acquire(); 1769 1769 1770 1770 if (RT_SUCCESS(vrc)) … … 1815 1815 * locking rule. This is the last chance to do that while we are still 1816 1816 * in a protective state which allows us to temporarily leave the lock*/ 1817 alock. unlock();1818 vboxLock. lock();1819 alock. lock();1817 alock.release(); 1818 vboxLock.acquire(); 1819 alock.acquire(); 1820 1820 1821 1821 /* we have already discarded the current state, so set the execution … … 2215 2215 HRESULT rc2 = S_OK; 2216 2216 2217 attachLock. unlock();2217 attachLock.release(); 2218 2218 2219 2219 // First we must detach the child (otherwise mergeTo() called … … 2362 2362 } 2363 2363 2364 alock. unlock();2364 alock.release(); 2365 2365 2366 2366 // whether we were successful or not, we need to set the machine … … 2381 2381 // (parent -> child locking order!) 2382 2382 AutoWriteLock vboxLock(mParent); 2383 alock. lock();2383 alock.acquire(); 2384 2384 2385 2385 saveSettings(SaveS_InformCallbacksAnyway); -
trunk/src/VBox/Main/include/AutoLock.h
r20932 r25279 41 41 { 42 42 43 //////////////////////////////////////////////////////////////////////////////// 44 // 45 // LockHandle and friends 46 // 47 //////////////////////////////////////////////////////////////////////////////// 48 43 49 /** 44 50 * Abstract lock operations. See LockHandle and AutoWriteLock for details. … … 245 251 }; 246 252 253 //////////////////////////////////////////////////////////////////////////////// 254 // 255 // Lockable 256 // 257 //////////////////////////////////////////////////////////////////////////////// 258 247 259 /** 248 260 * Lockable interface. … … 296 308 }; 297 309 298 /** 299 * Provides safe management of read/write semaphores in write mode. 300 * 301 * A read/write semaphore is represented by the LockHandle class. This semaphore 302 * can be requested ("locked") in two different modes: for reading and for 303 * writing. A write lock is exclusive and acts like a mutex: only one thread can 304 * acquire a write lock on the given semaphore at a time; all other threads 305 * trying to request a write lock or a read lock (see below) on the same 306 * semaphore will be indefinitely blocked until the owning thread releases the 307 * write lock. 308 * 309 * A read lock is shared. This means that several threads can acquire a read 310 * lock on the same semaphore at the same time provided that there is no thread 311 * that holds a write lock on that semaphore. Note that when there are one or 312 * more threads holding read locks, a request for a write lock on another thread 313 * will be indefinitely blocked until all threads holding read locks release 314 * them. 315 * 316 * Note that write locks can be nested -- the same thread can request a write 317 * lock on the same semaphore several times. In this case, the corresponding 318 * number of release calls must be done in order to completely release all 319 * nested write locks and make the semaphore available for locking by other 320 * threads. 321 * 322 * Read locks can be nested too in which case the same rule of the equal number 323 * of the release calls applies. Read locks can be also nested into write 324 * locks which means that the same thread can successfully request a read lock 325 * if it already holds a write lock. However, please note that the opposite is 326 * <b>not possible</b>: if a thread tries to request a write lock on the same 327 * semaphore it is already holding a read lock, it will definitely produce a 328 * <b>deadlock</b> (i.e. it will block forever waiting for itself). 329 * 330 * Note that instances of the AutoWriteLock class manage write locks of 331 * read/write semaphores only. In order to manage read locks, please use the 332 * AutoReadLock class. 333 * 334 * Safe semaphore management consists of the following: 335 * <ul> 336 * <li>When an instance of the AutoWriteLock class is constructed given a 337 * valid semaphore handle, it will automatically request a write lock on that 338 * semaphore. 339 * </li> 340 * <li>When an instance of the AutoWriteLock class constructed given a valid 341 * semaphore handle is destroyed (e.g. goes out of scope), it will 342 * automatically release the write lock that was requested upon construction 343 * and also all nested write locks requested later using the #lock() call 344 * (note that the latter is considered to be a program logic error, see the 345 * #~AutoWriteLock() description for details). 346 * </li> 347 * </ul> 348 * 349 * Note that the LockHandle class taken by AutoWriteLock constructors is an 350 * abstract base of the read/write semaphore. You should choose one of the 351 * existing subclasses of this abstract class or create your own subclass that 352 * implements necessary read and write lock semantics. The most suitable choice 353 * is the RWLockHandle class which provides full support for both read and write 354 * locks as describerd above. Alternatively, you can use the WriteLockHandle 355 * class if you only need write (exclusive) locking (WriteLockHandle requires 356 * less system resources and works faster). 357 * 358 * A typical usage pattern of the AutoWriteLock class is as follows: 359 * <code> 360 * struct Struct : public RWLockHandle 361 * { 362 * ... 363 * }; 364 * 365 * void foo (Struct &aStruct) 366 * { 367 * { 368 * // acquire a write lock of aStruct 369 * AutoWriteLock alock (aStruct); 370 * 371 * // now we can modify aStruct in a thread-safe manner 372 * aStruct.foo = ...; 373 * 374 * // note that the write lock will be automatically released upon 375 * // execution of the return statement below 376 * if (!aStruct.bar) 377 * return; 378 * 379 * ... 380 * } 381 * 382 * // note that the write lock is automatically released here 383 * } 384 * </code> 385 * 386 * <b>Locking policy</b> 387 * 388 * When there are multiple threads and multiple objects to lock, there is always 389 * a potential possibility to produce a deadlock if the lock order is mixed up. 390 * Here is a classical example of a deadlock when two threads need to lock the 391 * same two objects in a row but do it in different order: 392 * <code> 393 * Thread 1: 394 * #1: AutoWriteLock (mFoo); 395 * ... 396 * #2: AutoWriteLock (mBar); 397 * ... 398 * Thread 2: 399 * #3: AutoWriteLock (mBar); 400 * ... 401 * #4: AutoWriteLock (mFoo); 402 * ... 403 * </code> 404 * 405 * If the threads happen to be scheduled so that #3 completes after #1 has 406 * completed but before #2 got control, the threads will hit a deadlock: Thread 407 * 2 will be holding mBar and waiting for mFoo at #4 forever because Thread 1 is 408 * holding mFoo and won't release it until it acquires mBar at #2 that will 409 * never happen because mBar is held by Thread 2. 410 * 411 * One of ways to avoid the described behavior is to never lock more than one 412 * obhect in a row. While it is definitely a good and safe practice, it's not 413 * always possible: the application logic may require several simultaneous locks 414 * in order to provide data integrity. 415 * 416 * One of the possibilities to solve the deadlock problem is to make sure that 417 * the locking order is always the same across the application. In the above 418 * example, it would mean that <b>both</b> threads should first requiest a lock 419 * of mFoo and then mBar (or vice versa). One of the methods to guarantee the 420 * locking order consistent is to introduce a set of locking rules. The 421 * advantage of this method is that it doesn't require any special semaphore 422 * implementation or additional control structures. The disadvantage is that 423 * it's the programmer who must make sure these rules are obeyed across the 424 * whole application so the human factor applies. Taking the simplicity of this 425 * method into account, it is chosen to solve potential deadlock problems when 426 * using AutoWriteLock and AutoReadLock classes. Here are the locking rules 427 * that must be obeyed by <b>all</b> users of these classes. Note that if more 428 * than one rule matches the given group of objects to lock, all of these rules 429 * must be met: 430 * <ol> 431 * <li>If there is a parent-child (or master-slave) relationship between the 432 * locked objects, parent (master) objects must be locked before child 433 * (slave) objects. 434 * </li> 435 * <li>When a group of equal objects (in terms of parent-child or 436 * master-slave relationsip) needs to be locked in a raw, the lock order 437 * must match the sort order (which must be consistent for the given group). 438 * </ol> 439 * Note that if there is no pragrammatically expressed sort order (e.g. 440 * the objects are not part of the sorted vector or list but instead are 441 * separate data members of a class), object class names sorted in alphabetical 442 * order must be used to determine the lock order. If there is more than one 443 * object of the given class, the object variable names' alphabetical order must 444 * be used as a lock order. When objects are not represented as individual 445 * variables, as in case of unsorted arrays/lists, the list of alphabetically 446 * sorted object UUIDs must be used to determine the sort order. 447 * 448 * All non-standard locking order must be avoided by all means, but when 449 * absolutely necessary, it must be clearly documented at relevant places so it 450 * is well seen by other developers. For example, if a set of instances of some 451 * class needs to be locked but these instances are not part of the sorted list 452 * and don't have UUIDs, then the class description must state what to use to 453 * determine the lock order (maybe some property that returns an unique value 454 * per every object). 455 */ 456 class AutoWriteLock 310 //////////////////////////////////////////////////////////////////////////////// 311 // 312 // AutoLockBase 313 // 314 //////////////////////////////////////////////////////////////////////////////// 315 316 class AutoLockBase 317 { 318 protected: 319 AutoLockBase(LockHandle *pHandle) 320 : mHandle(pHandle), 321 mLockLevel(0), 322 mGlobalLockLevel(0) 323 { } 324 325 LockHandle *mHandle; 326 uint32_t mLockLevel; 327 uint32_t mGlobalLockLevel; 328 }; 329 330 //////////////////////////////////////////////////////////////////////////////// 331 // 332 // AutoWriteLock 333 // 334 //////////////////////////////////////////////////////////////////////////////// 335 336 class AutoWriteLock : public AutoLockBase 457 337 { 458 338 public: … … 466 346 * runtime. 467 347 */ 468 AutoWriteLock() : mHandle (NULL), mLockLevel (0), mGlobalLockLevel (0) {} 348 AutoWriteLock() 349 : AutoLockBase(NULL) 350 { } 469 351 470 352 /** … … 472 354 * semaphore by requesting a write lock. 473 355 */ 474 AutoWriteLock (LockHandle *aHandle) 475 : mHandle (aHandle), mLockLevel (0), mGlobalLockLevel (0) 476 { lock(); } 356 AutoWriteLock(LockHandle *aHandle) 357 : AutoLockBase(aHandle) 358 { 359 acquire(); 360 } 477 361 478 362 /** … … 480 364 * semaphore by requesting a write lock. 481 365 */ 482 AutoWriteLock (LockHandle &aHandle) 483 : mHandle (&aHandle), mLockLevel (0), mGlobalLockLevel (0) 484 { lock(); } 366 AutoWriteLock(LockHandle &aHandle) 367 : AutoLockBase(&aHandle) 368 { 369 acquire(); 370 } 485 371 486 372 /** … … 488 374 * semaphore by requesting a write lock. 489 375 */ 490 AutoWriteLock (const Lockable &aLockable) 491 : mHandle (aLockable.lockHandle()), mLockLevel (0), mGlobalLockLevel (0) 492 { lock(); } 376 AutoWriteLock(const Lockable &aLockable) 377 : AutoLockBase(aLockable.lockHandle()) 378 { 379 acquire(); 380 } 493 381 494 382 /** … … 496 384 * semaphore by requesting a write lock. 497 385 */ 498 AutoWriteLock (const Lockable *aLockable) 499 : mHandle (aLockable ? aLockable->lockHandle() : NULL) 500 , mLockLevel (0), mGlobalLockLevel (0) 501 { lock(); } 386 AutoWriteLock(const Lockable *aLockable) 387 : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL) 388 { 389 acquire(); 390 } 502 391 503 392 /** … … 518 407 mGlobalLockLevel -= mLockLevel; 519 408 mLockLevel = 0; 520 for (; mGlobalLockLevel; -- 409 for (; mGlobalLockLevel; --mGlobalLockLevel) 521 410 mHandle->lockWrite(); 522 411 } 523 412 524 AssertMsg 525 for (; mLockLevel; -- 413 AssertMsg(mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel)); 414 for (; mLockLevel; --mLockLevel) 526 415 mHandle->unlockWrite(); 527 416 } … … 535 424 * otherwise returns immediately. 536 425 */ 537 void lock()426 void acquire() 538 427 { 539 428 if (mHandle) 540 429 { 541 430 mHandle->lockWrite(); 542 ++ 543 Assert 431 ++mLockLevel; 432 Assert(mLockLevel != 0 /* overflow? */); 544 433 } 545 434 } … … 551 440 * available for locking by other threads. 552 441 */ 553 void unlock()442 void release() 554 443 { 555 444 if (mHandle) 556 445 { 557 AssertReturnVoid 446 AssertReturnVoid(mLockLevel != 0 /* unlock() w/o preceding lock()? */); 558 447 mHandle->unlockWrite(); 559 -- 448 --mLockLevel; 560 449 } 561 450 } … … 586 475 if (mHandle) 587 476 { 588 AssertReturnVoid 589 AssertReturnVoid 477 AssertReturnVoid(mLockLevel != 0 /* leave() w/o preceding lock()? */); 478 AssertReturnVoid(mGlobalLockLevel == 0 /* second leave() in a row? */); 590 479 591 480 mGlobalLockLevel = mHandle->writeLockLevel(); 592 AssertReturnVoid 593 594 for (uint32_t left = mGlobalLockLevel; left; -- 481 AssertReturnVoid(mGlobalLockLevel >= mLockLevel /* logic error! */); 482 483 for (uint32_t left = mGlobalLockLevel; left; --left) 595 484 mHandle->unlockWrite(); 596 485 } … … 629 518 if (mHandle) 630 519 { 631 AssertReturnVoid 632 AssertReturnVoid 633 634 for (; mGlobalLockLevel; -- 520 AssertReturnVoid(mLockLevel != 0 /* enter() w/o preceding lock()+leave()? */); 521 AssertReturnVoid(mGlobalLockLevel != 0 /* enter() w/o preceding leave()? */); 522 523 for (; mGlobalLockLevel; --mGlobalLockLevel) 635 524 mHandle->lockWrite(); 636 525 } … … 647 536 * @param aHandle New handle to attach. 648 537 */ 649 void attach 538 void attach(LockHandle *aHandle) 650 539 { 651 540 /* detect simple self-reattachment */ … … 661 550 mGlobalLockLevel -= mLockLevel; 662 551 mLockLevel = 0; 663 for (; mGlobalLockLevel; -- 552 for (; mGlobalLockLevel; --mGlobalLockLevel) 664 553 mHandle->lockWrite(); 665 554 } 666 555 667 AssertMsg 668 for (; mLockLevel; -- 556 AssertMsg(mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel)); 557 for (; mLockLevel; --mLockLevel) 669 558 mHandle->unlockWrite(); 670 559 } … … 674 563 675 564 if (mHandle) 676 for (; lockLevel; -- 565 for (; lockLevel; --lockLevel) 677 566 mHandle->lockWrite(); 678 567 } … … 680 569 681 570 /** @see attach (LockHandle *) */ 682 void attach (LockHandle &aHandle) { attach (&aHandle); } 571 void attach(LockHandle &aHandle) 572 { 573 attach(&aHandle); 574 } 683 575 684 576 /** @see attach (LockHandle *) */ 685 void attach (const Lockable &aLockable) { attach (aLockable.lockHandle()); } 577 void attach(const Lockable &aLockable) 578 { 579 attach(aLockable.lockHandle()); 580 } 686 581 687 582 /** @see attach (LockHandle *) */ 688 void attach (const Lockable *aLockable) 689 { attach (aLockable ? aLockable->lockHandle() : NULL); } 690 691 /** Verbose equivalent to <tt>attach (NULL)</tt>. */ 692 void detach() { attach ((LockHandle *) NULL); } 693 694 /** Returns @c true if this instance manages a null semaphore handle. */ 695 bool isNull() const { return mHandle == NULL; } 696 bool operator !() const { return isNull(); } 583 void attach(const Lockable *aLockable) 584 { 585 attach(aLockable ? aLockable->lockHandle() : NULL); 586 } 697 587 698 588 /** … … 724 614 } 725 615 726 /**727 * Returns @c true if this instance manages the given semaphore handle.728 *729 * @note Intended for debugging only.730 */731 bool belongsTo (const LockHandle &aHandle) const { return mHandle == &aHandle; }732 733 /**734 * Returns @c true if this instance manages the given semaphore handle.735 *736 * @note Intended for debugging only.737 */738 bool belongsTo (const LockHandle *aHandle) const { return mHandle == aHandle; }739 740 /**741 * Returns @c true if this instance manages the given lockable object.742 *743 * @note Intended for debugging only.744 */745 bool belongsTo (const Lockable &aLockable)746 {747 return belongsTo (aLockable.lockHandle());748 }749 750 /**751 * Returns @c true if this instance manages the given lockable object.752 *753 * @note Intended for debugging only.754 */755 bool belongsTo (const Lockable *aLockable)756 {757 return aLockable && belongsTo (aLockable->lockHandle());758 }759 760 616 private: 761 617 … … 763 619 DECLARE_CLS_NEW_DELETE_NOOP (AutoWriteLock) 764 620 765 LockHandle *mHandle;766 uint32_t mLockLevel;767 uint32_t mGlobalLockLevel;768 769 621 template <size_t> friend class AutoMultiWriteLockBase; 770 622 }; 771 623 772 624 //////////////////////////////////////////////////////////////////////////////// 773 774 /** 775 * Provides safe management of read/write semaphores in read mode. 776 * 777 * This class differs from the AutoWriteLock class is so that it's #lock() and 778 * #unlock() methods requests and release read (shared) locks on the managed 779 * read/write semaphore instead of write (exclusive) locks. See the 780 * AutoWriteLock class description for more information about read and write 781 * locks. 782 * 783 * Safe semaphore management consists of the following: 784 * <ul> 785 * <li>When an instance of the AutoReadLock class is constructed given a 786 * valid semaphore handle, it will automatically request a read lock on that 787 * semaphore. 788 * </li> 789 * <li>When an instance of the AutoReadLock class constructed given a valid 790 * semaphore handle is destroyed (e.g. goes out of scope), it will 791 * automatically release the read lock that was requested upon construction 792 * and also all nested read locks requested later using the #lock() call (note 793 * that the latter is considered to be a program logic error, see the 794 * #~AutoReadLock() description for details). 795 * </li> 796 * </ul> 797 * 798 * Note that the LockHandle class taken by AutoReadLock constructors is an 799 * abstract base of the read/write semaphore. You should choose one of the 800 * existing subclasses of this abstract class or create your own subclass that 801 * implements necessary read and write lock semantics. The most suitable choice 802 * is the RWLockHandle class which provides full support for both read and write 803 * locks as describerd in AutoWriteLock docs. Alternatively, you can use the 804 * WriteLockHandle class if you only need write (exclusive) locking 805 * (WriteLockHandle requires less system resources and works faster). 806 * 807 * However, please note that it absolutely does not make sense to manage 808 * WriteLockHandle semaphores with AutoReadLock instances because 809 * AutoReadLock instances will behave like AutoWriteLock instances in this 810 * case since WriteLockHandle provides only exclusive write locking. You have 811 * been warned. 812 813 * A typical usage pattern of the AutoReadLock class is as follows: 814 * <code> 815 * struct Struct : public RWLockHandle 816 * { 817 * ... 818 * }; 819 * 820 * void foo (Struct &aStruct) 821 * { 822 * { 823 * // acquire a read lock of aStruct (note that two foo() calls may be 824 * executed on separate threads simultaneously w/o blocking each other) 825 * AutoReadLock alock (aStruct); 826 * 827 * // now we can read aStruct in a thread-safe manner 828 * if (aStruct.foo) 829 * ...; 830 * 831 * // note that the read lock will be automatically released upon 832 * // execution of the return statement below 833 * if (!aStruct.bar) 834 * return; 835 * 836 * ... 837 * } 838 * 839 * // note that the read lock is automatically released here 840 * } 841 * </code> 842 */ 843 class AutoReadLock 625 // 626 // AutoReadLock 627 // 628 //////////////////////////////////////////////////////////////////////////////// 629 630 class AutoReadLock : public AutoLockBase 844 631 { 845 632 public: … … 853 640 * runtime. 854 641 */ 855 AutoReadLock() : mHandle (NULL), mLockLevel (0) {} 642 AutoReadLock() 643 : AutoLockBase(NULL) 644 { } 856 645 857 646 /** … … 859 648 * semaphore by requesting a read lock. 860 649 */ 861 AutoReadLock (LockHandle *aHandle) 862 : mHandle (aHandle), mLockLevel (0) 863 { lock(); } 650 AutoReadLock(LockHandle *aHandle) 651 : AutoLockBase(aHandle) 652 { 653 acquire(); 654 } 864 655 865 656 /** … … 867 658 * semaphore by requesting a read lock. 868 659 */ 869 AutoReadLock (LockHandle &aHandle) 870 : mHandle (&aHandle), mLockLevel (0) 871 { lock(); } 660 AutoReadLock(LockHandle &aHandle) 661 : AutoLockBase(&aHandle) 662 { 663 acquire(); 664 } 872 665 873 666 /** … … 875 668 * semaphore by requesting a read lock. 876 669 */ 877 AutoReadLock (const Lockable &aLockable) 878 : mHandle (aLockable.lockHandle()), mLockLevel (0) 879 { lock(); } 670 AutoReadLock(const Lockable &aLockable) 671 : AutoLockBase(aLockable.lockHandle()) 672 { 673 acquire(); 674 } 880 675 881 676 /** … … 883 678 * semaphore by requesting a read lock. 884 679 */ 885 AutoReadLock (const Lockable *aLockable) 886 : mHandle (aLockable ? aLockable->lockHandle() : NULL) 887 , mLockLevel (0) 888 { lock(); } 680 AutoReadLock(const Lockable *aLockable) 681 : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL) 682 { 683 acquire(); 684 } 889 685 890 686 /** … … 901 697 if (mHandle) 902 698 { 903 AssertMsg 904 for (; mLockLevel; -- 699 AssertMsg(mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel)); 700 for (; mLockLevel; --mLockLevel) 905 701 mHandle->unlockRead(); 906 702 } … … 919 715 * allows for read locks nested into write locks on the same thread. 920 716 */ 921 void lock()717 void acquire() 922 718 { 923 719 if (mHandle) 924 720 { 925 721 mHandle->lockRead(); 926 ++ 927 Assert 722 ++mLockLevel; 723 Assert(mLockLevel != 0 /* overflow? */); 928 724 } 929 725 } … … 935 731 * available for locking by other threads. 936 732 */ 937 void unlock()733 void release() 938 734 { 939 735 if (mHandle) 940 736 { 941 AssertReturnVoid 737 AssertReturnVoid(mLockLevel != 0 /* unlock() w/o preceding lock()? */); 942 738 mHandle->unlockRead(); 943 -- 739 --mLockLevel; 944 740 } 945 741 } … … 955 751 * @param aHandle New handle to attach. 956 752 */ 957 void attach 753 void attach(LockHandle *aHandle) 958 754 { 959 755 /* detect simple self-reattachment */ … … 962 758 uint32_t lockLevel = mLockLevel; 963 759 if (mHandle) 964 for (; mLockLevel; -- 760 for (; mLockLevel; --mLockLevel) 965 761 mHandle->unlockRead(); 966 762 mHandle = aHandle; 967 763 mLockLevel = lockLevel; 968 764 if (mHandle) 969 for (; lockLevel; -- 765 for (; lockLevel; --lockLevel) 970 766 mHandle->lockRead(); 971 767 } … … 973 769 974 770 /** @see attach (LockHandle *) */ 975 void attach (LockHandle &aHandle) { attach (&aHandle); } 771 void attach(LockHandle &aHandle) 772 { 773 attach(&aHandle); 774 } 976 775 977 776 /** @see attach (LockHandle *) */ 978 void attach (const Lockable &aLockable) { attach (aLockable.lockHandle()); } 777 void attach(const Lockable &aLockable) 778 { 779 attach(aLockable.lockHandle()); 780 } 979 781 980 782 /** @see attach (LockHandle *) */ 981 void attach (const Lockable *aLockable) 982 { attach (aLockable ? aLockable->lockHandle() : NULL); } 983 984 /** Verbose equivalent to <tt>attach (NULL)</tt>. */ 985 void detach() { attach ((LockHandle *) NULL); } 986 987 /** Returns @c true if this instance manages a null semaphore handle. */ 988 bool isNull() const { return mHandle == NULL; } 989 bool operator !() const { return isNull(); } 990 991 /** 992 * Returns @c true if this instance manages the given semaphore handle. 993 * 994 * @note Intended for debugging only. 995 */ 996 bool belongsTo (const LockHandle &aHandle) const { return mHandle == &aHandle; } 997 998 /** 999 * Returns @c true if this instance manages the given semaphore handle. 1000 * 1001 * @note Intended for debugging only. 1002 */ 1003 bool belongsTo (const LockHandle *aHandle) const { return mHandle == aHandle; } 1004 1005 /** 1006 * Returns @c true if this instance manages the given lockable object. 1007 * 1008 * @note Intended for debugging only. 1009 */ 1010 bool belongsTo (const Lockable &aLockable) 1011 { 1012 return belongsTo (aLockable.lockHandle()); 1013 } 1014 1015 /** 1016 * Returns @c true if this instance manages the given lockable object. 1017 * 1018 * @note Intended for debugging only. 1019 */ 1020 bool belongsTo (const Lockable *aLockable) 1021 { 1022 return aLockable && belongsTo (aLockable->lockHandle()); 783 void attach(const Lockable *aLockable) 784 { 785 attach(aLockable ? aLockable->lockHandle() : NULL); 1023 786 } 1024 787 … … 1027 790 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoReadLock) 1028 791 DECLARE_CLS_NEW_DELETE_NOOP (AutoReadLock) 1029 1030 LockHandle *mHandle; 1031 uint32_t mLockLevel; 1032 }; 1033 792 }; 793 794 //////////////////////////////////////////////////////////////////////////////// 795 // 796 // AutoMulti* 797 // 1034 798 //////////////////////////////////////////////////////////////////////////////// 1035 799 … … 1189 953 class AutoMultiWriteLockBase 1190 954 { 1191 public: 1192 1193 /** 1194 * Calls AutoWriteLock:: lock() methods for all managed semaphore handles in955 956 public: 957 /** 958 * Calls AutoWriteLock::acquire() methods for all managed semaphore handles in 1195 959 * order they were passed to the constructor. 1196 960 */ 1197 void lock()961 void acquire() 1198 962 { 1199 963 size_t i = 0; 1200 while (i < RT_ELEMENTS 1201 mLocks [i ++].lock();964 while (i < RT_ELEMENTS(mLocks)) 965 mLocks[i++].acquire(); 1202 966 } 1203 967 … … 1206 970 * in reverse to the order they were passed to the constructor. 1207 971 */ 1208 void unlock()1209 { 1210 AssertReturnVoid (RT_ELEMENTS(mLocks) > 0);1211 size_t i = RT_ELEMENTS 972 void release() 973 { 974 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0); 975 size_t i = RT_ELEMENTS(mLocks); 1212 976 do 1213 mLocks [-- i].unlock();977 mLocks[--i].release(); 1214 978 while (i != 0); 1215 979 } … … 1221 985 void leave() 1222 986 { 1223 AssertReturnVoid (RT_ELEMENTS(mLocks) > 0);1224 size_t i = RT_ELEMENTS 987 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0); 988 size_t i = RT_ELEMENTS(mLocks); 1225 989 do 1226 mLocks [--i].leave();990 mLocks[--i].leave(); 1227 991 while (i != 0); 1228 992 } … … 1234 998 void maybeLeave() 1235 999 { 1236 AssertReturnVoid (RT_ELEMENTS(mLocks) > 0);1237 size_t i = RT_ELEMENTS 1000 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0); 1001 size_t i = RT_ELEMENTS(mLocks); 1238 1002 do 1239 1003 mLocks [-- i].maybeLeave(); … … 1248 1012 { 1249 1013 size_t i = 0; 1250 while (i < RT_ELEMENTS 1251 mLocks [i++].maybeEnter();1014 while (i < RT_ELEMENTS(mLocks)) 1015 mLocks[i++].maybeEnter(); 1252 1016 } 1253 1017 … … 1259 1023 { 1260 1024 size_t i = 0; 1261 while (i < RT_ELEMENTS 1262 mLocks [i++].enter();1025 while (i < RT_ELEMENTS(mLocks)) 1026 mLocks[i++].enter(); 1263 1027 } 1264 1028 … … 1338 1102 public: 1339 1103 AutoMultiWriteLock2 (A(0), A(1)) 1340 { B(0); B(1); lock(); }1104 { B(0); B(1); acquire(); } 1341 1105 AutoMultiWriteLock2 (C(0), C(1)) 1342 { D(0); D(1); lock(); }1106 { D(0); D(1); acquire(); } 1343 1107 }; 1344 1108 … … 1348 1112 public: 1349 1113 AutoMultiWriteLock3 (A(0), A(1), A(2)) 1350 { B(0); B(1); B(2); lock(); }1114 { B(0); B(1); B(2); acquire(); } 1351 1115 AutoMultiWriteLock3 (C(0), C(1), C(2)) 1352 { D(0); D(1); D(2); lock(); }1116 { D(0); D(1); D(2); acquire(); } 1353 1117 }; 1354 1118 … … 1358 1122 public: 1359 1123 AutoMultiWriteLock4 (A(0), A(1), A(2), A(3)) 1360 { B(0); B(1); B(2); B(3); lock(); }1124 { B(0); B(1); B(2); B(3); acquire(); } 1361 1125 AutoMultiWriteLock4 (C(0), C(1), C(2), C(3)) 1362 { D(0); D(1); D(2); D(3); lock(); }1126 { D(0); D(1); D(2); D(3); acquire(); } 1363 1127 }; 1364 1128
Note:
See TracChangeset
for help on using the changeset viewer.