VirtualBox

Changeset 7992 in vbox


Ignore:
Timestamp:
Apr 15, 2008 1:53:12 PM (17 years ago)
Author:
vboxsync
Message:

Main: Implemented true AutoReaderLock (#2768).

Location:
trunk/src/VBox/Main
Files:
1 added
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/AudioAdapterImpl.cpp

    r7525 r7992  
    569569
    570570    /* 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);
    576577
    577578    if (mData.isBackedUp())
     
    599600
    600601    /* sanity too */
    601     AutoCaller thatCaller (mPeer);
     602    AutoCaller thatCaller (aThat);
    602603    AssertComRCReturnVoid (thatCaller.rc());
    603604
    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());
    606608
    607609    /* this will back up current data */
  • trunk/src/VBox/Main/ConsoleImpl.cpp

    r7939 r7992  
    24912491
    24922492/**
    2493  *  Called by IInternalSessionControl::OnDVDDriveChange().
    2494  *
    2495  *  @note Locks this object for reading.
     2493 * Called by IInternalSessionControl::OnDVDDriveChange().
     2494 *
     2495 * @note Locks this object for writing.
    24962496 */
    24972497HRESULT Console::onDVDDriveChange()
     
    25022502    AssertComRCReturnRC (autoCaller.rc());
    25032503
    2504     AutoReaderLock alock (this);
     2504    /* doDriveChange() needs a write lock */
     2505    AutoLock alock (this);
    25052506
    25062507    /* Ignore callbacks when there's no VM around */
     
    25872588
    25882589/**
    2589  *  Called by IInternalSessionControl::OnFloppyDriveChange().
    2590  *
    2591  *  @note Locks this object for reading.
     2590 * Called by IInternalSessionControl::OnFloppyDriveChange().
     2591 *
     2592 * @note Locks this object for writing.
    25922593 */
    25932594HRESULT Console::onFloppyDriveChange()
     
    25982599    AssertComRCReturnRC (autoCaller.rc());
    25992600
    2600     AutoReaderLock alock (this);
     2601    /* doDriveChange() needs a write lock */
     2602    AutoLock alock (this);
    26012603
    26022604    /* Ignore callbacks when there's no VM around */
     
    27042706 * @param   fPassthrough    Enables using passthrough mode of the host DVD drive if applicable.
    27052707 *
    2706  * @note Locks this object for reading.
     2708 * @note Locks this object for writing.
    27072709 */
    27082710HRESULT Console::doDriveChange (const char *pszDevice, unsigned uInstance, unsigned uLun, DriveState_T eState,
     
    27172719    AssertComRCReturnRC (autoCaller.rc());
    27182720
    2719     AutoReaderLock alock (this);
     2721    /* We will need to release the write lock before calling EMT */
     2722    AutoLock alock (this);
    27202723
    27212724    /* protect mpVM */
     
    27842787 *
    27852788 * @thread  EMT
    2786  * @note Locks the Console object for writing
     2789 * @note Locks the Console object for writing.
    27872790 */
    27882791DECLCALLBACK(int) Console::changeDrive (Console *pThis, const char *pszDevice, unsigned uInstance, unsigned uLun,
     
    28052808
    28062809    /*
    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 indirectly
    2809      *  modify the meDVDState/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).
    28102813     */
    28112814    AutoLock alock (pThis);
  • trunk/src/VBox/Main/DVDDriveImpl.cpp

    r6076 r7992  
    351351////////////////////////////////////////////////////////////////////////////////
    352352
    353 /** 
     353/**
    354354 *  Loads settings from the given machine node.
    355355 *  May be called once right after this object creation.
    356  * 
     356 *
    357357 *  @param aMachineNode <Machine> node.
    358  * 
    359  *  @note Locks this object for writing. 
     358 *
     359 *  @note Locks this object for writing.
    360360 */
    361361HRESULT DVDDrive::loadSettings (const settings::Key &aMachineNode)
     
    379379     * place when a setting of a newly created object must default to A while
    380380     * the same setting of an object loaded from the old settings file must
    381      * default to B. */ 
     381     * default to B. */
    382382
    383383    HRESULT rc = S_OK;
     
    435435}
    436436
    437 /** 
     437/**
    438438 *  Saves settings to the given machine node.
    439  * 
     439 *
    440440 *  @param aMachineNode <Machine> node.
    441  * 
    442  *  @note Locks this object for reading. 
     441 *
     442 *  @note Locks this object for reading.
    443443 */
    444444HRESULT DVDDrive::saveSettings (settings::Key &aMachineNode)
     
    497497}
    498498
    499 /** 
     499/**
    500500 *  @note Locks this object for writing.
    501501 */
     
    521521}
    522522
    523 /** 
     523/**
    524524 *  @note Locks this object for writing, together with the peer object (also
    525525 *  for writing) if there is one.
     
    532532
    533533    /* 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);
    539540
    540541    if (mData.isBackedUp())
     
    549550}
    550551
    551 /** 
     552/**
    552553 *  @note Locks this object for writing, together with the peer object
    553554 *  represented by @a aThat (locked for reading).
     
    562563
    563564    /* sanity too */
    564     AutoCaller thatCaller (mPeer);
     565    AutoCaller thatCaller (aThat);
    565566    AssertComRCReturnVoid (thatCaller.rc());
    566567
    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());
    569571
    570572    /* this will back up current data */
  • trunk/src/VBox/Main/FloppyDriveImpl.cpp

    r6076 r7992  
    358358/////////////////////////////////////////////////////////////////////////////
    359359
    360 /** 
     360/**
    361361 *  Loads settings from the given machine node.
    362362 *  May be called once right after this object creation.
    363  * 
     363 *
    364364 *  @param aMachineNode <Machine> node.
    365  * 
    366  *  @note Locks this object for writing. 
     365 *
     366 *  @note Locks this object for writing.
    367367 */
    368368HRESULT FloppyDrive::loadSettings (const settings::Key &aMachineNode)
     
    386386     * place when a setting of a newly created object must default to A while
    387387     * the same setting of an object loaded from the old settings file must
    388      * default to B. */ 
     388     * default to B. */
    389389
    390390    HRESULT rc = S_OK;
     
    442442}
    443443
    444 /** 
     444/**
    445445 *  Saves settings to the given machine node.
    446  * 
     446 *
    447447 *  @param aMachineNode <Machine> node.
    448  * 
    449  *  @note Locks this object for reading. 
     448 *
     449 *  @note Locks this object for reading.
    450450 */
    451451HRESULT FloppyDrive::saveSettings (settings::Key &aMachineNode)
     
    504504}
    505505
    506 /** 
     506/**
    507507 *  @note Locks this object for writing.
    508508 */
     
    528528}
    529529
    530 /** 
     530/**
    531531 *  @note Locks this object for writing, together with the peer object (also
    532532 *  for writing) if there is one.
     
    539539
    540540    /* 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);
    546547
    547548    if (mData.isBackedUp())
     
    556557}
    557558
    558 /** 
     559/**
    559560 *  @note Locks this object for writing, together with the peer object (locked
    560561 *  for reading) if there is one.
     
    567568
    568569    /* sanity too */
    569     AutoCaller thatCaller (mPeer);
     570    AutoCaller thatCaller (aThat);
    570571    AssertComRCReturnVoid (thatCaller.rc());
    571572
    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());
    574576
    575577    /* this will back up current data */
  • trunk/src/VBox/Main/HardDiskImpl.cpp

    r7277 r7992  
    196196        return E_POINTER;
    197197
    198     AutoLock alock (this);
     198    AutoReaderLock alock (this);
    199199    CHECK_READY();
    200200
     
    208208        return E_POINTER;
    209209
    210     AutoLock alock (this);
     210    AutoReaderLock alock (this);
    211211    CHECK_READY();
    212212
     
    220220        return E_POINTER;
    221221
    222     AutoLock alock (this);
     222    AutoReaderLock alock (this);
    223223    CHECK_READY();
    224224
     
    232232        return E_POINTER;
    233233
    234     AutoLock alock (this);
     234    AutoReaderLock alock (this);
    235235    CHECK_READY();
    236236
     
    274274        return E_POINTER;
    275275
    276     AutoLock alock (this);
     276    AutoReaderLock alock (this);
    277277    CHECK_READY();
    278278
     
    286286        return E_POINTER;
    287287
    288     AutoLock lock(this);
    289     CHECK_READY();
    290 
    291     AutoLock chLock (childrenLock());
     288    AutoReaderLock lock(this);
     289    CHECK_READY();
     290
     291    AutoReaderLock chLock (childrenLock());
    292292
    293293    ComObjPtr <HardDiskCollection> collection;
     
    303303        return E_POINTER;
    304304
    305     AutoLock lock(this);
     305    AutoReaderLock lock(this);
    306306    CHECK_READY();
    307307
     
    368368        return E_POINTER;
    369369
    370     AutoLock alock (this);
     370    AutoReaderLock alock (this);
    371371    CHECK_READY();
    372372
     
    380380        return E_POINTER;
    381381
    382     AutoLock alock (this);
     382    AutoReaderLock alock (this);
    383383    CHECK_READY();
    384384
     
    392392        return E_POINTER;
    393393
    394     AutoLock alock (this);
     394    AutoReaderLock alock (this);
    395395    CHECK_READY();
    396396
     
    600600                                     bool aCheckReaders /* = false */)
    601601{
    602     AutoLock alock (this);
     602    AutoReaderLock alock (this);
    603603    CHECK_READY();
    604604
     
    636636bool HardDisk::sameAs (HardDisk *that)
    637637{
    638     AutoLock alock (this);
     638    AutoReaderLock alock (this);
    639639    if (!isReady())
    640640        return false;
     
    744744bool HardDisk::hasForeignChildren()
    745745{
    746     AutoLock alock (this);
     746    AutoReaderLock alock (this);
    747747    AssertReturn (isReady(), false);
    748748
     
    750750
    751751    /* check all children */
    752     AutoLock chLock (childrenLock());
     752    AutoReaderLock chLock (childrenLock());
    753753    for (HardDiskList::const_iterator it = children().begin();
    754754         it != children().end();
     
    756756    {
    757757        ComObjPtr <HardDisk> child = *it;
    758         AutoLock childLock (child);
     758        AutoReaderLock childLock (child);
    759759        if (child->mMachineId != mMachineId)
    760760            return true;
     
    779779        return setError (E_FAIL, errMsg, toString().raw());
    780780
    781     AutoLock chLock (childrenLock());
     781    AutoReaderLock chLock (childrenLock());
    782782
    783783    for (HardDiskList::const_iterator it = children().begin();
     
    814814    AssertReturn (mBusy == true, (void) 0);
    815815
    816     AutoLock chLock (childrenLock());
     816    AutoReaderLock chLock (childrenLock());
    817817
    818818    for (HardDiskList::const_iterator it = children().begin();
     
    831831/**
    832832 *  Checks that this hard disk and all its direct children are accessible.
     833 *
     834 *  @note Locks this object for writing.
    833835 */
    834836HRESULT HardDisk::getAccessibleWithChildren (Bstr &aAccessError)
    835837{
     838    /* getAccessible() needs a write lock */
    836839    AutoLock alock (this);
    837840    AssertReturn (isReady(), E_FAIL);
     
    841844        return rc;
    842845
    843     AutoLock chLock (childrenLock());
     846    AutoReaderLock chLock (childrenLock());
    844847
    845848    for (HardDiskList::const_iterator it = children().begin();
     
    869872HRESULT HardDisk::checkConsistency()
    870873{
    871     AutoLock alock (this);
     874    AutoReaderLock alock (this);
    872875    AssertReturn (isReady(), E_FAIL);
    873876
     
    886889    HRESULT rc = S_OK;
    887890
    888     AutoLock chLock (childrenLock());
     891    AutoReaderLock chLock (childrenLock());
    889892
    890893    if (mParent.isNull() && mType == HardDiskType_Normal &&
     
    10221025
    10231026    /* update paths of all children */
    1024     AutoLock chLock (childrenLock());
     1027    AutoReaderLock chLock (childrenLock());
    10251028    for (HardDiskList::const_iterator it = children().begin();
    10261029         it != children().end();
     
    12621265 *
    12631266 *  @note
    1264  *      Must be called from under the object's lock
     1267 *      Must be called from under the object's read lock
    12651268 */
    12661269HRESULT HardDisk::saveSettings (settings::Key &aHDNode)
     
    12931296
    12941297    /* save all children */
    1295     AutoLock chLock (childrenLock());
     1298    AutoReaderLock chLock (childrenLock());
    12961299    for (HardDiskList::const_iterator it = children().begin();
    12971300         it != children().end();
     
    12991302    {
    13001303        ComObjPtr <HardDisk> child = *it;
    1301         AutoLock childLock (child);
     1304        AutoReaderLock childLock (child);
    13021305
    13031306        Key hdNode = aHDNode.appendKey ("DiffHardDisk");
     
    15061509        return E_POINTER;
    15071510
    1508     AutoLock alock (this);
     1511    AutoReaderLock alock (this);
    15091512    CHECK_READY();
    15101513
     
    15391542        return E_POINTER;
    15401543
    1541     AutoLock alock (this);
     1544    AutoReaderLock alock (this);
    15421545    CHECK_READY();
    15431546
     
    15551558        return E_POINTER;
    15561559
    1557     AutoLock alock (this);
     1560    AutoReaderLock alock (this);
    15581561    CHECK_READY();
    15591562
     
    15701573        return E_POINTER;
    15711574
    1572     AutoLock alock (this);
     1575    AutoReaderLock alock (this);
    15731576    CHECK_READY();
    15741577
     
    16121615        return E_POINTER;
    16131616
    1614     AutoLock alock (this);
     1617    AutoReaderLock alock (this);
    16151618    CHECK_READY();
    16161619
     
    17081711 *                      accessible, otherwise contains a message describing
    17091712 *                      the reason of inaccessibility.
     1713 *
     1714 *  @note Locks this object for writing.
    17101715 */
    17111716HRESULT HVirtualDiskImage::getAccessible (Bstr &aAccessError)
    17121717{
     1718    /* queryInformation() needs a write lock */
    17131719    AutoLock alock (this);
    17141720    CHECK_READY();
     
    17671773    AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
    17681774
    1769     AutoLock alock (this);
     1775    AutoReaderLock alock (this);
    17701776    CHECK_READY();
    17711777
     
    18221828 *
    18231829 *  @param aShort       if true, a short representation is returned
     1830 *
     1831 *  @note Locks this object for reading.
    18241832 */
    18251833Bstr HVirtualDiskImage::toString (bool aShort /* = false */)
    18261834{
    1827     AutoLock alock (this);
     1835    AutoReaderLock alock (this);
    18281836
    18291837    if (!aShort)
     
    21192127        HRESULT rc = S_OK;
    21202128
    2121         AutoLock chLock (childrenLock());
     2129        AutoReaderLock chLock (childrenLock());
    21222130
    21232131        for (HardDiskList::const_iterator it = children().begin();
     
    23882396 *  @param aAccessError not used when NULL, otherwise see #getAccessible()
    23892397 *
    2390  *  @note Must be called from under the object's lock, only after
     2398 *  @note Must be called from under the object's write lock, only after
    23912399 *        CHECK_BUSY_AND_READERS() succeeds.
    23922400 */
     
    29562964        return E_POINTER;
    29572965
    2958     AutoLock alock (this);
     2966    AutoReaderLock alock (this);
    29592967    CHECK_READY();
    29602968
     
    29852993        return E_POINTER;
    29862994
    2987     AutoLock alock (this);
     2995    AutoReaderLock alock (this);
    29882996    CHECK_READY();
    29892997
     
    29973005        return E_POINTER;
    29983006
    2999     AutoLock alock (this);
     3007    AutoReaderLock alock (this);
    30003008    CHECK_READY();
    30013009
     
    30123020        return E_POINTER;
    30133021
    3014     AutoLock alock (this);
     3022    AutoReaderLock alock (this);
    30153023    CHECK_READY();
    30163024
     
    30443052        return E_POINTER;
    30453053
    3046     AutoLock alock (this);
     3054    AutoReaderLock alock (this);
    30473055    CHECK_READY();
    30483056
     
    30733081        return E_POINTER;
    30743082
    3075     AutoLock alock (this);
     3083    AutoReaderLock alock (this);
    30763084    CHECK_READY();
    30773085
     
    31053113        return E_POINTER;
    31063114
    3107     AutoLock alock (this);
     3115    AutoReaderLock alock (this);
    31083116    CHECK_READY();
    31093117
     
    31343142        return E_POINTER;
    31353143
    3136     AutoLock alock (this);
     3144    AutoReaderLock alock (this);
    31373145    CHECK_READY();
    31383146
     
    31633171        return E_POINTER;
    31643172
    3165     AutoLock alock (this);
     3173    AutoReaderLock alock (this);
    31663174    CHECK_READY();
    31673175
     
    32143222/**
    32153223 *  Checks accessibility of this iSCSI hard disk.
     3224 *
     3225 *  @note Locks this object for writing.
    32163226 */
    32173227HRESULT HISCSIHardDisk::getAccessible (Bstr &aAccessError)
    32183228{
     3229   /* queryInformation() needs a write lock */
    32193230    AutoLock alock (this);
    32203231    CHECK_READY();
     
    32403251    AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
    32413252
    3242     AutoLock alock (this);
     3253    AutoReaderLock alock (this);
    32433254    CHECK_READY();
    32443255
     
    32673278 *
    32683279 *  @param aShort       if true, a short representation is returned
     3280 *
     3281 *  @note Locks this object for reading.
    32693282 */
    32703283Bstr HISCSIHardDisk::toString (bool aShort /* = false */)
    32713284{
    3272     AutoLock alock (this);
     3285    AutoReaderLock alock (this);
    32733286
    32743287    Bstr str;
     
    33463359 *
    33473360 *  @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.
    33503364 */
    33513365HRESULT HISCSIHardDisk::queryInformation (Bstr &aAccessError)
    33523366{
     3367    AssertReturn (isLockedOnCurrentThread(), E_FAIL);
     3368
     3369    /* create a lock object to completely release it later */
     3370    AutoLock alock (this);
     3371
    33533372    /// @todo (dmik) query info about this iSCSI disk,
    33543373    //  set mSize and mActualSize,
     
    35723591        return E_POINTER;
    35733592
    3574     AutoLock alock (this);
     3593    AutoReaderLock alock (this);
    35753594    CHECK_READY();
    35763595
     
    36093628        return E_POINTER;
    36103629
    3611     AutoLock alock (this);
     3630    AutoReaderLock alock (this);
    36123631    CHECK_READY();
    36133632
     
    36273646        return E_POINTER;
    36283647
    3629     AutoLock alock (this);
     3648    AutoReaderLock alock (this);
    36303649    CHECK_READY();
    36313650
     
    36423661        return E_POINTER;
    36433662
    3644     AutoLock alock (this);
     3663    AutoReaderLock alock (this);
    36453664    CHECK_READY();
    36463665
     
    36843703        return E_POINTER;
    36853704
    3686     AutoLock alock (this);
     3705    AutoReaderLock alock (this);
    36873706    CHECK_READY();
    36883707
     
    37923811 *                      accessible, otherwise contains a message describing
    37933812 *                      the reason of inaccessibility.
     3813 *
     3814 *  @note Locks this object for writing.
    37943815 */
    37953816HRESULT HVMDKImage::getAccessible (Bstr &aAccessError)
    37963817{
     3818   /* queryInformation() needs a write lock */
    37973819    AutoLock alock (this);
    37983820    CHECK_READY();
     
    38513873    AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
    38523874
    3853     AutoLock alock (this);
     3875    AutoReaderLock alock (this);
    38543876    CHECK_READY();
    38553877
     
    39063928 *
    39073929 *  @param aShort       if true, a short representation is returned
     3930 *
     3931 *  @note Locks this object for reading.
    39083932 */
    39093933Bstr HVMDKImage::toString (bool aShort /* = false */)
    39103934{
    3911     AutoLock alock (this);
     3935    AutoReaderLock alock (this);
    39123936
    39133937    if (!aShort)
     
    44824506        return E_POINTER;
    44834507
    4484     AutoLock alock (this);
     4508    AutoReaderLock alock (this);
    44854509    CHECK_READY();
    44864510
     
    45044528        return E_POINTER;
    45054529
    4506     AutoLock alock (this);
     4530    AutoReaderLock alock (this);
    45074531    CHECK_READY();
    45084532
     
    45164540        return E_POINTER;
    45174541
    4518     AutoLock alock (this);
     4542    AutoReaderLock alock (this);
    45194543    CHECK_READY();
    45204544
     
    45314555        return E_POINTER;
    45324556
    4533     AutoLock alock (this);
     4557    AutoReaderLock alock (this);
    45344558    CHECK_READY();
    45354559
     
    45774601        return E_POINTER;
    45784602
    4579     AutoLock alock (this);
     4603    AutoReaderLock alock (this);
    45804604    CHECK_READY();
    45814605
     
    45894613        return E_POINTER;
    45904614
    4591     AutoLock alock (this);
     4615    AutoReaderLock alock (this);
    45924616    CHECK_READY();
    45934617
     
    46654689 *                      accessible, otherwise contains a message describing
    46664690 *                      the reason of inaccessibility.
     4691 *
     4692 *  @note Locks this object for writing.
    46674693 */
    46684694HRESULT HCustomHardDisk::getAccessible (Bstr &aAccessError)
    46694695{
     4696   /* queryInformation() needs a write lock */
    46704697    AutoLock alock (this);
    46714698    CHECK_READY();
     
    47244751    AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
    47254752
    4726     AutoLock alock (this);
     4753    AutoReaderLock alock (this);
    47274754    CHECK_READY();
    47284755
     
    47434770 *
    47444771 *  @param aShort       if true, a short representation is returned
     4772 *
     4773 *  @note Locks this object for reading.
    47454774 */
    47464775Bstr HCustomHardDisk::toString (bool aShort /* = false */)
    47474776{
    4748     AutoLock alock (this);
     4777    AutoReaderLock alock (this);
    47494778
    47504779    /// @todo currently, we assume that location is always a file path for
     
    52705299        return E_POINTER;
    52715300
    5272     AutoLock alock (this);
     5301    AutoReaderLock alock (this);
    52735302    CHECK_READY();
    52745303
     
    53075336        return E_POINTER;
    53085337
    5309     AutoLock alock (this);
     5338    AutoReaderLock alock (this);
    53105339    CHECK_READY();
    53115340
     
    53255354        return E_POINTER;
    53265355
    5327     AutoLock alock (this);
     5356    AutoReaderLock alock (this);
    53285357    CHECK_READY();
    53295358
     
    53405369        return E_POINTER;
    53415370
    5342     AutoLock alock (this);
     5371    AutoReaderLock alock (this);
    53435372    CHECK_READY();
    53445373
     
    53825411        return E_POINTER;
    53835412
    5384     AutoLock alock (this);
     5413    AutoReaderLock alock (this);
    53855414    CHECK_READY();
    53865415
     
    54905519 *                      accessible, otherwise contains a message describing
    54915520 *                      the reason of inaccessibility.
     5521 *
     5522 *  @note Locks this object for writing.
    54925523 */
    54935524HRESULT HVHDImage::getAccessible (Bstr &aAccessError)
    54945525{
     5526    /* queryInformation() needs a write lock */
    54955527    AutoLock alock (this);
    54965528    CHECK_READY();
     
    55485580    AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
    55495581
    5550     AutoLock alock (this);
     5582    AutoReaderLock alock (this);
    55515583    CHECK_READY();
    55525584
     
    56035635 *
    56045636 *  @param aShort       if true, a short representation is returned
     5637 *
     5638 *  @note Locks this object for reading.
    56055639 */
    56065640Bstr HVHDImage::toString (bool aShort /* = false */)
    56075641{
    5608     AutoLock alock (this);
     5642    AutoReaderLock alock (this);
    56095643
    56105644    if (!aShort)
  • trunk/src/VBox/Main/MachineImpl.cpp

    r7991 r7992  
    123123
    124124    mMachineStateDeps = 0;
    125     mZeroMachineStateDepsSem = NIL_RTSEMEVENT;
    126     mWaitingStateDeps = FALSE;
     125    mMachineStateDepsSem = NIL_RTSEMEVENTMULTI;
     126    mMachineStateChangePending = 0;
    127127
    128128    mCurrentStateModified = TRUE;
     
    135135Machine::Data::~Data()
    136136{
    137     if (mZeroMachineStateDepsSem != NIL_RTSEMEVENT)
    138     {
    139         RTSemEventDestroy (mZeroMachineStateDepsSem);
    140         mZeroMachineStateDepsSem = NIL_RTSEMEVENT;
     137    if (mMachineStateDepsSem != NIL_RTSEMEVENTMULTI)
     138    {
     139        RTSemEventMultiDestroy (mMachineStateDepsSem);
     140        mMachineStateDepsSem = NIL_RTSEMEVENTMULTI;
    141141    }
    142142}
     
    612612    LogFlowThisFunc (("mRegistered=%d\n", mData->mRegistered));
    613613
    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.
    620619     */
    621     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     620    AutoMultiWriteLock2 alock (mParent, this);
    622621
    623622    if (!mData->mSession.mMachine.isNull())
    624623    {
    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.
    637635         */
    638636        LogWarningThisFunc (("Session machine is not NULL (%p), "
     
    16721670
    16731671    /* VirtualBox::getHardDisk() need read lock */
    1674     AutoMultiLock <2> alock (mParent->rlock(), this->wlock());
     1672    AutoMultiLock2 alock (mParent->rlock(), this->wlock());
    16751673
    16761674    HRESULT rc = checkStateDependency (MutableStateDep);
     
    21852183    /* VirtualBox::onExtraDataCanChange() and saveSettings() need mParent
    21862184     * lock (saveSettings() needs a write one) */
    2187     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     2185    AutoMultiWriteLock2 alock (mParent, this);
    21882186
    21892187    if (mType == IsSnapshotMachine)
     
    22962294
    22972295    /* saveSettings() needs mParent lock */
    2298     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     2296    AutoMultiWriteLock2 alock (mParent, this);
    22992297
    23002298    HRESULT rc = checkStateDependency (MutableStateDep);
     
    23172315
    23182316    /* saveSettings() needs mParent lock */
    2319     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     2317    AutoMultiWriteLock2 alock (mParent, this);
    23202318
    23212319    HRESULT rc = checkStateDependency (MutableStateDep);
     
    25302528    CheckComRCReturnRC (autoCaller.rc());
    25312529
    2532     AutoReaderLock alock (this);
     2530    AutoLock alock (this);
    25332531
    25342532    HRESULT rc = checkStateDependency (MutableStateDep);
     
    29192917
    29202918    /* We need VirtualBox lock because of Progress::notifyComplete() */
    2921     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     2919    AutoMultiWriteLock2 alock (mParent, this);
    29222920
    29232921    if (!mData->mRegistered)
     
    34283426
    34293427    /* wait for state dependants to drop to zero */
    3430     checkStateDependencies (alock);
     3428    ensureNoStateDependencies (alock);
    34313429
    34323430    ComAssertRet (mData->mRegistered != aRegistered, E_FAIL);
     
    35103508
    35113509/**
    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.
    35283527 */
    35293528HRESULT Machine::addStateDependency (StateDependency aDepType /* = AnyStateDep */,
     
    35343533    AssertComRCReturnRC (autoCaller.rc());
    35353534
    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);
    35523536
    35533537    HRESULT rc = checkStateDependency (aDepType);
    35543538    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    }
    35553561
    35563562    if (aState)
     
    35593565        *aRegistered = mData->mRegistered;
    35603566
    3561     ++ mData->mMachineStateDeps;
    3562 
    35633567    return S_OK;
    35643568}
    35653569
    35663570/**
    3567  *  Decreases the number of objects dependent on the machine state.
    3568  *  Must always complete the #addStateDependency() call after the state
    3569  *  dependency no 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.
    35703574 */
    35713575void Machine::releaseStateDependency()
    35723576{
     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
    35733581    AutoCaller autoCaller (this);
    35743582    AssertComRCReturnVoid (autoCaller.rc());
    35753583
    3576     AutoLock alock (this);
    3577 
    3578     AssertReturnVoid (mData->mMachineStateDeps > 0);
     3584    AssertReturnVoid (mData->mMachineStateDeps != 0
     3585                      /* releaseStateDependency() w/o addStateDependency()? */);
    35793586    -- mData->mMachineStateDeps;
    35803587
    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        }
    35863596    }
    35873597}
     
    36113621 *  @param aDepType     Dependency type to check.
    36123622 *
    3613  *  @note External classes should use #addStateDependency() and
     3623 *  @note Non Machine based classes should use #addStateDependency() and
    36143624 *  #releaseStateDependency() methods or the smart AutoStateDependency
    36153625 *  template.
    36163626 *
    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.
    36183629 */
    36193630HRESULT Machine::checkStateDependency (StateDependency aDepType)
    36203631{
    3621     AssertReturn (isLockedOnCurrentThread(), E_FAIL);
    3622 
    36233632    switch (aDepType)
    36243633    {
     
    38593868}
    38603869
    3861 
    38623870/**
    3863  *  Chhecks that there are no state dependants. If necessary, waits for the
    3864  *  number of dependants to drop to zero. Must be called from under
    3865  *  this object's lock.
    3866  *
    3867  *  @param aLock    This object's lock.
    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!
    38703878 */
    3871 void Machine::checkStateDependencies (AutoLock &aLock)
    3872 {
    3873     AssertReturnVoid (isLockedOnCurrentThread());
     3879void Machine::ensureNoStateDependencies (AutoLock &aLock)
     3880{
    38743881    AssertReturnVoid (aLock.belongsTo (this));
     3882    AssertReturnVoid (aLock.isLockedOnCurrentThread());
     3883
     3884    AutoLock stateLock (stateLockHandle());
    38753885
    38763886    /* Wait for all state dependants if necessary */
    3877     if (mData->mMachineStateDeps > 0)
    3878     {
    3879         /* lazy creation */
    3880         if (mData->mZeroMachineStateDepsSem == NIL_RTSEMEVENT)
    3881             RTSemEventCreate (&mData->mZeroMachineStateDepsSem);
     3887    if (mData->mMachineStateDeps != 0)
     3888    {
     3889        /* lazy semaphore creation */
     3890        if (mData->mMachineStateDepsSem == NIL_RTSEMEVENTMULTI)
     3891            RTSemEventMultiCreate (&mData->mMachineStateDepsSem);
    38823892
    38833893        LogFlowThisFunc (("Waiting for state deps (%d) to drop to zero...\n",
    38843894                          mData->mMachineStateDeps));
    38853895
    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();
    38883903        aLock.leave();
    38893904
    3890         RTSemEventWait (mData->mZeroMachineStateDepsSem, RT_INDEFINITE_WAIT);
     3905        RTSemEventMultiWait (mData->mMachineStateDepsSem, RT_INDEFINITE_WAIT);
    38913906
    38923907        aLock.enter();
    3893 
    3894         mData->mWaitingStateDeps = FALSE;
     3908        stateLock.enter();
     3909
     3910        -- mData->mMachineStateChangePending;
    38953911    }
    38963912}
     
    39123928
    39133929    /* 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);
    39183931
    39193932    if (mData->mMachineState != aMachineState)
     
    64326445
    64336446    /* accessing mParent methods below needs mParent lock */
    6434     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     6447    AutoMultiWriteLock2 alock (mParent, this);
    64356448
    64366449    HRESULT rc = S_OK;
     
    66196632
    66206633    /* accessing mParent methods below needs mParent lock */
    6621     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     6634    AutoMultiWriteLock2 alock (mParent, this);
    66226635
    66236636    /* short cut: check whether attachments are all the same */
     
    73227335    if (autoUninitSpan.initFailed())
    73237336    {
    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.
    73287340         */
    73297341        LogFlowThisFunc (("Initialization failed.\n"));
     
    73517363    }
    73527364
    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);
    73597369
    73607370    MachineState_T lastState = mData->mMachineState;
     
    75197529 *  with the primary Machine instance (mPeer).
    75207530 */
    7521 AutoLock::Handle *SessionMachine::lockHandle() const
     7531RWLockHandle *SessionMachine::lockHandle() const
    75227532{
    75237533    AssertReturn (!mPeer.isNull(), NULL);
     
    77017711
    77027712    /* Progress::init() needs mParent lock */
    7703     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     7713    AutoMultiWriteLock2 alock (mParent, this);
    77047714
    77057715    if (control.equalsTo (mData->mSession.mDirectControl))
     
    77667776
    77677777    /* mParent->addProgress() needs mParent lock */
    7768     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     7778    AutoMultiWriteLock2 alock (mParent, this);
    77697779
    77707780    AssertReturn (mData->mMachineState == MachineState_Paused &&
     
    78147824
    78157825    /* endSavingState() need mParent lock */
    7816     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     7826    AutoMultiWriteLock2 alock (mParent, this);
    78177827
    78187828    AssertReturn (mData->mMachineState == MachineState_Saving &&
     
    78887898
    78897899    /* Progress::init() needs mParent lock */
    7890     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     7900    AutoMultiWriteLock2 alock (mParent, this);
    78917901
    78927902    AssertReturn ((mData->mMachineState < MachineState_Running ||
     
    80488058
    80498059    /* Lock mParent because of endTakingSnapshot() */
    8050     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     8060    AutoMultiWriteLock2 alock (mParent, this);
    80518061
    80528062    AssertReturn (!aSuccess ||
     
    80858095
    80868096    /* Progress::init() needs mParent lock */
    8087     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     8097    AutoMultiWriteLock2 alock (mParent, this);
    80888098
    80898099    ComAssertRet (mData->mMachineState < MachineState_Running, E_FAIL);
     
    81708180
    81718181    /* Progress::init() needs mParent lock */
    8172     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     8182    AutoMultiWriteLock2 alock (mParent, this);
    81738183
    81748184    ComAssertRet (mData->mMachineState < MachineState_Running, E_FAIL);
     
    82348244
    82358245    /* Progress::init() needs mParent lock */
    8236     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     8246    AutoMultiWriteLock2 alock (mParent, this);
    82378247
    82388248    ComAssertRet (mData->mMachineState < MachineState_Running, E_FAIL);
     
    86878697
    86888698    /* mParent->removeProgress() and saveSettings() need mParent lock */
    8689     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     8699    AutoMultiWriteLock2 alock (mParent, this);
    86908700
    86918701    HRESULT rc = S_OK;
     
    87348744
    87358745    /* Progress object uninitialization needs mParent lock */
    8736     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     8746    AutoMultiWriteLock2 alock (mParent, this);
    87378747
    87388748    HRESULT rc = S_OK;
     
    88348844
    88358845    /* endTakingSnapshot() needs mParent lock */
    8836     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     8846    AutoMultiWriteLock2 alock (mParent, this);
    88378847
    88388848    HRESULT rc = S_OK;
     
    89308940    }
    89318941
     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
    89328948    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 */
    89408950
    89418951    HRESULT rc = S_OK;
     
    90609070                        hdRootString.raw())));
    90619071
    9062                     snapshotChildrenLock.unlock();
    9063                     snapshotLock.unlock();
    90649072                    alock.leave();
    90659073
     
    90679075
    90689076                    alock.enter();
    9069                     snapshotLock.lock();
    9070                     snapshotChildrenLock.lock();
    90719077
    90729078                    // debug code
     
    91309136                    /* merge the child to this basic image */
    91319137
    9132                     snapshotChildrenLock.unlock();
    9133                     snapshotLock.unlock();
    91349138                    alock.leave();
    91359139
     
    91379141
    91389142                    alock.enter();
    9139                     snapshotLock.lock();
    9140                     snapshotChildrenLock.lock();
    91419143
    91429144                    if (SUCCEEDED (rc))
     
    93259327
    93269328    /* Progress::notifyComplete() et al., saveSettings() need mParent lock */
    9327     AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
     9329    AutoMultiWriteLock2 alock (mParent, this);
    93289330
    93299331    /*
     
    94039405                curSnapshot->data().mMachine->mHDData->mHDAttachments;
    94049406
    9405             snapshotLock.unlock();
     9407            snapshotLock.leave();
    94069408            alock.leave();
    94079409            rc = createSnapshotDiffs (NULL, mUserData->mSnapshotFolderFull,
     
    94099411                                      false /* aOnline */);
    94109412            alock.enter();
    9411             snapshotLock.lock();
     9413            snapshotLock.enter();
    94129414
    94139415            if (FAILED (rc))
     
    94449446
    94459447                /* copy the state file */
    9446                 snapshotLock.unlock();
     9448                snapshotLock.leave();
    94479449                alock.leave();
    94489450                int vrc = RTFileCopyEx (snapStateFilePath, stateFilePath,
    94499451                                        0, progressCallback, aTask.progress);
    94509452                alock.enter();
    9451                 snapshotLock.lock();
     9453                snapshotLock.enter();
    94529454
    94539455                if (VBOX_SUCCESS (vrc))
     
    98229824 *                          (or NULL for the offline snapshot)
    98239825 *
    9824  *  @note Locks aSessionMachine object for reading.
     9826 *  @note The aSessionMachine must be locked for writing.
    98259827 */
    98269828HRESULT SnapshotMachine::init (SessionMachine *aSessionMachine,
     
    98379839    AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
    98389840
     9841    AssertReturn (aSessionMachine->isLockedOnCurrentThread(), E_FAIL);
     9842
    98399843    mSnapshotId = aSnapshotId;
    9840 
    9841     AutoReaderLock alock (aSessionMachine);
    98429844
    98439845    /* memorize the primary Machine instance (i.e. not SessionMachine!) */
     
    99369938 *                          (or NULL for the offline snapshot)
    99379939 *
    9938  *  @note Locks aMachine object for reading.
     9940 *  @note Doesn't lock anything.
    99399941 */
    99409942HRESULT SnapshotMachine::init (Machine *aMachine,
     
    99549956    AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
    99559957
     9958    /* Don't need to lock aMachine when VirtualBox is starting up */
     9959
    99569960    mSnapshotId = aSnapshotId;
    9957 
    9958     AutoReaderLock alock (aMachine);
    99599961
    99609962    /* memorize the primary Machine instance */
     
    1007110073 *  with the primary Machine instance (mPeer).
    1007210074 */
    10073 AutoLock::Handle *SnapshotMachine::lockHandle() const
     10075RWLockHandle *SnapshotMachine::lockHandle() const
    1007410076{
    1007510077    AssertReturn (!mPeer.isNull(), NULL);
  • trunk/src/VBox/Main/Makefile.kmk

    r7964 r7992  
    177177VBoxSVC_SOURCES = \
    178178        Logging.cpp \
     179        AutoLock.cpp \
    179180        Matching.cpp \
    180181        VirtualBoxBase.cpp \
     
    350351VBoxC_SOURCES = \
    351352        Logging.cpp \
     353        AutoLock.cpp \
    352354        VBoxDll.cpp \
    353355        Version.cpp \
  • trunk/src/VBox/Main/NetworkAdapterImpl.cpp

    r7207 r7992  
    11801180
    11811181    /* 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);
    11871188
    11881189    if (mData.isBackedUp())
     
    12101211
    12111212    /* sanity too */
    1212     AutoCaller thatCaller (mPeer);
     1213    AutoCaller thatCaller (aThat);
    12131214    AssertComRCReturnVoid (thatCaller.rc());
    12141215
    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());
    12171219
    12181220    /* this will back up current data */
  • trunk/src/VBox/Main/ParallelPortImpl.cpp

    r6168 r7992  
    163163 *  Loads settings from the given port node.
    164164 *  May be called once right after this object creation.
    165  * 
     165 *
    166166 *  @param aPortNode <Port> node.
    167  * 
     167 *
    168168 *  @note Locks this object for writing.
    169169 */
     
    188188     * place when a setting of a newly created object must default to A while
    189189     * the same setting of an object loaded from the old settings file must
    190      * default to B. */ 
     190     * default to B. */
    191191
    192192    /* enabled (required) */
     
    206206}
    207207
    208 /** 
     208/**
    209209 *  Saves settings to the given port node.
    210  * 
     210 *
    211211 *  Note that the given Port node is comletely empty on input.
    212212 *
    213213 *  @param aPortNode <Port> node.
    214  * 
    215  *  @note Locks this object for reading. 
     214 *
     215 *  @note Locks this object for reading.
    216216 */
    217217HRESULT ParallelPort::saveSettings (settings::Key &aPortNode)
     
    272272
    273273    /* 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);
    279280
    280281    if (mData.isBackedUp())
     
    302303
    303304    /* sanity too */
    304     AutoCaller thatCaller (mPeer);
     305    AutoCaller thatCaller (aThat);
    305306    AssertComRCReturnVoid (thatCaller.rc());
    306307
    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());
    309311
    310312    /* this will back up current data */
     
    504506}
    505507
    506 /** 
     508/**
    507509 *  Validates COMSETTER(Path) arguments.
    508510 */
  • trunk/src/VBox/Main/ProgressImpl.cpp

    r6935 r7992  
    162162    LogFlowMember (("ProgressBase::protectedUninit()\n"));
    163163
    164     Assert (alock.belongsTo (this) && alock.level() == 1);
     164    Assert (alock.belongsTo (this) && alock.isLockedOnCurrentThread() &&
     165            alock.writeLockLevel() == 1);
    165166    Assert (isReady());
    166167
     
    747748 *  If the result code indicates a success (|SUCCEEDED (@a aResultCode)|)
    748749 *  then the current operation is set to the last
    749  * 
     750 *
    750751 *  Note that this method may be called only once for the given Progress object.
    751752 *  Subsequent calls will assert.
     
    844845    Bstr text = Utf8StrFmtVA (aText, args);
    845846    va_end (args);
    846    
     847
    847848    return notifyCompleteBstr (aResultCode, aIID, aComponent, text);
    848849}
     
    855856 *  This method is preferred iy you have a ready (translated and formatted)
    856857 *  Bstr string, because it omits an extra conversion Utf8Str -> Bstr.
    857  * 
     858 *
    858859 *  @param  aResultCode operation result (error) code, must not be S_OK
    859860 *  @param  aIID        IID of the intrface that defines the error
  • trunk/src/VBox/Main/SATAControllerImpl.cpp

    r7556 r7992  
    321321/////////////////////////////////////////////////////////////////////////////
    322322
    323 /** 
     323/**
    324324 *  Loads settings from the given machine node.
    325325 *  May be called once right after this object creation.
    326  * 
     326 *
    327327 *  @param aMachineNode <Machine> node.
    328  * 
    329  *  @note Locks this object for writing. 
     328 *
     329 *  @note Locks this object for writing.
    330330 */
    331331HRESULT SATAController::loadSettings (const settings::Key &aMachineNode)
     
    358358}
    359359
    360 /** 
     360/**
    361361 *  Saves settings to the given machine node.
    362  * 
     362 *
    363363 *  @param aMachineNode <Machine> node.
    364  * 
     364 *
    365365 *  @note Locks this object for reading.
    366366 */
     
    451451}
    452452
    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 */
    454457void SATAController::commit()
    455458{
     459    /* sanity */
    456460    AutoCaller autoCaller (this);
    457461    AssertComRCReturnVoid (autoCaller.rc());
    458462
    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);
    460470
    461471    if (mData.isBackedUp())
     
    471481}
    472482
    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 */
    474487void SATAController::copyFrom (SATAController *aThat)
    475488{
     489    AssertReturnVoid (aThat != NULL);
     490
     491    /* sanity */
    476492    AutoCaller autoCaller (this);
    477493    AssertComRCReturnVoid (autoCaller.rc());
    478494
    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());
    480502
    481503    /* this will back up current data */
  • trunk/src/VBox/Main/SerialPortImpl.cpp

    r7207 r7992  
    308308
    309309    /* 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);
    315316
    316317    if (mData.isBackedUp())
     
    338339
    339340    /* sanity too */
    340     AutoCaller thatCaller (mPeer);
     341    AutoCaller thatCaller (aThat);
    341342    AssertComRCReturnVoid (thatCaller.rc());
    342343
    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());
    345347
    346348    /* this will back up current data */
  • trunk/src/VBox/Main/USBControllerImpl.cpp

    r7968 r7992  
    923923}
    924924
    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 */
    926929void USBController::commit()
    927930{
     931    /* sanity */
    928932    AutoCaller autoCaller (this);
    929933    AssertComRCReturnVoid (autoCaller.rc());
    930934
    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);
    932942
    933943    if (mData.isBackedUp())
     
    936946        if (mPeer)
    937947        {
    938             // attach new data to the peer and reshare it
     948            /* attach new data to the peer and reshare it */
    939949            AutoLock peerlock (mPeer);
    940950            mPeer->mData.attach (mData);
     
    949959        mDeviceFilters.commit();
    950960
    951         // apply changes to peer
     961        /* apply changes to peer */
    952962        if (mPeer)
    953963        {
    954964            AutoLock peerlock (mPeer);
    955             // commit all changes to new filters (this will reshare data with
    956             // 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) */
    957967            DeviceFilterList *newList = new DeviceFilterList();
    958968            DeviceFilterList::const_iterator it = mDeviceFilters->begin();
     
    961971                (*it)->commit();
    962972
    963                 // look if this filter has a peer filter
     973                /* look if this filter has a peer filter */
    964974                ComObjPtr <USBDeviceFilter> peer = (*it)->peer();
    965975                if (!peer)
    966976                {
    967                     // no peer means the filter is a newly created one;
    968                     // create a peer owning data this filter share it with
     977                    /* no peer means the filter is a newly created one;
     978                     * create a peer owning data this filter share it with */
    969979                    peer.createObject();
    970980                    peer->init (mPeer, *it, true /* aReshare */);
     
    972982                else
    973983                {
    974                     // remove peer from the old list
     984                    /* remove peer from the old list */
    975985                    mPeer->mDeviceFilters->remove (peer);
    976986                }
    977                 // and add it to the new list
     987                /* and add it to the new list */
    978988                newList->push_back (peer);
    979989
     
    981991            }
    982992
    983             // uninit old peer's filters that are left
     993            /* uninit old peer's filters that are left */
    984994            it = mPeer->mDeviceFilters->begin();
    985995            while (it != mPeer->mDeviceFilters->end())
     
    989999            }
    9901000
    991             // attach new list of filters to our peer
     1001            /* attach new list of filters to our peer */
    9921002            mPeer->mDeviceFilters.attach (newList);
    9931003        }
    9941004        else
    9951005        {
    996             // we have no peer (our parent is the newly created machine);
    997             // just commit changes to filters
     1006            /* we have no peer (our parent is the newly created machine);
     1007             * just commit changes to filters */
    9981008            commitFilters = true;
    9991009        }
     
    10011011    else
    10021012    {
    1003         // the list of filters itself is not changed,
    1004         // just commit changes to filters themselves
     1013        /* the list of filters itself is not changed,
     1014         * just commit changes to filters themselves */
    10051015        commitFilters = true;
    10061016    }
     
    10181028}
    10191029
    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 */
    10211034void USBController::copyFrom (USBController *aThat)
    10221035{
     1036    AssertReturnVoid (aThat != NULL);
     1037
     1038    /* sanity */
    10231039    AutoCaller autoCaller (this);
    10241040    AssertComRCReturnVoid (autoCaller.rc());
    10251041
    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());
    10271049
    10281050    if (mParent->isRegistered())
  • trunk/src/VBox/Main/VirtualBoxBase.cpp

    r6964 r7992  
    4343    mInitDoneSem = NIL_RTSEMEVENTMULTI;
    4444    mInitDoneSemUsers = 0;
    45     RTCritSectInit (&mStateLock);
    4645    mObjectLock = NULL;
    4746}
     
    5150    if (mObjectLock)
    5251        delete mObjectLock;
    53     RTCritSectDelete (&mStateLock);
    5452    Assert (mInitDoneSemUsers == 0);
    5553    Assert (mInitDoneSem == NIL_RTSEMEVENTMULTI);
     
    6260
    6361// AutoLock::Lockable interface
    64 AutoLock::Handle *VirtualBoxBaseNEXT_base::lockHandle() const
     62RWLockHandle *VirtualBoxBaseNEXT_base::lockHandle() const
    6563{
    6664    /* lasy initialization */
    6765    if (!mObjectLock)
    68         mObjectLock = new AutoLock::Handle;
     66        mObjectLock = new RWLockHandle;
    6967    return mObjectLock;
    7068}
  • trunk/src/VBox/Main/include/AutoLock.h

    r5999 r7992  
    55
    66/*
    7  * Copyright (C) 2006-2007 innotek GmbH
     7 * Copyright (C) 2006-2008 innotek GmbH
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2323#include <iprt/critsect.h>
    2424#include <iprt/thread.h>
     25#include <iprt/semaphore.h>
     26
     27#include <iprt/assert.h>
    2528
    2629#if defined(DEBUG)
     
    3134{
    3235
    33 template <size_t> class AutoMultiLock;
    34 namespace internal { struct LockableTag; }
    35 
    3636/**
    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 */
     39class LockOps
     40{
     41public:
     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 */
     52class ReadLockOps : public LockOps
     53{
     54public:
     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 */
     74class WriteLockOps : public LockOps
     75{
     76public:
     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 */
     103class LockHandle : protected ReadLockOps, protected WriteLockOps
     104{
     105public:
     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
     138private:
     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 */
     154class RWLockHandle : public LockHandle
     155{
     156public:
     157
     158    RWLockHandle();
     159    virtual ~RWLockHandle();
     160
     161    bool isLockedOnCurrentThread() const;
     162
     163private:
     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 */
     198class WriteLockHandle : public LockHandle
     199{
     200public:
     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
     217private:
     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 */
     256class Lockable
     257{
     258public:
     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).
    43456 */
    44457class AutoLock
     
    46459public:
    47460
    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)
    71516        {
    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();
    73528        }
    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)
    112541        {
    113             Handle *h = lockHandle();
    114             return h ? h->isLockedOnCurrentThread() : false;
     542            mHandle->lockWrite();
     543            ++ mLockLevel;
     544            Assert (mLockLevel != 0 /* overflow? */);
    115545        }
    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)
    158557        {
    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;
    169561        }
    170562    }
    171563
    172564    /**
    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)
    179588        {
    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();
    183597        }
    184598    }
    185599
    186600    /**
    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)
    193609        {
    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();
    198615        }
    199616    }
    200617
    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; }
    242620    bool operator !() const { return isNull(); }
    243621
    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     */
    257669    bool belongsTo (const Lockable &aLockable)
    258670    {
     
    260672    }
    261673
    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     */
    263679    bool belongsTo (const Lockable *aLockable)
    264680    {
    265681         return aLockable && belongsTo (aLockable->lockHandle());
    266682    }
    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);
    281683
    282684private:
     
    285687    DECLARE_CLS_NEW_DELETE_NOOP (AutoLock)
    286688
    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////////////////////////////////////////////////////////////////////////////////
    300697
    301698/**
    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 */
     766class AutoReaderLock
     767{
     768public:
     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    }
    317907
    318908private:
     
    320910    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoReaderLock)
    321911    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////////////////////////////////////////////////////////////////////////////////
    371918
    372919/**
    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 */
     924template <size_t Cnt>
     925class AutoMultiLockBase
     926{
     927public:
     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
     977protected:
     978
     979    AutoMultiLockBase() : mIsLocked (false) {}
     980
     981    LockOps *mOps [Cnt];
     982    bool mIsLocked;
     983
     984private:
     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. */
     991template<>
     992class AutoMultiLockBase <0> { private : AutoMultiLockBase(); };
     993
     994/** AutoMultiLockBase <1> is meaningless and forbidden. */
     995template<>
     996class 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 */
     1038class AutoMultiLock2 : public AutoMultiLockBase <2>
     1039{
     1040public:
     1041    AutoMultiLock2 (A(0), A(1))
     1042    { B(0); B(1); lock(); }
     1043};
     1044
     1045/** AutoMultiLock for 3 locks. See AutoMultiLock2 for more information. */
     1046class AutoMultiLock3 : public AutoMultiLockBase <3>
     1047{
     1048public:
     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. */
     1054class AutoMultiLock4 : public AutoMultiLockBase <4>
     1055{
     1056public:
     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 */
     1071template <size_t Cnt>
     1072class AutoMultiWriteLockBase
     1073{
     1074public:
     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.
    4921103     */
    4931104    void leave()
    4941105    {
    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.
    5061116     */
    5071117    void enter()
    5081118    {
    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
     1124protected:
     1125
     1126    AutoMultiWriteLockBase() {}
     1127
     1128    void setLockHandle (size_t aIdx, LockHandle *aHandle)
     1129    { mLocks [aIdx].mHandle = aHandle; }
    5131130
    5141131private:
    5151132
    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. */
     1140template<>
     1141class AutoMultiWriteLockBase <0> { private : AutoMultiWriteLockBase(); };
     1142
     1143/** AutoMultiWriteLockBase <1> is meaningless and forbidden. */
     1144template<>
     1145class 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)
    5271156
    5281157/**
    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 */
     1195class AutoMultiWriteLock2 : public AutoMultiWriteLockBase <2>
     1196{
     1197public:
     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. */
     1205class AutoMultiWriteLock3 : public AutoMultiWriteLockBase <3>
     1206{
     1207public:
     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. */
     1215class AutoMultiWriteLock4 : public AutoMultiWriteLockBase <4>
     1216{
     1217public:
     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
    5371228
    5381229} /* namespace util */
  • trunk/src/VBox/Main/include/HardDiskImpl.h

    r7207 r7992  
    117117
    118118    /** Shortcut to #dependentChildrenLock() */
    119     AutoLock::Handle &childrenLock() const { return dependentChildrenLock(); }
     119    RWLockHandle *childrenLock() const { return dependentChildrenLock(); }
    120120
    121121    /**
  • trunk/src/VBox/Main/include/MachineImpl.h

    r7990 r7992  
    147147        RTTIMESPEC mLastStateChange;
    148148
     149        /* Note: These are guarded by VirtualBoxBase::stateLockHandle() */
    149150        uint32_t mMachineStateDeps;
    150         RTSEMEVENT mZeroMachineStateDepsSem;
    151         BOOL mWaitingStateDeps;
     151        RTSEMEVENTMULTI mMachineStateDepsSem;
     152        uint32_t mMachineStateChangePending;
    152153
    153154        BOOL mCurrentStateModified;
     
    615616    void uninitDataAndChildObjects();
    616617
    617     void checkStateDependencies (AutoLock &aLock);
     618    void ensureNoStateDependencies (AutoLock &aLock);
    618619
    619620    virtual HRESULT setMachineState (MachineState_T aMachineState);
     
    775776    void uninit() { uninit (Uninit::Unexpected); }
    776777
    777     // AutoLock::Lockable interface
    778     AutoLock::Handle *lockHandle() const;
     778    // util::Lockable interface
     779    RWLockHandle *lockHandle() const;
    779780
    780781    // IInternalMachineControl methods
     
    934935    void uninit();
    935936
    936     // AutoLock::Lockable interface
    937     AutoLock::Handle *lockHandle() const;
     937    // util::Lockable interface
     938    RWLockHandle *lockHandle() const;
    938939
    939940    // public methods only for internal purposes
  • trunk/src/VBox/Main/include/SnapshotImpl.h

    r6076 r7992  
    9797
    9898    /** Shortcut to #dependentChildrenLock() */
    99     AutoLock::Handle &childrenLock() const { return dependentChildrenLock(); }
     99    RWLockHandle *childrenLock() const { return dependentChildrenLock(); }
    100100
    101101    /**
  • trunk/src/VBox/Main/include/VirtualBoxBase.h

    r6964 r7992  
    3131
    3232using namespace com;
    33 using util::AutoLock;
    34 using util::AutoReaderLock;
    35 using util::AutoMultiLock;
     33using namespace util;
    3634
    3735#include <iprt/cdefs.h>
     
    438436    : public CComObjectRootEx
    439437#endif
    440     , public AutoLock::Lockable
     438    , public Lockable
    441439{
    442440public:
     
    452450
    453451    // AutoLock::Lockable interface
    454     virtual AutoLock::Handle *lockHandle() const;
     452    virtual RWLockHandle *lockHandle() const;
    455453
    456454    /**
     
    863861    };
    864862
     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
    865871private:
    866872
     
    886892
    887893    /** Protects access to state related data members */
    888     RTCRITSECT mStateLock;
     894    WriteLockHandle mStateLock;
    889895
    890896    /** User-level object lock for subclasses */
    891     mutable AutoLock::Handle *mObjectLock;
     897    mutable RWLockHandle *mObjectLock;
    892898};
    893899
     
    16191625    VirtualBoxBaseWithChildren()
    16201626        : mUninitDoneSem (NIL_RTSEMEVENT), mChildrenLeft (0)
    1621     {
    1622         RTCritSectInit (&mMapLock);
    1623     }
     1627    {}
    16241628
    16251629    virtual ~VirtualBoxBaseWithChildren()
    1626     {
    1627         RTCritSectDelete (&mMapLock);
    1628     }
     1630    {}
    16291631
    16301632    /**
     
    16801682    DependentChildren mDependentChildren;
    16811683
    1682     RTCRITSECT mMapLock;
     1684    WriteLockHandle mMapLock;
     1685
    16831686    RTSEMEVENT mUninitDoneSem;
    16841687    unsigned mChildrenLeft;
     
    18251828
    18261829    /* Protects all the fields above */
    1827     AutoLock::Handle mMapLock;
     1830    RWLockHandle mMapLock;
    18281831};
    18291832
     
    19071910     *  </code>
    19081911     */
    1909     AutoLock::Handle &dependentChildrenLock() const { return mMapLock; }
     1912    RWLockHandle *dependentChildrenLock() const { return &mMapLock; }
    19101913
    19111914    /**
     
    19751978
    19761979    bool mInUninit;
    1977     mutable AutoLock::Handle mMapLock;
     1980    mutable RWLockHandle mMapLock;
    19781981};
    19791982
     
    20632066     * </code>
    20642067     */
    2065     AutoLock::Handle &dependentChildrenLock() const { return mMapLock; }
     2068    RWLockHandle *dependentChildrenLock() const { return &mMapLock; }
    20662069
    20672070    /**
     
    20972100
    20982101    /* Protects the two fields above */
    2099     mutable AutoLock::Handle mMapLock;
     2102    mutable RWLockHandle mMapLock;
    21002103};
    21012104
  • trunk/src/VBox/Main/include/VirtualBoxImpl.h

    r7387 r7992  
    467467    EventQueue * const mAsyncEventQ;
    468468    /** Lock for calling EventQueue->post() */
    469     AutoLock::Handle mAsyncEventQLock;
     469    RWLockHandle mAsyncEventQLock;
    470470
    471471    static Bstr sVersion;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette