VirtualBox

Changeset 25284 in vbox for trunk/src


Ignore:
Timestamp:
Dec 9, 2009 9:26:28 PM (15 years ago)
Author:
vboxsync
Message:

Main: preparation for deadlock detection: add AutoWriterLockBase in preparation of AutoMulti* conversion

Location:
trunk/src/VBox/Main
Files:
2 edited

Legend:

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

    r25283 r25284  
    214214////////////////////////////////////////////////////////////////////////////////
    215215//
    216 // AutoWriteLock
     216// AutoReadLock
     217//
     218////////////////////////////////////////////////////////////////////////////////
     219
     220/**
     221 * Release all read locks acquired by this instance through the #lock()
     222 * call and destroys the instance.
     223 *
     224 * Note that if there there are nested #lock() calls without the
     225 * corresponding number of #unlock() calls when the destructor is called, it
     226 * will assert. This is because having an unbalanced number of nested locks
     227 * is a program logic error which must be fixed.
     228 */
     229/*virtual*/ AutoReadLock::~AutoReadLock()
     230{
     231    LockHandle *pHandle = m->aHandles[0];
     232
     233    if (pHandle)
     234    {
     235        if (m->fIsLocked)
     236            pHandle->unlockRead();
     237    }
     238}
     239
     240/**
     241 * Implementation of the pure virtual declared in AutoLockBase.
     242 * This gets called by AutoLockBase.acquire() to actually request
     243 * the semaphore; in the AutoReadLock implementation, we request
     244 * the semaphore in read mode.
     245 */
     246/*virtual*/ void AutoReadLock::callLockImpl(LockHandle &l)
     247{
     248    l.lockRead();
     249}
     250
     251/**
     252 * Implementation of the pure virtual declared in AutoLockBase.
     253 * This gets called by AutoLockBase.release() to actually release
     254 * the semaphore; in the AutoReadLock implementation, we release
     255 * the semaphore in read mode.
     256 */
     257/*virtual*/ void AutoReadLock::callUnlockImpl(LockHandle &l)
     258{
     259    l.unlockRead();
     260}
     261
     262////////////////////////////////////////////////////////////////////////////////
     263//
     264// AutoWriteLockBase
    217265//
    218266////////////////////////////////////////////////////////////////////////////////
     
    224272 * the semaphore in write mode.
    225273 */
    226 /*virtual*/ void AutoWriteLock::callLockImpl(LockHandle &l)
     274/*virtual*/ void AutoWriteLockBase::callLockImpl(LockHandle &l)
    227275{
    228276    l.lockWrite();
     
    235283 * the semaphore in write mode.
    236284 */
    237 /*virtual*/ void AutoWriteLock::callUnlockImpl(LockHandle &l)
     285/*virtual*/ void AutoWriteLockBase::callUnlockImpl(LockHandle &l)
    238286{
    239287    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 */
     297bool 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 */
     313uint32_t AutoWriteLockBase::writeLockLevel() const
     314{
     315    return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0;
    240316}
    241317
     
    261337 * write or a read lock is owned by some other thread by that time.
    262338 */
    263 void AutoWriteLock::leave()
    264 {
    265     LockHandle *pHandle = m->aHandles[0];
    266 
    267     if (pHandle)
    268     {
    269         AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot leave()!"));
    270         AssertMsg(m->cUnlockedInLeave == 0, ("m->cUnlockedInLeave is %d, must be 0! Called leave() twice?", m->cUnlockedInLeave));
    271 
    272         m->cUnlockedInLeave = pHandle->writeLockLevel();
    273         AssertMsg(m->cUnlockedInLeave >= 1, ("m->cUnlockedInLeave is %d, must be >=1!", m->cUnlockedInLeave));
    274 
    275         for (uint32_t left = m->cUnlockedInLeave;
    276              left;
    277              --left)
    278             pHandle->unlockWrite();
     339void AutoWriteLockBase::leave()
     340{
     341    AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot leave()!"));
     342    AssertMsg(m->cUnlockedInLeave == 0, ("m->cUnlockedInLeave is %d, must be 0! Called leave() twice?", m->cUnlockedInLeave));
     343
     344    for (HandlesVector::iterator it = m->aHandles.begin();
     345         it != m->aHandles.end();
     346         ++it)
     347    {
     348        LockHandle *pHandle = *it;
     349        if (pHandle)
     350        {
     351            m->cUnlockedInLeave = pHandle->writeLockLevel();
     352            AssertMsg(m->cUnlockedInLeave >= 1, ("m->cUnlockedInLeave is %d, must be >=1!", m->cUnlockedInLeave));
     353
     354            for (uint32_t left = m->cUnlockedInLeave;
     355                 left;
     356                 --left)
     357                pHandle->unlockWrite();
     358        }
    279359    }
    280360}
     
    286366 * between.
    287367 */
    288 void AutoWriteLock::enter()
    289 {
    290     LockHandle *pHandle = m->aHandles[0];
    291 
    292     if (pHandle)
    293     {
    294         AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot enter()!"));
    295         AssertMsg(m->cUnlockedInLeave != 0, ("m->cUnlockedInLeave is 0! enter() without leave()?"));
    296 
    297         for (; m->cUnlockedInLeave; --m->cUnlockedInLeave)
    298             pHandle->lockWrite();
    299     }
    300 }
     368void AutoWriteLockBase::enter()
     369{
     370    AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot enter()!"));
     371    AssertMsg(m->cUnlockedInLeave != 0, ("m->cUnlockedInLeave is 0! enter() without leave()?"));
     372
     373    for (HandlesVector::iterator it = m->aHandles.begin();
     374         it != m->aHandles.end();
     375         ++it)
     376    {
     377        LockHandle *pHandle = *it;
     378        if (pHandle)
     379        {
     380            for (; m->cUnlockedInLeave; --m->cUnlockedInLeave)
     381                pHandle->lockWrite();
     382        }
     383    }
     384}
     385
     386////////////////////////////////////////////////////////////////////////////////
     387//
     388// AutoWriteLock
     389//
     390////////////////////////////////////////////////////////////////////////////////
    301391
    302392/**
     
    335425}
    336426
    337 /**
    338  * Returns @c true if the current thread holds a write lock on the managed
    339  * read/write semaphore. Returns @c false if the managed semaphore is @c
    340  * NULL.
    341  *
    342  * @note Intended for debugging only.
    343  */
    344 bool AutoWriteLock::isWriteLockOnCurrentThread() const
    345 {
    346     return m->aHandles[0] ? m->aHandles[0]->isWriteLockOnCurrentThread() : false;
    347 }
    348 
    349  /**
    350  * Returns the current write lock level of the managed smaphore. The lock
    351  * level determines the number of nested #lock() calls on the given
    352  * semaphore handle. Returns @c 0 if the managed semaphore is @c
    353  * NULL.
    354  *
    355  * Note that this call is valid only when the current thread owns a write
    356  * lock on the given semaphore handle and will assert otherwise.
    357  *
    358  * @note Intended for debugging only.
    359  */
    360 uint32_t AutoWriteLock::writeLockLevel() const
    361 {
    362     return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0;
    363 }
    364 
    365 ////////////////////////////////////////////////////////////////////////////////
    366 //
    367 // AutoReadLock
    368 //
    369 ////////////////////////////////////////////////////////////////////////////////
    370 
    371 /**
    372  * Release all read locks acquired by this instance through the #lock()
    373  * call and destroys the instance.
    374  *
    375  * Note that if there there are nested #lock() calls without the
    376  * corresponding number of #unlock() calls when the destructor is called, it
    377  * will assert. This is because having an unbalanced number of nested locks
    378  * is a program logic error which must be fixed.
    379  */
    380 /*virtual*/ AutoReadLock::~AutoReadLock()
    381 {
    382     LockHandle *pHandle = m->aHandles[0];
    383 
    384     if (pHandle)
    385     {
    386         if (m->fIsLocked)
    387             pHandle->unlockRead();
    388     }
    389 }
    390 
    391 /**
    392  * Implementation of the pure virtual declared in AutoLockBase.
    393  * This gets called by AutoLockBase.acquire() to actually request
    394  * the semaphore; in the AutoReadLock implementation, we request
    395  * the semaphore in read mode.
    396  */
    397 /*virtual*/ void AutoReadLock::callLockImpl(LockHandle &l)
    398 {
    399     l.lockRead();
    400 }
    401 
    402 /**
    403  * Implementation of the pure virtual declared in AutoLockBase.
    404  * This gets called by AutoLockBase.release() to actually release
    405  * the semaphore; in the AutoReadLock implementation, we release
    406  * the semaphore in read mode.
    407  */
    408 /*virtual*/ void AutoReadLock::callUnlockImpl(LockHandle &l)
    409 {
    410     l.unlockRead();
    411 }
    412 
    413427} /* namespace util */
    414428/* vi: set tabstop=4 shiftwidth=4 expandtab: */
  • trunk/src/VBox/Main/include/AutoLock.h

    r25283 r25284  
    153153    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (LockHandle)
    154154
     155    friend class AutoWriteLockBase;
    155156    friend class AutoWriteLock;
    156157    friend class AutoReadLock;
     
    343344////////////////////////////////////////////////////////////////////////////////
    344345//
    345 // AutoWriteLock
    346 //
    347 ////////////////////////////////////////////////////////////////////////////////
    348 
    349 class AutoWriteLock : public AutoLockBase
     346// AutoReadLock
     347//
     348////////////////////////////////////////////////////////////////////////////////
     349
     350class AutoReadLock : public AutoLockBase
    350351{
    351352public:
     
    359360     * runtime.
    360361     */
    361     AutoWriteLock()
     362    AutoReadLock()
    362363        : AutoLockBase(NULL)
    363364    { }
     
    365366    /**
    366367     * Constructs a new instance that will start managing the given read/write
    367      * semaphore by requesting a write lock.
    368      */
    369     AutoWriteLock(LockHandle *aHandle)
     368     * semaphore by requesting a read lock.
     369     */
     370    AutoReadLock(LockHandle *aHandle)
    370371        : AutoLockBase(aHandle)
    371372    {
    372373        acquire();
    373374    }
     375
     376    /**
     377     * Constructs a new instance that will start managing the given read/write
     378     * semaphore by requesting a read lock.
     379     */
     380    AutoReadLock(LockHandle &aHandle)
     381        : AutoLockBase(&aHandle)
     382    {
     383        acquire();
     384    }
     385
     386    /**
     387     * Constructs a new instance that will start managing the given read/write
     388     * semaphore by requesting a read lock.
     389     */
     390    AutoReadLock(const Lockable &aLockable)
     391        : AutoLockBase(aLockable.lockHandle())
     392    {
     393        acquire();
     394    }
     395
     396    /**
     397     * Constructs a new instance that will start managing the given read/write
     398     * semaphore by requesting a read lock.
     399     */
     400    AutoReadLock(const Lockable *aLockable)
     401        : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL)
     402    {
     403        acquire();
     404    }
     405
     406    virtual ~AutoReadLock();
     407
     408    virtual void callLockImpl(LockHandle &l);
     409    virtual void callUnlockImpl(LockHandle &l);
     410};
     411
     412////////////////////////////////////////////////////////////////////////////////
     413//
     414// AutoWriteLockBase
     415//
     416////////////////////////////////////////////////////////////////////////////////
     417
     418class AutoWriteLockBase : public AutoLockBase
     419{
     420protected:
     421    AutoWriteLockBase(LockHandle *pHandle)
     422        : AutoLockBase(pHandle)
     423    { }
     424
     425    virtual ~AutoWriteLockBase()
     426    { }
     427
     428    virtual void callLockImpl(LockHandle &l);
     429    virtual void callUnlockImpl(LockHandle &l);
     430
     431public:
     432    bool isWriteLockOnCurrentThread() const;
     433    uint32_t writeLockLevel() const;
     434
     435    void leave();
     436    void enter();
     437
     438    /**
     439     * Same as #leave() but checks if the current thread actally owns the lock
     440     * and only proceeds in this case. As a result, as opposed to #leave(),
     441     * doesn't assert when called with no lock being held.
     442     */
     443    void maybeLeave()
     444    {
     445        if (isWriteLockOnCurrentThread())
     446            leave();
     447    }
     448
     449    /**
     450     * Same as #enter() but checks if the current thread actally owns the lock
     451     * and only proceeds if not. As a result, as opposed to #enter(), doesn't
     452     * assert when called with the lock already being held.
     453     */
     454    void maybeEnter()
     455    {
     456        if (!isWriteLockOnCurrentThread())
     457            enter();
     458    }
     459
     460};
     461
     462////////////////////////////////////////////////////////////////////////////////
     463//
     464// AutoWriteLock
     465//
     466////////////////////////////////////////////////////////////////////////////////
     467
     468class AutoWriteLock : public AutoWriteLockBase
     469{
     470public:
     471
     472    /**
     473     * Constructs a null instance that does not manage any read/write
     474     * semaphore.
     475     *
     476     * Note that all method calls on a null instance are no-ops. This allows to
     477     * have the code where lock protection can be selected (or omitted) at
     478     * runtime.
     479     */
     480    AutoWriteLock()
     481        : AutoWriteLockBase(NULL)
     482    { }
    374483
    375484    /**
     
    377486     * semaphore by requesting a write lock.
    378487     */
    379     AutoWriteLock(LockHandle &aHandle)
    380         : AutoLockBase(&aHandle)
     488    AutoWriteLock(LockHandle *aHandle)
     489        : AutoWriteLockBase(aHandle)
    381490    {
    382491        acquire();
     
    387496     * semaphore by requesting a write lock.
    388497     */
    389     AutoWriteLock(const Lockable &aLockable)
    390         : AutoLockBase(aLockable.lockHandle())
     498    AutoWriteLock(LockHandle &aHandle)
     499        : AutoWriteLockBase(&aHandle)
    391500    {
    392501        acquire();
     
    397506     * semaphore by requesting a write lock.
    398507     */
     508    AutoWriteLock(const Lockable &aLockable)
     509        : AutoWriteLockBase(aLockable.lockHandle())
     510    {
     511        acquire();
     512    }
     513
     514    /**
     515     * Constructs a new instance that will start managing the given read/write
     516     * semaphore by requesting a write lock.
     517     */
    399518    AutoWriteLock(const Lockable *aLockable)
    400         : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL)
     519        : AutoWriteLockBase(aLockable ? aLockable->lockHandle() : NULL)
    401520    {
    402521        acquire();
     
    417536    }
    418537
    419     virtual void callLockImpl(LockHandle &l);
    420     virtual void callUnlockImpl(LockHandle &l);
    421 
    422     void leave();
    423     void enter();
    424 
    425     /**
    426      * Same as #leave() but checks if the current thread actally owns the lock
    427      * and only proceeds in this case. As a result, as opposed to #leave(),
    428      * doesn't assert when called with no lock being held.
    429      */
    430     void maybeLeave()
    431     {
    432         if (isWriteLockOnCurrentThread())
    433             leave();
    434     }
    435 
    436     /**
    437      * Same as #enter() but checks if the current thread actally owns the lock
    438      * and only proceeds if not. As a result, as opposed to #enter(), doesn't
    439      * assert when called with the lock already being held.
    440      */
    441     void maybeEnter()
    442     {
    443         if (!isWriteLockOnCurrentThread())
    444             enter();
    445     }
    446 
    447538    void attach(LockHandle *aHandle);
    448539
     
    466557
    467558    void attachRaw(LockHandle *ph);
    468 
    469     bool isWriteLockOnCurrentThread() const;
    470     uint32_t writeLockLevel() const;
    471 };
    472 
    473 ////////////////////////////////////////////////////////////////////////////////
    474 //
    475 // AutoReadLock
    476 //
    477 ////////////////////////////////////////////////////////////////////////////////
    478 
    479 class AutoReadLock : public AutoLockBase
    480 {
    481 public:
    482 
    483     /**
    484      * Constructs a null instance that does not manage any read/write
    485      * semaphore.
    486      *
    487      * Note that all method calls on a null instance are no-ops. This allows to
    488      * have the code where lock protection can be selected (or omitted) at
    489      * runtime.
    490      */
    491     AutoReadLock()
    492         : AutoLockBase(NULL)
    493     { }
    494 
    495     /**
    496      * Constructs a new instance that will start managing the given read/write
    497      * semaphore by requesting a read lock.
    498      */
    499     AutoReadLock(LockHandle *aHandle)
    500         : AutoLockBase(aHandle)
    501     {
    502         acquire();
    503     }
    504 
    505     /**
    506      * Constructs a new instance that will start managing the given read/write
    507      * semaphore by requesting a read lock.
    508      */
    509     AutoReadLock(LockHandle &aHandle)
    510         : AutoLockBase(&aHandle)
    511     {
    512         acquire();
    513     }
    514 
    515     /**
    516      * Constructs a new instance that will start managing the given read/write
    517      * semaphore by requesting a read lock.
    518      */
    519     AutoReadLock(const Lockable &aLockable)
    520         : AutoLockBase(aLockable.lockHandle())
    521     {
    522         acquire();
    523     }
    524 
    525     /**
    526      * Constructs a new instance that will start managing the given read/write
    527      * semaphore by requesting a read lock.
    528      */
    529     AutoReadLock(const Lockable *aLockable)
    530         : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL)
    531     {
    532         acquire();
    533     }
    534 
    535     virtual ~AutoReadLock();
    536 
    537     virtual void callLockImpl(LockHandle &l);
    538     virtual void callUnlockImpl(LockHandle &l);
    539559};
    540560
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