Changeset 7992 in vbox
- Timestamp:
- Apr 15, 2008 1:53:12 PM (17 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 1 added
- 20 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/AudioAdapterImpl.cpp
r7525 r7992 569 569 570 570 /* sanity too */ 571 AutoCaller thatCaller (mPeer); 572 AssertComRCReturnVoid (thatCaller.rc()); 573 574 /* lock both for writing since we modify both */ 575 AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer)); 571 AutoCaller peerCaller (mPeer); 572 AssertComRCReturnVoid (peerCaller.rc()); 573 574 /* lock both for writing since we modify both (mPeer is "master" so locked 575 * first) */ 576 AutoMultiWriteLock2 alock (mPeer, this); 576 577 577 578 if (mData.isBackedUp()) … … 599 600 600 601 /* sanity too */ 601 AutoCaller thatCaller ( mPeer);602 AutoCaller thatCaller (aThat); 602 603 AssertComRCReturnVoid (thatCaller.rc()); 603 604 604 /* peer is not modified, lock it for reading */ 605 AutoMultiLock <2> alock (this->wlock(), aThat->rlock()); 605 /* peer is not modified, lock it for reading (aThat is "master" so locked 606 * first) */ 607 AutoMultiLock2 alock (aThat->rlock(), this->wlock()); 606 608 607 609 /* this will back up current data */ -
trunk/src/VBox/Main/ConsoleImpl.cpp
r7939 r7992 2491 2491 2492 2492 /** 2493 * 2494 * 2495 * @note Locks this object for reading.2493 * Called by IInternalSessionControl::OnDVDDriveChange(). 2494 * 2495 * @note Locks this object for writing. 2496 2496 */ 2497 2497 HRESULT Console::onDVDDriveChange() … … 2502 2502 AssertComRCReturnRC (autoCaller.rc()); 2503 2503 2504 AutoReaderLock alock (this); 2504 /* doDriveChange() needs a write lock */ 2505 AutoLock alock (this); 2505 2506 2506 2507 /* Ignore callbacks when there's no VM around */ … … 2587 2588 2588 2589 /** 2589 * 2590 * 2591 * @note Locks this object for reading.2590 * Called by IInternalSessionControl::OnFloppyDriveChange(). 2591 * 2592 * @note Locks this object for writing. 2592 2593 */ 2593 2594 HRESULT Console::onFloppyDriveChange() … … 2598 2599 AssertComRCReturnRC (autoCaller.rc()); 2599 2600 2600 AutoReaderLock alock (this); 2601 /* doDriveChange() needs a write lock */ 2602 AutoLock alock (this); 2601 2603 2602 2604 /* Ignore callbacks when there's no VM around */ … … 2704 2706 * @param fPassthrough Enables using passthrough mode of the host DVD drive if applicable. 2705 2707 * 2706 * @note Locks this object for reading.2708 * @note Locks this object for writing. 2707 2709 */ 2708 2710 HRESULT Console::doDriveChange (const char *pszDevice, unsigned uInstance, unsigned uLun, DriveState_T eState, … … 2717 2719 AssertComRCReturnRC (autoCaller.rc()); 2718 2720 2719 AutoReaderLock alock (this); 2721 /* We will need to release the write lock before calling EMT */ 2722 AutoLock alock (this); 2720 2723 2721 2724 /* protect mpVM */ … … 2784 2787 * 2785 2788 * @thread EMT 2786 * @note Locks the Console object for writing 2789 * @note Locks the Console object for writing. 2787 2790 */ 2788 2791 DECLCALLBACK(int) Console::changeDrive (Console *pThis, const char *pszDevice, unsigned uInstance, unsigned uLun, … … 2805 2808 2806 2809 /* 2807 * Locking the object before doing VMR3* calls is quite safe here,2808 * since we're on EMT. Write lock is necessary because we're indirectly2809 * modify themeDVDState/meFloppyState members (pointed to by peState).2810 * Locking the object before doing VMR3* calls is quite safe here, since 2811 * we're on EMT. Write lock is necessary because we indirectly modify the 2812 * meDVDState/meFloppyState members (pointed to by peState). 2810 2813 */ 2811 2814 AutoLock alock (pThis); -
trunk/src/VBox/Main/DVDDriveImpl.cpp
r6076 r7992 351 351 //////////////////////////////////////////////////////////////////////////////// 352 352 353 /** 353 /** 354 354 * Loads settings from the given machine node. 355 355 * May be called once right after this object creation. 356 * 356 * 357 357 * @param aMachineNode <Machine> node. 358 * 359 * @note Locks this object for writing. 358 * 359 * @note Locks this object for writing. 360 360 */ 361 361 HRESULT DVDDrive::loadSettings (const settings::Key &aMachineNode) … … 379 379 * place when a setting of a newly created object must default to A while 380 380 * the same setting of an object loaded from the old settings file must 381 * default to B. */ 381 * default to B. */ 382 382 383 383 HRESULT rc = S_OK; … … 435 435 } 436 436 437 /** 437 /** 438 438 * Saves settings to the given machine node. 439 * 439 * 440 440 * @param aMachineNode <Machine> node. 441 * 442 * @note Locks this object for reading. 441 * 442 * @note Locks this object for reading. 443 443 */ 444 444 HRESULT DVDDrive::saveSettings (settings::Key &aMachineNode) … … 497 497 } 498 498 499 /** 499 /** 500 500 * @note Locks this object for writing. 501 501 */ … … 521 521 } 522 522 523 /** 523 /** 524 524 * @note Locks this object for writing, together with the peer object (also 525 525 * for writing) if there is one. … … 532 532 533 533 /* sanity too */ 534 AutoCaller thatCaller (mPeer); 535 AssertComRCReturnVoid (thatCaller.rc()); 536 537 /* lock both for writing since we modify both */ 538 AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer)); 534 AutoCaller peerCaller (mPeer); 535 AssertComRCReturnVoid (peerCaller.rc()); 536 537 /* lock both for writing since we modify both (mPeer is "master" so locked 538 * first) */ 539 AutoMultiWriteLock2 alock (mPeer, this); 539 540 540 541 if (mData.isBackedUp()) … … 549 550 } 550 551 551 /** 552 /** 552 553 * @note Locks this object for writing, together with the peer object 553 554 * represented by @a aThat (locked for reading). … … 562 563 563 564 /* sanity too */ 564 AutoCaller thatCaller ( mPeer);565 AutoCaller thatCaller (aThat); 565 566 AssertComRCReturnVoid (thatCaller.rc()); 566 567 567 /* peer is not modified, lock it for reading */ 568 AutoMultiLock <2> alock (this->wlock(), aThat->rlock()); 568 /* peer is not modified, lock it for reading (aThat is "master" so locked 569 * first) */ 570 AutoMultiLock2 alock (aThat->rlock(), this->wlock()); 569 571 570 572 /* this will back up current data */ -
trunk/src/VBox/Main/FloppyDriveImpl.cpp
r6076 r7992 358 358 ///////////////////////////////////////////////////////////////////////////// 359 359 360 /** 360 /** 361 361 * Loads settings from the given machine node. 362 362 * May be called once right after this object creation. 363 * 363 * 364 364 * @param aMachineNode <Machine> node. 365 * 366 * @note Locks this object for writing. 365 * 366 * @note Locks this object for writing. 367 367 */ 368 368 HRESULT FloppyDrive::loadSettings (const settings::Key &aMachineNode) … … 386 386 * place when a setting of a newly created object must default to A while 387 387 * the same setting of an object loaded from the old settings file must 388 * default to B. */ 388 * default to B. */ 389 389 390 390 HRESULT rc = S_OK; … … 442 442 } 443 443 444 /** 444 /** 445 445 * Saves settings to the given machine node. 446 * 446 * 447 447 * @param aMachineNode <Machine> node. 448 * 449 * @note Locks this object for reading. 448 * 449 * @note Locks this object for reading. 450 450 */ 451 451 HRESULT FloppyDrive::saveSettings (settings::Key &aMachineNode) … … 504 504 } 505 505 506 /** 506 /** 507 507 * @note Locks this object for writing. 508 508 */ … … 528 528 } 529 529 530 /** 530 /** 531 531 * @note Locks this object for writing, together with the peer object (also 532 532 * for writing) if there is one. … … 539 539 540 540 /* sanity too */ 541 AutoCaller thatCaller (mPeer); 542 AssertComRCReturnVoid (thatCaller.rc()); 543 544 /* lock both for writing since we modify both */ 545 AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer)); 541 AutoCaller peerCaller (mPeer); 542 AssertComRCReturnVoid (peerCaller.rc()); 543 544 /* lock both for writing since we modify both (mPeer is "master" so locked 545 * first) */ 546 AutoMultiWriteLock2 alock (mPeer, this); 546 547 547 548 if (mData.isBackedUp()) … … 556 557 } 557 558 558 /** 559 /** 559 560 * @note Locks this object for writing, together with the peer object (locked 560 561 * for reading) if there is one. … … 567 568 568 569 /* sanity too */ 569 AutoCaller thatCaller ( mPeer);570 AutoCaller thatCaller (aThat); 570 571 AssertComRCReturnVoid (thatCaller.rc()); 571 572 572 /* peer is not modified, lock it for reading */ 573 AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeRlock (mPeer)); 573 /* peer is not modified, lock it for reading (aThat is "master" so locked 574 * first) */ 575 AutoMultiLock2 alock (aThat->rlock(), this->wlock()); 574 576 575 577 /* this will back up current data */ -
trunk/src/VBox/Main/HardDiskImpl.cpp
r7277 r7992 196 196 return E_POINTER; 197 197 198 Auto Lock alock (this);198 AutoReaderLock alock (this); 199 199 CHECK_READY(); 200 200 … … 208 208 return E_POINTER; 209 209 210 Auto Lock alock (this);210 AutoReaderLock alock (this); 211 211 CHECK_READY(); 212 212 … … 220 220 return E_POINTER; 221 221 222 Auto Lock alock (this);222 AutoReaderLock alock (this); 223 223 CHECK_READY(); 224 224 … … 232 232 return E_POINTER; 233 233 234 Auto Lock alock (this);234 AutoReaderLock alock (this); 235 235 CHECK_READY(); 236 236 … … 274 274 return E_POINTER; 275 275 276 Auto Lock alock (this);276 AutoReaderLock alock (this); 277 277 CHECK_READY(); 278 278 … … 286 286 return E_POINTER; 287 287 288 Auto Lock lock(this);289 CHECK_READY(); 290 291 Auto Lock chLock (childrenLock());288 AutoReaderLock lock(this); 289 CHECK_READY(); 290 291 AutoReaderLock chLock (childrenLock()); 292 292 293 293 ComObjPtr <HardDiskCollection> collection; … … 303 303 return E_POINTER; 304 304 305 Auto Lock lock(this);305 AutoReaderLock lock(this); 306 306 CHECK_READY(); 307 307 … … 368 368 return E_POINTER; 369 369 370 Auto Lock alock (this);370 AutoReaderLock alock (this); 371 371 CHECK_READY(); 372 372 … … 380 380 return E_POINTER; 381 381 382 Auto Lock alock (this);382 AutoReaderLock alock (this); 383 383 CHECK_READY(); 384 384 … … 392 392 return E_POINTER; 393 393 394 Auto Lock alock (this);394 AutoReaderLock alock (this); 395 395 CHECK_READY(); 396 396 … … 600 600 bool aCheckReaders /* = false */) 601 601 { 602 Auto Lock alock (this);602 AutoReaderLock alock (this); 603 603 CHECK_READY(); 604 604 … … 636 636 bool HardDisk::sameAs (HardDisk *that) 637 637 { 638 Auto Lock alock (this);638 AutoReaderLock alock (this); 639 639 if (!isReady()) 640 640 return false; … … 744 744 bool HardDisk::hasForeignChildren() 745 745 { 746 Auto Lock alock (this);746 AutoReaderLock alock (this); 747 747 AssertReturn (isReady(), false); 748 748 … … 750 750 751 751 /* check all children */ 752 Auto Lock chLock (childrenLock());752 AutoReaderLock chLock (childrenLock()); 753 753 for (HardDiskList::const_iterator it = children().begin(); 754 754 it != children().end(); … … 756 756 { 757 757 ComObjPtr <HardDisk> child = *it; 758 Auto Lock childLock (child);758 AutoReaderLock childLock (child); 759 759 if (child->mMachineId != mMachineId) 760 760 return true; … … 779 779 return setError (E_FAIL, errMsg, toString().raw()); 780 780 781 Auto Lock chLock (childrenLock());781 AutoReaderLock chLock (childrenLock()); 782 782 783 783 for (HardDiskList::const_iterator it = children().begin(); … … 814 814 AssertReturn (mBusy == true, (void) 0); 815 815 816 Auto Lock chLock (childrenLock());816 AutoReaderLock chLock (childrenLock()); 817 817 818 818 for (HardDiskList::const_iterator it = children().begin(); … … 831 831 /** 832 832 * Checks that this hard disk and all its direct children are accessible. 833 * 834 * @note Locks this object for writing. 833 835 */ 834 836 HRESULT HardDisk::getAccessibleWithChildren (Bstr &aAccessError) 835 837 { 838 /* getAccessible() needs a write lock */ 836 839 AutoLock alock (this); 837 840 AssertReturn (isReady(), E_FAIL); … … 841 844 return rc; 842 845 843 Auto Lock chLock (childrenLock());846 AutoReaderLock chLock (childrenLock()); 844 847 845 848 for (HardDiskList::const_iterator it = children().begin(); … … 869 872 HRESULT HardDisk::checkConsistency() 870 873 { 871 Auto Lock alock (this);874 AutoReaderLock alock (this); 872 875 AssertReturn (isReady(), E_FAIL); 873 876 … … 886 889 HRESULT rc = S_OK; 887 890 888 Auto Lock chLock (childrenLock());891 AutoReaderLock chLock (childrenLock()); 889 892 890 893 if (mParent.isNull() && mType == HardDiskType_Normal && … … 1022 1025 1023 1026 /* update paths of all children */ 1024 Auto Lock chLock (childrenLock());1027 AutoReaderLock chLock (childrenLock()); 1025 1028 for (HardDiskList::const_iterator it = children().begin(); 1026 1029 it != children().end(); … … 1262 1265 * 1263 1266 * @note 1264 * Must be called from under the object's lock1267 * Must be called from under the object's read lock 1265 1268 */ 1266 1269 HRESULT HardDisk::saveSettings (settings::Key &aHDNode) … … 1293 1296 1294 1297 /* save all children */ 1295 Auto Lock chLock (childrenLock());1298 AutoReaderLock chLock (childrenLock()); 1296 1299 for (HardDiskList::const_iterator it = children().begin(); 1297 1300 it != children().end(); … … 1299 1302 { 1300 1303 ComObjPtr <HardDisk> child = *it; 1301 Auto Lock childLock (child);1304 AutoReaderLock childLock (child); 1302 1305 1303 1306 Key hdNode = aHDNode.appendKey ("DiffHardDisk"); … … 1506 1509 return E_POINTER; 1507 1510 1508 Auto Lock alock (this);1511 AutoReaderLock alock (this); 1509 1512 CHECK_READY(); 1510 1513 … … 1539 1542 return E_POINTER; 1540 1543 1541 Auto Lock alock (this);1544 AutoReaderLock alock (this); 1542 1545 CHECK_READY(); 1543 1546 … … 1555 1558 return E_POINTER; 1556 1559 1557 Auto Lock alock (this);1560 AutoReaderLock alock (this); 1558 1561 CHECK_READY(); 1559 1562 … … 1570 1573 return E_POINTER; 1571 1574 1572 Auto Lock alock (this);1575 AutoReaderLock alock (this); 1573 1576 CHECK_READY(); 1574 1577 … … 1612 1615 return E_POINTER; 1613 1616 1614 Auto Lock alock (this);1617 AutoReaderLock alock (this); 1615 1618 CHECK_READY(); 1616 1619 … … 1708 1711 * accessible, otherwise contains a message describing 1709 1712 * the reason of inaccessibility. 1713 * 1714 * @note Locks this object for writing. 1710 1715 */ 1711 1716 HRESULT HVirtualDiskImage::getAccessible (Bstr &aAccessError) 1712 1717 { 1718 /* queryInformation() needs a write lock */ 1713 1719 AutoLock alock (this); 1714 1720 CHECK_READY(); … … 1767 1773 AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL); 1768 1774 1769 Auto Lock alock (this);1775 AutoReaderLock alock (this); 1770 1776 CHECK_READY(); 1771 1777 … … 1822 1828 * 1823 1829 * @param aShort if true, a short representation is returned 1830 * 1831 * @note Locks this object for reading. 1824 1832 */ 1825 1833 Bstr HVirtualDiskImage::toString (bool aShort /* = false */) 1826 1834 { 1827 Auto Lock alock (this);1835 AutoReaderLock alock (this); 1828 1836 1829 1837 if (!aShort) … … 2119 2127 HRESULT rc = S_OK; 2120 2128 2121 Auto Lock chLock (childrenLock());2129 AutoReaderLock chLock (childrenLock()); 2122 2130 2123 2131 for (HardDiskList::const_iterator it = children().begin(); … … 2388 2396 * @param aAccessError not used when NULL, otherwise see #getAccessible() 2389 2397 * 2390 * @note Must be called from under the object's lock, only after2398 * @note Must be called from under the object's write lock, only after 2391 2399 * CHECK_BUSY_AND_READERS() succeeds. 2392 2400 */ … … 2956 2964 return E_POINTER; 2957 2965 2958 Auto Lock alock (this);2966 AutoReaderLock alock (this); 2959 2967 CHECK_READY(); 2960 2968 … … 2985 2993 return E_POINTER; 2986 2994 2987 Auto Lock alock (this);2995 AutoReaderLock alock (this); 2988 2996 CHECK_READY(); 2989 2997 … … 2997 3005 return E_POINTER; 2998 3006 2999 Auto Lock alock (this);3007 AutoReaderLock alock (this); 3000 3008 CHECK_READY(); 3001 3009 … … 3012 3020 return E_POINTER; 3013 3021 3014 Auto Lock alock (this);3022 AutoReaderLock alock (this); 3015 3023 CHECK_READY(); 3016 3024 … … 3044 3052 return E_POINTER; 3045 3053 3046 Auto Lock alock (this);3054 AutoReaderLock alock (this); 3047 3055 CHECK_READY(); 3048 3056 … … 3073 3081 return E_POINTER; 3074 3082 3075 Auto Lock alock (this);3083 AutoReaderLock alock (this); 3076 3084 CHECK_READY(); 3077 3085 … … 3105 3113 return E_POINTER; 3106 3114 3107 Auto Lock alock (this);3115 AutoReaderLock alock (this); 3108 3116 CHECK_READY(); 3109 3117 … … 3134 3142 return E_POINTER; 3135 3143 3136 Auto Lock alock (this);3144 AutoReaderLock alock (this); 3137 3145 CHECK_READY(); 3138 3146 … … 3163 3171 return E_POINTER; 3164 3172 3165 Auto Lock alock (this);3173 AutoReaderLock alock (this); 3166 3174 CHECK_READY(); 3167 3175 … … 3214 3222 /** 3215 3223 * Checks accessibility of this iSCSI hard disk. 3224 * 3225 * @note Locks this object for writing. 3216 3226 */ 3217 3227 HRESULT HISCSIHardDisk::getAccessible (Bstr &aAccessError) 3218 3228 { 3229 /* queryInformation() needs a write lock */ 3219 3230 AutoLock alock (this); 3220 3231 CHECK_READY(); … … 3240 3251 AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL); 3241 3252 3242 Auto Lock alock (this);3253 AutoReaderLock alock (this); 3243 3254 CHECK_READY(); 3244 3255 … … 3267 3278 * 3268 3279 * @param aShort if true, a short representation is returned 3280 * 3281 * @note Locks this object for reading. 3269 3282 */ 3270 3283 Bstr HISCSIHardDisk::toString (bool aShort /* = false */) 3271 3284 { 3272 Auto Lock alock (this);3285 AutoReaderLock alock (this); 3273 3286 3274 3287 Bstr str; … … 3346 3359 * 3347 3360 * @param aAccessError see #getAccessible() 3348 * @note 3349 * Must be called from under the object's lock! 3361 * 3362 * @note Must be called from under the object's write lock, only after 3363 * CHECK_BUSY_AND_READERS() succeeds. 3350 3364 */ 3351 3365 HRESULT HISCSIHardDisk::queryInformation (Bstr &aAccessError) 3352 3366 { 3367 AssertReturn (isLockedOnCurrentThread(), E_FAIL); 3368 3369 /* create a lock object to completely release it later */ 3370 AutoLock alock (this); 3371 3353 3372 /// @todo (dmik) query info about this iSCSI disk, 3354 3373 // set mSize and mActualSize, … … 3572 3591 return E_POINTER; 3573 3592 3574 Auto Lock alock (this);3593 AutoReaderLock alock (this); 3575 3594 CHECK_READY(); 3576 3595 … … 3609 3628 return E_POINTER; 3610 3629 3611 Auto Lock alock (this);3630 AutoReaderLock alock (this); 3612 3631 CHECK_READY(); 3613 3632 … … 3627 3646 return E_POINTER; 3628 3647 3629 Auto Lock alock (this);3648 AutoReaderLock alock (this); 3630 3649 CHECK_READY(); 3631 3650 … … 3642 3661 return E_POINTER; 3643 3662 3644 Auto Lock alock (this);3663 AutoReaderLock alock (this); 3645 3664 CHECK_READY(); 3646 3665 … … 3684 3703 return E_POINTER; 3685 3704 3686 Auto Lock alock (this);3705 AutoReaderLock alock (this); 3687 3706 CHECK_READY(); 3688 3707 … … 3792 3811 * accessible, otherwise contains a message describing 3793 3812 * the reason of inaccessibility. 3813 * 3814 * @note Locks this object for writing. 3794 3815 */ 3795 3816 HRESULT HVMDKImage::getAccessible (Bstr &aAccessError) 3796 3817 { 3818 /* queryInformation() needs a write lock */ 3797 3819 AutoLock alock (this); 3798 3820 CHECK_READY(); … … 3851 3873 AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL); 3852 3874 3853 Auto Lock alock (this);3875 AutoReaderLock alock (this); 3854 3876 CHECK_READY(); 3855 3877 … … 3906 3928 * 3907 3929 * @param aShort if true, a short representation is returned 3930 * 3931 * @note Locks this object for reading. 3908 3932 */ 3909 3933 Bstr HVMDKImage::toString (bool aShort /* = false */) 3910 3934 { 3911 Auto Lock alock (this);3935 AutoReaderLock alock (this); 3912 3936 3913 3937 if (!aShort) … … 4482 4506 return E_POINTER; 4483 4507 4484 Auto Lock alock (this);4508 AutoReaderLock alock (this); 4485 4509 CHECK_READY(); 4486 4510 … … 4504 4528 return E_POINTER; 4505 4529 4506 Auto Lock alock (this);4530 AutoReaderLock alock (this); 4507 4531 CHECK_READY(); 4508 4532 … … 4516 4540 return E_POINTER; 4517 4541 4518 Auto Lock alock (this);4542 AutoReaderLock alock (this); 4519 4543 CHECK_READY(); 4520 4544 … … 4531 4555 return E_POINTER; 4532 4556 4533 Auto Lock alock (this);4557 AutoReaderLock alock (this); 4534 4558 CHECK_READY(); 4535 4559 … … 4577 4601 return E_POINTER; 4578 4602 4579 Auto Lock alock (this);4603 AutoReaderLock alock (this); 4580 4604 CHECK_READY(); 4581 4605 … … 4589 4613 return E_POINTER; 4590 4614 4591 Auto Lock alock (this);4615 AutoReaderLock alock (this); 4592 4616 CHECK_READY(); 4593 4617 … … 4665 4689 * accessible, otherwise contains a message describing 4666 4690 * the reason of inaccessibility. 4691 * 4692 * @note Locks this object for writing. 4667 4693 */ 4668 4694 HRESULT HCustomHardDisk::getAccessible (Bstr &aAccessError) 4669 4695 { 4696 /* queryInformation() needs a write lock */ 4670 4697 AutoLock alock (this); 4671 4698 CHECK_READY(); … … 4724 4751 AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL); 4725 4752 4726 Auto Lock alock (this);4753 AutoReaderLock alock (this); 4727 4754 CHECK_READY(); 4728 4755 … … 4743 4770 * 4744 4771 * @param aShort if true, a short representation is returned 4772 * 4773 * @note Locks this object for reading. 4745 4774 */ 4746 4775 Bstr HCustomHardDisk::toString (bool aShort /* = false */) 4747 4776 { 4748 Auto Lock alock (this);4777 AutoReaderLock alock (this); 4749 4778 4750 4779 /// @todo currently, we assume that location is always a file path for … … 5270 5299 return E_POINTER; 5271 5300 5272 Auto Lock alock (this);5301 AutoReaderLock alock (this); 5273 5302 CHECK_READY(); 5274 5303 … … 5307 5336 return E_POINTER; 5308 5337 5309 Auto Lock alock (this);5338 AutoReaderLock alock (this); 5310 5339 CHECK_READY(); 5311 5340 … … 5325 5354 return E_POINTER; 5326 5355 5327 Auto Lock alock (this);5356 AutoReaderLock alock (this); 5328 5357 CHECK_READY(); 5329 5358 … … 5340 5369 return E_POINTER; 5341 5370 5342 Auto Lock alock (this);5371 AutoReaderLock alock (this); 5343 5372 CHECK_READY(); 5344 5373 … … 5382 5411 return E_POINTER; 5383 5412 5384 Auto Lock alock (this);5413 AutoReaderLock alock (this); 5385 5414 CHECK_READY(); 5386 5415 … … 5490 5519 * accessible, otherwise contains a message describing 5491 5520 * the reason of inaccessibility. 5521 * 5522 * @note Locks this object for writing. 5492 5523 */ 5493 5524 HRESULT HVHDImage::getAccessible (Bstr &aAccessError) 5494 5525 { 5526 /* queryInformation() needs a write lock */ 5495 5527 AutoLock alock (this); 5496 5528 CHECK_READY(); … … 5548 5580 AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL); 5549 5581 5550 Auto Lock alock (this);5582 AutoReaderLock alock (this); 5551 5583 CHECK_READY(); 5552 5584 … … 5603 5635 * 5604 5636 * @param aShort if true, a short representation is returned 5637 * 5638 * @note Locks this object for reading. 5605 5639 */ 5606 5640 Bstr HVHDImage::toString (bool aShort /* = false */) 5607 5641 { 5608 Auto Lock alock (this);5642 AutoReaderLock alock (this); 5609 5643 5610 5644 if (!aShort) -
trunk/src/VBox/Main/MachineImpl.cpp
r7991 r7992 123 123 124 124 mMachineStateDeps = 0; 125 m ZeroMachineStateDepsSem = NIL_RTSEMEVENT;126 m WaitingStateDeps = FALSE;125 mMachineStateDepsSem = NIL_RTSEMEVENTMULTI; 126 mMachineStateChangePending = 0; 127 127 128 128 mCurrentStateModified = TRUE; … … 135 135 Machine::Data::~Data() 136 136 { 137 if (m ZeroMachineStateDepsSem != NIL_RTSEMEVENT)138 { 139 RTSemEvent Destroy (mZeroMachineStateDepsSem);140 m ZeroMachineStateDepsSem = NIL_RTSEMEVENT;137 if (mMachineStateDepsSem != NIL_RTSEMEVENTMULTI) 138 { 139 RTSemEventMultiDestroy (mMachineStateDepsSem); 140 mMachineStateDepsSem = NIL_RTSEMEVENTMULTI; 141 141 } 142 142 } … … 612 612 LogFlowThisFunc (("mRegistered=%d\n", mData->mRegistered)); 613 613 614 /* 615 * Enter this object's lock because there may be a SessionMachine instance 616 * somewhere around, that shares our data and lock but doesn't use our 617 * addCaller()/removeCaller(), and it may be also accessing the same 618 * data members. mParent lock is necessary as well because of 619 * SessionMachine::uninit(), etc. 614 /* Enter this object lock because there may be a SessionMachine instance 615 * somewhere around, that shares our data and lock but doesn't use our 616 * addCaller()/removeCaller(), and it may be also accessing the same data 617 * members. mParent lock is necessary as well because of 618 * SessionMachine::uninit(), etc. 620 619 */ 621 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());620 AutoMultiWriteLock2 alock (mParent, this); 622 621 623 622 if (!mData->mSession.mMachine.isNull()) 624 623 { 625 /* 626 * Theoretically, this can only happen if the VirtualBox server has 627 * been terminated while there were clients running that owned open 628 * direct sessions. Since in this case we are definitely called by 629 * VirtualBox::uninit(), we may be sure that SessionMachine::uninit() 630 * won't happen on the client watcher thread (because it does 631 * VirtualBox::addCaller() for the duration of the 632 * SessionMachine::checkForDeath() call, so that VirtualBox::uninit() 633 * cannot happen until the VirtualBox caller is released). This is 634 * important, because SessionMachine::uninit() cannot correctly operate 635 * after we return from this method (it expects the Machine instance 636 * is still valid). We'll call it ourselves below. 624 /* Theoretically, this can only happen if the VirtualBox server has been 625 * terminated while there were clients running that owned open direct 626 * sessions. Since in this case we are definitely called by 627 * VirtualBox::uninit(), we may be sure that SessionMachine::uninit() 628 * won't happen on the client watcher thread (because it does 629 * VirtualBox::addCaller() for the duration of the 630 * SessionMachine::checkForDeath() call, so that VirtualBox::uninit() 631 * cannot happen until the VirtualBox caller is released). This is 632 * important, because SessionMachine::uninit() cannot correctly operate 633 * after we return from this method (it expects the Machine instance is 634 * still valid). We'll call it ourselves below. 637 635 */ 638 636 LogWarningThisFunc (("Session machine is not NULL (%p), " … … 1672 1670 1673 1671 /* VirtualBox::getHardDisk() need read lock */ 1674 AutoMultiLock <2>alock (mParent->rlock(), this->wlock());1672 AutoMultiLock2 alock (mParent->rlock(), this->wlock()); 1675 1673 1676 1674 HRESULT rc = checkStateDependency (MutableStateDep); … … 2185 2183 /* VirtualBox::onExtraDataCanChange() and saveSettings() need mParent 2186 2184 * lock (saveSettings() needs a write one) */ 2187 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());2185 AutoMultiWriteLock2 alock (mParent, this); 2188 2186 2189 2187 if (mType == IsSnapshotMachine) … … 2296 2294 2297 2295 /* saveSettings() needs mParent lock */ 2298 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());2296 AutoMultiWriteLock2 alock (mParent, this); 2299 2297 2300 2298 HRESULT rc = checkStateDependency (MutableStateDep); … … 2317 2315 2318 2316 /* saveSettings() needs mParent lock */ 2319 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());2317 AutoMultiWriteLock2 alock (mParent, this); 2320 2318 2321 2319 HRESULT rc = checkStateDependency (MutableStateDep); … … 2530 2528 CheckComRCReturnRC (autoCaller.rc()); 2531 2529 2532 Auto ReaderLock alock (this);2530 AutoLock alock (this); 2533 2531 2534 2532 HRESULT rc = checkStateDependency (MutableStateDep); … … 2919 2917 2920 2918 /* We need VirtualBox lock because of Progress::notifyComplete() */ 2921 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());2919 AutoMultiWriteLock2 alock (mParent, this); 2922 2920 2923 2921 if (!mData->mRegistered) … … 3428 3426 3429 3427 /* wait for state dependants to drop to zero */ 3430 checkStateDependencies (alock);3428 ensureNoStateDependencies (alock); 3431 3429 3432 3430 ComAssertRet (mData->mRegistered != aRegistered, E_FAIL); … … 3510 3508 3511 3509 /** 3512 * Increases the number of objects dependent on the machine state or on the 3513 * registered state. Guarantees that these two states will not change at 3514 * least until #releaseStateDependency() is called. 3515 * 3516 * Depending on the @a aDepType value, additional state checks may be 3517 * made. These checks will set extended error info on failure. See 3518 * #checkStateDependency() for more info. 3519 * 3520 * If this method returns a failure, the dependency is not added and the 3521 * caller is not allowed to rely on any particular machine state or 3522 * registration state value and may return the failed result code to the 3523 * upper level. 3524 * 3525 * @param aDepType Dependency type to add. 3526 * @param aState Current machine state (NULL if not interested). 3527 * @param aRegistered Current registered state (NULL if not interested). 3510 * Increases the number of objects dependent on the machine state or on the 3511 * registered state. Guarantees that these two states will not change at least 3512 * until #releaseStateDependency() is called. 3513 * 3514 * Depending on the @a aDepType value, additional state checks may be made. 3515 * These checks will set extended error info on failure. See 3516 * #checkStateDependency() for more info. 3517 * 3518 * If this method returns a failure, the dependency is not added and the caller 3519 * is not allowed to rely on any particular machine state or registration state 3520 * value and may return the failed result code to the upper level. 3521 * 3522 * @param aDepType Dependency type to add. 3523 * @param aState Current machine state (NULL if not interested). 3524 * @param aRegistered Current registered state (NULL if not interested). 3525 * 3526 * @note Locks this object for reading. 3528 3527 */ 3529 3528 HRESULT Machine::addStateDependency (StateDependency aDepType /* = AnyStateDep */, … … 3534 3533 AssertComRCReturnRC (autoCaller.rc()); 3535 3534 3536 AutoLock alock (this); 3537 3538 if (mData->mWaitingStateDeps && mData->mMachineStateDeps == 0) 3539 { 3540 /* checkStateDependencies() is at the point after RTSemEventWait() but 3541 * before entering the lock. Report an error. It would be better to 3542 * leave the lock now and re-schedule ourselves, but we don't have a 3543 * framework that can guarantee such a behavior in 100% cases. */ 3544 3545 AssertFailed(); /* <-- this is just to see how often it can happen */ 3546 3547 return setError (E_ACCESSDENIED, 3548 tr ("The machine is busy: state transition is in progress. " 3549 "Retry the operation (state is %d)"), 3550 mData->mMachineState); 3551 } 3535 AutoReaderLock alock (this); 3552 3536 3553 3537 HRESULT rc = checkStateDependency (aDepType); 3554 3538 CheckComRCReturnRC (rc); 3539 3540 { 3541 AutoLock stateLock (stateLockHandle()); 3542 3543 if (mData->mMachineStateChangePending != 0) 3544 { 3545 /* ensureNoStateDependencies() is waiting for state dependencies to 3546 * drop to zero so don't add more. It may make sense to wait a bit 3547 * and retry before reporting an error (since the pending state 3548 * transition should be really quick) but let's just assert for 3549 * now to see if it ever happens on practice. */ 3550 3551 AssertFailed(); 3552 3553 return setError (E_ACCESSDENIED, 3554 tr ("Machine state change is in progress. " 3555 "Please retry the operation later.")); 3556 } 3557 3558 ++ mData->mMachineStateDeps; 3559 Assert (mData->mMachineStateDeps != 0 /* overflow */); 3560 } 3555 3561 3556 3562 if (aState) … … 3559 3565 *aRegistered = mData->mRegistered; 3560 3566 3561 ++ mData->mMachineStateDeps;3562 3563 3567 return S_OK; 3564 3568 } 3565 3569 3566 3570 /** 3567 * 3568 * 3569 * dependencyno more necessary.3571 * Decreases the number of objects dependent on the machine state. 3572 * Must always complete the #addStateDependency() call after the state 3573 * dependency is no more necessary. 3570 3574 */ 3571 3575 void Machine::releaseStateDependency() 3572 3576 { 3577 /* stateLockHandle() is the same handle that is used by AutoCaller 3578 * so lock it in advance to avoid two mutex requests in a raw */ 3579 AutoLock stateLock (stateLockHandle()); 3580 3573 3581 AutoCaller autoCaller (this); 3574 3582 AssertComRCReturnVoid (autoCaller.rc()); 3575 3583 3576 AutoLock alock (this); 3577 3578 AssertReturnVoid (mData->mMachineStateDeps > 0); 3584 AssertReturnVoid (mData->mMachineStateDeps != 0 3585 /* releaseStateDependency() w/o addStateDependency()? */); 3579 3586 -- mData->mMachineStateDeps; 3580 3587 3581 if (mData->mMachineStateDeps == 0 && 3582 mData->mZeroMachineStateDepsSem != NIL_RTSEMEVENT) 3583 { 3584 /* inform checkStateDependencies() that there are no more deps */ 3585 RTSemEventSignal (mData->mZeroMachineStateDepsSem); 3588 if (mData->mMachineStateDeps == 0) 3589 { 3590 /* inform ensureNoStateDependencies() that there are no more deps */ 3591 if (mData->mMachineStateChangePending != 0) 3592 { 3593 Assert (mData->mMachineStateDepsSem != NIL_RTSEMEVENTMULTI); 3594 RTSemEventMultiSignal (mData->mMachineStateDepsSem); 3595 } 3586 3596 } 3587 3597 } … … 3611 3621 * @param aDepType Dependency type to check. 3612 3622 * 3613 * @note Externalclasses should use #addStateDependency() and3623 * @note Non Machine based classes should use #addStateDependency() and 3614 3624 * #releaseStateDependency() methods or the smart AutoStateDependency 3615 3625 * template. 3616 3626 * 3617 * @note This method must be called from under this object's lock. 3627 * @note This method must be called from under this object's read or write 3628 * lock. 3618 3629 */ 3619 3630 HRESULT Machine::checkStateDependency (StateDependency aDepType) 3620 3631 { 3621 AssertReturn (isLockedOnCurrentThread(), E_FAIL);3622 3623 3632 switch (aDepType) 3624 3633 { … … 3859 3868 } 3860 3869 3861 3862 3870 /** 3863 * Chhecks that there are no state dependants. If necessary, waits for the3864 * number of dependants to drop to zero. Must be called from under3865 * this object's lock.3866 * 3867 * @param aLock This object'slock.3868 * 3869 * @note This method may leave the object lock during its execution!3871 * Makes sure that there are no machine state dependants. If necessary, waits 3872 * for the number of dependants to drop to zero. Must be called from under this 3873 * object's write lock which will be released while waiting. 3874 * 3875 * @param aLock This object's write lock. 3876 * 3877 * @warning To be used only in methods that change the machine state! 3870 3878 */ 3871 void Machine::checkStateDependencies (AutoLock &aLock) 3872 { 3873 AssertReturnVoid (isLockedOnCurrentThread()); 3879 void Machine::ensureNoStateDependencies (AutoLock &aLock) 3880 { 3874 3881 AssertReturnVoid (aLock.belongsTo (this)); 3882 AssertReturnVoid (aLock.isLockedOnCurrentThread()); 3883 3884 AutoLock stateLock (stateLockHandle()); 3875 3885 3876 3886 /* Wait for all state dependants if necessary */ 3877 if (mData->mMachineStateDeps >0)3878 { 3879 /* lazy creation */3880 if (mData->m ZeroMachineStateDepsSem == NIL_RTSEMEVENT)3881 RTSemEvent Create (&mData->mZeroMachineStateDepsSem);3887 if (mData->mMachineStateDeps != 0) 3888 { 3889 /* lazy semaphore creation */ 3890 if (mData->mMachineStateDepsSem == NIL_RTSEMEVENTMULTI) 3891 RTSemEventMultiCreate (&mData->mMachineStateDepsSem); 3882 3892 3883 3893 LogFlowThisFunc (("Waiting for state deps (%d) to drop to zero...\n", 3884 3894 mData->mMachineStateDeps)); 3885 3895 3886 mData->mWaitingStateDeps = TRUE; 3887 3896 ++ mData->mMachineStateChangePending; 3897 3898 /* reset the semaphore before waiting, the last dependant will signal 3899 * it */ 3900 RTSemEventMultiReset (mData->mMachineStateDepsSem); 3901 3902 stateLock.leave(); 3888 3903 aLock.leave(); 3889 3904 3890 RTSemEvent Wait (mData->mZeroMachineStateDepsSem, RT_INDEFINITE_WAIT);3905 RTSemEventMultiWait (mData->mMachineStateDepsSem, RT_INDEFINITE_WAIT); 3891 3906 3892 3907 aLock.enter(); 3893 3894 mData->mWaitingStateDeps = FALSE; 3908 stateLock.enter(); 3909 3910 -- mData->mMachineStateChangePending; 3895 3911 } 3896 3912 } … … 3912 3928 3913 3929 /* wait for state dependants to drop to zero */ 3914 /// @todo it may be potentially unsafe to leave the lock here as 3915 // the below method does. Needs some thinking. The easiest solution may 3916 // be to provide a separate mutex for mMachineState and mRegistered. 3917 checkStateDependencies (alock); 3930 ensureNoStateDependencies (alock); 3918 3931 3919 3932 if (mData->mMachineState != aMachineState) … … 6432 6445 6433 6446 /* accessing mParent methods below needs mParent lock */ 6434 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());6447 AutoMultiWriteLock2 alock (mParent, this); 6435 6448 6436 6449 HRESULT rc = S_OK; … … 6619 6632 6620 6633 /* accessing mParent methods below needs mParent lock */ 6621 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());6634 AutoMultiWriteLock2 alock (mParent, this); 6622 6635 6623 6636 /* short cut: check whether attachments are all the same */ … … 7322 7335 if (autoUninitSpan.initFailed()) 7323 7336 { 7324 /* 7325 * We've been called by init() because it's failed. It's not really 7326 * necessary (nor it's safe) to perform the regular uninit sequence 7327 * below, the following is enough. 7337 /* We've been called by init() because it's failed. It's not really 7338 * necessary (nor it's safe) to perform the regular uninit sequense 7339 * below, the following is enough. 7328 7340 */ 7329 7341 LogFlowThisFunc (("Initialization failed.\n")); … … 7351 7363 } 7352 7364 7353 /* 7354 * We need to lock this object in uninit() because the lock is shared 7355 * with mPeer (as well as data we modify below). 7356 * mParent->addProcessToReap() and others need mParent lock. 7357 */ 7358 AutoMultiLock <2> alock (mParent->wlock(), this->wlock()); 7365 /* We need to lock this object in uninit() because the lock is shared 7366 * with mPeer (as well as data we modify below). mParent->addProcessToReap() 7367 * and others need mParent lock. */ 7368 AutoMultiWriteLock2 alock (mParent, this); 7359 7369 7360 7370 MachineState_T lastState = mData->mMachineState; … … 7519 7529 * with the primary Machine instance (mPeer). 7520 7530 */ 7521 AutoLock::Handle *SessionMachine::lockHandle() const7531 RWLockHandle *SessionMachine::lockHandle() const 7522 7532 { 7523 7533 AssertReturn (!mPeer.isNull(), NULL); … … 7701 7711 7702 7712 /* Progress::init() needs mParent lock */ 7703 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());7713 AutoMultiWriteLock2 alock (mParent, this); 7704 7714 7705 7715 if (control.equalsTo (mData->mSession.mDirectControl)) … … 7766 7776 7767 7777 /* mParent->addProgress() needs mParent lock */ 7768 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());7778 AutoMultiWriteLock2 alock (mParent, this); 7769 7779 7770 7780 AssertReturn (mData->mMachineState == MachineState_Paused && … … 7814 7824 7815 7825 /* endSavingState() need mParent lock */ 7816 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());7826 AutoMultiWriteLock2 alock (mParent, this); 7817 7827 7818 7828 AssertReturn (mData->mMachineState == MachineState_Saving && … … 7888 7898 7889 7899 /* Progress::init() needs mParent lock */ 7890 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());7900 AutoMultiWriteLock2 alock (mParent, this); 7891 7901 7892 7902 AssertReturn ((mData->mMachineState < MachineState_Running || … … 8048 8058 8049 8059 /* Lock mParent because of endTakingSnapshot() */ 8050 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());8060 AutoMultiWriteLock2 alock (mParent, this); 8051 8061 8052 8062 AssertReturn (!aSuccess || … … 8085 8095 8086 8096 /* Progress::init() needs mParent lock */ 8087 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());8097 AutoMultiWriteLock2 alock (mParent, this); 8088 8098 8089 8099 ComAssertRet (mData->mMachineState < MachineState_Running, E_FAIL); … … 8170 8180 8171 8181 /* Progress::init() needs mParent lock */ 8172 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());8182 AutoMultiWriteLock2 alock (mParent, this); 8173 8183 8174 8184 ComAssertRet (mData->mMachineState < MachineState_Running, E_FAIL); … … 8234 8244 8235 8245 /* Progress::init() needs mParent lock */ 8236 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());8246 AutoMultiWriteLock2 alock (mParent, this); 8237 8247 8238 8248 ComAssertRet (mData->mMachineState < MachineState_Running, E_FAIL); … … 8687 8697 8688 8698 /* mParent->removeProgress() and saveSettings() need mParent lock */ 8689 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());8699 AutoMultiWriteLock2 alock (mParent, this); 8690 8700 8691 8701 HRESULT rc = S_OK; … … 8734 8744 8735 8745 /* Progress object uninitialization needs mParent lock */ 8736 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());8746 AutoMultiWriteLock2 alock (mParent, this); 8737 8747 8738 8748 HRESULT rc = S_OK; … … 8834 8844 8835 8845 /* endTakingSnapshot() needs mParent lock */ 8836 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());8846 AutoMultiWriteLock2 alock (mParent, this); 8837 8847 8838 8848 HRESULT rc = S_OK; … … 8930 8940 } 8931 8941 8942 /* Progress::notifyComplete() et al., saveSettings() need mParent lock. 8943 * Also safely lock the snapshot stuff in the direction parent->child */ 8944 AutoMultiWriteLock4 alock (mParent->lockHandle(), this->lockHandle(), 8945 aTask.snapshot->lockHandle(), 8946 aTask.snapshot->childrenLock()); 8947 8932 8948 ComObjPtr <SnapshotMachine> sm = aTask.snapshot->data().mMachine; 8933 8934 /* Progress::notifyComplete() et al., saveSettings() need mParent lock */ 8935 AutoMultiLock <3> alock (mParent->wlock(), this->wlock(), sm->rlock()); 8936 8937 /* Safe locking in the direction parent->child */ 8938 AutoLock snapshotLock (aTask.snapshot); 8939 AutoLock snapshotChildrenLock (aTask.snapshot->childrenLock()); 8949 /* no need to lock the snapshot machine since it is const by definiton */ 8940 8950 8941 8951 HRESULT rc = S_OK; … … 9060 9070 hdRootString.raw()))); 9061 9071 9062 snapshotChildrenLock.unlock();9063 snapshotLock.unlock();9064 9072 alock.leave(); 9065 9073 … … 9067 9075 9068 9076 alock.enter(); 9069 snapshotLock.lock();9070 snapshotChildrenLock.lock();9071 9077 9072 9078 // debug code … … 9130 9136 /* merge the child to this basic image */ 9131 9137 9132 snapshotChildrenLock.unlock();9133 snapshotLock.unlock();9134 9138 alock.leave(); 9135 9139 … … 9137 9141 9138 9142 alock.enter(); 9139 snapshotLock.lock();9140 snapshotChildrenLock.lock();9141 9143 9142 9144 if (SUCCEEDED (rc)) … … 9325 9327 9326 9328 /* Progress::notifyComplete() et al., saveSettings() need mParent lock */ 9327 AutoMulti Lock <2> alock (mParent->wlock(), this->wlock());9329 AutoMultiWriteLock2 alock (mParent, this); 9328 9330 9329 9331 /* … … 9403 9405 curSnapshot->data().mMachine->mHDData->mHDAttachments; 9404 9406 9405 snapshotLock. unlock();9407 snapshotLock.leave(); 9406 9408 alock.leave(); 9407 9409 rc = createSnapshotDiffs (NULL, mUserData->mSnapshotFolderFull, … … 9409 9411 false /* aOnline */); 9410 9412 alock.enter(); 9411 snapshotLock. lock();9413 snapshotLock.enter(); 9412 9414 9413 9415 if (FAILED (rc)) … … 9444 9446 9445 9447 /* copy the state file */ 9446 snapshotLock. unlock();9448 snapshotLock.leave(); 9447 9449 alock.leave(); 9448 9450 int vrc = RTFileCopyEx (snapStateFilePath, stateFilePath, 9449 9451 0, progressCallback, aTask.progress); 9450 9452 alock.enter(); 9451 snapshotLock. lock();9453 snapshotLock.enter(); 9452 9454 9453 9455 if (VBOX_SUCCESS (vrc)) … … 9822 9824 * (or NULL for the offline snapshot) 9823 9825 * 9824 * @note Locks aSessionMachine object for reading.9826 * @note The aSessionMachine must be locked for writing. 9825 9827 */ 9826 9828 HRESULT SnapshotMachine::init (SessionMachine *aSessionMachine, … … 9837 9839 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED); 9838 9840 9841 AssertReturn (aSessionMachine->isLockedOnCurrentThread(), E_FAIL); 9842 9839 9843 mSnapshotId = aSnapshotId; 9840 9841 AutoReaderLock alock (aSessionMachine);9842 9844 9843 9845 /* memorize the primary Machine instance (i.e. not SessionMachine!) */ … … 9936 9938 * (or NULL for the offline snapshot) 9937 9939 * 9938 * @note Locks aMachine object for reading.9940 * @note Doesn't lock anything. 9939 9941 */ 9940 9942 HRESULT SnapshotMachine::init (Machine *aMachine, … … 9954 9956 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED); 9955 9957 9958 /* Don't need to lock aMachine when VirtualBox is starting up */ 9959 9956 9960 mSnapshotId = aSnapshotId; 9957 9958 AutoReaderLock alock (aMachine);9959 9961 9960 9962 /* memorize the primary Machine instance */ … … 10071 10073 * with the primary Machine instance (mPeer). 10072 10074 */ 10073 AutoLock::Handle *SnapshotMachine::lockHandle() const10075 RWLockHandle *SnapshotMachine::lockHandle() const 10074 10076 { 10075 10077 AssertReturn (!mPeer.isNull(), NULL); -
trunk/src/VBox/Main/Makefile.kmk
r7964 r7992 177 177 VBoxSVC_SOURCES = \ 178 178 Logging.cpp \ 179 AutoLock.cpp \ 179 180 Matching.cpp \ 180 181 VirtualBoxBase.cpp \ … … 350 351 VBoxC_SOURCES = \ 351 352 Logging.cpp \ 353 AutoLock.cpp \ 352 354 VBoxDll.cpp \ 353 355 Version.cpp \ -
trunk/src/VBox/Main/NetworkAdapterImpl.cpp
r7207 r7992 1180 1180 1181 1181 /* sanity too */ 1182 AutoCaller thatCaller (mPeer); 1183 AssertComRCReturnVoid (thatCaller.rc()); 1184 1185 /* lock both for writing since we modify both */ 1186 AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer)); 1182 AutoCaller peerCaller (mPeer); 1183 AssertComRCReturnVoid (peerCaller.rc()); 1184 1185 /* lock both for writing since we modify both (mPeer is "master" so locked 1186 * first) */ 1187 AutoMultiWriteLock2 alock (mPeer, this); 1187 1188 1188 1189 if (mData.isBackedUp()) … … 1210 1211 1211 1212 /* sanity too */ 1212 AutoCaller thatCaller ( mPeer);1213 AutoCaller thatCaller (aThat); 1213 1214 AssertComRCReturnVoid (thatCaller.rc()); 1214 1215 1215 /* peer is not modified, lock it for reading */ 1216 AutoMultiLock <2> alock (this->wlock(), aThat->rlock()); 1216 /* peer is not modified, lock it for reading (aThat is "master" so locked 1217 * first) */ 1218 AutoMultiLock2 alock (aThat->rlock(), this->wlock()); 1217 1219 1218 1220 /* this will back up current data */ -
trunk/src/VBox/Main/ParallelPortImpl.cpp
r6168 r7992 163 163 * Loads settings from the given port node. 164 164 * May be called once right after this object creation. 165 * 165 * 166 166 * @param aPortNode <Port> node. 167 * 167 * 168 168 * @note Locks this object for writing. 169 169 */ … … 188 188 * place when a setting of a newly created object must default to A while 189 189 * the same setting of an object loaded from the old settings file must 190 * default to B. */ 190 * default to B. */ 191 191 192 192 /* enabled (required) */ … … 206 206 } 207 207 208 /** 208 /** 209 209 * Saves settings to the given port node. 210 * 210 * 211 211 * Note that the given Port node is comletely empty on input. 212 212 * 213 213 * @param aPortNode <Port> node. 214 * 215 * @note Locks this object for reading. 214 * 215 * @note Locks this object for reading. 216 216 */ 217 217 HRESULT ParallelPort::saveSettings (settings::Key &aPortNode) … … 272 272 273 273 /* sanity too */ 274 AutoCaller thatCaller (mPeer); 275 AssertComRCReturnVoid (thatCaller.rc()); 276 277 /* lock both for writing since we modify both */ 278 AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer)); 274 AutoCaller peerCaller (mPeer); 275 AssertComRCReturnVoid (peerCaller.rc()); 276 277 /* lock both for writing since we modify both (mPeer is "master" so locked 278 * first) */ 279 AutoMultiWriteLock2 alock (mPeer, this); 279 280 280 281 if (mData.isBackedUp()) … … 302 303 303 304 /* sanity too */ 304 AutoCaller thatCaller ( mPeer);305 AutoCaller thatCaller (aThat); 305 306 AssertComRCReturnVoid (thatCaller.rc()); 306 307 307 /* peer is not modified, lock it for reading */ 308 AutoMultiLock <2> alock (this->wlock(), aThat->rlock()); 308 /* peer is not modified, lock it for reading (aThat is "master" so locked 309 * first) */ 310 AutoMultiLock2 alock (aThat->rlock(), this->wlock()); 309 311 310 312 /* this will back up current data */ … … 504 506 } 505 507 506 /** 508 /** 507 509 * Validates COMSETTER(Path) arguments. 508 510 */ -
trunk/src/VBox/Main/ProgressImpl.cpp
r6935 r7992 162 162 LogFlowMember (("ProgressBase::protectedUninit()\n")); 163 163 164 Assert (alock.belongsTo (this) && alock.level() == 1); 164 Assert (alock.belongsTo (this) && alock.isLockedOnCurrentThread() && 165 alock.writeLockLevel() == 1); 165 166 Assert (isReady()); 166 167 … … 747 748 * If the result code indicates a success (|SUCCEEDED (@a aResultCode)|) 748 749 * then the current operation is set to the last 749 * 750 * 750 751 * Note that this method may be called only once for the given Progress object. 751 752 * Subsequent calls will assert. … … 844 845 Bstr text = Utf8StrFmtVA (aText, args); 845 846 va_end (args); 846 847 847 848 return notifyCompleteBstr (aResultCode, aIID, aComponent, text); 848 849 } … … 855 856 * This method is preferred iy you have a ready (translated and formatted) 856 857 * Bstr string, because it omits an extra conversion Utf8Str -> Bstr. 857 * 858 * 858 859 * @param aResultCode operation result (error) code, must not be S_OK 859 860 * @param aIID IID of the intrface that defines the error -
trunk/src/VBox/Main/SATAControllerImpl.cpp
r7556 r7992 321 321 ///////////////////////////////////////////////////////////////////////////// 322 322 323 /** 323 /** 324 324 * Loads settings from the given machine node. 325 325 * May be called once right after this object creation. 326 * 326 * 327 327 * @param aMachineNode <Machine> node. 328 * 329 * @note Locks this object for writing. 328 * 329 * @note Locks this object for writing. 330 330 */ 331 331 HRESULT SATAController::loadSettings (const settings::Key &aMachineNode) … … 358 358 } 359 359 360 /** 360 /** 361 361 * Saves settings to the given machine node. 362 * 362 * 363 363 * @param aMachineNode <Machine> node. 364 * 364 * 365 365 * @note Locks this object for reading. 366 366 */ … … 451 451 } 452 452 453 /** @note Locks objects for writing! */ 453 /** 454 * @note Locks this object for writing, together with the peer object (also 455 * for writing) if there is one. 456 */ 454 457 void SATAController::commit() 455 458 { 459 /* sanity */ 456 460 AutoCaller autoCaller (this); 457 461 AssertComRCReturnVoid (autoCaller.rc()); 458 462 459 AutoLock alock (this); 463 /* sanity too */ 464 AutoCaller peerCaller (mPeer); 465 AssertComRCReturnVoid (peerCaller.rc()); 466 467 /* lock both for writing since we modify both (mPeer is "master" so locked 468 * first) */ 469 AutoMultiWriteLock2 alock (mPeer, this); 460 470 461 471 if (mData.isBackedUp()) … … 471 481 } 472 482 473 /** @note Locks object for writing and that object for reading! */ 483 /** 484 * @note Locks this object for writing, together with the peer object 485 * represented by @a aThat (locked for reading). 486 */ 474 487 void SATAController::copyFrom (SATAController *aThat) 475 488 { 489 AssertReturnVoid (aThat != NULL); 490 491 /* sanity */ 476 492 AutoCaller autoCaller (this); 477 493 AssertComRCReturnVoid (autoCaller.rc()); 478 494 479 AutoMultiLock <2> alock (this->wlock(), aThat->rlock()); 495 /* sanity too */ 496 AutoCaller thatCaller (aThat); 497 AssertComRCReturnVoid (thatCaller.rc()); 498 499 /* peer is not modified, lock it for reading (aThat is "master" so locked 500 * first) */ 501 AutoMultiLock2 alock (aThat->rlock(), this->wlock()); 480 502 481 503 /* this will back up current data */ -
trunk/src/VBox/Main/SerialPortImpl.cpp
r7207 r7992 308 308 309 309 /* sanity too */ 310 AutoCaller thatCaller (mPeer); 311 AssertComRCReturnVoid (thatCaller.rc()); 312 313 /* lock both for writing since we modify both */ 314 AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer)); 310 AutoCaller peerCaller (mPeer); 311 AssertComRCReturnVoid (peerCaller.rc()); 312 313 /* lock both for writing since we modify both (mPeer is "master" so locked 314 * first) */ 315 AutoMultiWriteLock2 alock (mPeer, this); 315 316 316 317 if (mData.isBackedUp()) … … 338 339 339 340 /* sanity too */ 340 AutoCaller thatCaller ( mPeer);341 AutoCaller thatCaller (aThat); 341 342 AssertComRCReturnVoid (thatCaller.rc()); 342 343 343 /* peer is not modified, lock it for reading */ 344 AutoMultiLock <2> alock (this->wlock(), aThat->rlock()); 344 /* peer is not modified, lock it for reading (aThat is "master" so locked 345 * first) */ 346 AutoMultiLock2 alock (aThat->rlock(), this->wlock()); 345 347 346 348 /* this will back up current data */ -
trunk/src/VBox/Main/USBControllerImpl.cpp
r7968 r7992 923 923 } 924 924 925 /** @note Locks objects for writing! */ 925 /** 926 * @note Locks this object for writing, together with the peer object (also 927 * for writing) if there is one. 928 */ 926 929 void USBController::commit() 927 930 { 931 /* sanity */ 928 932 AutoCaller autoCaller (this); 929 933 AssertComRCReturnVoid (autoCaller.rc()); 930 934 931 AutoLock alock (this); 935 /* sanity too */ 936 AutoCaller peerCaller (mPeer); 937 AssertComRCReturnVoid (peerCaller.rc()); 938 939 /* lock both for writing since we modify both (mPeer is "master" so locked 940 * first) */ 941 AutoMultiWriteLock2 alock (mPeer, this); 932 942 933 943 if (mData.isBackedUp()) … … 936 946 if (mPeer) 937 947 { 938 / / attach new data to the peer and reshare it948 /* attach new data to the peer and reshare it */ 939 949 AutoLock peerlock (mPeer); 940 950 mPeer->mData.attach (mData); … … 949 959 mDeviceFilters.commit(); 950 960 951 / / apply changes to peer961 /* apply changes to peer */ 952 962 if (mPeer) 953 963 { 954 964 AutoLock peerlock (mPeer); 955 / /commit all changes to new filters (this will reshare data with956 // peers for those who have peers)965 /* commit all changes to new filters (this will reshare data with 966 * peers for those who have peers) */ 957 967 DeviceFilterList *newList = new DeviceFilterList(); 958 968 DeviceFilterList::const_iterator it = mDeviceFilters->begin(); … … 961 971 (*it)->commit(); 962 972 963 / / look if this filter has a peer filter973 /* look if this filter has a peer filter */ 964 974 ComObjPtr <USBDeviceFilter> peer = (*it)->peer(); 965 975 if (!peer) 966 976 { 967 / /no peer means the filter is a newly created one;968 // create a peer owning data this filter share it with977 /* no peer means the filter is a newly created one; 978 * create a peer owning data this filter share it with */ 969 979 peer.createObject(); 970 980 peer->init (mPeer, *it, true /* aReshare */); … … 972 982 else 973 983 { 974 / / remove peer from the old list984 /* remove peer from the old list */ 975 985 mPeer->mDeviceFilters->remove (peer); 976 986 } 977 / / and add it to the new list987 /* and add it to the new list */ 978 988 newList->push_back (peer); 979 989 … … 981 991 } 982 992 983 / / uninit old peer's filters that are left993 /* uninit old peer's filters that are left */ 984 994 it = mPeer->mDeviceFilters->begin(); 985 995 while (it != mPeer->mDeviceFilters->end()) … … 989 999 } 990 1000 991 / / attach new list of filters to our peer1001 /* attach new list of filters to our peer */ 992 1002 mPeer->mDeviceFilters.attach (newList); 993 1003 } 994 1004 else 995 1005 { 996 / /we have no peer (our parent is the newly created machine);997 // just commit changes to filters1006 /* we have no peer (our parent is the newly created machine); 1007 * just commit changes to filters */ 998 1008 commitFilters = true; 999 1009 } … … 1001 1011 else 1002 1012 { 1003 / /the list of filters itself is not changed,1004 // just commit changes to filters themselves1013 /* the list of filters itself is not changed, 1014 * just commit changes to filters themselves */ 1005 1015 commitFilters = true; 1006 1016 } … … 1018 1028 } 1019 1029 1020 /** @note Locks object for writing and that object for reading! */ 1030 /** 1031 * @note Locks this object for writing, together with the peer object 1032 * represented by @a aThat (locked for reading). 1033 */ 1021 1034 void USBController::copyFrom (USBController *aThat) 1022 1035 { 1036 AssertReturnVoid (aThat != NULL); 1037 1038 /* sanity */ 1023 1039 AutoCaller autoCaller (this); 1024 1040 AssertComRCReturnVoid (autoCaller.rc()); 1025 1041 1026 AutoMultiLock <2> alock (this->wlock(), aThat->rlock()); 1042 /* sanity too */ 1043 AutoCaller thatCaller (aThat); 1044 AssertComRCReturnVoid (thatCaller.rc()); 1045 1046 /* peer is not modified, lock it for reading (aThat is "master" so locked 1047 * first) */ 1048 AutoMultiLock2 alock (aThat->rlock(), this->wlock()); 1027 1049 1028 1050 if (mParent->isRegistered()) -
trunk/src/VBox/Main/VirtualBoxBase.cpp
r6964 r7992 43 43 mInitDoneSem = NIL_RTSEMEVENTMULTI; 44 44 mInitDoneSemUsers = 0; 45 RTCritSectInit (&mStateLock);46 45 mObjectLock = NULL; 47 46 } … … 51 50 if (mObjectLock) 52 51 delete mObjectLock; 53 RTCritSectDelete (&mStateLock);54 52 Assert (mInitDoneSemUsers == 0); 55 53 Assert (mInitDoneSem == NIL_RTSEMEVENTMULTI); … … 62 60 63 61 // AutoLock::Lockable interface 64 AutoLock::Handle *VirtualBoxBaseNEXT_base::lockHandle() const62 RWLockHandle *VirtualBoxBaseNEXT_base::lockHandle() const 65 63 { 66 64 /* lasy initialization */ 67 65 if (!mObjectLock) 68 mObjectLock = new AutoLock::Handle;66 mObjectLock = new RWLockHandle; 69 67 return mObjectLock; 70 68 } -
trunk/src/VBox/Main/include/AutoLock.h
r5999 r7992 5 5 6 6 /* 7 * Copyright (C) 2006-200 7innotek GmbH7 * Copyright (C) 2006-2008 innotek GmbH 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 23 23 #include <iprt/critsect.h> 24 24 #include <iprt/thread.h> 25 #include <iprt/semaphore.h> 26 27 #include <iprt/assert.h> 25 28 26 29 #if defined(DEBUG) … … 31 34 { 32 35 33 template <size_t> class AutoMultiLock;34 namespace internal { struct LockableTag; }35 36 36 /** 37 * Smart class to safely manage critical sections. Also provides ecplicit 38 * lock, unlock leave and enter operations. 39 * 40 * When constructing an instance, it enters the given critical 41 * section. This critical section will be exited automatically when the 42 * instance goes out of scope (i.e. gets destroyed). 37 * Abstract lock operations. See LockHandle and AutoLock for details. 38 */ 39 class LockOps 40 { 41 public: 42 43 virtual ~LockOps() {} 44 45 virtual void lock() = 0; 46 virtual void unlock() = 0; 47 }; 48 49 /** 50 * Read lock operations. See LockHandle and AutoLock for details. 51 */ 52 class ReadLockOps : public LockOps 53 { 54 public: 55 56 /** 57 * Requests a read (shared) lock. 58 */ 59 virtual void lockRead() = 0; 60 61 /** 62 * Releases a read (shared) lock ackquired by lockRead(). 63 */ 64 virtual void unlockRead() = 0; 65 66 // LockOps interface 67 void lock() { lockRead(); } 68 void unlock() { unlockRead(); } 69 }; 70 71 /** 72 * Write lock operations. See LockHandle and AutoLock for details. 73 */ 74 class WriteLockOps : public LockOps 75 { 76 public: 77 78 /** 79 * Requests a write (exclusive) lock. 80 */ 81 virtual void lockWrite() = 0; 82 83 /** 84 * Releases a write (exclusive) lock ackquired by lockWrite(). 85 */ 86 virtual void unlockWrite() = 0; 87 88 // LockOps interface 89 void lock() { lockWrite(); } 90 void unlock() { unlockWrite(); } 91 }; 92 93 /** 94 * Abstract read/write semaphore handle. 95 * 96 * This is a base class to implement semaphores that provide read/write locking. 97 * Subclasses must implement all pure virtual methods of this class together 98 * with pure methods of ReadLockOps and WriteLockOps classes. 99 * 100 * See the AutoLock class documentation for the detailed description of read and 101 * write locks. 102 */ 103 class LockHandle : protected ReadLockOps, protected WriteLockOps 104 { 105 public: 106 107 LockHandle() {} 108 virtual ~LockHandle() {} 109 110 /** 111 * Returns @c true if the current thread holds a write lock on this 112 * read/write semaphore. Intended for debugging only. 113 */ 114 virtual bool isLockedOnCurrentThread() const = 0; 115 116 /** 117 * Returns the current write lock level of this semaphore. The lock level 118 * determines the number of nested #lock() calls on the given semaphore 119 * handle. 120 * 121 * Note that this call is valid only when the current thread owns a write 122 * lock on the given semaphore handle and will assert otherwise. 123 */ 124 virtual uint32_t writeLockLevel() const = 0; 125 126 /** 127 * Returns an interface to read lock operations of this semaphore. 128 * Used by constructors of AutoMultiLockN classes. 129 */ 130 LockOps *rlock() { return (ReadLockOps *) this; } 131 132 /** 133 * Returns an interface to write lock operations of this semaphore. 134 * Used by constructors of AutoMultiLockN classes. 135 */ 136 LockOps *wlock() { return (WriteLockOps *) this; } 137 138 private: 139 140 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (LockHandle) 141 142 friend class AutoLock; 143 friend class AutoReaderLock; 144 }; 145 146 /** 147 * Full-featured read/write semaphore handle implementation. 148 * 149 * This is an auxiliary base class for classes that need full-featured 150 * read/write locking as described in the AutoLock class documentation. 151 * Instances of classes inherited from this class can be passed as arguments to 152 * the AutoLock and AutoReaderLock constructors. 153 */ 154 class RWLockHandle : public LockHandle 155 { 156 public: 157 158 RWLockHandle(); 159 virtual ~RWLockHandle(); 160 161 bool isLockedOnCurrentThread() const; 162 163 private: 164 165 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (RWLockHandle) 166 167 void lockWrite(); 168 void unlockWrite(); 169 void lockRead(); 170 void unlockRead(); 171 172 uint32_t writeLockLevel() const; 173 174 mutable RTCRITSECT mCritSect; 175 RTSEMEVENT mGoWriteSem; 176 RTSEMEVENTMULTI mGoReadSem; 177 178 RTTHREAD mWriteLockThread; 179 180 uint32_t mReadLockCount; 181 uint32_t mWriteLockLevel; 182 uint32_t mWriteLockPending; 183 }; 184 185 /** 186 * Write-only semaphore handle implementation. 187 * 188 * This is an auxiliary base class for classes that need write-only (exclusive) 189 * locking and do not need read (shared) locking. This implementation uses a 190 * cheap and fast critical section for both lockWrite() and lockRead() methods 191 * which makes a lockRead() call fully equivalent to the lockWrite() call and 192 * therefore makes it pointless to use instahces of this class with 193 * AutoReaderLock instances -- shared locking will not be possible anyway and 194 * any call to lock() will block if there are lock owners on other threads. 195 * 196 * Use with care only when absolutely sure that shared locks are not necessary. 197 */ 198 class WriteLockHandle : public LockHandle 199 { 200 public: 201 202 WriteLockHandle() 203 { 204 RTCritSectInit (&mCritSect); 205 } 206 207 virtual ~WriteLockHandle() 208 { 209 RTCritSectDelete (&mCritSect); 210 } 211 212 bool isLockedOnCurrentThread() const 213 { 214 return RTCritSectIsOwner (&mCritSect); 215 } 216 217 private: 218 219 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (WriteLockHandle) 220 221 void lockWrite() 222 { 223 #if defined(DEBUG) 224 RTCritSectEnterDebug (&mCritSect, 225 "WriteLockHandle::lockWrite() return address >>>", 226 0, (RTUINTPTR) ASMReturnAddress()); 227 #else 228 RTCritSectEnter (&mCritSect); 229 #endif 230 } 231 232 void unlockWrite() 233 { 234 RTCritSectLeave (&mCritSect); 235 } 236 237 void lockRead() { lockWrite(); } 238 void unlockRead() { unlockWrite(); } 239 240 uint32_t writeLockLevel() const 241 { 242 return RTCritSectGetRecursion (&mCritSect); 243 } 244 245 mutable RTCRITSECT mCritSect; 246 }; 247 248 /** 249 * Lockable interface. 250 * 251 * This is an abstract base for classes that need read/write locking. Unlike 252 * RWLockHandle and other classes that makes the read/write semaphore a part of 253 * class data, this class allows subclasses to decide which semaphore handle to 254 * use. 255 */ 256 class Lockable 257 { 258 public: 259 260 /** 261 * Returns a pointer to a LockHandle used by AutoLock/AutoReaderLock for 262 * locking. Subclasses are allowed to return @c NULL -- in this case, 263 * the AutoLock/AutoReaderLock object constructed using an instance of 264 * such subclass will simply turn into no-op. 265 */ 266 virtual LockHandle *lockHandle() const = 0; 267 268 /** 269 * Equivalent to <tt>#lockHandle()->isLockedOnCurrentThread()</tt>. 270 * Returns @c false if lockHandle() returns @c NULL. 271 */ 272 bool isLockedOnCurrentThread() 273 { 274 LockHandle *h = lockHandle(); 275 return h ? h->isLockedOnCurrentThread() : false; 276 } 277 278 /** 279 * Equivalent to <tt>#lockHandle()->rlock()</tt>. 280 * Returns @c NULL false if lockHandle() returns @c NULL. 281 */ 282 LockOps *rlock() 283 { 284 LockHandle *h = lockHandle(); 285 return h ? h->rlock() : NULL; 286 } 287 288 /** 289 * Equivalent to <tt>#lockHandle()->wlock()</tt>. Returns @c NULL false if 290 * lockHandle() returns @c NULL. 291 */ 292 LockOps *wlock() 293 { 294 LockHandle *h = lockHandle(); 295 return h ? h->wlock() : NULL; 296 } 297 }; 298 299 /** 300 * Provides safe management of read/write semaphores in write mode. 301 * 302 * A read/write semaphore is represented by the LockHandle class. This semaphore 303 * can be requested ("locked") in two different modes: for reading and for 304 * writing. A write lock is exclusive and acts like a mutex: only one thread can 305 * acquire a write lock on the given semaphore at a time; all other threads 306 * trying to request a write lock or a read lock (see below) on the same 307 * semaphore will be indefinitely blocked until the owning thread releases the 308 * write lock. 309 * 310 * A read lock is shared. This means that several threads can acquire a read 311 * lock on the same semaphore at the same time provided that there is no thread 312 * that holds a write lock on that semaphore. Note that when there are one or 313 * more threads holding read locks, a request for a write lock on another thread 314 * will be indefinitely blocked until all threads holding read locks release 315 * them. 316 * 317 * Note that write locks can be nested -- the same thread can request a write 318 * lock on the same semaphore several times. In this case, the corresponding 319 * number of release calls must be done in order to completely release all 320 * nested write locks and make the semaphore available for locking by other 321 * threads. 322 * 323 * Read locks can be nested too in which case the same rule of the equal number 324 * of the release calls applies. Read locks can be also nested into write 325 * locks which means that the same thread can successfully request a read lock 326 * if it already holds a write lock. However, please note that the opposite is 327 * <b>not possible</b>: if a thread tries to request a write lock on the same 328 * semaphore it is already holding a read lock, it will definitely produce a 329 * <b>deadlock</b> (i.e. it will block forever waiting for itself). 330 * 331 * Note that instances of the AutoLock class manage write locks of read/write 332 * semaphores only. In order to manage read locks, please use the AutoReaderLock 333 * class. 334 * 335 * Safe semaphore management consists of the following: 336 * <ul> 337 * <li>When an instance of the AutoLock class is constructed given a valid 338 * semaphore handle, it will automatically request a write lock on that 339 * semaphore. 340 * </li> 341 * <li>When an instance of the AutoLock class constructed given a valid 342 * semaphore handle is destroyed (e.g. goes out of scope), it will 343 * automatically release the write lock that was requested upon construction 344 * and also all nested write locks requested later using the #lock() call 345 * (note that the latter is considered to be a program logic error, see the 346 * #~AutoLock() description for details). 347 * </li> 348 * </ul> 349 * 350 * Note that the LockHandle class taken by AutoLock constructors is an abstract 351 * base of the read/write semaphore. You should choose one of the existing 352 * subclasses of this abstract class or create your own subclass that implements 353 * necessary read and write lock semantics. The most suitable choice is the 354 * RWLockHandle class which provides full support for both read and write locks 355 * as describerd above. Alternatively, you can use the WriteLockHandle class if 356 * you only need write (exclusive) locking (WriteLockHandle requires less system 357 * resources and works faster). 358 * 359 * A typical usage pattern of the AutoLock class is as follows: 360 * <code> 361 * struct Struct : public RWLockHandle 362 * { 363 * ... 364 * }; 365 * 366 * void foo (Struct &aStruct) 367 * { 368 * { 369 * // acquire a write lock of aStruct 370 * AutoLock alock (aStruct); 371 * 372 * // now we can modify aStruct in a thread-safe manner 373 * aStruct.foo = ...; 374 * 375 * // note that the write lock will be automatically released upon 376 * // execution of the return statement below 377 * if (!aStruct.bar) 378 * return; 379 * 380 * ... 381 * } 382 * 383 * // note that the write lock is automatically released here 384 * } 385 * </code> 386 * 387 * <b>Locking policy</b> 388 * 389 * When there are multiple threads and multiple objects to lock, there is always 390 * a potential possibility to produce a deadlock if the lock order is mixed up. 391 * Here is a classical example of a deadlock when two threads need to lock the 392 * same two objects in a row but do it in different order: 393 * <code> 394 * Thread 1: 395 * #1: AutoLock (mFoo); 396 * ... 397 * #2: AutoLock (mBar); 398 * ... 399 * Thread 2: 400 * #3: AutoLock (mBar); 401 * ... 402 * #4: AutoLock (mFoo); 403 * ... 404 * </code> 405 * 406 * If the threads happen to be scheduled so that #3 completes after #1 has 407 * completed but before #2 got control, the threads will hit a deadlock: Thread 408 * 2 will be holding mBar and waiting for mFoo at #4 forever because Thread 1 is 409 * holding mFoo and won't release it until it acquires mBar at #2 that will 410 * never happen because mBar is held by Thread 2. 411 * 412 * One of ways to avoid the described behavior is to never lock more than one 413 * obhect in a row. While it is definitely a good and safe practice, it's not 414 * always possible: the application logic may require several simultaneous locks 415 * in order to provide data integrity. 416 * 417 * One of the possibilities to solve the deadlock problem is to make sure that 418 * the locking order is always the same across the application. In the above 419 * example, it would mean that <b>both</b> threads should first requiest a lock 420 * of mFoo and then mBar (or vice versa). One of the methods to guarantee the 421 * locking order consistent is to introduce a set of locking rules. The 422 * advantage of this method is that it doesn't require any special semaphore 423 * implementation or additional control structures. The disadvantage is that 424 * it's the programmer who must make sure these rules are obeyed across the 425 * whole application so the human factor applies. Taking the simplicity of this 426 * method into account, it is chosen to solve potential deadlock problems when 427 * using AutoLock and AutoReaderLock classes. Here are the locking rules that 428 * must be obeyed by <b>all</b> users of these classes. Note that if more than 429 * one rule matches the given group of objects to lock, all of these rules must 430 * be met: 431 * <ol> 432 * <li>If there is a parent-child (or master-slave) relationship between the 433 * locked objects, parent (master) objects must be locked before child 434 * (slave) objects. 435 * </li> 436 * <li>When a group of equal objects (in terms of parent-child or 437 * master-slave relationsip) needs to be locked in a raw, the lock order 438 * must match the sort order (which must be consistent for the given group). 439 * </ol> 440 * Note that if there is no pragrammatically expressed sort order (e.g. 441 * the objects are not part of the sorted vector or list but instead are 442 * separate data members of a class), object class names sorted in alphabetical 443 * order must be used to determine the lock order. If there is more than one 444 * object of the given class, the object variable names' alphabetical order must 445 * be used as a lock order. When objects are not represented as individual 446 * variables, as in case of unsorted arrays/lists, the list of alphabetically 447 * sorted object UUIDs must be used to determine the sort order. 448 * 449 * All non-standard locking order must be avoided by all means, but when 450 * absolutely necessary, it must be clearly documented at relevant places so it 451 * is well seen by other developers. For example, if a set of instances of some 452 * class needs to be locked but these instances are not part of the sorted list 453 * and don't have UUIDs, then the class description must state what to use to 454 * determine the lock order (maybe some property that returns an unique value 455 * per every object). 43 456 */ 44 457 class AutoLock … … 46 459 public: 47 460 48 #if defined(DEBUG) 49 # define ___CritSectEnter(cs) \ 50 RTCritSectEnterDebug ((cs), \ 51 "AutoLock::lock()/enter() return address >>>", 0, \ 52 (RTUINTPTR) ASMReturnAddress()) 53 #else 54 # define ___CritSectEnter(cs) RTCritSectEnter ((cs)) 55 #endif 56 57 /** 58 * Lock (critical section) handle. An auxiliary base class for structures 59 * that need locking. Instances of classes inherited from it can be passed 60 * as arguments to the AutoLock constructor. 61 */ 62 class Handle 63 { 64 public: 65 66 Handle() { RTCritSectInit (&mCritSect); } 67 virtual ~Handle() { RTCritSectDelete (&mCritSect); } 68 69 /** Returns |true| if this handle is locked on the current thread. */ 70 bool isLockedOnCurrentThread() const 461 /** 462 * Constructs a null instance that does not manage any read/write 463 * semaphore. 464 * 465 * Note that all method calls on a null instance are no-ops. This allows to 466 * have the code where lock protection can be selected (or omitted) at 467 * runtime. 468 */ 469 AutoLock() : mHandle (NULL), mLockLevel (0), mGlobalLockLevel (0) {} 470 471 /** 472 * Constructs a new instance that will start managing the given read/write 473 * semaphore by requesting a write lock. 474 */ 475 AutoLock (LockHandle *aHandle) 476 : mHandle (aHandle), mLockLevel (0), mGlobalLockLevel (0) 477 { lock(); } 478 479 /** 480 * Constructs a new instance that will start managing the given read/write 481 * semaphore by requesting a write lock. 482 */ 483 AutoLock (LockHandle &aHandle) 484 : mHandle (&aHandle), mLockLevel (0), mGlobalLockLevel (0) 485 { lock(); } 486 487 /** 488 * Constructs a new instance that will start managing the given read/write 489 * semaphore by requesting a write lock. 490 */ 491 AutoLock (const Lockable &aLockable) 492 : mHandle (aLockable.lockHandle()), mLockLevel (0), mGlobalLockLevel (0) 493 { lock(); } 494 495 /** 496 * Constructs a new instance that will start managing the given read/write 497 * semaphore by requesting a write lock. 498 */ 499 AutoLock (const Lockable *aLockable) 500 : mHandle (aLockable ? aLockable->lockHandle() : NULL) 501 , mLockLevel (0), mGlobalLockLevel (0) 502 { lock(); } 503 504 /** 505 * Release all write locks acquired by this instance through the #lock() 506 * call and destroys the instance. 507 * 508 * Note that if there there are nested #lock() calls without the 509 * corresponding number of #unlock() calls when the destructor is called, it 510 * will assert. This is because having an unbalanced number of nested locks 511 * is a program logic error which must be fixed. 512 */ 513 ~AutoLock() 514 { 515 if (mHandle) 71 516 { 72 return RTCritSectIsOwner (&mCritSect); 517 if (mGlobalLockLevel) 518 { 519 mGlobalLockLevel -= mLockLevel; 520 mLockLevel = 0; 521 for (; mGlobalLockLevel; -- mGlobalLockLevel) 522 mHandle->lockWrite(); 523 } 524 525 AssertMsg (mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel)); 526 for (; mLockLevel; -- mLockLevel) 527 mHandle->unlockWrite(); 73 528 } 74 75 /** Returns a tag to lock this handle for reading by AutoMultiLock */ 76 internal::LockableTag rlock() const; 77 /** Returns a tag to lock this handle for writing by AutoMultiLock */ 78 internal::LockableTag wlock() const; 79 80 private: 81 82 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (Handle) 83 84 mutable RTCRITSECT mCritSect; 85 86 friend class AutoLock; 87 template <size_t> friend class AutoMultiLock; 88 }; 89 90 /** 91 * Lockable interface. An abstract base for classes that need locking. 92 * Unlike Handle that makes the lock handle a part of class data, this 93 * class allows subclasses to decide which lock handle to use. 94 */ 95 class Lockable 96 { 97 public: 98 99 /** 100 * Returns a pointer to a Handle used by AutoLock for locking. 101 * Subclasses are allowed to return |NULL| -- in this case, 102 * the AutoLock object constructed using an instance of such 103 * subclass will simply turn into no-op. 104 */ 105 virtual Handle *lockHandle() const = 0; 106 107 /** 108 * Equivalent to |#lockHandle()->isLockedOnCurrentThread()|. 109 * Returns |false| if lockHandle() returns NULL. 110 */ 111 bool isLockedOnCurrentThread() 529 } 530 531 /** 532 * Requests a write (exclusive) lock. If a write lock is already owned by 533 * this thread, increases the lock level (allowing for nested write locks on 534 * the same thread). Blocks indefinitely if a write lock or a read lock is 535 * already owned by another thread until that tread releases the locks, 536 * otherwise returns immediately. 537 */ 538 void lock() 539 { 540 if (mHandle) 112 541 { 113 Handle *h = lockHandle(); 114 return h ? h->isLockedOnCurrentThread() : false; 542 mHandle->lockWrite(); 543 ++ mLockLevel; 544 Assert (mLockLevel != 0 /* overflow? */); 115 545 } 116 117 /** 118 * Returns a tag to lock this handle for reading by AutoMultiLock. 119 * Shortcut to |lockHandle()->rlock()|. 120 * The returned tag is a no-op, when lockHandle() returns |NULL|. 121 */ 122 internal::LockableTag rlock() const; 123 124 /** 125 * Returns a tag to lock this handle for writing by AutoMultiLock. 126 * Shortcut to |lockHandle()->wlock()|. 127 * The returned tag is a no-op, when lockHandle() returns |NULL|. 128 */ 129 internal::LockableTag wlock() const; 130 }; 131 132 AutoLock() : mCritSect (NULL), mLevel (0), mLeftLevel (0) {} 133 134 AutoLock (RTCRITSECT &aCritSect) 135 : mCritSect (&aCritSect), mLevel (0), mLeftLevel (0) { lock(); } 136 137 AutoLock (RTCRITSECT *aCritSect) 138 : mCritSect (aCritSect), mLevel (0), mLeftLevel (0) { lock(); } 139 140 AutoLock (const Handle &aHandle) 141 : mCritSect (&aHandle.mCritSect), mLevel (0), mLeftLevel (0) { lock(); } 142 143 AutoLock (const Handle *aHandle) 144 : mCritSect (aHandle ? &aHandle->mCritSect : NULL) 145 , mLevel (0), mLeftLevel (0) { lock(); } 146 147 AutoLock (const Lockable &aLockable) 148 : mCritSect (critSect (&aLockable)) 149 , mLevel (0), mLeftLevel (0) { lock(); } 150 151 AutoLock (const Lockable *aLockable) 152 : mCritSect (aLockable ? critSect (aLockable) : NULL) 153 , mLevel (0), mLeftLevel (0) { lock(); } 154 155 ~AutoLock() 156 { 157 if (mCritSect) 546 } 547 548 /** 549 * Decreases the write lock level increased by #lock(). If the level drops 550 * to zero (e.g. the number of nested #unlock() calls matches the number of 551 * nested #lock() calls), releases the lock making the managed semaphore 552 * available for locking by other threads. 553 */ 554 void unlock() 555 { 556 if (mHandle) 158 557 { 159 if (mLeftLevel) 160 { 161 mLeftLevel -= mLevel; 162 mLevel = 0; 163 for (; mLeftLevel; -- mLeftLevel) 164 RTCritSectEnter (mCritSect); 165 } 166 AssertMsg (mLevel <= 1, ("Lock level > 1: %d\n", mLevel)); 167 for (; mLevel; -- mLevel) 168 RTCritSectLeave (mCritSect); 558 AssertReturnVoid (mLockLevel != 0 /* unlock() w/o preceding lock()? */); 559 mHandle->unlockWrite(); 560 -- mLockLevel; 169 561 } 170 562 } 171 563 172 564 /** 173 * Tries to acquire the lock or increases the lock level 174 * if the lock is already owned by this thread. 175 */ 176 void lock() 177 { 178 if (mCritSect) 565 * Causes the current thread to completely release the write lock to make 566 * the managed semaphore immediately available for locking by other threads. 567 * 568 * This implies that all nested write locks on the semaphore will be 569 * released, even those that were acquired through the calls to #lock() 570 * methods of all other AutoLock/AutoReaderLock instances managing the 571 * <b>same</b> read/write semaphore. 572 * 573 * After calling this method, the only method you are allowed to call is 574 * #enter(). It will acquire the write lock again and restore the same 575 * level of nesting as it had before calling #leave(). 576 * 577 * If this instance is destroyed without calling #enter(), the destructor 578 * will try to restore the write lock level that existed when #leave() was 579 * called minus the number of nested #lock() calls made on this instance 580 * itself. This is done to preserve lock levels of other 581 * AutoLock/AutoReaderLock instances managing the same semaphore (if any). 582 * Tiis also means that the destructor may indefinitely block if a write or 583 * a read lock is owned by some other thread by that time. 584 */ 585 void leave() 586 { 587 if (mHandle) 179 588 { 180 AssertMsgReturn (mLeftLevel == 0, ("lock() after leave()\n"), (void) 0); 181 ___CritSectEnter (mCritSect); 182 ++ mLevel; 589 AssertReturnVoid (mLockLevel != 0 /* leave() w/o preceding lock()? */); 590 AssertReturnVoid (mGlobalLockLevel == 0 /* second leave() in a row? */); 591 592 mGlobalLockLevel = mHandle->writeLockLevel(); 593 AssertReturnVoid (mGlobalLockLevel >= mLockLevel /* logic error! */); 594 595 for (uint32_t left = mGlobalLockLevel; left; -- left) 596 mHandle->unlockWrite(); 183 597 } 184 598 } 185 599 186 600 /** 187 * Decreases the lock level. If the level goes to zero, the lock 188 * is released by the current thread. 189 */ 190 void unlock() 191 { 192 if (mCritSect) 601 * Causes the current thread to restore the write lock level after the 602 * #leave() call. This call will indefinitely block if another thread has 603 * successfully acquired a write or a read lock on the same semaphore in 604 * between. 605 */ 606 void enter() 607 { 608 if (mHandle) 193 609 { 194 AssertMsgReturn (mLevel > 0, ("Lock level is zero\n"), (void) 0); 195 AssertMsgReturn (mLeftLevel == 0, ("lock() after leave()\n"), (void) 0); 196 -- mLevel; 197 RTCritSectLeave (mCritSect); 610 AssertReturnVoid (mLockLevel != 0 /* enter() w/o preceding lock()+leave()? */); 611 AssertReturnVoid (mGlobalLockLevel != 0 /* enter() w/o preceding leave()? */); 612 613 for (; mGlobalLockLevel; -- mGlobalLockLevel) 614 mHandle->lockWrite(); 198 615 } 199 616 } 200 617 201 /** 202 * Causes the current thread to completely release the lock 203 * (including locks acquired by all other instances of this class 204 * referring to the same object or handle). #enter() must be called 205 * to acquire the lock back and restore all lock levels. 206 */ 207 void leave() 208 { 209 if (mCritSect) 210 { 211 AssertMsg (mLevel > 0, ("Lock level is zero\n")); 212 AssertMsgReturn (mLeftLevel == 0, ("leave() w/o enter()\n"), (void) 0); 213 mLeftLevel = RTCritSectGetRecursion (mCritSect); 214 for (uint32_t left = mLeftLevel; left; -- left) 215 RTCritSectLeave (mCritSect); 216 Assert (mLeftLevel >= mLevel); 217 } 218 } 219 220 /** 221 * Causes the current thread to acquire the lock again and restore 222 * all lock levels after calling #leave(). 223 */ 224 void enter() 225 { 226 if (mCritSect) 227 { 228 AssertMsg (mLevel > 0, ("Lock level is zero\n")); 229 AssertMsgReturn (mLeftLevel > 0, ("enter() w/o leave()\n"), (void) 0); 230 for (; mLeftLevel; -- mLeftLevel) 231 ___CritSectEnter (mCritSect); 232 } 233 } 234 235 /** 236 * Current level of the nested lock. 1 means the lock is not currently 237 * nested. 238 */ 239 uint32_t level() const { return RTCritSectGetRecursion (mCritSect); } 240 241 bool isNull() const { return mCritSect == NULL; } 618 /** Returns @c true if this instance manages a null semaphore handle. */ 619 bool isNull() const { return mHandle == NULL; } 242 620 bool operator !() const { return isNull(); } 243 621 244 /** Returns |true| if this instance manages the given lock handle. */ 245 bool belongsTo (const Handle &aHandle) 246 { 247 return &aHandle.mCritSect == mCritSect; 248 } 249 250 /** Returns |true| if this instance manages the given lock handle. */ 251 bool belongsTo (const Handle *aHandle) 252 { 253 return aHandle && &aHandle->mCritSect == mCritSect; 254 } 255 256 /** Returns |true| if this instance manages the given lockable object. */ 622 /** 623 * Returns @c true if the current thread holds a write lock on the managed 624 * read/write semaphore. Returns @c false if the managed semaphore is @c 625 * NULL. 626 * 627 * @note Intended for debugging only. 628 */ 629 bool isLockedOnCurrentThread() const 630 { 631 return mHandle ? mHandle->isLockedOnCurrentThread() : false; 632 } 633 634 /** 635 * Returns the current write lock level of the managed smaphore. The lock 636 * level determines the number of nested #lock() calls on the given 637 * semaphore handle. Returns @c 0 if the managed semaphore is @c 638 * NULL. 639 * 640 * Note that this call is valid only when the current thread owns a write 641 * lock on the given semaphore handle and will assert otherwise. 642 * 643 * @note Intended for debugging only. 644 */ 645 uint32_t writeLockLevel() const 646 { 647 return mHandle ? mHandle->writeLockLevel() : 0; 648 } 649 650 /** 651 * Returns @c true if this instance manages the given semaphore handle. 652 * 653 * @note Intended for debugging only. 654 */ 655 bool belongsTo (const LockHandle &aHandle) const { return mHandle == &aHandle; } 656 657 /** 658 * Returns @c true if this instance manages the given semaphore handle. 659 * 660 * @note Intended for debugging only. 661 */ 662 bool belongsTo (const LockHandle *aHandle) const { return mHandle == aHandle; } 663 664 /** 665 * Returns @c true if this instance manages the given lockable object. 666 * 667 * @note Intended for debugging only. 668 */ 257 669 bool belongsTo (const Lockable &aLockable) 258 670 { … … 260 672 } 261 673 262 /** Returns |true| if this instance manages the given lockable object. */ 674 /** 675 * Returns @c true if this instance manages the given lockable object. 676 * 677 * @note Intended for debugging only. 678 */ 263 679 bool belongsTo (const Lockable *aLockable) 264 680 { 265 681 return aLockable && belongsTo (aLockable->lockHandle()); 266 682 } 267 268 /**269 * Returns a tag to lock the given Lockable for reading by AutoMultiLock.270 * Shortcut to |aL->lockHandle()->rlock()|.271 * The returned tag is a no-op when @a aL is |NULL|.272 */273 static internal::LockableTag maybeRlock (Lockable *aL);274 275 /**276 * Returns a tag to lock the given Lockable for writing by AutoMultiLock.277 * Shortcut to |aL->lockHandle()->wlock()|.278 * The returned tag is a no-op when @a aL is |NULL|.279 */280 static internal::LockableTag maybeWlock (Lockable *aL);281 683 282 684 private: … … 285 687 DECLARE_CLS_NEW_DELETE_NOOP (AutoLock) 286 688 287 inline static RTCRITSECT *critSect (const Lockable *l) 288 { 289 Assert (l); 290 Handle *h = l->lockHandle(); 291 return h ? &h->mCritSect : NULL; 292 } 293 294 RTCRITSECT *mCritSect; 295 uint32_t mLevel; 296 uint32_t mLeftLevel; 297 298 #undef ___CritSectEnter 299 }; 689 LockHandle *mHandle; 690 uint32_t mLockLevel; 691 uint32_t mGlobalLockLevel; 692 693 template <size_t> friend class AutoMultiWriteLockBase; 694 }; 695 696 //////////////////////////////////////////////////////////////////////////////// 300 697 301 698 /** 302 * Prototype. Later will be used to acquire a read-only lock 303 * (read-only locks differ from regular (write) locks so that more than one 304 * read lock can be acquired simultaneously provided that there are no 305 * active write locks). 306 * @todo Implement it! 307 */ 308 class AutoReaderLock : public AutoLock 309 { 310 public: 311 312 AutoReaderLock (const Handle &aHandle) : AutoLock (aHandle) {} 313 AutoReaderLock (const Handle *aHandle) : AutoLock (aHandle) {} 314 315 AutoReaderLock (const Lockable &aLockable) : AutoLock (aLockable) {} 316 AutoReaderLock (const Lockable *aLockable) : AutoLock (aLockable) {} 699 * Provides safe management of read/write semaphores in read mode. 700 * 701 * This class differs from the AutoLock class is so that it's #lock() and 702 * #unlock() methods requests and release read (shared) locks on the managed 703 * read/write semaphore instead of write (exclusive) locks. See the AutoLock 704 * class description for more information about read and write locks. 705 * 706 * Safe semaphore management consists of the following: 707 * <ul> 708 * <li>When an instance of the AutoReaderLock class is constructed given a 709 * valid semaphore handle, it will automatically request a read lock on that 710 * semaphore. 711 * </li> 712 * <li>When an instance of the AutoReaderLock class constructed given a valid 713 * semaphore handle is destroyed (e.g. goes out of scope), it will 714 * automatically release the read lock that was requested upon construction 715 * and also all nested read locks requested later using the #lock() call (note 716 * that the latter is considered to be a program logic error, see the 717 * #~AutoReaderLock() description for details). 718 * </li> 719 * </ul> 720 * 721 * Note that the LockHandle class taken by AutoReaderLock constructors is an 722 * abstract base of the read/write semaphore. You should choose one of the 723 * existing subclasses of this abstract class or create your own subclass that 724 * implements necessary read and write lock semantics. The most suitable choice 725 * is the RWLockHandle class which provides full support for both read and write 726 * locks as describerd in AutoLock docs. Alternatively, you can use the 727 * WriteLockHandle class if you only need write (exclusive) locking 728 * (WriteLockHandle requires less system resources and works faster). 729 * 730 * However, please note that it absolutely does not make sense to manage 731 * WriteLockHandle semaphores with AutoReaderLock instances because 732 * AutoReaderLock instances will behave like AutoLock instances in this case 733 * since WriteLockHandle provides only exclusive write locking. You have been 734 * warned. 735 736 * A typical usage pattern of the AutoReaderLock class is as follows: 737 * <code> 738 * struct Struct : public RWLockHandle 739 * { 740 * ... 741 * }; 742 * 743 * void foo (Struct &aStruct) 744 * { 745 * { 746 * // acquire a read lock of aStruct (note that two foo() calls may be 747 * executed on separate threads simultaneously w/o blocking each other) 748 * AutoReaderLock alock (aStruct); 749 * 750 * // now we can read aStruct in a thread-safe manner 751 * if (aStruct.foo) 752 * ...; 753 * 754 * // note that the read lock will be automatically released upon 755 * // execution of the return statement below 756 * if (!aStruct.bar) 757 * return; 758 * 759 * ... 760 * } 761 * 762 * // note that the read lock is automatically released here 763 * } 764 * </code> 765 */ 766 class AutoReaderLock 767 { 768 public: 769 770 /** 771 * Constructs a null instance that does not manage any read/write 772 * semaphore. 773 * 774 * Note that all method calls on a null instance are no-ops. This allows to 775 * have the code where lock protection can be selected (or omitted) at 776 * runtime. 777 */ 778 AutoReaderLock() : mHandle (NULL), mLockLevel (0) {} 779 780 /** 781 * Constructs a new instance that will start managing the given read/write 782 * semaphore by requesting a read lock. 783 */ 784 AutoReaderLock (LockHandle *aHandle) 785 : mHandle (aHandle), mLockLevel (0) 786 { lock(); } 787 788 /** 789 * Constructs a new instance that will start managing the given read/write 790 * semaphore by requesting a read lock. 791 */ 792 AutoReaderLock (LockHandle &aHandle) 793 : mHandle (&aHandle), mLockLevel (0) 794 { lock(); } 795 796 /** 797 * Constructs a new instance that will start managing the given read/write 798 * semaphore by requesting a read lock. 799 */ 800 AutoReaderLock (const Lockable &aLockable) 801 : mHandle (aLockable.lockHandle()), mLockLevel (0) 802 { lock(); } 803 804 /** 805 * Constructs a new instance that will start managing the given read/write 806 * semaphore by requesting a read lock. 807 */ 808 AutoReaderLock (const Lockable *aLockable) 809 : mHandle (aLockable ? aLockable->lockHandle() : NULL) 810 , mLockLevel (0) 811 { lock(); } 812 813 /** 814 * Release all read locks acquired by this instance through the #lock() 815 * call and destroys the instance. 816 * 817 * Note that if there there are nested #lock() calls without the 818 * corresponding number of #unlock() calls when the destructor is called, it 819 * will assert. This is because having an unbalanced number of nested locks 820 * is a program logic error which must be fixed. 821 */ 822 ~AutoReaderLock() 823 { 824 if (mHandle) 825 { 826 AssertMsg (mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel)); 827 for (; mLockLevel; -- mLockLevel) 828 mHandle->unlockRead(); 829 } 830 } 831 832 /** 833 * Requests a read (shared) lock. If a read lock is already owned by 834 * this thread, increases the lock level (allowing for nested read locks on 835 * the same thread). Blocks indefinitely if a write lock is already owned by 836 * another thread until that tread releases the write lock, otherwise 837 * returns immediately. 838 * 839 * Note that this method returns immediately even if any number of other 840 * threads owns read locks on the same semaphore. Also returns immediately 841 * if a write lock on this semaphore is owned by the current thread which 842 * allows for read locks nested into write locks on the same thread. 843 */ 844 void lock() 845 { 846 if (mHandle) 847 { 848 mHandle->lockRead(); 849 ++ mLockLevel; 850 Assert (mLockLevel != 0 /* overflow? */); 851 } 852 } 853 854 /** 855 * Decreases the read lock level increased by #lock(). If the level drops to 856 * zero (e.g. the number of nested #unlock() calls matches the number of 857 * nested #lock() calls), releases the lock making the managed semaphore 858 * available for locking by other threads. 859 */ 860 void unlock() 861 { 862 if (mHandle) 863 { 864 AssertReturnVoid (mLockLevel != 0 /* unlock() w/o preceding lock()? */); 865 mHandle->unlockRead(); 866 -- mLockLevel; 867 } 868 } 869 870 /** Returns @c true if this instance manages a null semaphore handle. */ 871 bool isNull() const { return mHandle == NULL; } 872 bool operator !() const { return isNull(); } 873 874 /** 875 * Returns @c true if this instance manages the given semaphore handle. 876 * 877 * @note Intended for debugging only. 878 */ 879 bool belongsTo (const LockHandle &aHandle) const { return mHandle == &aHandle; } 880 881 /** 882 * Returns @c true if this instance manages the given semaphore handle. 883 * 884 * @note Intended for debugging only. 885 */ 886 bool belongsTo (const LockHandle *aHandle) const { return mHandle == aHandle; } 887 888 /** 889 * Returns @c true if this instance manages the given lockable object. 890 * 891 * @note Intended for debugging only. 892 */ 893 bool belongsTo (const Lockable &aLockable) 894 { 895 return belongsTo (aLockable.lockHandle()); 896 } 897 898 /** 899 * Returns @c true if this instance manages the given lockable object. 900 * 901 * @note Intended for debugging only. 902 */ 903 bool belongsTo (const Lockable *aLockable) 904 { 905 return aLockable && belongsTo (aLockable->lockHandle()); 906 } 317 907 318 908 private: … … 320 910 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoReaderLock) 321 911 DECLARE_CLS_NEW_DELETE_NOOP (AutoReaderLock) 322 }; 323 324 namespace internal 325 { 326 /** 327 * @internal 328 * Special struct to differentiate between read and write locks 329 * in AutoMultiLock constructors. 330 */ 331 struct LockableTag 332 { 333 LockableTag (const AutoLock::Handle *h, char m) 334 : handle (h), mode (m) {} 335 const AutoLock::Handle * const handle; 336 const char mode; 337 }; 338 } 339 340 inline internal::LockableTag AutoLock::Handle::rlock() const 341 { 342 return internal::LockableTag (this, 'r'); 343 } 344 345 inline internal::LockableTag AutoLock::Handle::wlock() const 346 { 347 return internal::LockableTag (this, 'w'); 348 } 349 350 inline internal::LockableTag AutoLock::Lockable::rlock() const 351 { 352 return internal::LockableTag (lockHandle(), 'r'); 353 } 354 355 inline internal::LockableTag AutoLock::Lockable::wlock() const 356 { 357 return internal::LockableTag (lockHandle(), 'w'); 358 } 359 360 /* static */ 361 inline internal::LockableTag AutoLock::maybeRlock (AutoLock::Lockable *aL) 362 { 363 return internal::LockableTag (aL ? aL->lockHandle() : NULL, 'r'); 364 } 365 366 /* static */ 367 inline internal::LockableTag AutoLock::maybeWlock (AutoLock::Lockable *aL) 368 { 369 return internal::LockableTag (aL ? aL->lockHandle() : NULL, 'w'); 370 } 912 913 LockHandle *mHandle; 914 uint32_t mLockLevel; 915 }; 916 917 //////////////////////////////////////////////////////////////////////////////// 371 918 372 919 /** 373 * Smart template class to safely enter and leave a list of critical sections. 374 * 375 * When constructing an instance, it enters all given critical sections 376 * (in an "atomic", "all or none" fashion). These critical sections will be 377 * exited automatically when the instance goes out of scope (i.e. gets destroyed). 378 * 379 * It is possible to lock different critical sections in two different modes: 380 * for writing (as AutoLock does) or for reading (as AutoReaderLock does). 381 * The lock mode is determined by the method called on an AutoLock::Handle or 382 * AutoLock::Lockable instance when passing it to the AutoMultiLock constructor: 383 * |rlock()| to lock for reading or |wlock()| to lock for writing. 384 * 385 * Instances of this class are constructed as follows: 386 * <code> 387 * ... 388 * AutoLock::Handle data1, data2; 389 * ... 390 * { 391 * AutoMultiLock <2> multiLock (data1.wlock(), data2.rlock()); 392 * // all locks are entered here: 393 * // data1 is entered in write mode (like AutoLock) 394 * // data2 is entered in read mode (like AutoReaderLock), 395 * } 396 * // all locks are exited here 397 * </code> 398 * 399 * The number of critical sections passed to the constructor must exactly 400 * match the number specified as the @a tCnt parameter of the template. 401 * 402 * @param tCnt number of critical sections to manage 403 */ 404 template <size_t tCnt> 405 class AutoMultiLock 406 { 407 public: 408 409 #if defined(DEBUG) 410 # define ___CritSectEnterMulti(n, acs) \ 411 RTCritSectEnterMultipleDebug ((n), (acs), \ 412 "AutoMultiLock instantiation address >>>", 0, \ 413 (RTUINTPTR) ASMReturnAddress()) 414 #else 415 # define ___CritSectEnterMulti(n, acs) RTCritSectEnterMultiple ((n), (acs)) 416 #endif 417 418 #define A(n) internal::LockableTag l##n 419 #define B(n) if (l##n.handle) { /* skip NULL tags */ \ 420 mS[i] = &l##n.handle->mCritSect; \ 421 mM[i++] = l##n.mode; \ 422 } else 423 #define C(n) \ 424 mLocked = true; \ 425 mM [0] = 0; /* for safety in case of early return */ \ 426 AssertMsg (tCnt == n, \ 427 ("This AutoMultiLock is for %d locks, but %d were passed!\n", tCnt, n)); \ 428 if (tCnt != n) return; \ 429 int i = 0 430 /// @todo (dmik) this will change when we switch to RTSemRW* 431 #define D() mM [i] = 0; /* end of array */ \ 432 ___CritSectEnterMulti ((unsigned) strlen (mM), mS) 433 434 AutoMultiLock (A(0), A(1)) 435 { 436 C(2); 437 B(0); 438 B(1); 439 D(); 440 } 441 AutoMultiLock (A(0), A(1), A(2)) 442 { C(3); B(0); B(1); B(2); D(); } 443 AutoMultiLock (A(0), A(1), A(2), A(3)) 444 { C(4); B(0); B(1); B(2); B(3); D(); } 445 AutoMultiLock (A(0), A(1), A(2), A(3), A(4)) 446 { C(5); B(0); B(1); B(2); B(3); B(4); D(); } 447 AutoMultiLock (A(0), A(1), A(2), A(3), A(4), A(5)) 448 { C(6); B(0); B(1); B(2); B(3); B(4); B(5); D(); } 449 AutoMultiLock (A(0), A(1), A(2), A(3), A(4), A(5), A(6)) 450 { C(7); B(0); B(1); B(2); B(3); B(4); B(5); B(6); D(); } 451 AutoMultiLock (A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7)) 452 { C(8); B(0); B(1); B(2); B(3); B(4); B(5); B(6); B(7); D(); } 453 AutoMultiLock (A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8)) 454 { C(9); B(0); B(1); B(2); B(3); B(4); B(5); B(6); B(7); B(8); D(); } 455 AutoMultiLock (A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9)) 456 { C(10); B(0); B(1); B(2); B(3); B(4); B(5); B(6); B(7); B(8); B(9); D(); } 457 458 #undef D 459 #undef C 460 #undef B 461 #undef A 462 463 /** 464 * Releases all locks if not yet released by #leave() and 465 * destroys the instance. 466 */ 467 ~AutoMultiLock() 468 { 469 /// @todo (dmik) this will change when we switch to RTSemRW* 470 if (mLocked) 471 RTCritSectLeaveMultiple ((unsigned) strlen (mM), mS); 472 } 473 474 /** 475 * Releases all locks temporarily in order to enter them again using 476 * #enter(). 477 * 478 * @note There is no need to call this method unless you want later call 479 * #enter(). The destructor calls it automatically when necessary. 480 * 481 * @note Calling this method twice without calling #enter() in between will 482 * definitely fail. 483 * 484 * @note Unlike AutoLock::leave(), this method doesn't cause a complete 485 * release of all involved locks; if any of the locks was entered on the 486 * current thread prior constructing the AutoMultiLock instanve, they will 487 * remain acquired after this call! For this reason, using this method in 488 * the custom code doesn't make any practical sense. 489 * 490 * @todo Rename this method to unlock() and rename #enter() to lock() 491 * for similarity with AutoLock. 920 * Helper template class for AutoMultiLockN classes. 921 * 922 * @param Cnt number of read/write semaphores to manage. 923 */ 924 template <size_t Cnt> 925 class AutoMultiLockBase 926 { 927 public: 928 929 /** 930 * Releases all locks if not yet released by #unlock() and destroys the 931 * instance. 932 */ 933 ~AutoMultiLockBase() 934 { 935 if (mIsLocked) 936 unlock(); 937 } 938 939 /** 940 * Calls LockOps::lock() methods of all managed semaphore handles 941 * in order they were passed to the constructor. 942 * 943 * Note that as opposed to LockHandle::lock(), this call cannot be nested 944 * and will assert if so. 945 */ 946 void lock() 947 { 948 AssertReturnVoid (!mIsLocked); 949 950 size_t i = 0; 951 while (i < ELEMENTS (mOps)) 952 if (mOps [i]) 953 mOps [i ++]->lock(); 954 mIsLocked = true; 955 } 956 957 /** 958 * Calls LockOps::unlock() methods of all managed semaphore handles in 959 * reverse to the order they were passed to the constructor. 960 * 961 * Note that as opposed to LockHandle::unlock(), this call cannot be nested 962 * and will assert if so. 963 */ 964 void unlock() 965 { 966 AssertReturnVoid (mIsLocked); 967 968 AssertReturnVoid (ELEMENTS (mOps) > 0); 969 size_t i = ELEMENTS (mOps); 970 do 971 if (mOps [-- i]) 972 mOps [i]->unlock(); 973 while (i != 0); 974 mIsLocked = false; 975 } 976 977 protected: 978 979 AutoMultiLockBase() : mIsLocked (false) {} 980 981 LockOps *mOps [Cnt]; 982 bool mIsLocked; 983 984 private: 985 986 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiLockBase) 987 DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiLockBase) 988 }; 989 990 /** AutoMultiLockBase <0> is meaningless and forbidden. */ 991 template<> 992 class AutoMultiLockBase <0> { private : AutoMultiLockBase(); }; 993 994 /** AutoMultiLockBase <1> is meaningless and forbidden. */ 995 template<> 996 class AutoMultiLockBase <1> { private : AutoMultiLockBase(); }; 997 998 //////////////////////////////////////////////////////////////////////////////// 999 1000 /* AutoMultiLockN class definitions */ 1001 1002 #define A(n) LockOps *l##n 1003 #define B(n) mOps [n] = l##n 1004 1005 /** 1006 * AutoMultiLock for 2 locks. 1007 * 1008 * The AutoMultiLockN family of classes provides a possibility to manage several 1009 * read/write semaphores at once. This is handy if all managed semaphores need 1010 * to be locked and unlocked synchronously and will also help to avoid locking 1011 * order errors. 1012 * 1013 * Instances of AutoMultiLockN classes are constructed from a list of LockOps 1014 * arguments. The AutoMultiLockBase::lock() method will make sure that the given 1015 * list of semaphores represented by LockOps pointers will be locked in order 1016 * they are passed to the constructor. The AutoMultiLockBase::unlock() method 1017 * will make sure that they will be unlocked in reverse order. 1018 * 1019 * The type of the lock to request is specified for each semaphore individually 1020 * using the corresponding LockOps getter of a LockHandle or Lockable object: 1021 * LockHandle::wlock() in order to request a write lock or LockHandle::rlock() 1022 * in order to request a read lock. 1023 * 1024 * Here is a typical usage pattern: 1025 * <code> 1026 * ... 1027 * LockHandle data1, data2; 1028 * ... 1029 * { 1030 * AutoMultiLock2 multiLock (data1.wlock(), data2.rlock()); 1031 * // both locks are held here: 1032 * // - data1 is locked in write mode (like AutoLock) 1033 * // - data2 is locked in read mode (like AutoReaderLock) 1034 * } 1035 * // both locks are released here 1036 * </code> 1037 */ 1038 class AutoMultiLock2 : public AutoMultiLockBase <2> 1039 { 1040 public: 1041 AutoMultiLock2 (A(0), A(1)) 1042 { B(0); B(1); lock(); } 1043 }; 1044 1045 /** AutoMultiLock for 3 locks. See AutoMultiLock2 for more information. */ 1046 class AutoMultiLock3 : public AutoMultiLockBase <3> 1047 { 1048 public: 1049 AutoMultiLock3 (A(0), A(1), A(2)) 1050 { B(0); B(1); B(2); lock(); } 1051 }; 1052 1053 /** AutoMultiLock for 4 locks. See AutoMultiLock2 for more information. */ 1054 class AutoMultiLock4 : public AutoMultiLockBase <4> 1055 { 1056 public: 1057 AutoMultiLock4 (A(0), A(1), A(2), A(3)) 1058 { B(0); B(1); B(2); B(3); lock(); } 1059 }; 1060 1061 #undef B 1062 #undef A 1063 1064 //////////////////////////////////////////////////////////////////////////////// 1065 1066 /** 1067 * Helper template class for AutoMultiWriteLockN classes. 1068 * 1069 * @param Cnt number of write semaphores to manage. 1070 */ 1071 template <size_t Cnt> 1072 class AutoMultiWriteLockBase 1073 { 1074 public: 1075 1076 /** 1077 * Calls AutoLock::lock() methods for all managed semaphore handles in order 1078 * they were passed to the constructor. 1079 */ 1080 void lock() 1081 { 1082 size_t i = 0; 1083 while (i < ELEMENTS (mLocks)) 1084 mLocks [i ++].lock(); 1085 } 1086 1087 /** 1088 * Calls AutoLock::unlock() methods for all managed semaphore handles in 1089 * reverse to the order they were passed to the constructor. 1090 */ 1091 void unlock() 1092 { 1093 AssertReturnVoid (ELEMENTS (mLocks) > 0); 1094 size_t i = ELEMENTS (mLocks); 1095 do 1096 mLocks [-- i].unlock(); 1097 while (i != 0); 1098 } 1099 1100 /** 1101 * Calls AutoLock::leave() methods for all managed semaphore handles in 1102 * reverse to the order they were passed to the constructor. 492 1103 */ 493 1104 void leave() 494 1105 { 495 AssertMsgReturn (mLocked, ("Already released all locks"), (void) 0); 496 /// @todo (dmik) this will change when we switch to RTSemRW* 497 RTCritSectLeaveMultiple ((unsigned) strlen (mM), mS); 498 mLocked = false; 499 } 500 501 /** 502 * Tries to enter all locks temporarily released by #unlock(). 503 * 504 * @note This method succeeds only after #unlock() and always fails 505 * otherwise. 1106 AssertReturnVoid (ELEMENTS (mLocks) > 0); 1107 size_t i = ELEMENTS (mLocks); 1108 do 1109 mLocks [-- i].leave(); 1110 while (i != 0); 1111 } 1112 1113 /** 1114 * Calls AutoLock::enter() methods for all managed semaphore handles in order 1115 * they were passed to the constructor. 506 1116 */ 507 1117 void enter() 508 1118 { 509 AssertMsgReturn (!mLocked, ("Already entered all locks"), (void) 0); 510 ___CritSectEnterMulti ((unsigned) strlen (mM), mS); 511 mLocked = true; 512 } 1119 size_t i = 0; 1120 while (i < ELEMENTS (mLocks)) 1121 mLocks [i ++].enter(); 1122 } 1123 1124 protected: 1125 1126 AutoMultiWriteLockBase() {} 1127 1128 void setLockHandle (size_t aIdx, LockHandle *aHandle) 1129 { mLocks [aIdx].mHandle = aHandle; } 513 1130 514 1131 private: 515 1132 516 AutoMultiLock(); 517 518 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiLock) 519 DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiLock) 520 521 RTCRITSECT *mS [tCnt]; 522 char mM [tCnt + 1]; 523 bool mLocked; 524 525 #undef ___CritSectEnterMulti 526 }; 1133 AutoLock mLocks [Cnt]; 1134 1135 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiWriteLockBase) 1136 DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiWriteLockBase) 1137 }; 1138 1139 /** AutoMultiWriteLockBase <0> is meaningless and forbidden. */ 1140 template<> 1141 class AutoMultiWriteLockBase <0> { private : AutoMultiWriteLockBase(); }; 1142 1143 /** AutoMultiWriteLockBase <1> is meaningless and forbidden. */ 1144 template<> 1145 class AutoMultiWriteLockBase <1> { private : AutoMultiWriteLockBase(); }; 1146 1147 //////////////////////////////////////////////////////////////////////////////// 1148 1149 /* AutoMultiLockN class definitions */ 1150 1151 #define A(n) LockHandle *l##n 1152 #define B(n) setLockHandle (n, l##n) 1153 1154 #define C(n) Lockable *l##n 1155 #define D(n) setLockHandle (n, l##n ? l##n->lockHandle() : NULL) 527 1156 528 1157 /** 529 * Disable instantiations of AutoMultiLock for zero and one 530 * number of locks. 531 */ 532 template<> 533 class AutoMultiLock <0> { private : AutoMultiLock(); }; 534 535 template<> 536 class AutoMultiLock <1> { private : AutoMultiLock(); }; 1158 * AutoMultiWriteLock for 2 locks. 1159 * 1160 * The AutoMultiWriteLockN family of classes provides a possibility to manage 1161 * several read/write semaphores at once. This is handy if all managed 1162 * semaphores need to be locked and unlocked synchronously and will also help to 1163 * avoid locking order errors. 1164 * 1165 * The functionality of the AutoMultiWriteLockN class family is similar to the 1166 * functionality of the AutoMultiLockN class family (see the AutoMultiLock2 1167 * class for details) with two important differences: 1168 * <ol> 1169 * <li>Instances of AutoMultiWriteLockN classes are constructed from a list 1170 * of LockHandle or Lockable arguments directly instead of getting 1171 * intermediate LockOps interface pointers. 1172 * </li> 1173 * <li>All locks are requested in <b>write</b> mode. 1174 * </li> 1175 * <li>Since all locks are requested in write mode, bulk 1176 * AutoMultiWriteLockBase::leave() and AutoMultiWriteLockBase::enter() 1177 * operations are also available, that will leave and enter all managed 1178 * semaphores at once in the proper order (similarly to 1179 * AutoMultiWriteLockBase::lock() and AutoMultiWriteLockBase::unlock()). 1180 * </li> 1181 * </ol> 1182 * 1183 * Here is a typical usage pattern: 1184 * <code> 1185 * ... 1186 * LockHandle data1, data2; 1187 * ... 1188 * { 1189 * AutoMultiWriteLock2 multiLock (&data1, &data2); 1190 * // both locks are held in write mode here 1191 * } 1192 * // both locks are released here 1193 * </code> 1194 */ 1195 class AutoMultiWriteLock2 : public AutoMultiWriteLockBase <2> 1196 { 1197 public: 1198 AutoMultiWriteLock2 (A(0), A(1)) 1199 { B(0); B(1); lock(); } 1200 AutoMultiWriteLock2 (C(0), C(1)) 1201 { D(0); D(1); lock(); } 1202 }; 1203 1204 /** AutoMultiWriteLock for 3 locks. See AutoMultiWriteLock2 for more details. */ 1205 class AutoMultiWriteLock3 : public AutoMultiWriteLockBase <3> 1206 { 1207 public: 1208 AutoMultiWriteLock3 (A(0), A(1), A(2)) 1209 { B(0); B(1); B(2); lock(); } 1210 AutoMultiWriteLock3 (C(0), C(1), C(2)) 1211 { D(0); D(1); D(2); lock(); } 1212 }; 1213 1214 /** AutoMultiWriteLock for 4 locks. See AutoMultiWriteLock2 for more details. */ 1215 class AutoMultiWriteLock4 : public AutoMultiWriteLockBase <4> 1216 { 1217 public: 1218 AutoMultiWriteLock4 (A(0), A(1), A(2), A(3)) 1219 { B(0); B(1); B(2); B(3); lock(); } 1220 AutoMultiWriteLock4 (C(0), C(1), C(2), C(3)) 1221 { D(0); D(1); D(2); D(3); lock(); } 1222 }; 1223 1224 #undef D 1225 #undef C 1226 #undef B 1227 #undef A 537 1228 538 1229 } /* namespace util */ -
trunk/src/VBox/Main/include/HardDiskImpl.h
r7207 r7992 117 117 118 118 /** Shortcut to #dependentChildrenLock() */ 119 AutoLock::Handle &childrenLock() const { return dependentChildrenLock(); }119 RWLockHandle *childrenLock() const { return dependentChildrenLock(); } 120 120 121 121 /** -
trunk/src/VBox/Main/include/MachineImpl.h
r7990 r7992 147 147 RTTIMESPEC mLastStateChange; 148 148 149 /* Note: These are guarded by VirtualBoxBase::stateLockHandle() */ 149 150 uint32_t mMachineStateDeps; 150 RTSEMEVENT mZeroMachineStateDepsSem;151 BOOL mWaitingStateDeps;151 RTSEMEVENTMULTI mMachineStateDepsSem; 152 uint32_t mMachineStateChangePending; 152 153 153 154 BOOL mCurrentStateModified; … … 615 616 void uninitDataAndChildObjects(); 616 617 617 void checkStateDependencies (AutoLock &aLock);618 void ensureNoStateDependencies (AutoLock &aLock); 618 619 619 620 virtual HRESULT setMachineState (MachineState_T aMachineState); … … 775 776 void uninit() { uninit (Uninit::Unexpected); } 776 777 777 // AutoLock::Lockable interface778 AutoLock::Handle *lockHandle() const;778 // util::Lockable interface 779 RWLockHandle *lockHandle() const; 779 780 780 781 // IInternalMachineControl methods … … 934 935 void uninit(); 935 936 936 // AutoLock::Lockable interface937 AutoLock::Handle *lockHandle() const;937 // util::Lockable interface 938 RWLockHandle *lockHandle() const; 938 939 939 940 // public methods only for internal purposes -
trunk/src/VBox/Main/include/SnapshotImpl.h
r6076 r7992 97 97 98 98 /** Shortcut to #dependentChildrenLock() */ 99 AutoLock::Handle &childrenLock() const { return dependentChildrenLock(); }99 RWLockHandle *childrenLock() const { return dependentChildrenLock(); } 100 100 101 101 /** -
trunk/src/VBox/Main/include/VirtualBoxBase.h
r6964 r7992 31 31 32 32 using namespace com; 33 using util::AutoLock; 34 using util::AutoReaderLock; 35 using util::AutoMultiLock; 33 using namespace util; 36 34 37 35 #include <iprt/cdefs.h> … … 438 436 : public CComObjectRootEx 439 437 #endif 440 , public AutoLock::Lockable438 , public Lockable 441 439 { 442 440 public: … … 452 450 453 451 // AutoLock::Lockable interface 454 virtual AutoLock::Handle *lockHandle() const;452 virtual RWLockHandle *lockHandle() const; 455 453 456 454 /** … … 863 861 }; 864 862 863 /** 864 * Returns a lock handle used to protect the primary state fields (used by 865 * #addCaller(), AutoInitSpan, AutoUninitSpan, etc.). Only intended to be 866 * used for similar purposes in subclasses. WARNING: NO any other locks may 867 * be requested while holding this lock! 868 */ 869 WriteLockHandle *stateLockHandle() { return &mStateLock; } 870 865 871 private: 866 872 … … 886 892 887 893 /** Protects access to state related data members */ 888 RTCRITSECTmStateLock;894 WriteLockHandle mStateLock; 889 895 890 896 /** User-level object lock for subclasses */ 891 mutable AutoLock::Handle *mObjectLock;897 mutable RWLockHandle *mObjectLock; 892 898 }; 893 899 … … 1619 1625 VirtualBoxBaseWithChildren() 1620 1626 : mUninitDoneSem (NIL_RTSEMEVENT), mChildrenLeft (0) 1621 { 1622 RTCritSectInit (&mMapLock); 1623 } 1627 {} 1624 1628 1625 1629 virtual ~VirtualBoxBaseWithChildren() 1626 { 1627 RTCritSectDelete (&mMapLock); 1628 } 1630 {} 1629 1631 1630 1632 /** … … 1680 1682 DependentChildren mDependentChildren; 1681 1683 1682 RTCRITSECT mMapLock; 1684 WriteLockHandle mMapLock; 1685 1683 1686 RTSEMEVENT mUninitDoneSem; 1684 1687 unsigned mChildrenLeft; … … 1825 1828 1826 1829 /* Protects all the fields above */ 1827 AutoLock::Handle mMapLock;1830 RWLockHandle mMapLock; 1828 1831 }; 1829 1832 … … 1907 1910 * </code> 1908 1911 */ 1909 AutoLock::Handle &dependentChildrenLock() const { returnmMapLock; }1912 RWLockHandle *dependentChildrenLock() const { return &mMapLock; } 1910 1913 1911 1914 /** … … 1975 1978 1976 1979 bool mInUninit; 1977 mutable AutoLock::Handle mMapLock;1980 mutable RWLockHandle mMapLock; 1978 1981 }; 1979 1982 … … 2063 2066 * </code> 2064 2067 */ 2065 AutoLock::Handle &dependentChildrenLock() const { returnmMapLock; }2068 RWLockHandle *dependentChildrenLock() const { return &mMapLock; } 2066 2069 2067 2070 /** … … 2097 2100 2098 2101 /* Protects the two fields above */ 2099 mutable AutoLock::Handle mMapLock;2102 mutable RWLockHandle mMapLock; 2100 2103 }; 2101 2104 -
trunk/src/VBox/Main/include/VirtualBoxImpl.h
r7387 r7992 467 467 EventQueue * const mAsyncEventQ; 468 468 /** Lock for calling EventQueue->post() */ 469 AutoLock::Handle mAsyncEventQLock;469 RWLockHandle mAsyncEventQLock; 470 470 471 471 static Bstr sVersion;
Note:
See TracChangeset
for help on using the changeset viewer.