Index: /trunk/src/VBox/Main/AudioAdapterImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/AudioAdapterImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/AudioAdapterImpl.cpp	(revision 7992)
@@ -569,9 +569,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
-    AssertComRCReturnVoid (thatCaller.rc());
-
-    /* lock both for writing since we modify both */
-    AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer));
+    AutoCaller peerCaller (mPeer);
+    AssertComRCReturnVoid (peerCaller.rc());
+
+    /* lock both for writing since we modify both (mPeer is "master" so locked
+     * first) */
+    AutoMultiWriteLock2 alock (mPeer, this);
 
     if (mData.isBackedUp())
@@ -599,9 +600,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
+    AutoCaller thatCaller (aThat);
     AssertComRCReturnVoid (thatCaller.rc());
 
-    /* peer is not modified, lock it for reading */
-    AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
+    /* peer is not modified, lock it for reading (aThat is "master" so locked
+     * first) */
+    AutoMultiLock2 alock (aThat->rlock(), this->wlock());
 
     /* this will back up current data */
Index: /trunk/src/VBox/Main/AutoLock.cpp
===================================================================
--- /trunk/src/VBox/Main/AutoLock.cpp	(revision 7992)
+++ /trunk/src/VBox/Main/AutoLock.cpp	(revision 7992)
@@ -0,0 +1,186 @@
+/** @file
+ *
+ * AutoLock: smart critical section wrapper
+ */
+
+/*
+ * Copyright (C) 2006-2008 innotek GmbH
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "AutoLock.h"
+
+#include "Logging.h"
+
+namespace util
+{
+
+RWLockHandle::RWLockHandle()
+{
+    RTCritSectInit (&mCritSect);
+    RTSemEventCreate (&mGoWriteSem);
+    RTSemEventMultiCreate (&mGoReadSem);
+
+    mWriteLockThread = NIL_RTTHREAD;
+
+    mReadLockCount = 0;
+    mWriteLockLevel = 0;
+    mWriteLockPending = 0;
+}
+
+RWLockHandle::~RWLockHandle()
+{
+    RTSemEventMultiDestroy (mGoReadSem);
+    RTSemEventDestroy (mGoWriteSem);
+    RTCritSectDelete (&mCritSect);
+}
+
+bool RWLockHandle::isLockedOnCurrentThread() const
+{
+    RTCritSectEnter (&mCritSect);
+    bool locked = mWriteLockThread == RTThreadSelf();
+    RTCritSectLeave (&mCritSect);
+    return locked;
+}
+
+void RWLockHandle::lockWrite()
+{
+    RTCritSectEnter (&mCritSect);
+
+    if (mWriteLockThread != RTThreadSelf())
+    {
+        if (mReadLockCount != 0 || mWriteLockThread != NIL_RTTHREAD)
+        {
+            /* wait until all read locks or another write lock is released */
+            ++ mWriteLockPending;
+            Assert (mWriteLockPending != 0 /* pending writer overflow? */);
+            RTCritSectLeave (&mCritSect);
+            RTSemEventWait (mGoWriteSem, RT_INDEFINITE_WAIT);
+            RTCritSectEnter (&mCritSect);
+            -- mWriteLockPending;
+        }
+
+        Assert (mWriteLockThread == NIL_RTTHREAD);
+        mWriteLockThread = RTThreadSelf();
+    }
+
+    ++ mWriteLockLevel;
+    Assert (mWriteLockLevel != 0 /* overflow */);
+
+    RTCritSectLeave (&mCritSect);
+}
+
+void RWLockHandle::unlockWrite()
+{
+    RTCritSectEnter (&mCritSect);
+
+    Assert (mWriteLockLevel != 0 /* unlockWrite() w/o preceding lockWrite()? */);
+    if (mWriteLockLevel != 0)
+    {
+        -- mWriteLockLevel;
+        if (mWriteLockLevel == 0)
+        {
+            mWriteLockThread = NIL_RTTHREAD;
+
+            /* no write locks, let writers go if there are any (top priority),
+             * otherwise let readers go if there are any */
+            if (mWriteLockPending != 0)
+                RTSemEventSignal (mGoWriteSem);
+            else if (mReadLockCount != 0)
+                RTSemEventMultiSignal (mGoReadSem);
+        }
+    }
+
+    RTCritSectLeave (&mCritSect);
+}
+
+void RWLockHandle::lockRead()
+{
+    RTCritSectEnter (&mCritSect);
+
+    ++ mReadLockCount;
+    Assert (mReadLockCount != 0 /* read lock overflow? */);
+
+    bool isWriteLock = mWriteLockLevel != 0;
+    bool isFirstReadLock = mReadLockCount == 1;
+
+    if (isWriteLock && mWriteLockThread == RTThreadSelf())
+    {
+        /* read lock nested into the write lock, cause return immediately */
+        isWriteLock = false;
+    }
+    else
+    {
+        if (!isWriteLock)
+        {
+            /* write locks are top priority, so let them go if they are
+             * pending */
+            if (mWriteLockPending != 0)
+            {
+                isWriteLock = true;
+                /* the first postponed reader kicks pending writers */
+                if (isFirstReadLock)
+                    RTSemEventSignal (mGoWriteSem);
+            }
+        }
+
+        /* the first waiting reader resets the semaphore before letting it be
+         * posted (i.e. before leaving the critical section) */
+        if (isWriteLock && isFirstReadLock)
+            RTSemEventMultiReset (mGoReadSem);
+    }
+
+    RTCritSectLeave (&mCritSect);
+
+    /* wait until the write lock is released */
+    if (isWriteLock)
+        RTSemEventMultiWait (mGoReadSem, RT_INDEFINITE_WAIT);
+}
+
+void RWLockHandle::unlockRead()
+{
+    RTCritSectEnter (&mCritSect);
+
+    Assert (mReadLockCount != 0 /* unlockRead() w/o preceding lockRead()? */);
+    if (mReadLockCount != 0)
+    {
+        if (mWriteLockLevel != 0)
+        {
+            /* read unlock nested into the write lock, just decrease the
+             * counter */
+            Assert (mWriteLockThread == RTThreadSelf()
+                    /* unlockRead() after lockWrite()? */);
+            if (mWriteLockThread == RTThreadSelf())
+                -- mReadLockCount;
+        }
+        else
+        {
+            -- mReadLockCount;
+            if (mReadLockCount == 0)
+            {
+                /* no read locks, let writers go if there are any */
+                if (mWriteLockPending != 0)
+                    RTSemEventSignal (mGoWriteSem);
+            }
+        }
+    }
+
+    RTCritSectLeave (&mCritSect);
+}
+
+uint32_t RWLockHandle::writeLockLevel() const
+{
+    Assert (mWriteLockLevel != 0);
+
+    return mWriteLockLevel;
+}
+
+} /* namespace util */
+
Index: /trunk/src/VBox/Main/ConsoleImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/ConsoleImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/ConsoleImpl.cpp	(revision 7992)
@@ -2491,7 +2491,7 @@
 
 /**
- *  Called by IInternalSessionControl::OnDVDDriveChange().
- *
- *  @note Locks this object for reading.
+ * Called by IInternalSessionControl::OnDVDDriveChange().
+ *
+ * @note Locks this object for writing.
  */
 HRESULT Console::onDVDDriveChange()
@@ -2502,5 +2502,6 @@
     AssertComRCReturnRC (autoCaller.rc());
 
-    AutoReaderLock alock (this);
+    /* doDriveChange() needs a write lock */
+    AutoLock alock (this);
 
     /* Ignore callbacks when there's no VM around */
@@ -2587,7 +2588,7 @@
 
 /**
- *  Called by IInternalSessionControl::OnFloppyDriveChange().
- *
- *  @note Locks this object for reading.
+ * Called by IInternalSessionControl::OnFloppyDriveChange().
+ *
+ * @note Locks this object for writing.
  */
 HRESULT Console::onFloppyDriveChange()
@@ -2598,5 +2599,6 @@
     AssertComRCReturnRC (autoCaller.rc());
 
-    AutoReaderLock alock (this);
+    /* doDriveChange() needs a write lock */
+    AutoLock alock (this);
 
     /* Ignore callbacks when there's no VM around */
@@ -2704,5 +2706,5 @@
  * @param   fPassthrough    Enables using passthrough mode of the host DVD drive if applicable.
  *
- * @note Locks this object for reading.
+ * @note Locks this object for writing.
  */
 HRESULT Console::doDriveChange (const char *pszDevice, unsigned uInstance, unsigned uLun, DriveState_T eState,
@@ -2717,5 +2719,6 @@
     AssertComRCReturnRC (autoCaller.rc());
 
-    AutoReaderLock alock (this);
+    /* We will need to release the write lock before calling EMT */
+    AutoLock alock (this);
 
     /* protect mpVM */
@@ -2784,5 +2787,5 @@
  *
  * @thread  EMT
- * @note Locks the Console object for writing
+ * @note Locks the Console object for writing.
  */
 DECLCALLBACK(int) Console::changeDrive (Console *pThis, const char *pszDevice, unsigned uInstance, unsigned uLun,
@@ -2805,7 +2808,7 @@
 
     /*
-     *  Locking the object before doing VMR3* calls is quite safe here,
-     *  since we're on EMT. Write lock is necessary because we're indirectly
-     *  modify the meDVDState/meFloppyState members (pointed to by peState).
+     * Locking the object before doing VMR3* calls is quite safe here, since
+     * we're on EMT. Write lock is necessary because we indirectly modify the
+     * meDVDState/meFloppyState members (pointed to by peState).
      */
     AutoLock alock (pThis);
Index: /trunk/src/VBox/Main/DVDDriveImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/DVDDriveImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/DVDDriveImpl.cpp	(revision 7992)
@@ -351,11 +351,11 @@
 ////////////////////////////////////////////////////////////////////////////////
 
-/** 
+/**
  *  Loads settings from the given machine node.
  *  May be called once right after this object creation.
- * 
+ *
  *  @param aMachineNode <Machine> node.
- * 
- *  @note Locks this object for writing. 
+ *
+ *  @note Locks this object for writing.
  */
 HRESULT DVDDrive::loadSettings (const settings::Key &aMachineNode)
@@ -379,5 +379,5 @@
      * place when a setting of a newly created object must default to A while
      * the same setting of an object loaded from the old settings file must
-     * default to B. */ 
+     * default to B. */
 
     HRESULT rc = S_OK;
@@ -435,10 +435,10 @@
 }
 
-/** 
+/**
  *  Saves settings to the given machine node.
- * 
+ *
  *  @param aMachineNode <Machine> node.
- * 
- *  @note Locks this object for reading. 
+ *
+ *  @note Locks this object for reading.
  */
 HRESULT DVDDrive::saveSettings (settings::Key &aMachineNode)
@@ -497,5 +497,5 @@
 }
 
-/** 
+/**
  *  @note Locks this object for writing.
  */
@@ -521,5 +521,5 @@
 }
 
-/** 
+/**
  *  @note Locks this object for writing, together with the peer object (also
  *  for writing) if there is one.
@@ -532,9 +532,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
-    AssertComRCReturnVoid (thatCaller.rc());
-
-    /* lock both for writing since we modify both */
-    AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer));
+    AutoCaller peerCaller (mPeer);
+    AssertComRCReturnVoid (peerCaller.rc());
+
+    /* lock both for writing since we modify both (mPeer is "master" so locked
+     * first) */
+    AutoMultiWriteLock2 alock (mPeer, this);
 
     if (mData.isBackedUp())
@@ -549,5 +550,5 @@
 }
 
-/** 
+/**
  *  @note Locks this object for writing, together with the peer object
  *  represented by @a aThat (locked for reading).
@@ -562,9 +563,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
+    AutoCaller thatCaller (aThat);
     AssertComRCReturnVoid (thatCaller.rc());
 
-    /* peer is not modified, lock it for reading */
-    AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
+    /* peer is not modified, lock it for reading (aThat is "master" so locked
+     * first) */
+    AutoMultiLock2 alock (aThat->rlock(), this->wlock());
 
     /* this will back up current data */
Index: /trunk/src/VBox/Main/FloppyDriveImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/FloppyDriveImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/FloppyDriveImpl.cpp	(revision 7992)
@@ -358,11 +358,11 @@
 /////////////////////////////////////////////////////////////////////////////
 
-/** 
+/**
  *  Loads settings from the given machine node.
  *  May be called once right after this object creation.
- * 
+ *
  *  @param aMachineNode <Machine> node.
- * 
- *  @note Locks this object for writing. 
+ *
+ *  @note Locks this object for writing.
  */
 HRESULT FloppyDrive::loadSettings (const settings::Key &aMachineNode)
@@ -386,5 +386,5 @@
      * place when a setting of a newly created object must default to A while
      * the same setting of an object loaded from the old settings file must
-     * default to B. */ 
+     * default to B. */
 
     HRESULT rc = S_OK;
@@ -442,10 +442,10 @@
 }
 
-/** 
+/**
  *  Saves settings to the given machine node.
- * 
+ *
  *  @param aMachineNode <Machine> node.
- * 
- *  @note Locks this object for reading. 
+ *
+ *  @note Locks this object for reading.
  */
 HRESULT FloppyDrive::saveSettings (settings::Key &aMachineNode)
@@ -504,5 +504,5 @@
 }
 
-/** 
+/**
  *  @note Locks this object for writing.
  */
@@ -528,5 +528,5 @@
 }
 
-/** 
+/**
  *  @note Locks this object for writing, together with the peer object (also
  *  for writing) if there is one.
@@ -539,9 +539,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
-    AssertComRCReturnVoid (thatCaller.rc());
-
-    /* lock both for writing since we modify both */
-    AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer));
+    AutoCaller peerCaller (mPeer);
+    AssertComRCReturnVoid (peerCaller.rc());
+
+    /* lock both for writing since we modify both (mPeer is "master" so locked
+     * first) */
+    AutoMultiWriteLock2 alock (mPeer, this);
 
     if (mData.isBackedUp())
@@ -556,5 +557,5 @@
 }
 
-/** 
+/**
  *  @note Locks this object for writing, together with the peer object (locked
  *  for reading) if there is one.
@@ -567,9 +568,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
+    AutoCaller thatCaller (aThat);
     AssertComRCReturnVoid (thatCaller.rc());
 
-    /* peer is not modified, lock it for reading */
-    AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeRlock (mPeer));
+    /* peer is not modified, lock it for reading (aThat is "master" so locked
+     * first) */
+    AutoMultiLock2 alock (aThat->rlock(), this->wlock());
 
     /* this will back up current data */
Index: /trunk/src/VBox/Main/HardDiskImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/HardDiskImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/HardDiskImpl.cpp	(revision 7992)
@@ -196,5 +196,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -208,5 +208,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -220,5 +220,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -232,5 +232,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -274,5 +274,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -286,8 +286,8 @@
         return E_POINTER;
 
-    AutoLock lock(this);
-    CHECK_READY();
-
-    AutoLock chLock (childrenLock());
+    AutoReaderLock lock(this);
+    CHECK_READY();
+
+    AutoReaderLock chLock (childrenLock());
 
     ComObjPtr <HardDiskCollection> collection;
@@ -303,5 +303,5 @@
         return E_POINTER;
 
-    AutoLock lock(this);
+    AutoReaderLock lock(this);
     CHECK_READY();
 
@@ -368,5 +368,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -380,5 +380,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -392,5 +392,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -600,5 +600,5 @@
                                      bool aCheckReaders /* = false */)
 {
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -636,5 +636,5 @@
 bool HardDisk::sameAs (HardDisk *that)
 {
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     if (!isReady())
         return false;
@@ -744,5 +744,5 @@
 bool HardDisk::hasForeignChildren()
 {
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     AssertReturn (isReady(), false);
 
@@ -750,5 +750,5 @@
 
     /* check all children */
-    AutoLock chLock (childrenLock());
+    AutoReaderLock chLock (childrenLock());
     for (HardDiskList::const_iterator it = children().begin();
          it != children().end();
@@ -756,5 +756,5 @@
     {
         ComObjPtr <HardDisk> child = *it;
-        AutoLock childLock (child);
+        AutoReaderLock childLock (child);
         if (child->mMachineId != mMachineId)
             return true;
@@ -779,5 +779,5 @@
         return setError (E_FAIL, errMsg, toString().raw());
 
-    AutoLock chLock (childrenLock());
+    AutoReaderLock chLock (childrenLock());
 
     for (HardDiskList::const_iterator it = children().begin();
@@ -814,5 +814,5 @@
     AssertReturn (mBusy == true, (void) 0);
 
-    AutoLock chLock (childrenLock());
+    AutoReaderLock chLock (childrenLock());
 
     for (HardDiskList::const_iterator it = children().begin();
@@ -831,7 +831,10 @@
 /**
  *  Checks that this hard disk and all its direct children are accessible.
+ *
+ *  @note Locks this object for writing.
  */
 HRESULT HardDisk::getAccessibleWithChildren (Bstr &aAccessError)
 {
+    /* getAccessible() needs a write lock */
     AutoLock alock (this);
     AssertReturn (isReady(), E_FAIL);
@@ -841,5 +844,5 @@
         return rc;
 
-    AutoLock chLock (childrenLock());
+    AutoReaderLock chLock (childrenLock());
 
     for (HardDiskList::const_iterator it = children().begin();
@@ -869,5 +872,5 @@
 HRESULT HardDisk::checkConsistency()
 {
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     AssertReturn (isReady(), E_FAIL);
 
@@ -886,5 +889,5 @@
     HRESULT rc = S_OK;
 
-    AutoLock chLock (childrenLock());
+    AutoReaderLock chLock (childrenLock());
 
     if (mParent.isNull() && mType == HardDiskType_Normal &&
@@ -1022,5 +1025,5 @@
 
     /* update paths of all children */
-    AutoLock chLock (childrenLock());
+    AutoReaderLock chLock (childrenLock());
     for (HardDiskList::const_iterator it = children().begin();
          it != children().end();
@@ -1262,5 +1265,5 @@
  *
  *  @note
- *      Must be called from under the object's lock
+ *      Must be called from under the object's read lock
  */
 HRESULT HardDisk::saveSettings (settings::Key &aHDNode)
@@ -1293,5 +1296,5 @@
 
     /* save all children */
-    AutoLock chLock (childrenLock());
+    AutoReaderLock chLock (childrenLock());
     for (HardDiskList::const_iterator it = children().begin();
          it != children().end();
@@ -1299,5 +1302,5 @@
     {
         ComObjPtr <HardDisk> child = *it;
-        AutoLock childLock (child);
+        AutoReaderLock childLock (child);
 
         Key hdNode = aHDNode.appendKey ("DiffHardDisk");
@@ -1506,5 +1509,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -1539,5 +1542,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -1555,5 +1558,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -1570,5 +1573,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -1612,5 +1615,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -1708,7 +1711,10 @@
  *                      accessible, otherwise contains a message describing
  *                      the reason of inaccessibility.
+ *
+ *  @note Locks this object for writing.
  */
 HRESULT HVirtualDiskImage::getAccessible (Bstr &aAccessError)
 {
+    /* queryInformation() needs a write lock */
     AutoLock alock (this);
     CHECK_READY();
@@ -1767,5 +1773,5 @@
     AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -1822,8 +1828,10 @@
  *
  *  @param aShort       if true, a short representation is returned
+ *
+ *  @note Locks this object for reading.
  */
 Bstr HVirtualDiskImage::toString (bool aShort /* = false */)
 {
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
 
     if (!aShort)
@@ -2119,5 +2127,5 @@
         HRESULT rc = S_OK;
 
-        AutoLock chLock (childrenLock());
+        AutoReaderLock chLock (childrenLock());
 
         for (HardDiskList::const_iterator it = children().begin();
@@ -2388,5 +2396,5 @@
  *  @param aAccessError not used when NULL, otherwise see #getAccessible()
  *
- *  @note Must be called from under the object's lock, only after
+ *  @note Must be called from under the object's write lock, only after
  *        CHECK_BUSY_AND_READERS() succeeds.
  */
@@ -2956,5 +2964,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -2985,5 +2993,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -2997,5 +3005,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3012,5 +3020,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3044,5 +3052,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3073,5 +3081,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3105,5 +3113,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3134,5 +3142,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3163,5 +3171,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3214,7 +3222,10 @@
 /**
  *  Checks accessibility of this iSCSI hard disk.
+ *
+ *  @note Locks this object for writing.
  */
 HRESULT HISCSIHardDisk::getAccessible (Bstr &aAccessError)
 {
+   /* queryInformation() needs a write lock */
     AutoLock alock (this);
     CHECK_READY();
@@ -3240,5 +3251,5 @@
     AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3267,8 +3278,10 @@
  *
  *  @param aShort       if true, a short representation is returned
+ *
+ *  @note Locks this object for reading.
  */
 Bstr HISCSIHardDisk::toString (bool aShort /* = false */)
 {
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
 
     Bstr str;
@@ -3346,9 +3359,15 @@
  *
  *  @param aAccessError see #getAccessible()
- *  @note
- *      Must be called from under the object's lock!
+ *
+ *  @note Must be called from under the object's write lock, only after
+ *        CHECK_BUSY_AND_READERS() succeeds.
  */
 HRESULT HISCSIHardDisk::queryInformation (Bstr &aAccessError)
 {
+    AssertReturn (isLockedOnCurrentThread(), E_FAIL);
+
+    /* create a lock object to completely release it later */
+    AutoLock alock (this);
+
     /// @todo (dmik) query info about this iSCSI disk,
     //  set mSize and mActualSize,
@@ -3572,5 +3591,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3609,5 +3628,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3627,5 +3646,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3642,5 +3661,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3684,5 +3703,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3792,7 +3811,10 @@
  *                      accessible, otherwise contains a message describing
  *                      the reason of inaccessibility.
+ *
+ *  @note Locks this object for writing.
  */
 HRESULT HVMDKImage::getAccessible (Bstr &aAccessError)
 {
+   /* queryInformation() needs a write lock */
     AutoLock alock (this);
     CHECK_READY();
@@ -3851,5 +3873,5 @@
     AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -3906,8 +3928,10 @@
  *
  *  @param aShort       if true, a short representation is returned
+ *
+ *  @note Locks this object for reading.
  */
 Bstr HVMDKImage::toString (bool aShort /* = false */)
 {
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
 
     if (!aShort)
@@ -4482,5 +4506,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -4504,5 +4528,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -4516,5 +4540,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -4531,5 +4555,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -4577,5 +4601,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -4589,5 +4613,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -4665,7 +4689,10 @@
  *                      accessible, otherwise contains a message describing
  *                      the reason of inaccessibility.
+ *
+ *  @note Locks this object for writing.
  */
 HRESULT HCustomHardDisk::getAccessible (Bstr &aAccessError)
 {
+   /* queryInformation() needs a write lock */
     AutoLock alock (this);
     CHECK_READY();
@@ -4724,5 +4751,5 @@
     AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -4743,8 +4770,10 @@
  *
  *  @param aShort       if true, a short representation is returned
+ *
+ *  @note Locks this object for reading.
  */
 Bstr HCustomHardDisk::toString (bool aShort /* = false */)
 {
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
 
     /// @todo currently, we assume that location is always a file path for
@@ -5270,5 +5299,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -5307,5 +5336,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -5325,5 +5354,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -5340,5 +5369,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -5382,5 +5411,5 @@
         return E_POINTER;
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -5490,7 +5519,10 @@
  *                      accessible, otherwise contains a message describing
  *                      the reason of inaccessibility.
+ *
+ *  @note Locks this object for writing.
  */
 HRESULT HVHDImage::getAccessible (Bstr &aAccessError)
 {
+    /* queryInformation() needs a write lock */
     AutoLock alock (this);
     CHECK_READY();
@@ -5548,5 +5580,5 @@
     AssertReturn (!aHDNode.isNull() && !aStorageNode.isNull(), E_FAIL);
 
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
     CHECK_READY();
 
@@ -5603,8 +5635,10 @@
  *
  *  @param aShort       if true, a short representation is returned
+ *
+ *  @note Locks this object for reading.
  */
 Bstr HVHDImage::toString (bool aShort /* = false */)
 {
-    AutoLock alock (this);
+    AutoReaderLock alock (this);
 
     if (!aShort)
Index: /trunk/src/VBox/Main/MachineImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/MachineImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/MachineImpl.cpp	(revision 7992)
@@ -123,6 +123,6 @@
 
     mMachineStateDeps = 0;
-    mZeroMachineStateDepsSem = NIL_RTSEMEVENT;
-    mWaitingStateDeps = FALSE;
+    mMachineStateDepsSem = NIL_RTSEMEVENTMULTI;
+    mMachineStateChangePending = 0;
 
     mCurrentStateModified = TRUE;
@@ -135,8 +135,8 @@
 Machine::Data::~Data()
 {
-    if (mZeroMachineStateDepsSem != NIL_RTSEMEVENT)
-    {
-        RTSemEventDestroy (mZeroMachineStateDepsSem);
-        mZeroMachineStateDepsSem = NIL_RTSEMEVENT;
+    if (mMachineStateDepsSem != NIL_RTSEMEVENTMULTI)
+    {
+        RTSemEventMultiDestroy (mMachineStateDepsSem);
+        mMachineStateDepsSem = NIL_RTSEMEVENTMULTI;
     }
 }
@@ -612,27 +612,25 @@
     LogFlowThisFunc (("mRegistered=%d\n", mData->mRegistered));
 
-    /*
-     *  Enter this object's lock because there may be a SessionMachine instance
-     *  somewhere around, that shares our data and lock but doesn't use our
-     *  addCaller()/removeCaller(), and it may be also accessing the same
-     *  data members. mParent lock is necessary as well because of
-     *  SessionMachine::uninit(), etc.
+    /* Enter this object lock because there may be a SessionMachine instance
+     * somewhere around, that shares our data and lock but doesn't use our
+     * addCaller()/removeCaller(), and it may be also accessing the same data
+     * members. mParent lock is necessary as well because of
+     * SessionMachine::uninit(), etc.
      */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     if (!mData->mSession.mMachine.isNull())
     {
-        /*
-         *  Theoretically, this can only happen if the VirtualBox server has
-         *  been terminated while there were clients running that owned open
-         *  direct sessions. Since in this case we are definitely called by
-         *  VirtualBox::uninit(), we may be sure that SessionMachine::uninit()
-         *  won't happen on the client watcher thread (because it does
-         *  VirtualBox::addCaller() for the duration of the
-         *  SessionMachine::checkForDeath() call, so that VirtualBox::uninit()
-         *  cannot happen until the VirtualBox caller is released). This is
-         *  important, because SessionMachine::uninit() cannot correctly operate
-         *  after we return from this method (it expects the Machine instance
-         *  is still valid). We'll call it ourselves below.
+        /* Theoretically, this can only happen if the VirtualBox server has been
+         * terminated while there were clients running that owned open direct
+         * sessions. Since in this case we are definitely called by
+         * VirtualBox::uninit(), we may be sure that SessionMachine::uninit()
+         * won't happen on the client watcher thread (because it does
+         * VirtualBox::addCaller() for the duration of the
+         * SessionMachine::checkForDeath() call, so that VirtualBox::uninit()
+         * cannot happen until the VirtualBox caller is released). This is
+         * important, because SessionMachine::uninit() cannot correctly operate
+         * after we return from this method (it expects the Machine instance is
+         * still valid). We'll call it ourselves below.
          */
         LogWarningThisFunc (("Session machine is not NULL (%p), "
@@ -1672,5 +1670,5 @@
 
     /* VirtualBox::getHardDisk() need read lock */
-    AutoMultiLock <2> alock (mParent->rlock(), this->wlock());
+    AutoMultiLock2 alock (mParent->rlock(), this->wlock());
 
     HRESULT rc = checkStateDependency (MutableStateDep);
@@ -2185,5 +2183,5 @@
     /* VirtualBox::onExtraDataCanChange() and saveSettings() need mParent
      * lock (saveSettings() needs a write one) */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     if (mType == IsSnapshotMachine)
@@ -2296,5 +2294,5 @@
 
     /* saveSettings() needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     HRESULT rc = checkStateDependency (MutableStateDep);
@@ -2317,5 +2315,5 @@
 
     /* saveSettings() needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     HRESULT rc = checkStateDependency (MutableStateDep);
@@ -2530,5 +2528,5 @@
     CheckComRCReturnRC (autoCaller.rc());
 
-    AutoReaderLock alock (this);
+    AutoLock alock (this);
 
     HRESULT rc = checkStateDependency (MutableStateDep);
@@ -2919,5 +2917,5 @@
 
     /* We need VirtualBox lock because of Progress::notifyComplete() */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     if (!mData->mRegistered)
@@ -3428,5 +3426,5 @@
 
     /* wait for state dependants to drop to zero */
-    checkStateDependencies (alock);
+    ensureNoStateDependencies (alock);
 
     ComAssertRet (mData->mRegistered != aRegistered, E_FAIL);
@@ -3510,20 +3508,21 @@
 
 /**
- *  Increases the number of objects dependent on the machine state or on the
- *  registered state.  Guarantees that these two states will not change at
- *  least until #releaseStateDependency() is called.
- *
- *  Depending on the @a aDepType value, additional state checks may be
- *  made. These checks will set extended error info on failure. See
- *  #checkStateDependency() for more info.
- *
- *  If this method returns a failure, the dependency is not added and the
- *  caller is not allowed to rely on any particular machine state or
- *  registration state value and may return the failed result code to the
- *  upper level.
- *
- *  @param aDepType     Dependency type to add.
- *  @param aState       Current machine state (NULL if not interested).
- *  @param aRegistered  Current registered state (NULL if not interested).
+ * Increases the number of objects dependent on the machine state or on the
+ * registered state. Guarantees that these two states will not change at least
+ * until #releaseStateDependency() is called.
+ *
+ * Depending on the @a aDepType value, additional state checks may be made.
+ * These checks will set extended error info on failure. See
+ * #checkStateDependency() for more info.
+ *
+ * If this method returns a failure, the dependency is not added and the caller
+ * is not allowed to rely on any particular machine state or registration state
+ * value and may return the failed result code to the upper level.
+ *
+ * @param aDepType      Dependency type to add.
+ * @param aState        Current machine state (NULL if not interested).
+ * @param aRegistered   Current registered state (NULL if not interested).
+ *
+ * @note Locks this object for reading.
  */
 HRESULT Machine::addStateDependency (StateDependency aDepType /* = AnyStateDep */,
@@ -3534,23 +3533,30 @@
     AssertComRCReturnRC (autoCaller.rc());
 
-    AutoLock alock (this);
-
-    if (mData->mWaitingStateDeps && mData->mMachineStateDeps == 0)
-    {
-        /* checkStateDependencies() is at the point after RTSemEventWait() but
-         * before entering the lock. Report an error. It would be better to
-         * leave the lock now and re-schedule ourselves, but we don't have a
-         * framework that can guarantee such a behavior in 100% cases. */
-
-        AssertFailed(); /* <-- this is just to see how often it can happen */
-
-        return setError (E_ACCESSDENIED,
-            tr ("The machine is busy: state transition is in progress. "
-                "Retry the operation (state is %d)"),
-            mData->mMachineState);
-    }
+    AutoReaderLock alock (this);
 
     HRESULT rc = checkStateDependency (aDepType);
     CheckComRCReturnRC (rc);
+
+    {
+        AutoLock stateLock (stateLockHandle());
+
+        if (mData->mMachineStateChangePending != 0)
+        {
+            /* ensureNoStateDependencies() is waiting for state dependencies to
+             * drop to zero so don't add more. It may make sense to wait a bit
+             * and retry before reporting an error (since the pending state
+             * transition should be really quick) but let's just assert for
+             * now to see if it ever happens on practice. */
+
+            AssertFailed();
+
+            return setError (E_ACCESSDENIED,
+                tr ("Machine state change is in progress. "
+                    "Please retry the operation later."));
+        }
+
+        ++ mData->mMachineStateDeps;
+        Assert (mData->mMachineStateDeps != 0 /* overflow */);
+    }
 
     if (aState)
@@ -3559,29 +3565,33 @@
         *aRegistered = mData->mRegistered;
 
-    ++ mData->mMachineStateDeps;
-
     return S_OK;
 }
 
 /**
- *  Decreases the number of objects dependent on the machine state.
- *  Must always complete the #addStateDependency() call after the state
- *  dependency no more necessary.
+ * Decreases the number of objects dependent on the machine state.
+ * Must always complete the #addStateDependency() call after the state
+ * dependency is no more necessary.
  */
 void Machine::releaseStateDependency()
 {
+    /* stateLockHandle() is the same handle that is used by AutoCaller
+     * so lock it in advance to avoid two mutex requests in a raw */
+    AutoLock stateLock (stateLockHandle());
+
     AutoCaller autoCaller (this);
     AssertComRCReturnVoid (autoCaller.rc());
 
-    AutoLock alock (this);
-
-    AssertReturnVoid (mData->mMachineStateDeps > 0);
+    AssertReturnVoid (mData->mMachineStateDeps != 0
+                      /* releaseStateDependency() w/o addStateDependency()? */);
     -- mData->mMachineStateDeps;
 
-    if (mData->mMachineStateDeps == 0 &&
-        mData->mZeroMachineStateDepsSem != NIL_RTSEMEVENT)
-    {
-        /* inform checkStateDependencies() that there are no more deps */
-        RTSemEventSignal (mData->mZeroMachineStateDepsSem);
+    if (mData->mMachineStateDeps == 0)
+    {
+        /* inform ensureNoStateDependencies() that there are no more deps */
+        if (mData->mMachineStateChangePending != 0)
+        {
+            Assert (mData->mMachineStateDepsSem != NIL_RTSEMEVENTMULTI);
+            RTSemEventMultiSignal (mData->mMachineStateDepsSem);
+        }
     }
 }
@@ -3611,14 +3621,13 @@
  *  @param aDepType     Dependency type to check.
  *
- *  @note External classes should use #addStateDependency() and
+ *  @note Non Machine based classes should use #addStateDependency() and
  *  #releaseStateDependency() methods or the smart AutoStateDependency
  *  template.
  *
- *  @note This method must be called from under this object's lock.
+ *  @note This method must be called from under this object's read or write
+ *        lock.
  */
 HRESULT Machine::checkStateDependency (StateDependency aDepType)
 {
-    AssertReturn (isLockedOnCurrentThread(), E_FAIL);
-
     switch (aDepType)
     {
@@ -3859,38 +3868,45 @@
 }
 
-
 /**
- *  Chhecks that there are no state dependants. If necessary, waits for the
- *  number of dependants to drop to zero. Must be called from under
- *  this object's lock.
- *
- *  @param aLock    This object's lock.
- *
- *  @note This method may leave the object lock during its execution!
+ * Makes sure that there are no machine state dependants. If necessary, waits
+ * for the number of dependants to drop to zero. Must be called from under this
+ * object's write lock which will be released while waiting.
+ *
+ * @param aLock This object's write lock.
+ *
+ * @warning To be used only in methods that change the machine state!
  */
-void Machine::checkStateDependencies (AutoLock &aLock)
-{
-    AssertReturnVoid (isLockedOnCurrentThread());
+void Machine::ensureNoStateDependencies (AutoLock &aLock)
+{
     AssertReturnVoid (aLock.belongsTo (this));
+    AssertReturnVoid (aLock.isLockedOnCurrentThread());
+
+    AutoLock stateLock (stateLockHandle());
 
     /* Wait for all state dependants if necessary */
-    if (mData->mMachineStateDeps > 0)
-    {
-        /* lazy creation */
-        if (mData->mZeroMachineStateDepsSem == NIL_RTSEMEVENT)
-            RTSemEventCreate (&mData->mZeroMachineStateDepsSem);
+    if (mData->mMachineStateDeps != 0)
+    {
+        /* lazy semaphore creation */
+        if (mData->mMachineStateDepsSem == NIL_RTSEMEVENTMULTI)
+            RTSemEventMultiCreate (&mData->mMachineStateDepsSem);
 
         LogFlowThisFunc (("Waiting for state deps (%d) to drop to zero...\n",
                           mData->mMachineStateDeps));
 
-        mData->mWaitingStateDeps = TRUE;
-
+        ++ mData->mMachineStateChangePending;
+
+        /* reset the semaphore before waiting, the last dependant will signal
+         * it */
+        RTSemEventMultiReset (mData->mMachineStateDepsSem);
+
+        stateLock.leave();
         aLock.leave();
 
-        RTSemEventWait (mData->mZeroMachineStateDepsSem, RT_INDEFINITE_WAIT);
+        RTSemEventMultiWait (mData->mMachineStateDepsSem, RT_INDEFINITE_WAIT);
 
         aLock.enter();
-
-        mData->mWaitingStateDeps = FALSE;
+        stateLock.enter();
+
+        -- mData->mMachineStateChangePending;
     }
 }
@@ -3912,8 +3928,5 @@
 
     /* wait for state dependants to drop to zero */
-	/// @todo it may be potentially unsafe to leave the lock here as
-    //  the below method does. Needs some thinking. The easiest solution may
-    //  be to provide a separate mutex for mMachineState and mRegistered.
-    checkStateDependencies (alock);
+    ensureNoStateDependencies (alock);
 
     if (mData->mMachineState != aMachineState)
@@ -6432,5 +6445,5 @@
 
     /* accessing mParent methods below needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     HRESULT rc = S_OK;
@@ -6619,5 +6632,5 @@
 
     /* accessing mParent methods below needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     /* short cut: check whether attachments are all the same */
@@ -7322,8 +7335,7 @@
     if (autoUninitSpan.initFailed())
     {
-        /*
-         *  We've been called by init() because it's failed. It's not really
-         *  necessary (nor it's safe) to perform the regular uninit sequence
-         *  below, the following is enough.
+        /* We've been called by init() because it's failed. It's not really
+         * necessary (nor it's safe) to perform the regular uninit sequense
+         * below, the following is enough.
          */
         LogFlowThisFunc (("Initialization failed.\n"));
@@ -7351,10 +7363,8 @@
     }
 
-    /*
-     *  We need to lock this object in uninit() because the lock is shared
-     *  with mPeer (as well as data we modify below).
-     *  mParent->addProcessToReap() and others need mParent lock.
-     */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    /* We need to lock this object in uninit() because the lock is shared
+     * with mPeer (as well as data we modify below). mParent->addProcessToReap()
+     * and others need mParent lock. */
+    AutoMultiWriteLock2 alock (mParent, this);
 
     MachineState_T lastState = mData->mMachineState;
@@ -7519,5 +7529,5 @@
  *  with the primary Machine instance (mPeer).
  */
-AutoLock::Handle *SessionMachine::lockHandle() const
+RWLockHandle *SessionMachine::lockHandle() const
 {
     AssertReturn (!mPeer.isNull(), NULL);
@@ -7701,5 +7711,5 @@
 
     /* Progress::init() needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     if (control.equalsTo (mData->mSession.mDirectControl))
@@ -7766,5 +7776,5 @@
 
     /* mParent->addProgress() needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     AssertReturn (mData->mMachineState == MachineState_Paused &&
@@ -7814,5 +7824,5 @@
 
     /* endSavingState() need mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     AssertReturn (mData->mMachineState == MachineState_Saving &&
@@ -7888,5 +7898,5 @@
 
     /* Progress::init() needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     AssertReturn ((mData->mMachineState < MachineState_Running ||
@@ -8048,5 +8058,5 @@
 
     /* Lock mParent because of endTakingSnapshot() */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     AssertReturn (!aSuccess ||
@@ -8085,5 +8095,5 @@
 
     /* Progress::init() needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     ComAssertRet (mData->mMachineState < MachineState_Running, E_FAIL);
@@ -8170,5 +8180,5 @@
 
     /* Progress::init() needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     ComAssertRet (mData->mMachineState < MachineState_Running, E_FAIL);
@@ -8234,5 +8244,5 @@
 
     /* Progress::init() needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     ComAssertRet (mData->mMachineState < MachineState_Running, E_FAIL);
@@ -8687,5 +8697,5 @@
 
     /* mParent->removeProgress() and saveSettings() need mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     HRESULT rc = S_OK;
@@ -8734,5 +8744,5 @@
 
     /* Progress object uninitialization needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     HRESULT rc = S_OK;
@@ -8834,5 +8844,5 @@
 
     /* endTakingSnapshot() needs mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     HRESULT rc = S_OK;
@@ -8930,12 +8940,12 @@
     }
 
+    /* Progress::notifyComplete() et al., saveSettings() need mParent lock.
+     * Also safely lock the snapshot stuff in the direction parent->child */
+    AutoMultiWriteLock4 alock (mParent->lockHandle(), this->lockHandle(),
+                               aTask.snapshot->lockHandle(),
+                               aTask.snapshot->childrenLock());
+
     ComObjPtr <SnapshotMachine> sm = aTask.snapshot->data().mMachine;
-
-    /* Progress::notifyComplete() et al., saveSettings() need mParent lock */
-    AutoMultiLock <3> alock (mParent->wlock(), this->wlock(), sm->rlock());
-
-    /* Safe locking in the direction parent->child */
-    AutoLock snapshotLock (aTask.snapshot);
-    AutoLock snapshotChildrenLock (aTask.snapshot->childrenLock());
+    /* no need to lock the snapshot machine since it is const by definiton */
 
     HRESULT rc = S_OK;
@@ -9060,6 +9070,4 @@
                         hdRootString.raw())));
 
-                    snapshotChildrenLock.unlock();
-                    snapshotLock.unlock();
                     alock.leave();
 
@@ -9067,6 +9075,4 @@
 
                     alock.enter();
-                    snapshotLock.lock();
-                    snapshotChildrenLock.lock();
 
                     // debug code
@@ -9130,6 +9136,4 @@
                     /* merge the child to this basic image */
 
-                    snapshotChildrenLock.unlock();
-                    snapshotLock.unlock();
                     alock.leave();
 
@@ -9137,6 +9141,4 @@
 
                     alock.enter();
-                    snapshotLock.lock();
-                    snapshotChildrenLock.lock();
 
                     if (SUCCEEDED (rc))
@@ -9325,5 +9327,5 @@
 
     /* Progress::notifyComplete() et al., saveSettings() need mParent lock */
-    AutoMultiLock <2> alock (mParent->wlock(), this->wlock());
+    AutoMultiWriteLock2 alock (mParent, this);
 
     /*
@@ -9403,5 +9405,5 @@
                 curSnapshot->data().mMachine->mHDData->mHDAttachments;
 
-            snapshotLock.unlock();
+            snapshotLock.leave();
             alock.leave();
             rc = createSnapshotDiffs (NULL, mUserData->mSnapshotFolderFull,
@@ -9409,5 +9411,5 @@
                                       false /* aOnline */);
             alock.enter();
-            snapshotLock.lock();
+            snapshotLock.enter();
 
             if (FAILED (rc))
@@ -9444,10 +9446,10 @@
 
                 /* copy the state file */
-                snapshotLock.unlock();
+                snapshotLock.leave();
                 alock.leave();
                 int vrc = RTFileCopyEx (snapStateFilePath, stateFilePath,
                                         0, progressCallback, aTask.progress);
                 alock.enter();
-                snapshotLock.lock();
+                snapshotLock.enter();
 
                 if (VBOX_SUCCESS (vrc))
@@ -9822,5 +9824,5 @@
  *                          (or NULL for the offline snapshot)
  *
- *  @note Locks aSessionMachine object for reading.
+ *  @note The aSessionMachine must be locked for writing.
  */
 HRESULT SnapshotMachine::init (SessionMachine *aSessionMachine,
@@ -9837,7 +9839,7 @@
     AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
 
+    AssertReturn (aSessionMachine->isLockedOnCurrentThread(), E_FAIL);
+
     mSnapshotId = aSnapshotId;
-
-    AutoReaderLock alock (aSessionMachine);
 
     /* memorize the primary Machine instance (i.e. not SessionMachine!) */
@@ -9936,5 +9938,5 @@
  *                          (or NULL for the offline snapshot)
  *
- *  @note Locks aMachine object for reading.
+ *  @note Doesn't lock anything.
  */
 HRESULT SnapshotMachine::init (Machine *aMachine,
@@ -9954,7 +9956,7 @@
     AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
 
+    /* Don't need to lock aMachine when VirtualBox is starting up */
+
     mSnapshotId = aSnapshotId;
-
-    AutoReaderLock alock (aMachine);
 
     /* memorize the primary Machine instance */
@@ -10071,5 +10073,5 @@
  *  with the primary Machine instance (mPeer).
  */
-AutoLock::Handle *SnapshotMachine::lockHandle() const
+RWLockHandle *SnapshotMachine::lockHandle() const
 {
     AssertReturn (!mPeer.isNull(), NULL);
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 7991)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 7992)
@@ -177,4 +177,5 @@
 VBoxSVC_SOURCES = \
 	Logging.cpp \
+	AutoLock.cpp \
 	Matching.cpp \
 	VirtualBoxBase.cpp \
@@ -350,4 +351,5 @@
 VBoxC_SOURCES = \
 	Logging.cpp \
+	AutoLock.cpp \
 	VBoxDll.cpp \
 	Version.cpp \
Index: /trunk/src/VBox/Main/NetworkAdapterImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/NetworkAdapterImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/NetworkAdapterImpl.cpp	(revision 7992)
@@ -1180,9 +1180,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
-    AssertComRCReturnVoid (thatCaller.rc());
-
-    /* lock both for writing since we modify both */
-    AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer));
+    AutoCaller peerCaller (mPeer);
+    AssertComRCReturnVoid (peerCaller.rc());
+
+    /* lock both for writing since we modify both (mPeer is "master" so locked
+     * first) */
+    AutoMultiWriteLock2 alock (mPeer, this);
 
     if (mData.isBackedUp())
@@ -1210,9 +1211,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
+    AutoCaller thatCaller (aThat);
     AssertComRCReturnVoid (thatCaller.rc());
 
-    /* peer is not modified, lock it for reading */
-    AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
+    /* peer is not modified, lock it for reading (aThat is "master" so locked
+     * first) */
+    AutoMultiLock2 alock (aThat->rlock(), this->wlock());
 
     /* this will back up current data */
Index: /trunk/src/VBox/Main/ParallelPortImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/ParallelPortImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/ParallelPortImpl.cpp	(revision 7992)
@@ -163,7 +163,7 @@
  *  Loads settings from the given port node.
  *  May be called once right after this object creation.
- * 
+ *
  *  @param aPortNode <Port> node.
- * 
+ *
  *  @note Locks this object for writing.
  */
@@ -188,5 +188,5 @@
      * place when a setting of a newly created object must default to A while
      * the same setting of an object loaded from the old settings file must
-     * default to B. */ 
+     * default to B. */
 
     /* enabled (required) */
@@ -206,12 +206,12 @@
 }
 
-/** 
+/**
  *  Saves settings to the given port node.
- * 
+ *
  *  Note that the given Port node is comletely empty on input.
  *
  *  @param aPortNode <Port> node.
- * 
- *  @note Locks this object for reading. 
+ *
+ *  @note Locks this object for reading.
  */
 HRESULT ParallelPort::saveSettings (settings::Key &aPortNode)
@@ -272,9 +272,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
-    AssertComRCReturnVoid (thatCaller.rc());
-
-    /* lock both for writing since we modify both */
-    AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer));
+    AutoCaller peerCaller (mPeer);
+    AssertComRCReturnVoid (peerCaller.rc());
+
+    /* lock both for writing since we modify both (mPeer is "master" so locked
+     * first) */
+    AutoMultiWriteLock2 alock (mPeer, this);
 
     if (mData.isBackedUp())
@@ -302,9 +303,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
+    AutoCaller thatCaller (aThat);
     AssertComRCReturnVoid (thatCaller.rc());
 
-    /* peer is not modified, lock it for reading */
-    AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
+    /* peer is not modified, lock it for reading (aThat is "master" so locked
+     * first) */
+    AutoMultiLock2 alock (aThat->rlock(), this->wlock());
 
     /* this will back up current data */
@@ -504,5 +506,5 @@
 }
 
-/** 
+/**
  *  Validates COMSETTER(Path) arguments.
  */
Index: /trunk/src/VBox/Main/ProgressImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/ProgressImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/ProgressImpl.cpp	(revision 7992)
@@ -162,5 +162,6 @@
     LogFlowMember (("ProgressBase::protectedUninit()\n"));
 
-    Assert (alock.belongsTo (this) && alock.level() == 1);
+    Assert (alock.belongsTo (this) && alock.isLockedOnCurrentThread() &&
+            alock.writeLockLevel() == 1);
     Assert (isReady());
 
@@ -747,5 +748,5 @@
  *  If the result code indicates a success (|SUCCEEDED (@a aResultCode)|)
  *  then the current operation is set to the last
- *  
+ *
  *  Note that this method may be called only once for the given Progress object.
  *  Subsequent calls will assert.
@@ -844,5 +845,5 @@
     Bstr text = Utf8StrFmtVA (aText, args);
     va_end (args);
-    
+
     return notifyCompleteBstr (aResultCode, aIID, aComponent, text);
 }
@@ -855,5 +856,5 @@
  *  This method is preferred iy you have a ready (translated and formatted)
  *  Bstr string, because it omits an extra conversion Utf8Str -> Bstr.
- * 
+ *
  *  @param  aResultCode operation result (error) code, must not be S_OK
  *  @param  aIID        IID of the intrface that defines the error
Index: /trunk/src/VBox/Main/SATAControllerImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/SATAControllerImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/SATAControllerImpl.cpp	(revision 7992)
@@ -321,11 +321,11 @@
 /////////////////////////////////////////////////////////////////////////////
 
-/** 
+/**
  *  Loads settings from the given machine node.
  *  May be called once right after this object creation.
- * 
+ *
  *  @param aMachineNode <Machine> node.
- * 
- *  @note Locks this object for writing. 
+ *
+ *  @note Locks this object for writing.
  */
 HRESULT SATAController::loadSettings (const settings::Key &aMachineNode)
@@ -358,9 +358,9 @@
 }
 
-/** 
+/**
  *  Saves settings to the given machine node.
- * 
+ *
  *  @param aMachineNode <Machine> node.
- * 
+ *
  *  @note Locks this object for reading.
  */
@@ -451,11 +451,21 @@
 }
 
-/** @note Locks objects for writing! */
+/**
+ *  @note Locks this object for writing, together with the peer object (also
+ *  for writing) if there is one.
+ */
 void SATAController::commit()
 {
+    /* sanity */
     AutoCaller autoCaller (this);
     AssertComRCReturnVoid (autoCaller.rc());
 
-    AutoLock alock (this);
+    /* sanity too */
+    AutoCaller peerCaller (mPeer);
+    AssertComRCReturnVoid (peerCaller.rc());
+
+    /* lock both for writing since we modify both (mPeer is "master" so locked
+     * first) */
+    AutoMultiWriteLock2 alock (mPeer, this);
 
     if (mData.isBackedUp())
@@ -471,11 +481,23 @@
 }
 
-/** @note Locks object for writing and that object for reading! */
+/**
+ *  @note Locks this object for writing, together with the peer object
+ *  represented by @a aThat (locked for reading).
+ */
 void SATAController::copyFrom (SATAController *aThat)
 {
+    AssertReturnVoid (aThat != NULL);
+
+    /* sanity */
     AutoCaller autoCaller (this);
     AssertComRCReturnVoid (autoCaller.rc());
 
-    AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
+    /* sanity too */
+    AutoCaller thatCaller (aThat);
+    AssertComRCReturnVoid (thatCaller.rc());
+
+    /* peer is not modified, lock it for reading (aThat is "master" so locked
+     * first) */
+    AutoMultiLock2 alock (aThat->rlock(), this->wlock());
 
     /* this will back up current data */
Index: /trunk/src/VBox/Main/SerialPortImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/SerialPortImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/SerialPortImpl.cpp	(revision 7992)
@@ -308,9 +308,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
-    AssertComRCReturnVoid (thatCaller.rc());
-
-    /* lock both for writing since we modify both */
-    AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer));
+    AutoCaller peerCaller (mPeer);
+    AssertComRCReturnVoid (peerCaller.rc());
+
+    /* lock both for writing since we modify both (mPeer is "master" so locked
+     * first) */
+    AutoMultiWriteLock2 alock (mPeer, this);
 
     if (mData.isBackedUp())
@@ -338,9 +339,10 @@
 
     /* sanity too */
-    AutoCaller thatCaller (mPeer);
+    AutoCaller thatCaller (aThat);
     AssertComRCReturnVoid (thatCaller.rc());
 
-    /* peer is not modified, lock it for reading */
-    AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
+    /* peer is not modified, lock it for reading (aThat is "master" so locked
+     * first) */
+    AutoMultiLock2 alock (aThat->rlock(), this->wlock());
 
     /* this will back up current data */
Index: /trunk/src/VBox/Main/USBControllerImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/USBControllerImpl.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/USBControllerImpl.cpp	(revision 7992)
@@ -923,11 +923,21 @@
 }
 
-/** @note Locks objects for writing! */
+/**
+ *  @note Locks this object for writing, together with the peer object (also
+ *  for writing) if there is one.
+ */
 void USBController::commit()
 {
+    /* sanity */
     AutoCaller autoCaller (this);
     AssertComRCReturnVoid (autoCaller.rc());
 
-    AutoLock alock (this);
+    /* sanity too */
+    AutoCaller peerCaller (mPeer);
+    AssertComRCReturnVoid (peerCaller.rc());
+
+    /* lock both for writing since we modify both (mPeer is "master" so locked
+     * first) */
+    AutoMultiWriteLock2 alock (mPeer, this);
 
     if (mData.isBackedUp())
@@ -936,5 +946,5 @@
         if (mPeer)
         {
-            // attach new data to the peer and reshare it
+            /* attach new data to the peer and reshare it */
             AutoLock peerlock (mPeer);
             mPeer->mData.attach (mData);
@@ -949,10 +959,10 @@
         mDeviceFilters.commit();
 
-        // apply changes to peer
+        /* apply changes to peer */
         if (mPeer)
         {
             AutoLock peerlock (mPeer);
-            // commit all changes to new filters (this will reshare data with
-            // peers for those who have peers)
+            /* commit all changes to new filters (this will reshare data with
+             * peers for those who have peers) */
             DeviceFilterList *newList = new DeviceFilterList();
             DeviceFilterList::const_iterator it = mDeviceFilters->begin();
@@ -961,10 +971,10 @@
                 (*it)->commit();
 
-                // look if this filter has a peer filter
+                /* look if this filter has a peer filter */
                 ComObjPtr <USBDeviceFilter> peer = (*it)->peer();
                 if (!peer)
                 {
-                    // no peer means the filter is a newly created one;
-                    // create a peer owning data this filter share it with
+                    /* no peer means the filter is a newly created one;
+                     * create a peer owning data this filter share it with */
                     peer.createObject();
                     peer->init (mPeer, *it, true /* aReshare */);
@@ -972,8 +982,8 @@
                 else
                 {
-                    // remove peer from the old list
+                    /* remove peer from the old list */
                     mPeer->mDeviceFilters->remove (peer);
                 }
-                // and add it to the new list
+                /* and add it to the new list */
                 newList->push_back (peer);
 
@@ -981,5 +991,5 @@
             }
 
-            // uninit old peer's filters that are left
+            /* uninit old peer's filters that are left */
             it = mPeer->mDeviceFilters->begin();
             while (it != mPeer->mDeviceFilters->end())
@@ -989,11 +999,11 @@
             }
 
-            // attach new list of filters to our peer
+            /* attach new list of filters to our peer */
             mPeer->mDeviceFilters.attach (newList);
         }
         else
         {
-            // we have no peer (our parent is the newly created machine);
-            // just commit changes to filters
+            /* we have no peer (our parent is the newly created machine);
+             * just commit changes to filters */
             commitFilters = true;
         }
@@ -1001,6 +1011,6 @@
     else
     {
-        // the list of filters itself is not changed,
-        // just commit changes to filters themselves
+        /* the list of filters itself is not changed,
+         * just commit changes to filters themselves */
         commitFilters = true;
     }
@@ -1018,11 +1028,23 @@
 }
 
-/** @note Locks object for writing and that object for reading! */
+/**
+ *  @note Locks this object for writing, together with the peer object
+ *  represented by @a aThat (locked for reading).
+ */
 void USBController::copyFrom (USBController *aThat)
 {
+    AssertReturnVoid (aThat != NULL);
+
+    /* sanity */
     AutoCaller autoCaller (this);
     AssertComRCReturnVoid (autoCaller.rc());
 
-    AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
+    /* sanity too */
+    AutoCaller thatCaller (aThat);
+    AssertComRCReturnVoid (thatCaller.rc());
+
+    /* peer is not modified, lock it for reading (aThat is "master" so locked
+     * first) */
+    AutoMultiLock2 alock (aThat->rlock(), this->wlock());
 
     if (mParent->isRegistered())
Index: /trunk/src/VBox/Main/VirtualBoxBase.cpp
===================================================================
--- /trunk/src/VBox/Main/VirtualBoxBase.cpp	(revision 7991)
+++ /trunk/src/VBox/Main/VirtualBoxBase.cpp	(revision 7992)
@@ -43,5 +43,4 @@
     mInitDoneSem = NIL_RTSEMEVENTMULTI;
     mInitDoneSemUsers = 0;
-    RTCritSectInit (&mStateLock);
     mObjectLock = NULL;
 }
@@ -51,5 +50,4 @@
     if (mObjectLock)
         delete mObjectLock;
-    RTCritSectDelete (&mStateLock);
     Assert (mInitDoneSemUsers == 0);
     Assert (mInitDoneSem == NIL_RTSEMEVENTMULTI);
@@ -62,9 +60,9 @@
 
 // AutoLock::Lockable interface
-AutoLock::Handle *VirtualBoxBaseNEXT_base::lockHandle() const
+RWLockHandle *VirtualBoxBaseNEXT_base::lockHandle() const
 {
     /* lasy initialization */
     if (!mObjectLock)
-        mObjectLock = new AutoLock::Handle;
+        mObjectLock = new RWLockHandle;
     return mObjectLock;
 }
Index: /trunk/src/VBox/Main/include/AutoLock.h
===================================================================
--- /trunk/src/VBox/Main/include/AutoLock.h	(revision 7991)
+++ /trunk/src/VBox/Main/include/AutoLock.h	(revision 7992)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2007 innotek GmbH
+ * Copyright (C) 2006-2008 innotek GmbH
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -23,4 +23,7 @@
 #include <iprt/critsect.h>
 #include <iprt/thread.h>
+#include <iprt/semaphore.h>
+
+#include <iprt/assert.h>
 
 #if defined(DEBUG)
@@ -31,14 +34,424 @@
 {
 
-template <size_t> class AutoMultiLock;
-namespace internal { struct LockableTag; }
-
 /**
- *  Smart class to safely manage critical sections. Also provides ecplicit
- *  lock, unlock leave and enter operations.
- *
- *  When constructing an instance, it enters the given critical
- *  section. This critical section will be exited automatically when the
- *  instance goes out of scope (i.e. gets destroyed).
+ * Abstract lock operations. See LockHandle and AutoLock for details.
+ */
+class LockOps
+{
+public:
+
+    virtual ~LockOps() {}
+
+    virtual void lock() = 0;
+    virtual void unlock() = 0;
+};
+
+/**
+ * Read lock operations. See LockHandle and AutoLock for details.
+ */
+class ReadLockOps : public LockOps
+{
+public:
+
+    /**
+     * Requests a read (shared) lock.
+     */
+    virtual void lockRead() = 0;
+
+    /**
+     * Releases a read (shared) lock ackquired by lockRead().
+     */
+    virtual void unlockRead() = 0;
+
+    // LockOps interface
+    void lock() { lockRead(); }
+    void unlock() { unlockRead(); }
+};
+
+/**
+ * Write lock operations. See LockHandle and AutoLock for details.
+ */
+class WriteLockOps : public LockOps
+{
+public:
+
+    /**
+     * Requests a write (exclusive) lock.
+     */
+    virtual void lockWrite() = 0;
+
+    /**
+     * Releases a write (exclusive) lock ackquired by lockWrite().
+     */
+    virtual void unlockWrite() = 0;
+
+    // LockOps interface
+    void lock() { lockWrite(); }
+    void unlock() { unlockWrite(); }
+};
+
+/**
+ * Abstract read/write semaphore handle.
+ *
+ * This is a base class to implement semaphores that provide read/write locking.
+ * Subclasses must implement all pure virtual methods of this class together
+ * with pure methods of ReadLockOps and WriteLockOps classes.
+ *
+ * See the AutoLock class documentation for the detailed description of read and
+ * write locks.
+ */
+class LockHandle : protected ReadLockOps, protected WriteLockOps
+{
+public:
+
+    LockHandle() {}
+    virtual ~LockHandle() {}
+
+    /**
+     * Returns @c true if the current thread holds a write lock on this
+     * read/write semaphore. Intended for debugging only.
+     */
+    virtual bool isLockedOnCurrentThread() const = 0;
+
+    /**
+     * Returns the current write lock level of this semaphore. The lock level
+     * determines the number of nested #lock() calls on the given semaphore
+     * handle.
+     *
+     * Note that this call is valid only when the current thread owns a write
+     * lock on the given semaphore handle and will assert otherwise.
+     */
+    virtual uint32_t writeLockLevel() const = 0;
+
+    /**
+     * Returns an interface to read lock operations of this semaphore.
+     * Used by constructors of AutoMultiLockN classes.
+     */
+    LockOps *rlock() { return (ReadLockOps *) this; }
+
+    /**
+     * Returns an interface to write lock operations of this semaphore.
+     * Used by constructors of AutoMultiLockN classes.
+     */
+    LockOps *wlock() { return (WriteLockOps *) this; }
+
+private:
+
+    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (LockHandle)
+
+    friend class AutoLock;
+    friend class AutoReaderLock;
+};
+
+/**
+ * Full-featured read/write semaphore handle implementation.
+ *
+ * This is an auxiliary base class for classes that need full-featured
+ * read/write locking as described in the AutoLock class documentation.
+ * Instances of classes inherited from this class can be passed as arguments to
+ * the AutoLock and AutoReaderLock constructors.
+ */
+class RWLockHandle : public LockHandle
+{
+public:
+
+    RWLockHandle();
+    virtual ~RWLockHandle();
+
+    bool isLockedOnCurrentThread() const;
+
+private:
+
+    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (RWLockHandle)
+
+    void lockWrite();
+    void unlockWrite();
+    void lockRead();
+    void unlockRead();
+
+    uint32_t writeLockLevel() const;
+
+    mutable RTCRITSECT mCritSect;
+    RTSEMEVENT mGoWriteSem;
+    RTSEMEVENTMULTI mGoReadSem;
+
+    RTTHREAD mWriteLockThread;
+
+    uint32_t mReadLockCount;
+    uint32_t mWriteLockLevel;
+    uint32_t mWriteLockPending;
+};
+
+/**
+ * Write-only semaphore handle implementation.
+ *
+ * This is an auxiliary base class for classes that need write-only (exclusive)
+ * locking and do not need read (shared) locking. This implementation uses a
+ * cheap and fast critical section for both lockWrite() and lockRead() methods
+ * which makes a lockRead() call fully equivalent to the lockWrite() call and
+ * therefore makes it pointless to use instahces of this class with
+ * AutoReaderLock instances -- shared locking will not be possible anyway and
+ * any call to lock() will block if there are lock owners on other threads.
+ *
+ * Use with care only when absolutely sure that shared locks are not necessary.
+ */
+class WriteLockHandle : public LockHandle
+{
+public:
+
+    WriteLockHandle()
+    {
+        RTCritSectInit (&mCritSect);
+    }
+
+    virtual ~WriteLockHandle()
+    {
+        RTCritSectDelete (&mCritSect);
+    }
+
+    bool isLockedOnCurrentThread() const
+    {
+        return RTCritSectIsOwner (&mCritSect);
+    }
+
+private:
+
+    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (WriteLockHandle)
+
+    void lockWrite()
+    {
+#if defined(DEBUG)
+        RTCritSectEnterDebug (&mCritSect,
+                              "WriteLockHandle::lockWrite() return address >>>",
+                              0, (RTUINTPTR) ASMReturnAddress());
+#else
+        RTCritSectEnter (&mCritSect);
+#endif
+    }
+
+    void unlockWrite()
+    {
+        RTCritSectLeave (&mCritSect);
+    }
+
+    void lockRead() { lockWrite(); }
+    void unlockRead() { unlockWrite(); }
+
+    uint32_t writeLockLevel() const
+    {
+        return RTCritSectGetRecursion (&mCritSect);
+    }
+
+    mutable RTCRITSECT mCritSect;
+};
+
+/**
+ * Lockable interface.
+ *
+ * This is an abstract base for classes that need read/write locking. Unlike
+ * RWLockHandle and other classes that makes the read/write semaphore a part of
+ * class data, this class allows subclasses to decide which semaphore handle to
+ * use.
+ */
+class Lockable
+{
+public:
+
+    /**
+     * Returns a pointer to a LockHandle used by AutoLock/AutoReaderLock for
+     * locking. Subclasses are allowed to return @c NULL -- in this case,
+     * the AutoLock/AutoReaderLock object constructed using an instance of
+     * such subclass will simply turn into no-op.
+     */
+    virtual LockHandle *lockHandle() const = 0;
+
+    /**
+     * Equivalent to <tt>#lockHandle()->isLockedOnCurrentThread()</tt>.
+     * Returns @c false if lockHandle() returns @c NULL.
+     */
+    bool isLockedOnCurrentThread()
+    {
+        LockHandle *h = lockHandle();
+        return h ? h->isLockedOnCurrentThread() : false;
+    }
+
+    /**
+     * Equivalent to <tt>#lockHandle()->rlock()</tt>.
+     * Returns @c NULL false if lockHandle() returns @c NULL.
+     */
+    LockOps *rlock()
+    {
+        LockHandle *h = lockHandle();
+        return h ? h->rlock() : NULL;
+    }
+
+    /**
+     * Equivalent to <tt>#lockHandle()->wlock()</tt>. Returns @c NULL false if
+     * lockHandle() returns @c NULL.
+     */
+    LockOps *wlock()
+    {
+        LockHandle *h = lockHandle();
+        return h ? h->wlock() : NULL;
+    }
+};
+
+/**
+ * Provides safe management of read/write semaphores in write mode.
+ *
+ * A read/write semaphore is represented by the LockHandle class. This semaphore
+ * can be requested ("locked") in two different modes: for reading and for
+ * writing. A write lock is exclusive and acts like a mutex: only one thread can
+ * acquire a write lock on the given semaphore at a time; all other threads
+ * trying to request a write lock or a read lock (see below) on the same
+ * semaphore will be indefinitely blocked until the owning thread releases the
+ * write lock.
+ *
+ * A read lock is shared. This means that several threads can acquire a read
+ * lock on the same semaphore at the same time provided that there is no thread
+ * that holds a write lock on that semaphore. Note that when there are one or
+ * more threads holding read locks, a request for a write lock on another thread
+ * will be indefinitely blocked until all threads holding read locks release
+ * them.
+ *
+ * Note that write locks can be nested -- the same thread can request a write
+ * lock on the same semaphore several times. In this case, the corresponding
+ * number of release calls must be done in order to completely release all
+ * nested write locks and make the semaphore available for locking by other
+ * threads.
+ *
+ * Read locks can be nested too in which case the same rule of the equal number
+ * of the release calls applies. Read locks can be also nested into write
+ * locks which means that the same thread can successfully request a read lock
+ * if it already holds a write lock. However, please note that the opposite is
+ * <b>not possible</b>: if a thread tries to request a write lock on the same
+ * semaphore it is already holding a read lock, it will definitely produce a
+ * <b>deadlock</b> (i.e. it will block forever waiting for itself).
+ *
+ * Note that instances of the AutoLock class manage write locks of read/write
+ * semaphores only. In order to manage read locks, please use the AutoReaderLock
+ * class.
+ *
+ * Safe semaphore management consists of the following:
+ * <ul>
+ *   <li>When an instance of the AutoLock class is constructed given a valid
+ *   semaphore handle, it will automatically request a write lock on that
+ *   semaphore.
+ *   </li>
+ *   <li>When an instance of the AutoLock class constructed given a valid
+ *   semaphore handle is destroyed (e.g. goes out of scope), it will
+ *   automatically release the write lock that was requested upon construction
+ *   and also all nested write locks requested later using the #lock() call
+ *   (note that the latter is considered to be a program logic error, see the
+ *   #~AutoLock() description for details).
+ *   </li>
+ * </ul>
+ *
+ * Note that the LockHandle class taken by AutoLock constructors is an abstract
+ * base of the read/write semaphore. You should choose one of the existing
+ * subclasses of this abstract class or create your own subclass that implements
+ * necessary read and write lock semantics. The most suitable choice is the
+ * RWLockHandle class which provides full support for both read and write locks
+ * as describerd above. Alternatively, you can use the WriteLockHandle class if
+ * you only need write (exclusive) locking (WriteLockHandle requires less system
+ * resources and works faster).
+ *
+ * A typical usage pattern of the AutoLock class is as follows:
+ * <code>
+ *  struct Struct : public RWLockHandle
+ *  {
+ *      ...
+ *  };
+ *
+ *  void foo (Struct &aStruct)
+ *  {
+ *      {
+ *          // acquire a write lock of aStruct
+ *          AutoLock alock (aStruct);
+ *
+ *          // now we can modify aStruct in a thread-safe manner
+ *          aStruct.foo = ...;
+ *
+ *          // note that the write lock will be automatically released upon
+ *          // execution of the return statement below
+ *          if (!aStruct.bar)
+ *              return;
+ *
+ *          ...
+ *      }
+ *
+ *      // note that the write lock is automatically released here
+ *  }
+ * </code>
+ *
+ * <b>Locking policy</b>
+ *
+ * When there are multiple threads and multiple objects to lock, there is always
+ * a potential possibility to produce a deadlock if the lock order is mixed up.
+ * Here is a classical example of a deadlock when two threads need to lock the
+ * same two objects in a row but do it in different order:
+ * <code>
+ *  Thread 1:
+ *    #1: AutoLock (mFoo);
+ *        ...
+ *    #2: AutoLock (mBar);
+ *        ...
+ *  Thread 2:
+ *    #3: AutoLock (mBar);
+ *        ...
+ *    #4: AutoLock (mFoo);
+ *        ...
+ * </code>
+ *
+ * If the threads happen to be scheduled so that #3 completes after #1 has
+ * completed but before #2 got control, the threads will hit a deadlock: Thread
+ * 2 will be holding mBar and waiting for mFoo at #4 forever because Thread 1 is
+ * holding mFoo and won't release it until it acquires mBar at #2 that will
+ * never happen because mBar is held by Thread 2.
+ *
+ * One of ways to avoid the described behavior is to never lock more than one
+ * obhect in a row. While it is definitely a good and safe practice, it's not
+ * always possible: the application logic may require several simultaneous locks
+ * in order to provide data integrity.
+ *
+ * One of the possibilities to solve the deadlock problem is to make sure that
+ * the locking order is always the same across the application. In the above
+ * example, it would mean that <b>both</b> threads should first requiest a lock
+ * of mFoo and then mBar (or vice versa). One of the methods to guarantee the
+ * locking order consistent is to introduce a set of locking rules. The
+ * advantage of this method is that it doesn't require any special semaphore
+ * implementation or additional control structures. The disadvantage is that
+ * it's the programmer who must make sure these rules are obeyed across the
+ * whole application so the human factor applies. Taking the simplicity of this
+ * method into account, it is chosen to solve potential deadlock problems when
+ * using AutoLock and AutoReaderLock classes. Here are the locking rules that
+ * must be obeyed by <b>all</b> users of these classes. Note that if more than
+ * one rule matches the given group of objects to lock, all of these rules must
+ * be met:
+ * <ol>
+ *     <li>If there is a parent-child (or master-slave) relationship between the
+ *     locked objects, parent (master) objects must be locked before child
+ *     (slave) objects.
+ *     </li>
+ *     <li>When a group of equal objects (in terms of parent-child or
+ *     master-slave relationsip) needs to be locked in a raw, the lock order
+ *     must match the sort order (which must be consistent for the given group).
+ * </ol>
+ * Note that if there is no pragrammatically expressed sort order (e.g.
+ * the objects are not part of the sorted vector or list but instead are
+ * separate data members of a class), object class names sorted in alphabetical
+ * order must be used to determine the lock order. If there is more than one
+ * object of the given class, the object variable names' alphabetical order must
+ * be used as a lock order. When objects are not represented as individual
+ * variables, as in case of unsorted arrays/lists, the list of alphabetically
+ * sorted object UUIDs must be used to determine the sort order.
+ *
+ * All non-standard locking order must be avoided by all means, but when
+ * absolutely necessary, it must be clearly documented at relevant places so it
+ * is well seen by other developers. For example, if a set of instances of some
+ * class needs to be locked but these instances are not part of the sorted list
+ * and don't have UUIDs, then the class description must state what to use to
+ * determine the lock order (maybe some property that returns an unique value
+ * per every object).
  */
 class AutoLock
@@ -46,213 +459,212 @@
 public:
 
-    #if defined(DEBUG)
-    # define ___CritSectEnter(cs) \
-        RTCritSectEnterDebug ((cs), \
-            "AutoLock::lock()/enter() return address >>>", 0, \
-            (RTUINTPTR) ASMReturnAddress())
-    #else
-    # define ___CritSectEnter(cs) RTCritSectEnter ((cs))
-    #endif
-
-    /**
-     *  Lock (critical section) handle. An auxiliary base class for structures
-     *  that need locking. Instances of classes inherited from it can be passed
-     *  as arguments to the AutoLock constructor.
-     */
-    class Handle
-    {
-    public:
-
-        Handle() { RTCritSectInit (&mCritSect); }
-        virtual ~Handle() { RTCritSectDelete (&mCritSect); }
-
-        /** Returns |true| if this handle is locked on the current thread. */
-        bool isLockedOnCurrentThread() const
+    /**
+     * Constructs a null instance that does not manage any read/write
+     * semaphore.
+     *
+     * Note that all method calls on a null instance are no-ops. This allows to
+     * have the code where lock protection can be selected (or omitted) at
+     * runtime.
+     */
+    AutoLock() : mHandle (NULL), mLockLevel (0), mGlobalLockLevel (0) {}
+
+    /**
+     * Constructs a new instance that will start managing the given read/write
+     * semaphore by requesting a write lock.
+     */
+    AutoLock (LockHandle *aHandle)
+        : mHandle (aHandle), mLockLevel (0), mGlobalLockLevel (0)
+    { lock(); }
+
+    /**
+     * Constructs a new instance that will start managing the given read/write
+     * semaphore by requesting a write lock.
+     */
+    AutoLock (LockHandle &aHandle)
+        : mHandle (&aHandle), mLockLevel (0), mGlobalLockLevel (0)
+    { lock(); }
+
+    /**
+     * Constructs a new instance that will start managing the given read/write
+     * semaphore by requesting a write lock.
+     */
+    AutoLock (const Lockable &aLockable)
+        : mHandle (aLockable.lockHandle()), mLockLevel (0), mGlobalLockLevel (0)
+    { lock(); }
+
+    /**
+     * Constructs a new instance that will start managing the given read/write
+     * semaphore by requesting a write lock.
+     */
+    AutoLock (const Lockable *aLockable)
+        : mHandle (aLockable ? aLockable->lockHandle() : NULL)
+        , mLockLevel (0), mGlobalLockLevel (0)
+    { lock(); }
+
+    /**
+     * Release all write locks acquired by this instance through the #lock()
+     * call and destroys the instance.
+     *
+     * Note that if there there are nested #lock() calls without the
+     * corresponding number of #unlock() calls when the destructor is called, it
+     * will assert. This is because having an unbalanced number of nested locks
+     * is a program logic error which must be fixed.
+     */
+    ~AutoLock()
+    {
+        if (mHandle)
         {
-            return RTCritSectIsOwner (&mCritSect);
+            if (mGlobalLockLevel)
+            {
+                mGlobalLockLevel -= mLockLevel;
+                mLockLevel = 0;
+                for (; mGlobalLockLevel; -- mGlobalLockLevel)
+                    mHandle->lockWrite();
+            }
+
+            AssertMsg (mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel));
+            for (; mLockLevel; -- mLockLevel)
+                mHandle->unlockWrite();
         }
-
-        /** Returns a tag to lock this handle for reading by AutoMultiLock */
-        internal::LockableTag rlock() const;
-        /** Returns a tag to lock this handle for writing by AutoMultiLock */
-        internal::LockableTag wlock() const;
-
-    private:
-
-        DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (Handle)
-
-        mutable RTCRITSECT mCritSect;
-
-        friend class AutoLock;
-        template <size_t> friend class AutoMultiLock;
-    };
-
-    /**
-     *  Lockable interface. An abstract base for classes that need locking.
-     *  Unlike Handle that makes the lock handle a part of class data, this
-     *  class allows subclasses to decide which lock handle to use.
-     */
-    class Lockable
-    {
-    public:
-
-        /**
-         *  Returns a pointer to a Handle used by AutoLock for locking.
-         *  Subclasses are allowed to return |NULL| -- in this case,
-         *  the AutoLock object constructed using an instance of such
-         *  subclass will simply turn into no-op.
-         */
-        virtual Handle *lockHandle() const = 0;
-
-        /**
-         *  Equivalent to |#lockHandle()->isLockedOnCurrentThread()|.
-         *  Returns |false| if lockHandle() returns NULL.
-         */
-        bool isLockedOnCurrentThread()
+    }
+
+    /**
+     * Requests a write (exclusive) lock. If a write lock is already owned by
+     * this thread, increases the lock level (allowing for nested write locks on
+     * the same thread). Blocks indefinitely if a write lock or a read lock is
+     * already owned by another thread until that tread releases the locks,
+     * otherwise returns immediately.
+     */
+    void lock()
+    {
+        if (mHandle)
         {
-            Handle *h = lockHandle();
-            return h ? h->isLockedOnCurrentThread() : false;
+            mHandle->lockWrite();
+            ++ mLockLevel;
+            Assert (mLockLevel != 0 /* overflow? */);
         }
-
-        /**
-         *  Returns a tag to lock this handle for reading by AutoMultiLock.
-         *  Shortcut to |lockHandle()->rlock()|.
-         *  The returned tag is a no-op, when lockHandle() returns |NULL|.
-         */
-        internal::LockableTag rlock() const;
-
-        /**
-         *  Returns a tag to lock this handle for writing by AutoMultiLock.
-         *  Shortcut to |lockHandle()->wlock()|.
-         *  The returned tag is a no-op, when lockHandle() returns |NULL|.
-         */
-        internal::LockableTag wlock() const;
-    };
-
-    AutoLock() : mCritSect (NULL), mLevel (0), mLeftLevel (0) {}
-
-    AutoLock (RTCRITSECT &aCritSect)
-        : mCritSect (&aCritSect), mLevel (0), mLeftLevel (0) { lock(); }
-
-    AutoLock (RTCRITSECT *aCritSect)
-        : mCritSect (aCritSect), mLevel (0), mLeftLevel (0) { lock(); }
-
-    AutoLock (const Handle &aHandle)
-        : mCritSect (&aHandle.mCritSect), mLevel (0), mLeftLevel (0) { lock(); }
-
-    AutoLock (const Handle *aHandle)
-        : mCritSect (aHandle ? &aHandle->mCritSect : NULL)
-        , mLevel (0), mLeftLevel (0) { lock(); }
-
-    AutoLock (const Lockable &aLockable)
-        : mCritSect (critSect (&aLockable))
-        , mLevel (0), mLeftLevel (0) { lock(); }
-
-    AutoLock (const Lockable *aLockable)
-        : mCritSect (aLockable ? critSect (aLockable) : NULL)
-        , mLevel (0), mLeftLevel (0) { lock(); }
-
-    ~AutoLock()
-    {
-        if (mCritSect)
+    }
+
+    /**
+     * Decreases the write lock level increased by #lock(). If the level drops
+     * to zero (e.g. the number of nested #unlock() calls matches the number of
+     * nested #lock() calls), releases the lock making the managed semaphore
+     * available for locking by other threads.
+     */
+    void unlock()
+    {
+        if (mHandle)
         {
-            if (mLeftLevel)
-            {
-                mLeftLevel -= mLevel;
-                mLevel = 0;
-                for (; mLeftLevel; -- mLeftLevel)
-                    RTCritSectEnter (mCritSect);
-            }
-            AssertMsg (mLevel <= 1, ("Lock level > 1: %d\n", mLevel));
-            for (; mLevel; -- mLevel)
-                RTCritSectLeave (mCritSect);
+            AssertReturnVoid (mLockLevel != 0 /* unlock() w/o preceding lock()? */);
+            mHandle->unlockWrite();
+            -- mLockLevel;
         }
     }
 
     /**
-     *  Tries to acquire the lock or increases the lock level
-     *  if the lock is already owned by this thread.
-     */
-    void lock()
-    {
-        if (mCritSect)
+     * Causes the current thread to completely release the write lock to make
+     * the managed semaphore immediately available for locking by other threads.
+     *
+     * This implies that all nested write locks on the semaphore will be
+     * released, even those that were acquired through the calls to #lock()
+     * methods of all other AutoLock/AutoReaderLock instances managing the
+     * <b>same</b> read/write semaphore.
+     *
+     * After calling this method, the only method you are allowed to call is
+     * #enter(). It will acquire the write lock again and restore the same
+     * level of nesting as it had before calling #leave().
+     *
+     * If this instance is destroyed without calling #enter(), the destructor
+     * will try to restore the write lock level that existed when #leave() was
+     * called minus the number of nested #lock() calls made on this instance
+     * itself. This is done to preserve lock levels of other
+     * AutoLock/AutoReaderLock instances managing the same semaphore (if any).
+     * Tiis also means that the destructor may indefinitely block if a write or
+     * a read lock is owned by some other thread by that time.
+     */
+    void leave()
+    {
+        if (mHandle)
         {
-            AssertMsgReturn (mLeftLevel == 0, ("lock() after leave()\n"), (void) 0);
-            ___CritSectEnter (mCritSect);
-            ++ mLevel;
+            AssertReturnVoid (mLockLevel != 0 /* leave() w/o preceding lock()? */);
+            AssertReturnVoid (mGlobalLockLevel == 0 /* second leave() in a row? */);
+
+            mGlobalLockLevel = mHandle->writeLockLevel();
+            AssertReturnVoid (mGlobalLockLevel >= mLockLevel /* logic error! */);
+
+            for (uint32_t left = mGlobalLockLevel; left; -- left)
+                mHandle->unlockWrite();
         }
     }
 
     /**
-     *  Decreases the lock level. If the level goes to zero, the lock
-     *  is released by the current thread.
-     */
-    void unlock()
-    {
-        if (mCritSect)
+     * Causes the current thread to restore the write lock level after the
+     * #leave() call. This call will indefinitely block if another thread has
+     * successfully acquired a write or a read lock on the same semaphore in
+     * between.
+     */
+    void enter()
+    {
+        if (mHandle)
         {
-            AssertMsgReturn (mLevel > 0, ("Lock level is zero\n"), (void) 0);
-            AssertMsgReturn (mLeftLevel == 0, ("lock() after leave()\n"), (void) 0);
-            -- mLevel;
-            RTCritSectLeave (mCritSect);
+            AssertReturnVoid (mLockLevel != 0 /* enter() w/o preceding lock()+leave()? */);
+            AssertReturnVoid (mGlobalLockLevel != 0 /* enter() w/o preceding leave()? */);
+
+            for (; mGlobalLockLevel; -- mGlobalLockLevel)
+                mHandle->lockWrite();
         }
     }
 
-    /**
-     *  Causes the current thread to completely release the lock
-     *  (including locks acquired by all other instances of this class
-     *  referring to the same object or handle). #enter() must be called
-     *  to acquire the lock back and restore all lock levels.
-     */
-    void leave()
-    {
-        if (mCritSect)
-        {
-            AssertMsg (mLevel > 0, ("Lock level is zero\n"));
-            AssertMsgReturn (mLeftLevel == 0, ("leave() w/o enter()\n"), (void) 0);
-            mLeftLevel = RTCritSectGetRecursion (mCritSect);
-            for (uint32_t left = mLeftLevel; left; -- left)
-                RTCritSectLeave (mCritSect);
-            Assert (mLeftLevel >= mLevel);
-        }
-    }
-
-    /**
-     *  Causes the current thread to acquire the lock again and restore
-     *  all lock levels after calling #leave().
-     */
-    void enter()
-    {
-        if (mCritSect)
-        {
-            AssertMsg (mLevel > 0, ("Lock level is zero\n"));
-            AssertMsgReturn (mLeftLevel > 0, ("enter() w/o leave()\n"), (void) 0);
-            for (; mLeftLevel; -- mLeftLevel)
-                ___CritSectEnter (mCritSect);
-        }
-    }
-
-    /**
-     *  Current level of the nested lock. 1 means the lock is not currently
-     *  nested.
-     */
-    uint32_t level() const { return RTCritSectGetRecursion (mCritSect); }
-
-    bool isNull() const { return mCritSect == NULL; }
+    /** Returns @c true if this instance manages a null semaphore handle. */
+    bool isNull() const { return mHandle == NULL; }
     bool operator !() const { return isNull(); }
 
-    /** Returns |true| if this instance manages the given lock handle. */
-    bool belongsTo (const Handle &aHandle)
-    {
-         return &aHandle.mCritSect == mCritSect;
-    }
-
-    /** Returns |true| if this instance manages the given lock handle. */
-    bool belongsTo (const Handle *aHandle)
-    {
-         return aHandle && &aHandle->mCritSect == mCritSect;
-    }
-
-    /** Returns |true| if this instance manages the given lockable object. */
+    /**
+     * Returns @c true if the current thread holds a write lock on the managed
+     * read/write semaphore. Returns @c false if the managed semaphore is @c
+     * NULL.
+     *
+     * @note Intended for debugging only.
+     */
+    bool isLockedOnCurrentThread() const
+    {
+        return mHandle ? mHandle->isLockedOnCurrentThread() : false;
+    }
+
+    /**
+     * Returns the current write lock level of the managed smaphore. The lock
+     * level determines the number of nested #lock() calls on the given
+     * semaphore handle. Returns @c 0 if the managed semaphore is @c
+     * NULL.
+     *
+     * Note that this call is valid only when the current thread owns a write
+     * lock on the given semaphore handle and will assert otherwise.
+     *
+     * @note Intended for debugging only.
+     */
+    uint32_t writeLockLevel() const
+    {
+        return mHandle ? mHandle->writeLockLevel() : 0;
+    }
+
+    /**
+     * Returns @c true if this instance manages the given semaphore handle.
+     *
+     * @note Intended for debugging only.
+     */
+    bool belongsTo (const LockHandle &aHandle) const { return mHandle == &aHandle; }
+
+    /**
+     * Returns @c true if this instance manages the given semaphore handle.
+     *
+     * @note Intended for debugging only.
+     */
+    bool belongsTo (const LockHandle *aHandle) const { return mHandle == aHandle; }
+
+    /**
+     * Returns @c true if this instance manages the given lockable object.
+     *
+     * @note Intended for debugging only.
+     */
     bool belongsTo (const Lockable &aLockable)
     {
@@ -260,23 +672,13 @@
     }
 
-    /** Returns |true| if this instance manages the given lockable object. */
+    /**
+     * Returns @c true if this instance manages the given lockable object.
+     *
+     * @note Intended for debugging only.
+     */
     bool belongsTo (const Lockable *aLockable)
     {
          return aLockable && belongsTo (aLockable->lockHandle());
     }
-
-    /**
-     *  Returns a tag to lock the given Lockable for reading by AutoMultiLock.
-     *  Shortcut to |aL->lockHandle()->rlock()|.
-     *  The returned tag is a no-op when @a aL is |NULL|.
-     */
-    static internal::LockableTag maybeRlock (Lockable *aL);
-
-    /**
-     *  Returns a tag to lock the given Lockable for writing by AutoMultiLock.
-     *  Shortcut to |aL->lockHandle()->wlock()|.
-     *  The returned tag is a no-op when @a aL is |NULL|.
-     */
-    static internal::LockableTag maybeWlock (Lockable *aL);
 
 private:
@@ -285,34 +687,222 @@
     DECLARE_CLS_NEW_DELETE_NOOP (AutoLock)
 
-    inline static RTCRITSECT *critSect (const Lockable *l)
-    {
-        Assert (l);
-        Handle *h = l->lockHandle();
-        return h ? &h->mCritSect : NULL;
-    }
-
-    RTCRITSECT *mCritSect;
-    uint32_t mLevel;
-    uint32_t mLeftLevel;
-
-    #undef ___CritSectEnter
-};
+    LockHandle *mHandle;
+    uint32_t mLockLevel;
+    uint32_t mGlobalLockLevel;
+
+    template <size_t> friend class AutoMultiWriteLockBase;
+};
+
+////////////////////////////////////////////////////////////////////////////////
 
 /**
- *  Prototype. Later will be used to acquire a read-only lock
- *  (read-only locks differ from regular (write) locks so that more than one
- *  read lock can be acquired simultaneously provided that there are no
- *  active write locks).
- *  @todo Implement it!
- */
-class AutoReaderLock : public AutoLock
-{
-public:
-
-    AutoReaderLock (const Handle &aHandle) : AutoLock (aHandle) {}
-    AutoReaderLock (const Handle *aHandle) : AutoLock (aHandle) {}
-
-    AutoReaderLock (const Lockable &aLockable) : AutoLock (aLockable) {}
-    AutoReaderLock (const Lockable *aLockable) : AutoLock (aLockable) {}
+ * Provides safe management of read/write semaphores in read mode.
+ *
+ * This class differs from the AutoLock class is so that it's #lock() and
+ * #unlock() methods requests and release read (shared) locks on the managed
+ * read/write semaphore instead of write (exclusive) locks. See the AutoLock
+ * class description for more information about read and write locks.
+ *
+ * Safe semaphore management consists of the following:
+ * <ul>
+ *   <li>When an instance of the AutoReaderLock class is constructed given a
+ *   valid semaphore handle, it will automatically request a read lock on that
+ *   semaphore.
+ *   </li>
+ *   <li>When an instance of the AutoReaderLock class constructed given a valid
+ *   semaphore handle is destroyed (e.g. goes out of scope), it will
+ *   automatically release the read lock that was requested upon construction
+ *   and also all nested read locks requested later using the #lock() call (note
+ *   that the latter is considered to be a program logic error, see the
+ *   #~AutoReaderLock() description for details).
+ *   </li>
+ * </ul>
+ *
+ * Note that the LockHandle class taken by AutoReaderLock constructors is an
+ * abstract base of the read/write semaphore. You should choose one of the
+ * existing subclasses of this abstract class or create your own subclass that
+ * implements necessary read and write lock semantics. The most suitable choice
+ * is the RWLockHandle class which provides full support for both read and write
+ * locks as describerd in AutoLock docs. Alternatively, you can use the
+ * WriteLockHandle class if you only need write (exclusive) locking
+ * (WriteLockHandle requires less system resources and works faster).
+ *
+ * However, please note that it absolutely does not make sense to manage
+ * WriteLockHandle semaphores with AutoReaderLock instances because
+ * AutoReaderLock instances will behave like AutoLock instances in this case
+ * since WriteLockHandle provides only exclusive write locking. You have been
+ * warned.
+
+ * A typical usage pattern of the AutoReaderLock class is as follows:
+ * <code>
+ *  struct Struct : public RWLockHandle
+ *  {
+ *      ...
+ *  };
+ *
+ *  void foo (Struct &aStruct)
+ *  {
+ *      {
+ *          // acquire a read lock of aStruct (note that two foo() calls may be
+ *          executed on separate threads simultaneously w/o blocking each other)
+ *          AutoReaderLock alock (aStruct);
+ *
+ *          // now we can read aStruct in a thread-safe manner
+ *          if (aStruct.foo)
+ *              ...;
+ *
+ *          // note that the read lock will be automatically released upon
+ *          // execution of the return statement below
+ *          if (!aStruct.bar)
+ *              return;
+ *
+ *          ...
+ *      }
+ *
+ *      // note that the read lock is automatically released here
+ *  }
+ * </code>
+ */
+class AutoReaderLock
+{
+public:
+
+    /**
+     * Constructs a null instance that does not manage any read/write
+     * semaphore.
+     *
+     * Note that all method calls on a null instance are no-ops. This allows to
+     * have the code where lock protection can be selected (or omitted) at
+     * runtime.
+     */
+    AutoReaderLock() : mHandle (NULL), mLockLevel (0) {}
+
+    /**
+     * Constructs a new instance that will start managing the given read/write
+     * semaphore by requesting a read lock.
+     */
+    AutoReaderLock (LockHandle *aHandle)
+        : mHandle (aHandle), mLockLevel (0)
+    { lock(); }
+
+    /**
+     * Constructs a new instance that will start managing the given read/write
+     * semaphore by requesting a read lock.
+     */
+    AutoReaderLock (LockHandle &aHandle)
+        : mHandle (&aHandle), mLockLevel (0)
+    { lock(); }
+
+    /**
+     * Constructs a new instance that will start managing the given read/write
+     * semaphore by requesting a read lock.
+     */
+    AutoReaderLock (const Lockable &aLockable)
+        : mHandle (aLockable.lockHandle()), mLockLevel (0)
+    { lock(); }
+
+    /**
+     * Constructs a new instance that will start managing the given read/write
+     * semaphore by requesting a read lock.
+     */
+    AutoReaderLock (const Lockable *aLockable)
+        : mHandle (aLockable ? aLockable->lockHandle() : NULL)
+        , mLockLevel (0)
+    { lock(); }
+
+    /**
+     * Release all read locks acquired by this instance through the #lock()
+     * call and destroys the instance.
+     *
+     * Note that if there there are nested #lock() calls without the
+     * corresponding number of #unlock() calls when the destructor is called, it
+     * will assert. This is because having an unbalanced number of nested locks
+     * is a program logic error which must be fixed.
+     */
+    ~AutoReaderLock()
+    {
+        if (mHandle)
+        {
+            AssertMsg (mLockLevel <= 1, ("Lock level > 1: %d\n", mLockLevel));
+            for (; mLockLevel; -- mLockLevel)
+                mHandle->unlockRead();
+        }
+    }
+
+    /**
+     * Requests a read (shared) lock. If a read lock is already owned by
+     * this thread, increases the lock level (allowing for nested read locks on
+     * the same thread). Blocks indefinitely if a write lock is already owned by
+     * another thread until that tread releases the write lock, otherwise
+     * returns immediately.
+     *
+     * Note that this method returns immediately even if any number of other
+     * threads owns read locks on the same semaphore. Also returns immediately
+     * if a write lock on this semaphore is owned by the current thread which
+     * allows for read locks nested into write locks on the same thread.
+     */
+    void lock()
+    {
+        if (mHandle)
+        {
+            mHandle->lockRead();
+            ++ mLockLevel;
+            Assert (mLockLevel != 0 /* overflow? */);
+        }
+    }
+
+    /**
+     * Decreases the read lock level increased by #lock(). If the level drops to
+     * zero (e.g. the number of nested #unlock() calls matches the number of
+     * nested #lock() calls), releases the lock making the managed semaphore
+     * available for locking by other threads.
+     */
+    void unlock()
+    {
+        if (mHandle)
+        {
+            AssertReturnVoid (mLockLevel != 0 /* unlock() w/o preceding lock()? */);
+            mHandle->unlockRead();
+            -- mLockLevel;
+        }
+    }
+
+    /** Returns @c true if this instance manages a null semaphore handle. */
+    bool isNull() const { return mHandle == NULL; }
+    bool operator !() const { return isNull(); }
+
+    /**
+     * Returns @c true if this instance manages the given semaphore handle.
+     *
+     * @note Intended for debugging only.
+     */
+    bool belongsTo (const LockHandle &aHandle) const { return mHandle == &aHandle; }
+
+    /**
+     * Returns @c true if this instance manages the given semaphore handle.
+     *
+     * @note Intended for debugging only.
+     */
+    bool belongsTo (const LockHandle *aHandle) const { return mHandle == aHandle; }
+
+    /**
+     * Returns @c true if this instance manages the given lockable object.
+     *
+     * @note Intended for debugging only.
+     */
+    bool belongsTo (const Lockable &aLockable)
+    {
+         return belongsTo (aLockable.lockHandle());
+    }
+
+    /**
+     * Returns @c true if this instance manages the given lockable object.
+     *
+     * @note Intended for debugging only.
+     */
+    bool belongsTo (const Lockable *aLockable)
+    {
+         return aLockable && belongsTo (aLockable->lockHandle());
+    }
 
 private:
@@ -320,219 +910,320 @@
     DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoReaderLock)
     DECLARE_CLS_NEW_DELETE_NOOP (AutoReaderLock)
-};
-
-namespace internal
-{
-    /**
-     *  @internal
-     *  Special struct to differentiate between read and write locks
-     *  in AutoMultiLock constructors.
-     */
-    struct LockableTag
-    {
-        LockableTag (const AutoLock::Handle *h, char m)
-            : handle (h), mode (m) {}
-        const AutoLock::Handle * const handle;
-        const char mode;
-    };
-}
-
-inline internal::LockableTag AutoLock::Handle::rlock() const
-{
-    return internal::LockableTag (this, 'r');
-}
-
-inline internal::LockableTag AutoLock::Handle::wlock() const
-{
-    return internal::LockableTag (this, 'w');
-}
-
-inline internal::LockableTag AutoLock::Lockable::rlock() const
-{
-    return internal::LockableTag (lockHandle(), 'r');
-}
-
-inline internal::LockableTag AutoLock::Lockable::wlock() const
-{
-    return internal::LockableTag (lockHandle(), 'w');
-}
-
-/* static */
-inline internal::LockableTag AutoLock::maybeRlock (AutoLock::Lockable *aL)
-{
-    return internal::LockableTag (aL ? aL->lockHandle() : NULL, 'r');
-}
-
-/* static */
-inline internal::LockableTag AutoLock::maybeWlock (AutoLock::Lockable *aL)
-{
-    return internal::LockableTag (aL ? aL->lockHandle() : NULL, 'w');
-}
+
+    LockHandle *mHandle;
+    uint32_t mLockLevel;
+};
+
+////////////////////////////////////////////////////////////////////////////////
 
 /**
- *  Smart template class to safely enter and leave a list of critical sections.
- *
- *  When constructing an instance, it enters all given critical sections
- *  (in an "atomic", "all or none" fashion). These critical sections will be
- *  exited automatically when the instance goes out of scope (i.e. gets destroyed).
- *
- *  It is possible to lock different critical sections in two different modes:
- *  for writing (as AutoLock does) or for reading (as AutoReaderLock does).
- *  The lock mode is determined by the method called on an AutoLock::Handle or
- *  AutoLock::Lockable instance when passing it to the AutoMultiLock constructor:
- *  |rlock()| to lock for reading or |wlock()| to lock for writing.
- *
- *  Instances of this class are constructed as follows:
- *  <code>
- *      ...
- *      AutoLock::Handle data1, data2;
- *      ...
- *      {
- *          AutoMultiLock <2> multiLock (data1.wlock(), data2.rlock());
- *          // all locks are entered here:
- *          // data1 is entered in write mode (like AutoLock)
- *          // data2 is entered in read mode (like AutoReaderLock),
- *      }
- *      // all locks are exited here
- *  </code>
- *
- *  The number of critical sections passed to the constructor must exactly
- *  match the number specified as the @a tCnt parameter of the template.
- *
- *  @param tCnt number of critical sections to manage
- */
-template <size_t tCnt>
-class AutoMultiLock
-{
-public:
-
-    #if defined(DEBUG)
-    # define ___CritSectEnterMulti(n, acs) \
-        RTCritSectEnterMultipleDebug ((n), (acs), \
-            "AutoMultiLock instantiation address >>>", 0, \
-            (RTUINTPTR) ASMReturnAddress())
-    #else
-    # define ___CritSectEnterMulti(n, acs) RTCritSectEnterMultiple ((n), (acs))
-    #endif
-
-    #define A(n) internal::LockableTag l##n
-    #define B(n) if (l##n.handle) { /* skip NULL tags */ \
-                     mS[i] = &l##n.handle->mCritSect; \
-                     mM[i++] = l##n.mode; \
-                 } else
-    #define C(n) \
-        mLocked = true; \
-        mM [0] = 0; /* for safety in case of early return */ \
-        AssertMsg (tCnt == n, \
-            ("This AutoMultiLock is for %d locks, but %d were passed!\n", tCnt, n)); \
-        if (tCnt != n) return; \
-        int i = 0
-    /// @todo (dmik) this will change when we switch to RTSemRW*
-    #define D() mM [i] = 0; /* end of array */ \
-                ___CritSectEnterMulti ((unsigned) strlen (mM), mS)
-
-    AutoMultiLock (A(0), A(1))
-    {
-        C(2);
-        B(0);
-        B(1);
-        D();
-    }
-    AutoMultiLock (A(0), A(1), A(2))
-    { C(3); B(0); B(1); B(2); D(); }
-    AutoMultiLock (A(0), A(1), A(2), A(3))
-    { C(4); B(0); B(1); B(2); B(3); D(); }
-    AutoMultiLock (A(0), A(1), A(2), A(3), A(4))
-    { C(5); B(0); B(1); B(2); B(3); B(4); D(); }
-    AutoMultiLock (A(0), A(1), A(2), A(3), A(4), A(5))
-    { C(6); B(0); B(1); B(2); B(3); B(4); B(5); D(); }
-    AutoMultiLock (A(0), A(1), A(2), A(3), A(4), A(5), A(6))
-    { C(7); B(0); B(1); B(2); B(3); B(4); B(5); B(6); D(); }
-    AutoMultiLock (A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7))
-    { C(8); B(0); B(1); B(2); B(3); B(4); B(5); B(6); B(7); D(); }
-    AutoMultiLock (A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8))
-    { C(9); B(0); B(1); B(2); B(3); B(4); B(5); B(6); B(7); B(8); D(); }
-    AutoMultiLock (A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9))
-    { C(10); B(0); B(1); B(2); B(3); B(4); B(5); B(6); B(7); B(8); B(9); D(); }
-
-    #undef D
-    #undef C
-    #undef B
-    #undef A
-
-    /**
-     *  Releases all locks if not yet released by #leave() and
-     *  destroys the instance.
-     */
-    ~AutoMultiLock()
-    {
-        /// @todo (dmik) this will change when we switch to RTSemRW*
-        if (mLocked)
-            RTCritSectLeaveMultiple ((unsigned) strlen (mM), mS);
-    }
-
-    /**
-     *  Releases all locks temporarily in order to enter them again using
-     *  #enter().
-     *
-     *  @note There is no need to call this method unless you want later call
-     *  #enter(). The destructor calls it automatically when necessary.
-     *
-     *  @note Calling this method twice without calling #enter() in between will
-     *  definitely fail.
-     *
-     *  @note Unlike AutoLock::leave(), this method doesn't cause a complete
-     *  release of all involved locks; if any of the locks was entered on the
-     *  current thread prior constructing the AutoMultiLock instanve, they will
-     *  remain acquired after this call! For this reason, using this method in
-     *  the custom code doesn't make any practical sense.
-     *
-     *  @todo Rename this method to unlock() and rename #enter() to lock()
-     *  for similarity with AutoLock.
+ * Helper template class for AutoMultiLockN classes.
+ *
+ * @param Cnt number of read/write semaphores to manage.
+ */
+template <size_t Cnt>
+class AutoMultiLockBase
+{
+public:
+
+    /**
+     * Releases all locks if not yet released by #unlock() and destroys the
+     * instance.
+     */
+    ~AutoMultiLockBase()
+    {
+        if (mIsLocked)
+            unlock();
+    }
+
+    /**
+     * Calls LockOps::lock() methods of all managed semaphore handles
+     * in order they were passed to the constructor.
+     *
+     * Note that as opposed to LockHandle::lock(), this call cannot be nested
+     * and will assert if so.
+     */
+    void lock()
+    {
+        AssertReturnVoid (!mIsLocked);
+
+        size_t i = 0;
+        while (i < ELEMENTS (mOps))
+            if (mOps [i])
+                mOps [i ++]->lock();
+        mIsLocked = true;
+    }
+
+    /**
+     * Calls LockOps::unlock() methods of all managed semaphore handles in
+     * reverse to the order they were passed to the constructor.
+     *
+     * Note that as opposed to LockHandle::unlock(), this call cannot be nested
+     * and will assert if so.
+     */
+    void unlock()
+    {
+        AssertReturnVoid (mIsLocked);
+
+        AssertReturnVoid (ELEMENTS (mOps) > 0);
+        size_t i = ELEMENTS (mOps);
+        do
+            if (mOps [-- i])
+                mOps [i]->unlock();
+        while (i != 0);
+        mIsLocked = false;
+    }
+
+protected:
+
+    AutoMultiLockBase() : mIsLocked (false) {}
+
+    LockOps *mOps [Cnt];
+    bool mIsLocked;
+
+private:
+
+    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiLockBase)
+    DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiLockBase)
+};
+
+/** AutoMultiLockBase <0> is meaningless and forbidden. */
+template<>
+class AutoMultiLockBase <0> { private : AutoMultiLockBase(); };
+
+/** AutoMultiLockBase <1> is meaningless and forbidden. */
+template<>
+class AutoMultiLockBase <1> { private : AutoMultiLockBase(); };
+
+////////////////////////////////////////////////////////////////////////////////
+
+/* AutoMultiLockN class definitions */
+
+#define A(n) LockOps *l##n
+#define B(n) mOps [n] = l##n
+
+/**
+ * AutoMultiLock for 2 locks.
+ *
+ * The AutoMultiLockN family of classes provides a possibility to manage several
+ * read/write semaphores at once. This is handy if all managed semaphores need
+ * to be locked and unlocked synchronously and will also help to avoid locking
+ * order errors.
+ *
+ * Instances of AutoMultiLockN classes are constructed from a list of LockOps
+ * arguments. The AutoMultiLockBase::lock() method will make sure that the given
+ * list of semaphores represented by LockOps pointers will be locked in order
+ * they are passed to the constructor. The AutoMultiLockBase::unlock() method
+ * will make sure that they will be unlocked in reverse order.
+ *
+ * The type of the lock to request is specified for each semaphore individually
+ * using the corresponding LockOps getter of a LockHandle or Lockable object:
+ * LockHandle::wlock() in order to request a write lock or LockHandle::rlock()
+ * in order to request a read lock.
+ *
+ * Here is a typical usage pattern:
+ * <code>
+ *  ...
+ *  LockHandle data1, data2;
+ *  ...
+ *  {
+ *      AutoMultiLock2 multiLock (data1.wlock(), data2.rlock());
+ *      // both locks are held here:
+ *      // - data1 is locked in write mode (like AutoLock)
+ *      // - data2 is locked in read mode (like AutoReaderLock)
+ *  }
+ *  // both locks are released here
+ * </code>
+ */
+class AutoMultiLock2 : public AutoMultiLockBase <2>
+{
+public:
+    AutoMultiLock2 (A(0), A(1))
+    { B(0); B(1); lock(); }
+};
+
+/** AutoMultiLock for 3 locks. See AutoMultiLock2 for more information. */
+class AutoMultiLock3 : public AutoMultiLockBase <3>
+{
+public:
+    AutoMultiLock3 (A(0), A(1), A(2))
+    { B(0); B(1); B(2); lock(); }
+};
+
+/** AutoMultiLock for 4 locks. See AutoMultiLock2 for more information. */
+class AutoMultiLock4 : public AutoMultiLockBase <4>
+{
+public:
+    AutoMultiLock4 (A(0), A(1), A(2), A(3))
+    { B(0); B(1); B(2); B(3); lock(); }
+};
+
+#undef B
+#undef A
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Helper template class for AutoMultiWriteLockN classes.
+ *
+ * @param Cnt number of write semaphores to manage.
+ */
+template <size_t Cnt>
+class AutoMultiWriteLockBase
+{
+public:
+
+    /**
+     * Calls AutoLock::lock() methods for all managed semaphore handles in order
+     * they were passed to the constructor.
+     */
+    void lock()
+    {
+        size_t i = 0;
+        while (i < ELEMENTS (mLocks))
+            mLocks [i ++].lock();
+    }
+
+    /**
+     * Calls AutoLock::unlock() methods for all managed semaphore handles in
+     * reverse to the order they were passed to the constructor.
+     */
+    void unlock()
+    {
+        AssertReturnVoid (ELEMENTS (mLocks) > 0);
+        size_t i = ELEMENTS (mLocks);
+        do
+            mLocks [-- i].unlock();
+        while (i != 0);
+    }
+
+    /**
+     * Calls AutoLock::leave() methods for all managed semaphore handles in
+     * reverse to the order they were passed to the constructor.
      */
     void leave()
     {
-        AssertMsgReturn (mLocked, ("Already released all locks"), (void) 0);
-        /// @todo (dmik) this will change when we switch to RTSemRW*
-        RTCritSectLeaveMultiple ((unsigned) strlen (mM), mS);
-        mLocked = false;
-    }
-
-    /**
-     *  Tries to enter all locks temporarily released by #unlock().
-     *
-     *  @note This method succeeds only after #unlock() and always fails
-     *  otherwise.
+        AssertReturnVoid (ELEMENTS (mLocks) > 0);
+        size_t i = ELEMENTS (mLocks);
+        do
+            mLocks [-- i].leave();
+        while (i != 0);
+    }
+
+    /**
+     * Calls AutoLock::enter() methods for all managed semaphore handles in order
+     * they were passed to the constructor.
      */
     void enter()
     {
-        AssertMsgReturn (!mLocked, ("Already entered all locks"), (void) 0);
-        ___CritSectEnterMulti ((unsigned) strlen (mM), mS);
-        mLocked = true;
-    }
+        size_t i = 0;
+        while (i < ELEMENTS (mLocks))
+            mLocks [i ++].enter();
+    }
+
+protected:
+
+    AutoMultiWriteLockBase() {}
+
+    void setLockHandle (size_t aIdx, LockHandle *aHandle)
+    { mLocks [aIdx].mHandle = aHandle; }
 
 private:
 
-    AutoMultiLock();
-
-    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiLock)
-    DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiLock)
-
-    RTCRITSECT *mS [tCnt];
-    char mM [tCnt + 1];
-    bool mLocked;
-
-    #undef ___CritSectEnterMulti
-};
+    AutoLock mLocks [Cnt];
+
+    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiWriteLockBase)
+    DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiWriteLockBase)
+};
+
+/** AutoMultiWriteLockBase <0> is meaningless and forbidden. */
+template<>
+class AutoMultiWriteLockBase <0> { private : AutoMultiWriteLockBase(); };
+
+/** AutoMultiWriteLockBase <1> is meaningless and forbidden. */
+template<>
+class AutoMultiWriteLockBase <1> { private : AutoMultiWriteLockBase(); };
+
+////////////////////////////////////////////////////////////////////////////////
+
+/* AutoMultiLockN class definitions */
+
+#define A(n) LockHandle *l##n
+#define B(n) setLockHandle (n, l##n)
+
+#define C(n) Lockable *l##n
+#define D(n) setLockHandle (n, l##n ? l##n->lockHandle() : NULL)
 
 /**
- *  Disable instantiations of AutoMultiLock for zero and one
- *  number of locks.
- */
-template<>
-class AutoMultiLock <0> { private : AutoMultiLock(); };
-
-template<>
-class AutoMultiLock <1> { private : AutoMultiLock(); };
+ * AutoMultiWriteLock for 2 locks.
+ *
+ * The AutoMultiWriteLockN family of classes provides a possibility to manage
+ * several read/write semaphores at once. This is handy if all managed
+ * semaphores need to be locked and unlocked synchronously and will also help to
+ * avoid locking order errors.
+ *
+ * The functionality of the AutoMultiWriteLockN class family is similar to the
+ * functionality of the AutoMultiLockN class family (see the AutoMultiLock2
+ * class for details) with two important differences:
+ * <ol>
+ *     <li>Instances of AutoMultiWriteLockN classes are constructed from a list
+ *     of LockHandle or Lockable arguments directly instead of getting
+ *     intermediate LockOps interface pointers.
+ *     </li>
+ *     <li>All locks are requested in <b>write</b> mode.
+ *     </li>
+ *     <li>Since all locks are requested in write mode, bulk
+ *     AutoMultiWriteLockBase::leave() and AutoMultiWriteLockBase::enter()
+ *     operations are also available, that will leave and enter all managed
+ *     semaphores at once in the proper order (similarly to
+ *     AutoMultiWriteLockBase::lock() and AutoMultiWriteLockBase::unlock()).
+ *     </li>
+ * </ol>
+ *
+ * Here is a typical usage pattern:
+ * <code>
+ *  ...
+ *  LockHandle data1, data2;
+ *  ...
+ *  {
+ *      AutoMultiWriteLock2 multiLock (&data1, &data2);
+ *      // both locks are held in write mode here
+ *  }
+ *  // both locks are released here
+ * </code>
+ */
+class AutoMultiWriteLock2 : public AutoMultiWriteLockBase <2>
+{
+public:
+    AutoMultiWriteLock2 (A(0), A(1))
+    { B(0); B(1); lock(); }
+    AutoMultiWriteLock2 (C(0), C(1))
+    { D(0); D(1); lock(); }
+};
+
+/** AutoMultiWriteLock for 3 locks. See AutoMultiWriteLock2 for more details. */
+class AutoMultiWriteLock3 : public AutoMultiWriteLockBase <3>
+{
+public:
+    AutoMultiWriteLock3 (A(0), A(1), A(2))
+    { B(0); B(1); B(2); lock(); }
+    AutoMultiWriteLock3 (C(0), C(1), C(2))
+    { D(0); D(1); D(2); lock(); }
+};
+
+/** AutoMultiWriteLock for 4 locks. See AutoMultiWriteLock2 for more details. */
+class AutoMultiWriteLock4 : public AutoMultiWriteLockBase <4>
+{
+public:
+    AutoMultiWriteLock4 (A(0), A(1), A(2), A(3))
+    { B(0); B(1); B(2); B(3); lock(); }
+    AutoMultiWriteLock4 (C(0), C(1), C(2), C(3))
+    { D(0); D(1); D(2); D(3); lock(); }
+};
+
+#undef D
+#undef C
+#undef B
+#undef A
 
 } /* namespace util */
Index: /trunk/src/VBox/Main/include/HardDiskImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/HardDiskImpl.h	(revision 7991)
+++ /trunk/src/VBox/Main/include/HardDiskImpl.h	(revision 7992)
@@ -117,5 +117,5 @@
 
     /** Shortcut to #dependentChildrenLock() */
-    AutoLock::Handle &childrenLock() const { return dependentChildrenLock(); }
+    RWLockHandle *childrenLock() const { return dependentChildrenLock(); }
 
     /**
Index: /trunk/src/VBox/Main/include/MachineImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/MachineImpl.h	(revision 7991)
+++ /trunk/src/VBox/Main/include/MachineImpl.h	(revision 7992)
@@ -147,7 +147,8 @@
         RTTIMESPEC mLastStateChange;
 
+        /* Note: These are guarded by VirtualBoxBase::stateLockHandle() */
         uint32_t mMachineStateDeps;
-        RTSEMEVENT mZeroMachineStateDepsSem;
-        BOOL mWaitingStateDeps;
+        RTSEMEVENTMULTI mMachineStateDepsSem;
+        uint32_t mMachineStateChangePending;
 
         BOOL mCurrentStateModified;
@@ -615,5 +616,5 @@
     void uninitDataAndChildObjects();
 
-    void checkStateDependencies (AutoLock &aLock);
+    void ensureNoStateDependencies (AutoLock &aLock);
 
     virtual HRESULT setMachineState (MachineState_T aMachineState);
@@ -775,6 +776,6 @@
     void uninit() { uninit (Uninit::Unexpected); }
 
-    // AutoLock::Lockable interface
-    AutoLock::Handle *lockHandle() const;
+    // util::Lockable interface
+    RWLockHandle *lockHandle() const;
 
     // IInternalMachineControl methods
@@ -934,6 +935,6 @@
     void uninit();
 
-    // AutoLock::Lockable interface
-    AutoLock::Handle *lockHandle() const;
+    // util::Lockable interface
+    RWLockHandle *lockHandle() const;
 
     // public methods only for internal purposes
Index: /trunk/src/VBox/Main/include/SnapshotImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/SnapshotImpl.h	(revision 7991)
+++ /trunk/src/VBox/Main/include/SnapshotImpl.h	(revision 7992)
@@ -97,5 +97,5 @@
 
     /** Shortcut to #dependentChildrenLock() */
-    AutoLock::Handle &childrenLock() const { return dependentChildrenLock(); }
+    RWLockHandle *childrenLock() const { return dependentChildrenLock(); }
 
     /**
Index: /trunk/src/VBox/Main/include/VirtualBoxBase.h
===================================================================
--- /trunk/src/VBox/Main/include/VirtualBoxBase.h	(revision 7991)
+++ /trunk/src/VBox/Main/include/VirtualBoxBase.h	(revision 7992)
@@ -31,7 +31,5 @@
 
 using namespace com;
-using util::AutoLock;
-using util::AutoReaderLock;
-using util::AutoMultiLock;
+using namespace util;
 
 #include <iprt/cdefs.h>
@@ -438,5 +436,5 @@
     : public CComObjectRootEx
 #endif
-    , public AutoLock::Lockable
+    , public Lockable
 {
 public:
@@ -452,5 +450,5 @@
 
     // AutoLock::Lockable interface
-    virtual AutoLock::Handle *lockHandle() const;
+    virtual RWLockHandle *lockHandle() const;
 
     /**
@@ -863,4 +861,12 @@
     };
 
+    /**
+     * Returns a lock handle used to protect the primary state fields (used by
+     * #addCaller(), AutoInitSpan, AutoUninitSpan, etc.). Only intended to be
+     * used for similar purposes in subclasses. WARNING: NO any other locks may
+     * be requested while holding this lock!
+     */
+    WriteLockHandle *stateLockHandle() { return &mStateLock; }
+
 private:
 
@@ -886,8 +892,8 @@
 
     /** Protects access to state related data members */
-    RTCRITSECT mStateLock;
+    WriteLockHandle mStateLock;
 
     /** User-level object lock for subclasses */
-    mutable AutoLock::Handle *mObjectLock;
+    mutable RWLockHandle *mObjectLock;
 };
 
@@ -1619,12 +1625,8 @@
     VirtualBoxBaseWithChildren()
         : mUninitDoneSem (NIL_RTSEMEVENT), mChildrenLeft (0)
-    {
-        RTCritSectInit (&mMapLock);
-    }
+    {}
 
     virtual ~VirtualBoxBaseWithChildren()
-    {
-        RTCritSectDelete (&mMapLock);
-    }
+    {}
 
     /**
@@ -1680,5 +1682,6 @@
     DependentChildren mDependentChildren;
 
-    RTCRITSECT mMapLock;
+    WriteLockHandle mMapLock;
+
     RTSEMEVENT mUninitDoneSem;
     unsigned mChildrenLeft;
@@ -1825,5 +1828,5 @@
 
     /* Protects all the fields above */
-    AutoLock::Handle mMapLock;
+    RWLockHandle mMapLock;
 };
 
@@ -1907,5 +1910,5 @@
      *  </code>
      */
-    AutoLock::Handle &dependentChildrenLock() const { return mMapLock; }
+    RWLockHandle *dependentChildrenLock() const { return &mMapLock; }
 
     /**
@@ -1975,5 +1978,5 @@
 
     bool mInUninit;
-    mutable AutoLock::Handle mMapLock;
+    mutable RWLockHandle mMapLock;
 };
 
@@ -2063,5 +2066,5 @@
      * </code>
      */
-    AutoLock::Handle &dependentChildrenLock() const { return mMapLock; }
+    RWLockHandle *dependentChildrenLock() const { return &mMapLock; }
 
     /**
@@ -2097,5 +2100,5 @@
 
     /* Protects the two fields above */
-    mutable AutoLock::Handle mMapLock;
+    mutable RWLockHandle mMapLock;
 };
 
Index: /trunk/src/VBox/Main/include/VirtualBoxImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/VirtualBoxImpl.h	(revision 7991)
+++ /trunk/src/VBox/Main/include/VirtualBoxImpl.h	(revision 7992)
@@ -467,5 +467,5 @@
     EventQueue * const mAsyncEventQ;
     /** Lock for calling EventQueue->post() */
-    AutoLock::Handle mAsyncEventQLock;
+    RWLockHandle mAsyncEventQLock;
 
     static Bstr sVersion;
