VirtualBox

Changeset 25285 in vbox for trunk/src/VBox/Main/AutoLock.cpp


Ignore:
Timestamp:
Dec 9, 2009 11:38:58 PM (15 years ago)
Author:
vboxsync
Message:

Main: preparation for deadlock detection: convert AutoMultiWriteLock*: inheritance instead of template

File:
1 edited

Legend:

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

    r25284 r25285  
    9696
    9797typedef std::vector<LockHandle*> HandlesVector;
     98typedef std::vector<uint32_t> CountsVector;
    9899
    99100struct AutoLockBase::Data
    100101{
    101102    Data(size_t cHandles)
    102         : aHandles(cHandles),       // size of array
    103           fIsLocked(false),
    104           cUnlockedInLeave(0)
    105     { }
    106 
     103        : fIsLocked(false),
     104          aHandles(cHandles),       // size of array
     105          acUnlockedInLeave(cHandles)
     106    {
     107        for (uint32_t i = 0; i < cHandles; ++i)
     108        {
     109            acUnlockedInLeave[i] = 0;
     110            aHandles[i] = NULL;
     111        }
     112    }
     113
     114    bool            fIsLocked;          // if true, then all items in aHandles are locked by this AutoLock and
     115                                        // need to be unlocked in the destructor
    107116    HandlesVector   aHandles;           // array (vector) of LockHandle instances; in the case of AutoWriteLock
    108117                                        // and AutoReadLock, there will only be one item on the list; with the
    109118                                        // AutoMulti* derivatives, there will be multiple
    110     bool            fIsLocked;          // if true, then all items in aHandles are locked by this AutoLock and
    111                                         // need to be unlocked in the destructor
    112     uint32_t        cUnlockedInLeave;   // how many times the handle was unlocked in leave(); otherwise 0
     119    CountsVector    acUnlockedInLeave;  // for each lock handle, how many times the handle was unlocked in leave(); otherwise 0
    113120};
    114121
    115 AutoLockBase::AutoLockBase(LockHandle *pHandle)
    116 {
     122AutoLockBase::AutoLockBase(uint32_t cHandles)
     123{
     124    m = new Data(cHandles);
     125}
     126
     127AutoLockBase::AutoLockBase(uint32_t cHandles, LockHandle *pHandle)
     128{
     129    Assert(cHandles == 1);
    117130    m = new Data(1);
    118131    m->aHandles[0] = pHandle;
     
    176189void AutoLockBase::cleanup()
    177190{
    178     if (m->cUnlockedInLeave)
    179     {
    180         // there was a leave() before the destruction: then restore the
    181         // lock level that might have been set by locks other than our own
    182         if (m->fIsLocked)
    183             --m->cUnlockedInLeave;       // no lock for our own
    184         m->fIsLocked = false;
    185         for (; m->cUnlockedInLeave; --m->cUnlockedInLeave)
    186             callLockOnAllHandles();
    187     }
    188 
    189     if (m->fIsLocked)
     191    bool fAnyUnlockedInLeave = false;
     192
     193    uint32_t i = 0;
     194    for (HandlesVector::iterator it = m->aHandles.begin();
     195         it != m->aHandles.end();
     196         ++it)
     197    {
     198        LockHandle *pHandle = *it;
     199        if (pHandle)
     200        {
     201            if (m->acUnlockedInLeave[i])
     202            {
     203                // there was a leave() before the destruction: then restore the
     204                // lock level that might have been set by locks other than our own
     205                if (m->fIsLocked)
     206                {
     207                    --m->acUnlockedInLeave[i];
     208                    fAnyUnlockedInLeave = true;
     209                }
     210                for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])
     211                    callLockImpl(*pHandle);
     212            }
     213        }
     214        ++i;
     215    }
     216
     217    if (m->fIsLocked && !fAnyUnlockedInLeave)
    190218        callUnlockOnAllHandles();
    191219}
     
    286314{
    287315    l.unlockWrite();
    288 }
    289 
    290 /**
    291  * Returns @c true if the current thread holds a write lock on the managed
    292  * read/write semaphore. Returns @c false if the managed semaphore is @c
    293  * NULL.
    294  *
    295  * @note Intended for debugging only.
    296  */
    297 bool AutoWriteLockBase::isWriteLockOnCurrentThread() const
    298 {
    299     return m->aHandles[0] ? m->aHandles[0]->isWriteLockOnCurrentThread() : false;
    300 }
    301 
    302  /**
    303  * Returns the current write lock level of the managed smaphore. The lock
    304  * level determines the number of nested #lock() calls on the given
    305  * semaphore handle. Returns @c 0 if the managed semaphore is @c
    306  * NULL.
    307  *
    308  * Note that this call is valid only when the current thread owns a write
    309  * lock on the given semaphore handle and will assert otherwise.
    310  *
    311  * @note Intended for debugging only.
    312  */
    313 uint32_t AutoWriteLockBase::writeLockLevel() const
    314 {
    315     return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0;
    316316}
    317317
     
    340340{
    341341    AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot leave()!"));
    342     AssertMsg(m->cUnlockedInLeave == 0, ("m->cUnlockedInLeave is %d, must be 0! Called leave() twice?", m->cUnlockedInLeave));
    343 
     342
     343    uint32_t i = 0;
    344344    for (HandlesVector::iterator it = m->aHandles.begin();
    345345         it != m->aHandles.end();
     
    349349        if (pHandle)
    350350        {
    351             m->cUnlockedInLeave = pHandle->writeLockLevel();
    352             AssertMsg(m->cUnlockedInLeave >= 1, ("m->cUnlockedInLeave is %d, must be >=1!", m->cUnlockedInLeave));
    353 
    354             for (uint32_t left = m->cUnlockedInLeave;
     351            AssertMsg(m->acUnlockedInLeave[i] == 0, ("m->cUnlockedInLeave[%d] is %d, must be 0! Called leave() twice?", i, m->acUnlockedInLeave[i]));
     352            m->acUnlockedInLeave[i] = pHandle->writeLockLevel();
     353            AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i]));
     354
     355            for (uint32_t left = m->acUnlockedInLeave[i];
    355356                 left;
    356357                 --left)
    357358                pHandle->unlockWrite();
    358359        }
     360        ++i;
    359361    }
    360362}
     
    369371{
    370372    AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot enter()!"));
    371     AssertMsg(m->cUnlockedInLeave != 0, ("m->cUnlockedInLeave is 0! enter() without leave()?"));
    372 
     373
     374    uint32_t i = 0;
    373375    for (HandlesVector::iterator it = m->aHandles.begin();
    374376         it != m->aHandles.end();
     
    378380        if (pHandle)
    379381        {
    380             for (; m->cUnlockedInLeave; --m->cUnlockedInLeave)
     382            AssertMsg(m->acUnlockedInLeave[i] != 0, ("m->cUnlockedInLeave[%d] is 0! enter() without leave()?", i));
     383
     384            for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])
    381385                pHandle->lockWrite();
    382386        }
     387        ++i;
     388    }
     389}
     390
     391/**
     392 * Same as #leave() but checks if the current thread actally owns the lock
     393 * and only proceeds in this case. As a result, as opposed to #leave(),
     394 * doesn't assert when called with no lock being held.
     395 */
     396void AutoWriteLockBase::maybeLeave()
     397{
     398    uint32_t i = 0;
     399    for (HandlesVector::iterator it = m->aHandles.begin();
     400         it != m->aHandles.end();
     401         ++it)
     402    {
     403        LockHandle *pHandle = *it;
     404        if (pHandle)
     405        {
     406            if (pHandle->isWriteLockOnCurrentThread())
     407            {
     408                m->acUnlockedInLeave[i] = pHandle->writeLockLevel();
     409                AssertMsg(m->acUnlockedInLeave[i] >= 1, ("m->cUnlockedInLeave[%d] is %d, must be >=1!", i, m->acUnlockedInLeave[i]));
     410
     411                for (uint32_t left = m->acUnlockedInLeave[i];
     412                     left;
     413                     --left)
     414                    pHandle->unlockWrite();
     415            }
     416        }
     417        ++i;
     418    }
     419}
     420
     421/**
     422 * Same as #enter() but checks if the current thread actally owns the lock
     423 * and only proceeds if not. As a result, as opposed to #enter(), doesn't
     424 * assert when called with the lock already being held.
     425 */
     426void AutoWriteLockBase::maybeEnter()
     427{
     428    uint32_t i = 0;
     429    for (HandlesVector::iterator it = m->aHandles.begin();
     430         it != m->aHandles.end();
     431         ++it)
     432    {
     433        LockHandle *pHandle = *it;
     434        if (pHandle)
     435        {
     436            if (!pHandle->isWriteLockOnCurrentThread())
     437            {
     438                for (; m->acUnlockedInLeave[i]; --m->acUnlockedInLeave[i])
     439                    pHandle->lockWrite();
     440            }
     441        }
     442        ++i;
    383443    }
    384444}
     
    425485}
    426486
     487/**
     488 * Returns @c true if the current thread holds a write lock on the managed
     489 * read/write semaphore. Returns @c false if the managed semaphore is @c
     490 * NULL.
     491 *
     492 * @note Intended for debugging only.
     493 */
     494bool AutoWriteLock::isWriteLockOnCurrentThread() const
     495{
     496    return m->aHandles[0] ? m->aHandles[0]->isWriteLockOnCurrentThread() : false;
     497}
     498
     499 /**
     500 * Returns the current write lock level of the managed smaphore. The lock
     501 * level determines the number of nested #lock() calls on the given
     502 * semaphore handle. Returns @c 0 if the managed semaphore is @c
     503 * NULL.
     504 *
     505 * Note that this call is valid only when the current thread owns a write
     506 * lock on the given semaphore handle and will assert otherwise.
     507 *
     508 * @note Intended for debugging only.
     509 */
     510uint32_t AutoWriteLock::writeLockLevel() const
     511{
     512    return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0;
     513}
     514
     515////////////////////////////////////////////////////////////////////////////////
     516//
     517// AutoMultiWriteLock*
     518//
     519////////////////////////////////////////////////////////////////////////////////
     520
     521AutoMultiWriteLock2::AutoMultiWriteLock2(Lockable *pl1, Lockable *pl2)
     522    : AutoWriteLockBase(2)
     523{
     524    if (pl1)
     525        m->aHandles[0] = pl1->lockHandle();
     526    if (pl2)
     527        m->aHandles[1] = pl2->lockHandle();
     528    acquire();
     529}
     530
     531AutoMultiWriteLock2::AutoMultiWriteLock2(LockHandle *pl1, LockHandle *pl2)
     532    : AutoWriteLockBase(2)
     533{
     534    m->aHandles[0] = pl1;
     535    m->aHandles[1] = pl2;
     536    acquire();
     537}
     538
     539AutoMultiWriteLock3::AutoMultiWriteLock3(Lockable *pl1, Lockable *pl2, Lockable *pl3)
     540    : AutoWriteLockBase(3)
     541{
     542    if (pl1)
     543        m->aHandles[0] = pl1->lockHandle();
     544    if (pl2)
     545        m->aHandles[1] = pl2->lockHandle();
     546    if (pl3)
     547        m->aHandles[2] = pl3->lockHandle();
     548    acquire();
     549}
     550
     551AutoMultiWriteLock3::AutoMultiWriteLock3(LockHandle *pl1, LockHandle *pl2, LockHandle *pl3)
     552    : AutoWriteLockBase(3)
     553{
     554    m->aHandles[0] = pl1;
     555    m->aHandles[1] = pl2;
     556    m->aHandles[2] = pl3;
     557    acquire();
     558}
     559
    427560} /* namespace util */
    428561/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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