VirtualBox

Changeset 25279 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Dec 9, 2009 5:50:26 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
55821
Message:

Main: preparation for deadlock detection: clean up autolock classes

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

Legend:

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

    r25149 r25279  
    10371037
    10381038        /* Unlock the appliance for the reading thread */
    1039         appLock.unlock();
     1039        appLock.release();
    10401040        /* Wait until the reading is done, but report the progress back to the
    10411041           caller */
     
    10441044
    10451045        /* Again lock the appliance for the next steps */
    1046         appLock.lock();
     1046        appLock.acquire();
    10471047    }
    10481048    catch(HRESULT aRC)
     
    21042104
    21052105        /* Unlock the appliance for the fs import thread */
    2106         appLock.unlock();
     2106        appLock.release();
    21072107        /* Wait until the import is done, but report the progress back to the
    21082108           caller */
     
    21112111
    21122112        /* Again lock the appliance for the next steps */
    2113         appLock.lock();
     2113        appLock.acquire();
    21142114    }
    21152115    catch(HRESULT aRC)
     
    31263126
    31273127        /* Unlock the appliance for the writing thread */
    3128         appLock.unlock();
     3128        appLock.release();
    31293129        /* Wait until the writing is done, but report the progress back to the
    31303130           caller */
     
    31333133
    31343134        /* Again lock the appliance for the next steps */
    3135         appLock.lock();
     3135        appLock.acquire();
    31363136
    31373137        vrc = RTPathExists(strTmpOvf.c_str()); /* Paranoid check */
  • trunk/src/VBox/Main/AutoLock.cpp

    r24000 r25279  
    2929namespace util
    3030{
     31
     32////////////////////////////////////////////////////////////////////////////////
     33//
     34// RWLockHandle
     35//
     36////////////////////////////////////////////////////////////////////////////////
    3137
    3238RWLockHandle::RWLockHandle()
  • trunk/src/VBox/Main/ConsoleImpl.cpp

    r25149 r25279  
    32173217       described above.
    32183218     */
    3219     alock.unlock();
     3219    alock.release();
    32203220
    32213221    /*
  • trunk/src/VBox/Main/HostImpl.cpp

    r25200 r25279  
    13561356
    13571357    /* save the global settings */
    1358     alock.unlock();
     1358    alock.release();
    13591359    return rc = m->pParent->saveSettings();
    13601360#else
     
    14111411
    14121412    /* save the global settings */
    1413     alock.unlock();
     1413    alock.release();
    14141414    return rc = m->pParent->saveSettings();
    14151415#else
     
    18001800
    18011801        // save the global settings... yeah, on every single filter property change
    1802         alock.unlock();
     1802        alock.release();
    18031803        return m->pParent->saveSettings();
    18041804    }
  • trunk/src/VBox/Main/MachineImpl.cpp

    r25203 r25279  
    34893489
    34903490        /* just be on the safe side when calling another process */
    3491         alock.unlock();
     3491        alock.release();
    34923492
    34933493        /* fail if we were called after #OnSessionEnd() is called.  This is a
     
    37333733
    37343734        /* just be on the safe side when calling another process */
    3735         alock.unlock();
     3735        alock.release();
    37363736
    37373737        if (!directControl)
     
    92969296    mHWData->mPropertyServiceActive = false;
    92979297
    9298     alock.unlock();
     9298    alock.release();
    92999299    SaveSettings();
    93009300
    93019301    /* Restore the mRegistered flag. */
    9302     alock.lock();
     9302    alock.acquire();
    93039303    mData->mRegistered = TRUE;
    93049304
  • trunk/src/VBox/Main/MediumImpl.cpp

    r25184 r25279  
    33463346            // deleteStorageAndWait calls unregisterWithVirtualBox which gets
    33473347            // a write tree lock, so don't deadlock
    3348             treeLock.unlock();
    3349             alock.unlock();
     3348            treeLock.release();
     3349            alock.release();
    33503350
    33513351            rc = deleteStorageAndWait(&aProgress);
  • trunk/src/VBox/Main/NetworkAdapterImpl.cpp

    r25149 r25279  
    227227
    228228        /* leave the lock before informing callbacks */
    229         alock.unlock();
     229        alock.release();
    230230
    231231        mParent->onNetworkAdapterChange (this, FALSE);
     
    280280
    281281        /* leave the lock before informing callbacks */
    282         alock.unlock();
     282        alock.release();
    283283
    284284        mParent->onNetworkAdapterChange (this, FALSE);
     
    376376    {
    377377        /* leave the lock before informing callbacks */
    378         alock.unlock();
     378        alock.release();
    379379
    380380        mParent->onNetworkAdapterChange (this, FALSE);
     
    434434
    435435        /* leave the lock before informing callbacks */
    436         alock.unlock();
     436        alock.release();
    437437
    438438        mParent->onNetworkAdapterChange (this, FALSE);
     
    482482
    483483        /* leave the lock before informing callbacks */
    484         alock.unlock();
     484        alock.release();
    485485
    486486        mParent->onNetworkAdapterChange (this, FALSE);
     
    525525
    526526        /* leave the lock before informing callbacks */
    527         alock.unlock();
     527        alock.release();
    528528
    529529        mParent->onNetworkAdapterChange (this, FALSE);
     
    564564
    565565        /* leave the lock before informing callbacks */
    566         alock.unlock();
     566        alock.release();
    567567
    568568        mParent->onNetworkAdapterChange (this, FALSE);
     
    603603
    604604        /* leave the lock before informing callbacks */
    605         alock.unlock();
     605        alock.release();
    606606
    607607        mParent->onNetworkAdapterChange (this, FALSE);
     
    641641
    642642        /* leave the lock before informing callbacks */
    643         alock.unlock();
     643        alock.release();
    644644
    645645        mParent->onNetworkAdapterChange (this, TRUE);
     
    680680
    681681        /* leave the lock before informing callbacks */
    682         alock.unlock();
     682        alock.release();
    683683
    684684        mParent->onNetworkAdapterChange (this, FALSE);
     
    713713
    714714        /* leave the lock before informing callbacks */
    715         alock.unlock();
     715        alock.release();
    716716
    717717        HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
     
    755755
    756756        /* leave the lock before informing callbacks */
    757         alock.unlock();
     757        alock.release();
    758758
    759759        HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
     
    805805
    806806        /* leave the lock before informing callbacks */
    807         alock.unlock();
     807        alock.release();
    808808
    809809        HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
     
    847847
    848848        /* leave the lock before informing callbacks */
    849         alock.unlock();
     849        alock.release();
    850850
    851851        HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
     
    883883
    884884        /* leave the lock before informing callbacks */
    885         alock.unlock();
     885        alock.release();
    886886
    887887        mParent->onNetworkAdapterChange (this, TRUE);
  • trunk/src/VBox/Main/ParallelPortImpl.cpp

    r25203 r25279  
    230230
    231231        /* leave the lock before informing callbacks */
    232         alock.unlock();
     232        alock.release();
    233233
    234234        m->pMachine->onParallelPortChange (this);
     
    298298    {
    299299        /* leave the lock before informing callbacks */
    300         alock.unlock();
     300        alock.release();
    301301
    302302        m->pMachine->onParallelPortChange (this);
     
    352352    {
    353353        /* leave the lock before informing callbacks */
    354         alock.unlock();
     354        alock.release();
    355355
    356356        m->pMachine->onParallelPortChange (this);
     
    395395
    396396        /* leave the lock before informing callbacks */
    397         alock.unlock();
     397        alock.release();
    398398
    399399        return m->pMachine->onParallelPortChange(this);
  • trunk/src/VBox/Main/SerialPortImpl.cpp

    r25203 r25279  
    226226
    227227        /* leave the lock before informing callbacks */
    228         alock.unlock();
     228        alock.release();
    229229
    230230        m->pMachine->onSerialPortChange (this);
     
    300300    {
    301301        /* leave the lock before informing callbacks */
    302         alock.unlock();
     302        alock.release();
    303303
    304304        m->pMachine->onSerialPortChange (this);
     
    368368    {
    369369        /* leave the lock before informing callbacks */
    370         alock.unlock();
     370        alock.release();
    371371
    372372        m->pMachine->onSerialPortChange (this);
     
    422422    {
    423423        /* leave the lock before informing callbacks */
    424         alock.unlock();
     424        alock.release();
    425425
    426426        m->pMachine->onSerialPortChange (this);
     
    469469
    470470        /* leave the lock before informing callbacks */
    471         alock.unlock();
     471        alock.release();
    472472
    473473        return m->pMachine->onSerialPortChange(this);
     
    508508
    509509        /* leave the lock before informing callbacks */
    510         alock.unlock();
     510        alock.release();
    511511
    512512        m->pMachine->onSerialPortChange (this);
  • trunk/src/VBox/Main/SnapshotImpl.cpp

    r25200 r25279  
    586586    else
    587587    {
    588         alock.unlock();
     588        alock.release();
    589589        for (SnapshotsList::const_iterator it = m->llChildren.begin();
    590590             it != m->llChildren.end();
     
    619619    else
    620620    {
    621         alock.unlock();
     621        alock.release();
    622622        for (SnapshotsList::const_iterator it = m->llChildren.begin();
    623623             it != m->llChildren.end();
     
    720720    if (FAILED(rc)) return rc;
    721721
    722     alock.unlock();
     722    alock.release();
    723723
    724724    data.llChildSnapshots.clear();
     
    16701670     * provide an AutoWriteLock argument that lets create a non-locking
    16711671     * instance */
    1672     vboxLock.unlock();
     1672    vboxLock.release();
    16731673
    16741674    AutoWriteLock alock(this);
     
    17191719
    17201720            /* leave the locks before the potentially lengthy operation */
    1721             snapshotLock.unlock();
     1721            snapshotLock.release();
    17221722            alock.leave();
    17231723
     
    17291729
    17301730            alock.enter();
    1731             snapshotLock.lock();
     1731            snapshotLock.acquire();
    17321732
    17331733            /* Note: on success, current (old) hard disks will be
     
    17551755
    17561756                /* leave the lock before the potentially lengthy operation */
    1757                 snapshotLock.unlock();
     1757                snapshotLock.release();
    17581758                alock.leave();
    17591759
     
    17661766
    17671767                alock.enter();
    1768                 snapshotLock.lock();
     1768                snapshotLock.acquire();
    17691769
    17701770                if (RT_SUCCESS(vrc))
     
    18151815         * locking rule. This is the last chance to do that while we are still
    18161816         * in a protective state which allows us to temporarily leave the lock*/
    1817         alock.unlock();
    1818         vboxLock.lock();
    1819         alock.lock();
     1817        alock.release();
     1818        vboxLock.acquire();
     1819        alock.acquire();
    18201820
    18211821        /* we have already discarded the current state, so set the execution
     
    22152215                    HRESULT rc2 = S_OK;
    22162216
    2217                     attachLock.unlock();
     2217                    attachLock.release();
    22182218
    22192219                    // First we must detach the child (otherwise mergeTo() called
     
    23622362    }
    23632363
    2364     alock.unlock();
     2364    alock.release();
    23652365
    23662366    // whether we were successful or not, we need to set the machine
     
    23812381            // (parent -> child locking order!)
    23822382            AutoWriteLock vboxLock(mParent);
    2383             alock.lock();
     2383            alock.acquire();
    23842384
    23852385            saveSettings(SaveS_InformCallbacksAnyway);
  • trunk/src/VBox/Main/include/AutoLock.h

    r20932 r25279  
    4141{
    4242
     43////////////////////////////////////////////////////////////////////////////////
     44//
     45// LockHandle and friends
     46//
     47////////////////////////////////////////////////////////////////////////////////
     48
    4349/**
    4450 * Abstract lock operations. See LockHandle and AutoWriteLock for details.
     
    245251};
    246252
     253////////////////////////////////////////////////////////////////////////////////
     254//
     255// Lockable
     256//
     257////////////////////////////////////////////////////////////////////////////////
     258
    247259/**
    248260 * Lockable interface.
     
    296308};
    297309
    298 /**
    299  * Provides safe management of read/write semaphores in write mode.
    300  *
    301  * A read/write semaphore is represented by the LockHandle class. This semaphore
    302  * can be requested ("locked") in two different modes: for reading and for
    303  * writing. A write lock is exclusive and acts like a mutex: only one thread can
    304  * acquire a write lock on the given semaphore at a time; all other threads
    305  * trying to request a write lock or a read lock (see below) on the same
    306  * semaphore will be indefinitely blocked until the owning thread releases the
    307  * write lock.
    308  *
    309  * A read lock is shared. This means that several threads can acquire a read
    310  * lock on the same semaphore at the same time provided that there is no thread
    311  * that holds a write lock on that semaphore. Note that when there are one or
    312  * more threads holding read locks, a request for a write lock on another thread
    313  * will be indefinitely blocked until all threads holding read locks release
    314  * them.
    315  *
    316  * Note that write locks can be nested -- the same thread can request a write
    317  * lock on the same semaphore several times. In this case, the corresponding
    318  * number of release calls must be done in order to completely release all
    319  * nested write locks and make the semaphore available for locking by other
    320  * threads.
    321  *
    322  * Read locks can be nested too in which case the same rule of the equal number
    323  * of the release calls applies. Read locks can be also nested into write
    324  * locks which means that the same thread can successfully request a read lock
    325  * if it already holds a write lock. However, please note that the opposite is
    326  * <b>not possible</b>: if a thread tries to request a write lock on the same
    327  * semaphore it is already holding a read lock, it will definitely produce a
    328  * <b>deadlock</b> (i.e. it will block forever waiting for itself).
    329  *
    330  * Note that instances of the AutoWriteLock class manage write locks of
    331  * read/write semaphores only. In order to manage read locks, please use the
    332  * AutoReadLock class.
    333  *
    334  * Safe semaphore management consists of the following:
    335  * <ul>
    336  *   <li>When an instance of the AutoWriteLock class is constructed given a
    337  *   valid semaphore handle, it will automatically request a write lock on that
    338  *   semaphore.
    339  *   </li>
    340  *   <li>When an instance of the AutoWriteLock class constructed given a valid
    341  *   semaphore handle is destroyed (e.g. goes out of scope), it will
    342  *   automatically release the write lock that was requested upon construction
    343  *   and also all nested write locks requested later using the #lock() call
    344  *   (note that the latter is considered to be a program logic error, see the
    345  *   #~AutoWriteLock() description for details).
    346  *   </li>
    347  * </ul>
    348  *
    349  * Note that the LockHandle class taken by AutoWriteLock constructors is an
    350  * abstract base of the read/write semaphore. You should choose one of the
    351  * existing subclasses of this abstract class or create your own subclass that
    352  * implements necessary read and write lock semantics. The most suitable choice
    353  * is the RWLockHandle class which provides full support for both read and write
    354  * locks as describerd above. Alternatively, you can use the WriteLockHandle
    355  * class if you only need write (exclusive) locking (WriteLockHandle requires
    356  * less system resources and works faster).
    357  *
    358  * A typical usage pattern of the AutoWriteLock class is as follows:
    359  * <code>
    360  *  struct Struct : public RWLockHandle
    361  *  {
    362  *      ...
    363  *  };
    364  *
    365  *  void foo (Struct &aStruct)
    366  *  {
    367  *      {
    368  *          // acquire a write lock of aStruct
    369  *          AutoWriteLock alock (aStruct);
    370  *
    371  *          // now we can modify aStruct in a thread-safe manner
    372  *          aStruct.foo = ...;
    373  *
    374  *          // note that the write lock will be automatically released upon
    375  *          // execution of the return statement below
    376  *          if (!aStruct.bar)
    377  *              return;
    378  *
    379  *          ...
    380  *      }
    381  *
    382  *      // note that the write lock is automatically released here
    383  *  }
    384  * </code>
    385  *
    386  * <b>Locking policy</b>
    387  *
    388  * When there are multiple threads and multiple objects to lock, there is always
    389  * a potential possibility to produce a deadlock if the lock order is mixed up.
    390  * Here is a classical example of a deadlock when two threads need to lock the
    391  * same two objects in a row but do it in different order:
    392  * <code>
    393  *  Thread 1:
    394  *    #1: AutoWriteLock (mFoo);
    395  *        ...
    396  *    #2: AutoWriteLock (mBar);
    397  *        ...
    398  *  Thread 2:
    399  *    #3: AutoWriteLock (mBar);
    400  *        ...
    401  *    #4: AutoWriteLock (mFoo);
    402  *        ...
    403  * </code>
    404  *
    405  * If the threads happen to be scheduled so that #3 completes after #1 has
    406  * completed but before #2 got control, the threads will hit a deadlock: Thread
    407  * 2 will be holding mBar and waiting for mFoo at #4 forever because Thread 1 is
    408  * holding mFoo and won't release it until it acquires mBar at #2 that will
    409  * never happen because mBar is held by Thread 2.
    410  *
    411  * One of ways to avoid the described behavior is to never lock more than one
    412  * obhect in a row. While it is definitely a good and safe practice, it's not
    413  * always possible: the application logic may require several simultaneous locks
    414  * in order to provide data integrity.
    415  *
    416  * One of the possibilities to solve the deadlock problem is to make sure that
    417  * the locking order is always the same across the application. In the above
    418  * example, it would mean that <b>both</b> threads should first requiest a lock
    419  * of mFoo and then mBar (or vice versa). One of the methods to guarantee the
    420  * locking order consistent is to introduce a set of locking rules. The
    421  * advantage of this method is that it doesn't require any special semaphore
    422  * implementation or additional control structures. The disadvantage is that
    423  * it's the programmer who must make sure these rules are obeyed across the
    424  * whole application so the human factor applies. Taking the simplicity of this
    425  * method into account, it is chosen to solve potential deadlock problems when
    426  * using AutoWriteLock and AutoReadLock classes. Here are the locking rules
    427  * that must be obeyed by <b>all</b> users of these classes. Note that if more
    428  * than one rule matches the given group of objects to lock, all of these rules
    429  * must be met:
    430  * <ol>
    431  *     <li>If there is a parent-child (or master-slave) relationship between the
    432  *     locked objects, parent (master) objects must be locked before child
    433  *     (slave) objects.
    434  *     </li>
    435  *     <li>When a group of equal objects (in terms of parent-child or
    436  *     master-slave relationsip) needs to be locked in a raw, the lock order
    437  *     must match the sort order (which must be consistent for the given group).
    438  * </ol>
    439  * Note that if there is no pragrammatically expressed sort order (e.g.
    440  * the objects are not part of the sorted vector or list but instead are
    441  * separate data members of a class), object class names sorted in alphabetical
    442  * order must be used to determine the lock order. If there is more than one
    443  * object of the given class, the object variable names' alphabetical order must
    444  * be used as a lock order. When objects are not represented as individual
    445  * variables, as in case of unsorted arrays/lists, the list of alphabetically
    446  * sorted object UUIDs must be used to determine the sort order.
    447  *
    448  * All non-standard locking order must be avoided by all means, but when
    449  * absolutely necessary, it must be clearly documented at relevant places so it
    450  * is well seen by other developers. For example, if a set of instances of some
    451  * class needs to be locked but these instances are not part of the sorted list
    452  * and don't have UUIDs, then the class description must state what to use to
    453  * determine the lock order (maybe some property that returns an unique value
    454  * per every object).
    455  */
    456 class AutoWriteLock
     310////////////////////////////////////////////////////////////////////////////////
     311//
     312// AutoLockBase
     313//
     314////////////////////////////////////////////////////////////////////////////////
     315
     316class AutoLockBase
     317{
     318protected:
     319    AutoLockBase(LockHandle *pHandle)
     320        : mHandle(pHandle),
     321          mLockLevel(0),
     322          mGlobalLockLevel(0)
     323    { }
     324
     325    LockHandle *mHandle;
     326    uint32_t mLockLevel;
     327    uint32_t mGlobalLockLevel;
     328};
     329
     330////////////////////////////////////////////////////////////////////////////////
     331//
     332// AutoWriteLock
     333//
     334////////////////////////////////////////////////////////////////////////////////
     335
     336class AutoWriteLock : public AutoLockBase
    457337{
    458338public:
     
    466346     * runtime.
    467347     */
    468     AutoWriteLock() : mHandle (NULL), mLockLevel (0), mGlobalLockLevel (0) {}
     348    AutoWriteLock()
     349        : AutoLockBase(NULL)
     350    { }
    469351
    470352    /**
     
    472354     * semaphore by requesting a write lock.
    473355     */
    474     AutoWriteLock (LockHandle *aHandle)
    475         : mHandle (aHandle), mLockLevel (0), mGlobalLockLevel (0)
    476     { lock(); }
     356    AutoWriteLock(LockHandle *aHandle)
     357        : AutoLockBase(aHandle)
     358    {
     359        acquire();
     360    }
    477361
    478362    /**
     
    480364     * semaphore by requesting a write lock.
    481365     */
    482     AutoWriteLock (LockHandle &aHandle)
    483         : mHandle (&aHandle), mLockLevel (0), mGlobalLockLevel (0)
    484     { lock(); }
     366    AutoWriteLock(LockHandle &aHandle)
     367        : AutoLockBase(&aHandle)
     368    {
     369        acquire();
     370    }
    485371
    486372    /**
     
    488374     * semaphore by requesting a write lock.
    489375     */
    490     AutoWriteLock (const Lockable &aLockable)
    491         : mHandle (aLockable.lockHandle()), mLockLevel (0), mGlobalLockLevel (0)
    492     { lock(); }
     376    AutoWriteLock(const Lockable &aLockable)
     377        : AutoLockBase(aLockable.lockHandle())
     378    {
     379        acquire();
     380    }
    493381
    494382    /**
     
    496384     * semaphore by requesting a write lock.
    497385     */
    498     AutoWriteLock (const Lockable *aLockable)
    499         : mHandle (aLockable ? aLockable->lockHandle() : NULL)
    500         , mLockLevel (0), mGlobalLockLevel (0)
    501     { lock(); }
     386    AutoWriteLock(const Lockable *aLockable)
     387        : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL)
     388    {
     389        acquire();
     390    }
    502391
    503392    /**
     
    518407                mGlobalLockLevel -= mLockLevel;
    519408                mLockLevel = 0;
    520                 for (; mGlobalLockLevel; -- mGlobalLockLevel)
     409                for (; mGlobalLockLevel; --mGlobalLockLevel)
    521410                    mHandle->lockWrite();
    522411            }
    523412
    524             AssertMsg (mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel));
    525             for (; mLockLevel; -- mLockLevel)
     413            AssertMsg(mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel));
     414            for (; mLockLevel; --mLockLevel)
    526415                mHandle->unlockWrite();
    527416        }
     
    535424     * otherwise returns immediately.
    536425     */
    537     void lock()
     426    void acquire()
    538427    {
    539428        if (mHandle)
    540429        {
    541430            mHandle->lockWrite();
    542             ++ mLockLevel;
    543             Assert (mLockLevel != 0 /* overflow? */);
     431            ++mLockLevel;
     432            Assert(mLockLevel != 0 /* overflow? */);
    544433        }
    545434    }
     
    551440     * available for locking by other threads.
    552441     */
    553     void unlock()
     442    void release()
    554443    {
    555444        if (mHandle)
    556445        {
    557             AssertReturnVoid (mLockLevel != 0 /* unlock() w/o preceding lock()? */);
     446            AssertReturnVoid(mLockLevel != 0 /* unlock() w/o preceding lock()? */);
    558447            mHandle->unlockWrite();
    559             -- mLockLevel;
     448            --mLockLevel;
    560449        }
    561450    }
     
    586475        if (mHandle)
    587476        {
    588             AssertReturnVoid (mLockLevel != 0 /* leave() w/o preceding lock()? */);
    589             AssertReturnVoid (mGlobalLockLevel == 0 /* second leave() in a row? */);
     477            AssertReturnVoid(mLockLevel != 0 /* leave() w/o preceding lock()? */);
     478            AssertReturnVoid(mGlobalLockLevel == 0 /* second leave() in a row? */);
    590479
    591480            mGlobalLockLevel = mHandle->writeLockLevel();
    592             AssertReturnVoid (mGlobalLockLevel >= mLockLevel /* logic error! */);
    593 
    594             for (uint32_t left = mGlobalLockLevel; left; -- left)
     481            AssertReturnVoid(mGlobalLockLevel >= mLockLevel /* logic error! */);
     482
     483            for (uint32_t left = mGlobalLockLevel; left; --left)
    595484                mHandle->unlockWrite();
    596485        }
     
    629518        if (mHandle)
    630519        {
    631             AssertReturnVoid (mLockLevel != 0 /* enter() w/o preceding lock()+leave()? */);
    632             AssertReturnVoid (mGlobalLockLevel != 0 /* enter() w/o preceding leave()? */);
    633 
    634             for (; mGlobalLockLevel; -- mGlobalLockLevel)
     520            AssertReturnVoid(mLockLevel != 0 /* enter() w/o preceding lock()+leave()? */);
     521            AssertReturnVoid(mGlobalLockLevel != 0 /* enter() w/o preceding leave()? */);
     522
     523            for (; mGlobalLockLevel; --mGlobalLockLevel)
    635524                mHandle->lockWrite();
    636525        }
     
    647536     * @param aHandle   New handle to attach.
    648537     */
    649     void attach (LockHandle *aHandle)
     538    void attach(LockHandle *aHandle)
    650539    {
    651540        /* detect simple self-reattachment */
     
    661550                    mGlobalLockLevel -= mLockLevel;
    662551                    mLockLevel = 0;
    663                     for (; mGlobalLockLevel; -- mGlobalLockLevel)
     552                    for (; mGlobalLockLevel; --mGlobalLockLevel)
    664553                        mHandle->lockWrite();
    665554                }
    666555
    667                 AssertMsg (mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel));
    668                 for (; mLockLevel; -- mLockLevel)
     556                AssertMsg(mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel));
     557                for (; mLockLevel; --mLockLevel)
    669558                    mHandle->unlockWrite();
    670559            }
     
    674563
    675564            if (mHandle)
    676                 for (; lockLevel; -- lockLevel)
     565                for (; lockLevel; --lockLevel)
    677566                    mHandle->lockWrite();
    678567        }
     
    680569
    681570    /** @see attach (LockHandle *) */
    682     void attach (LockHandle &aHandle) { attach (&aHandle); }
     571    void attach(LockHandle &aHandle)
     572    {
     573        attach(&aHandle);
     574    }
    683575
    684576    /** @see attach (LockHandle *) */
    685     void attach (const Lockable &aLockable) { attach (aLockable.lockHandle()); }
     577    void attach(const Lockable &aLockable)
     578    {
     579        attach(aLockable.lockHandle());
     580    }
    686581
    687582    /** @see attach (LockHandle *) */
    688     void attach (const Lockable *aLockable)
    689     { attach (aLockable ? aLockable->lockHandle() : NULL); }
    690 
    691     /** Verbose equivalent to <tt>attach (NULL)</tt>. */
    692     void detach() { attach ((LockHandle *) NULL); }
    693 
    694     /** Returns @c true if this instance manages a null semaphore handle. */
    695     bool isNull() const { return mHandle == NULL; }
    696     bool operator !() const { return isNull(); }
     583    void attach(const Lockable *aLockable)
     584    {
     585        attach(aLockable ? aLockable->lockHandle() : NULL);
     586    }
    697587
    698588    /**
     
    724614    }
    725615
    726     /**
    727      * Returns @c true if this instance manages the given semaphore handle.
    728      *
    729      * @note Intended for debugging only.
    730      */
    731     bool belongsTo (const LockHandle &aHandle) const { return mHandle == &aHandle; }
    732 
    733     /**
    734      * Returns @c true if this instance manages the given semaphore handle.
    735      *
    736      * @note Intended for debugging only.
    737      */
    738     bool belongsTo (const LockHandle *aHandle) const { return mHandle == aHandle; }
    739 
    740     /**
    741      * Returns @c true if this instance manages the given lockable object.
    742      *
    743      * @note Intended for debugging only.
    744      */
    745     bool belongsTo (const Lockable &aLockable)
    746     {
    747          return belongsTo (aLockable.lockHandle());
    748     }
    749 
    750     /**
    751      * Returns @c true if this instance manages the given lockable object.
    752      *
    753      * @note Intended for debugging only.
    754      */
    755     bool belongsTo (const Lockable *aLockable)
    756     {
    757          return aLockable && belongsTo (aLockable->lockHandle());
    758     }
    759 
    760616private:
    761617
     
    763619    DECLARE_CLS_NEW_DELETE_NOOP (AutoWriteLock)
    764620
    765     LockHandle *mHandle;
    766     uint32_t mLockLevel;
    767     uint32_t mGlobalLockLevel;
    768 
    769621    template <size_t> friend class AutoMultiWriteLockBase;
    770622};
    771623
    772624////////////////////////////////////////////////////////////////////////////////
    773 
    774 /**
    775  * Provides safe management of read/write semaphores in read mode.
    776  *
    777  * This class differs from the AutoWriteLock class is so that it's #lock() and
    778  * #unlock() methods requests and release read (shared) locks on the managed
    779  * read/write semaphore instead of write (exclusive) locks. See the
    780  * AutoWriteLock class description for more information about read and write
    781  * locks.
    782  *
    783  * Safe semaphore management consists of the following:
    784  * <ul>
    785  *   <li>When an instance of the AutoReadLock class is constructed given a
    786  *   valid semaphore handle, it will automatically request a read lock on that
    787  *   semaphore.
    788  *   </li>
    789  *   <li>When an instance of the AutoReadLock class constructed given a valid
    790  *   semaphore handle is destroyed (e.g. goes out of scope), it will
    791  *   automatically release the read lock that was requested upon construction
    792  *   and also all nested read locks requested later using the #lock() call (note
    793  *   that the latter is considered to be a program logic error, see the
    794  *   #~AutoReadLock() description for details).
    795  *   </li>
    796  * </ul>
    797  *
    798  * Note that the LockHandle class taken by AutoReadLock constructors is an
    799  * abstract base of the read/write semaphore. You should choose one of the
    800  * existing subclasses of this abstract class or create your own subclass that
    801  * implements necessary read and write lock semantics. The most suitable choice
    802  * is the RWLockHandle class which provides full support for both read and write
    803  * locks as describerd in AutoWriteLock docs. Alternatively, you can use the
    804  * WriteLockHandle class if you only need write (exclusive) locking
    805  * (WriteLockHandle requires less system resources and works faster).
    806  *
    807  * However, please note that it absolutely does not make sense to manage
    808  * WriteLockHandle semaphores with AutoReadLock instances because
    809  * AutoReadLock instances will behave like AutoWriteLock instances in this
    810  * case since WriteLockHandle provides only exclusive write locking. You have
    811  * been warned.
    812 
    813  * A typical usage pattern of the AutoReadLock class is as follows:
    814  * <code>
    815  *  struct Struct : public RWLockHandle
    816  *  {
    817  *      ...
    818  *  };
    819  *
    820  *  void foo (Struct &aStruct)
    821  *  {
    822  *      {
    823  *          // acquire a read lock of aStruct (note that two foo() calls may be
    824  *          executed on separate threads simultaneously w/o blocking each other)
    825  *          AutoReadLock alock (aStruct);
    826  *
    827  *          // now we can read aStruct in a thread-safe manner
    828  *          if (aStruct.foo)
    829  *              ...;
    830  *
    831  *          // note that the read lock will be automatically released upon
    832  *          // execution of the return statement below
    833  *          if (!aStruct.bar)
    834  *              return;
    835  *
    836  *          ...
    837  *      }
    838  *
    839  *      // note that the read lock is automatically released here
    840  *  }
    841  * </code>
    842  */
    843 class AutoReadLock
     625//
     626// AutoReadLock
     627//
     628////////////////////////////////////////////////////////////////////////////////
     629
     630class AutoReadLock : public AutoLockBase
    844631{
    845632public:
     
    853640     * runtime.
    854641     */
    855     AutoReadLock() : mHandle (NULL), mLockLevel (0) {}
     642    AutoReadLock()
     643        : AutoLockBase(NULL)
     644    { }
    856645
    857646    /**
     
    859648     * semaphore by requesting a read lock.
    860649     */
    861     AutoReadLock (LockHandle *aHandle)
    862         : mHandle (aHandle), mLockLevel (0)
    863     { lock(); }
     650    AutoReadLock(LockHandle *aHandle)
     651        : AutoLockBase(aHandle)
     652    {
     653        acquire();
     654    }
    864655
    865656    /**
     
    867658     * semaphore by requesting a read lock.
    868659     */
    869     AutoReadLock (LockHandle &aHandle)
    870         : mHandle (&aHandle), mLockLevel (0)
    871     { lock(); }
     660    AutoReadLock(LockHandle &aHandle)
     661        : AutoLockBase(&aHandle)
     662    {
     663        acquire();
     664    }
    872665
    873666    /**
     
    875668     * semaphore by requesting a read lock.
    876669     */
    877     AutoReadLock (const Lockable &aLockable)
    878         : mHandle (aLockable.lockHandle()), mLockLevel (0)
    879     { lock(); }
     670    AutoReadLock(const Lockable &aLockable)
     671        : AutoLockBase(aLockable.lockHandle())
     672    {
     673        acquire();
     674    }
    880675
    881676    /**
     
    883678     * semaphore by requesting a read lock.
    884679     */
    885     AutoReadLock (const Lockable *aLockable)
    886         : mHandle (aLockable ? aLockable->lockHandle() : NULL)
    887         , mLockLevel (0)
    888     { lock(); }
     680    AutoReadLock(const Lockable *aLockable)
     681        : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL)
     682    {
     683        acquire();
     684    }
    889685
    890686    /**
     
    901697        if (mHandle)
    902698        {
    903             AssertMsg (mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel));
    904             for (; mLockLevel; -- mLockLevel)
     699            AssertMsg(mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel));
     700            for (; mLockLevel; --mLockLevel)
    905701                mHandle->unlockRead();
    906702        }
     
    919715     * allows for read locks nested into write locks on the same thread.
    920716     */
    921     void lock()
     717    void acquire()
    922718    {
    923719        if (mHandle)
    924720        {
    925721            mHandle->lockRead();
    926             ++ mLockLevel;
    927             Assert (mLockLevel != 0 /* overflow? */);
     722            ++mLockLevel;
     723            Assert(mLockLevel != 0 /* overflow? */);
    928724        }
    929725    }
     
    935731     * available for locking by other threads.
    936732     */
    937     void unlock()
     733    void release()
    938734    {
    939735        if (mHandle)
    940736        {
    941             AssertReturnVoid (mLockLevel != 0 /* unlock() w/o preceding lock()? */);
     737            AssertReturnVoid(mLockLevel != 0 /* unlock() w/o preceding lock()? */);
    942738            mHandle->unlockRead();
    943             -- mLockLevel;
     739            --mLockLevel;
    944740        }
    945741    }
     
    955751     * @param aHandle   New handle to attach.
    956752     */
    957     void attach (LockHandle *aHandle)
     753    void attach(LockHandle *aHandle)
    958754    {
    959755        /* detect simple self-reattachment */
     
    962758            uint32_t lockLevel = mLockLevel;
    963759            if (mHandle)
    964                 for (; mLockLevel; -- mLockLevel)
     760                for (; mLockLevel; --mLockLevel)
    965761                    mHandle->unlockRead();
    966762            mHandle = aHandle;
    967763            mLockLevel = lockLevel;
    968764            if (mHandle)
    969                 for (; lockLevel; -- lockLevel)
     765                for (; lockLevel; --lockLevel)
    970766                    mHandle->lockRead();
    971767        }
     
    973769
    974770    /** @see attach (LockHandle *) */
    975     void attach (LockHandle &aHandle) { attach (&aHandle); }
     771    void attach(LockHandle &aHandle)
     772    {
     773        attach(&aHandle);
     774    }
    976775
    977776    /** @see attach (LockHandle *) */
    978     void attach (const Lockable &aLockable) { attach (aLockable.lockHandle()); }
     777    void attach(const Lockable &aLockable)
     778    {
     779        attach(aLockable.lockHandle());
     780    }
    979781
    980782    /** @see attach (LockHandle *) */
    981     void attach (const Lockable *aLockable)
    982     { attach (aLockable ? aLockable->lockHandle() : NULL); }
    983 
    984     /** Verbose equivalent to <tt>attach (NULL)</tt>. */
    985     void detach() { attach ((LockHandle *) NULL); }
    986 
    987     /** Returns @c true if this instance manages a null semaphore handle. */
    988     bool isNull() const { return mHandle == NULL; }
    989     bool operator !() const { return isNull(); }
    990 
    991     /**
    992      * Returns @c true if this instance manages the given semaphore handle.
    993      *
    994      * @note Intended for debugging only.
    995      */
    996     bool belongsTo (const LockHandle &aHandle) const { return mHandle == &aHandle; }
    997 
    998     /**
    999      * Returns @c true if this instance manages the given semaphore handle.
    1000      *
    1001      * @note Intended for debugging only.
    1002      */
    1003     bool belongsTo (const LockHandle *aHandle) const { return mHandle == aHandle; }
    1004 
    1005     /**
    1006      * Returns @c true if this instance manages the given lockable object.
    1007      *
    1008      * @note Intended for debugging only.
    1009      */
    1010     bool belongsTo (const Lockable &aLockable)
    1011     {
    1012          return belongsTo (aLockable.lockHandle());
    1013     }
    1014 
    1015     /**
    1016      * Returns @c true if this instance manages the given lockable object.
    1017      *
    1018      * @note Intended for debugging only.
    1019      */
    1020     bool belongsTo (const Lockable *aLockable)
    1021     {
    1022          return aLockable && belongsTo (aLockable->lockHandle());
     783    void attach(const Lockable *aLockable)
     784    {
     785        attach(aLockable ? aLockable->lockHandle() : NULL);
    1023786    }
    1024787
     
    1027790    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoReadLock)
    1028791    DECLARE_CLS_NEW_DELETE_NOOP (AutoReadLock)
    1029 
    1030     LockHandle *mHandle;
    1031     uint32_t mLockLevel;
    1032 };
    1033 
     792};
     793
     794////////////////////////////////////////////////////////////////////////////////
     795//
     796// AutoMulti*
     797//
    1034798////////////////////////////////////////////////////////////////////////////////
    1035799
     
    1189953class AutoMultiWriteLockBase
    1190954{
    1191 public:
    1192 
    1193     /**
    1194      * Calls AutoWriteLock::lock() methods for all managed semaphore handles in
     955
     956public:
     957    /**
     958     * Calls AutoWriteLock::acquire() methods for all managed semaphore handles in
    1195959     * order they were passed to the constructor.
    1196960     */
    1197     void lock()
     961    void acquire()
    1198962    {
    1199963        size_t i = 0;
    1200         while (i < RT_ELEMENTS (mLocks))
    1201             mLocks [i ++].lock();
     964        while (i < RT_ELEMENTS(mLocks))
     965            mLocks[i++].acquire();
    1202966    }
    1203967
     
    1206970     * in reverse to the order they were passed to the constructor.
    1207971     */
    1208     void unlock()
    1209     {
    1210         AssertReturnVoid (RT_ELEMENTS (mLocks) > 0);
    1211         size_t i = RT_ELEMENTS (mLocks);
     972    void release()
     973    {
     974        AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);
     975        size_t i = RT_ELEMENTS(mLocks);
    1212976        do
    1213             mLocks [-- i].unlock();
     977            mLocks[--i].release();
    1214978        while (i != 0);
    1215979    }
     
    1221985    void leave()
    1222986    {
    1223         AssertReturnVoid (RT_ELEMENTS (mLocks) > 0);
    1224         size_t i = RT_ELEMENTS (mLocks);
     987        AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);
     988        size_t i = RT_ELEMENTS(mLocks);
    1225989        do
    1226             mLocks [-- i].leave();
     990            mLocks[--i].leave();
    1227991        while (i != 0);
    1228992    }
     
    1234998    void maybeLeave()
    1235999    {
    1236         AssertReturnVoid (RT_ELEMENTS (mLocks) > 0);
    1237         size_t i = RT_ELEMENTS (mLocks);
     1000        AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);
     1001        size_t i = RT_ELEMENTS(mLocks);
    12381002        do
    12391003            mLocks [-- i].maybeLeave();
     
    12481012    {
    12491013        size_t i = 0;
    1250         while (i < RT_ELEMENTS (mLocks))
    1251             mLocks [i ++].maybeEnter();
     1014        while (i < RT_ELEMENTS(mLocks))
     1015            mLocks[i++].maybeEnter();
    12521016    }
    12531017
     
    12591023    {
    12601024        size_t i = 0;
    1261         while (i < RT_ELEMENTS (mLocks))
    1262             mLocks [i ++].enter();
     1025        while (i < RT_ELEMENTS(mLocks))
     1026            mLocks[i++].enter();
    12631027    }
    12641028
     
    13381102public:
    13391103    AutoMultiWriteLock2 (A(0), A(1))
    1340     { B(0); B(1); lock(); }
     1104    { B(0); B(1); acquire(); }
    13411105    AutoMultiWriteLock2 (C(0), C(1))
    1342     { D(0); D(1); lock(); }
     1106    { D(0); D(1); acquire(); }
    13431107};
    13441108
     
    13481112public:
    13491113    AutoMultiWriteLock3 (A(0), A(1), A(2))
    1350     { B(0); B(1); B(2); lock(); }
     1114    { B(0); B(1); B(2); acquire(); }
    13511115    AutoMultiWriteLock3 (C(0), C(1), C(2))
    1352     { D(0); D(1); D(2); lock(); }
     1116    { D(0); D(1); D(2); acquire(); }
    13531117};
    13541118
     
    13581122public:
    13591123    AutoMultiWriteLock4 (A(0), A(1), A(2), A(3))
    1360     { B(0); B(1); B(2); B(3); lock(); }
     1124    { B(0); B(1); B(2); B(3); acquire(); }
    13611125    AutoMultiWriteLock4 (C(0), C(1), C(2), C(3))
    1362     { D(0); D(1); D(2); D(3); lock(); }
     1126    { D(0); D(1); D(2); D(3); acquire(); }
    13631127};
    13641128
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