Index: trunk/src/VBox/VMM/VMMAll/PDMAllCritSect.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/PDMAllCritSect.cpp	(revision 90376)
+++ trunk/src/VBox/VMM/VMMAll/PDMAllCritSect.cpp	(revision 90379)
@@ -249,4 +249,5 @@
 
     RTNATIVETHREAD hNativeSelf = pdmCritSectGetNativeSelf(pVM, pCritSect);
+    AssertReturn(hNativeSelf != NIL_RTNATIVETHREAD, VERR_VM_THREAD_NOT_EMT);
     /* ... not owned ... */
     if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, 0, -1))
@@ -291,6 +292,6 @@
     return pdmR3R0CritSectEnterContended(pVM, pCritSect, hNativeSelf, pSrcPos);
 
-#else
-# ifdef IN_RING0
+#elif defined(IN_RING0)
+# if 0 /* new code */
     /*
      * In ring-0 context we have to take the special VT-x/AMD-V HM context into
@@ -304,41 +305,27 @@
      * We must never block if VMMRZCallRing3Disable is active.
      */
-
-    /** @todo If preemption is disabled it means we're in VT-x/AMD-V context
-     *        and would be better off switching out of that while waiting for
-     *        the lock.  Several of the locks jumps back to ring-3 just to
-     *        get the lock, the ring-3 code will then call the kernel to do
-     *        the lock wait and when the call return it will call ring-0
-     *        again and resume via in setjmp style.  Not very efficient. */
-#  if 0
-    if (ASMIntAreEnabled()) /** @todo this can be handled as well by changing
-                             * callers not prepared for longjmp/blocking to
-                             * use PDMCritSectTryEnter. */
-    {
-        /*
-         * Leave HM context while waiting if necessary.
-         */
-        int rc;
-        if (RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+    PVMCPUCC pVCpu = VMMGetCpu(pVM);
+    if (pVCpu)
+    {
+        VMMR0EMTBLOCKCTX Ctx;
+        int rc = VMMR0EmtPrepareToBlock(pVCpu, rcBusy, __FUNCTION__, pCritSect, &Ctx);
+        if (rc == VINF_SUCCESS)
         {
-            STAM_REL_COUNTER_ADD(&pCritSect->s.StatContentionRZLock,    1000000);
+            Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+
             rc = pdmR3R0CritSectEnterContended(pVM, pCritSect, hNativeSelf, pSrcPos);
+
+            VMMR0EmtResumeAfterBlocking(pVCpu, &Ctx);
         }
         else
-        {
-            STAM_REL_COUNTER_ADD(&pCritSect->s.StatContentionRZLock, 1000000000);
-            PVMCC     pVM   = pCritSect->s.CTX_SUFF(pVM);
-            PVMCPUCC  pVCpu = VMMGetCpu(pVM);
-            HMR0Leave(pVM, pVCpu);
-            RTThreadPreemptRestore(NIL_RTTHREAD, XXX);
-
-            rc = pdmR3R0CritSectEnterContended(pVM, pCritSect, hNativeSelf, pSrcPos);
-
-            RTThreadPreemptDisable(NIL_RTTHREAD, XXX);
-            HMR0Enter(pVM, pVCpu);
-        }
+            STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionRZLockBusy);
         return rc;
     }
-#  else
+
+    /* Non-EMT. */
+    Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+    return pdmR3R0CritSectEnterContended(pVM, pCritSect, hNativeSelf, pSrcPos);
+
+# else /* old code: */
     /*
      * We preemption hasn't been disabled, we can block here in ring-0.
@@ -347,6 +334,4 @@
         && ASMIntAreEnabled())
         return pdmR3R0CritSectEnterContended(pVM, pCritSect, hNativeSelf, pSrcPos);
-#  endif
-# endif /* IN_RING0 */
 
     STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionRZLock);
@@ -367,5 +352,8 @@
     LogFlow(("PDMCritSectEnter: locked => R3 (%Rrc)\n", rcBusy));
     return rcBusy;
-#endif /* !IN_RING3 */
+# endif  /* old code */
+#else
+# error "Unsupported context"
+#endif
 }
 
@@ -460,4 +448,5 @@
 
     RTNATIVETHREAD hNativeSelf = pdmCritSectGetNativeSelf(pVM, pCritSect);
+    AssertReturn(hNativeSelf != NIL_RTNATIVETHREAD, VERR_VM_THREAD_NOT_EMT);
     /* ... not owned ... */
     if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, 0, -1))
@@ -485,5 +474,5 @@
     STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionR3);
 #else
-    STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionRZLock);
+    STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionRZLockBusy);
 #endif
     LogFlow(("PDMCritSectTryEnter: locked\n"));
@@ -595,5 +584,5 @@
      */
     RTNATIVETHREAD const hNativeSelf = pdmCritSectGetNativeSelf(pVM, pCritSect);
-    AssertReleaseMsgReturn(pCritSect->s.Core.NativeThreadOwner == hNativeSelf,
+    AssertReleaseMsgReturn(pCritSect->s.Core.NativeThreadOwner == hNativeSelf || hNativeSelf == NIL_RTNATIVETHREAD,
                            ("%p %s: %p != %p; cLockers=%d cNestings=%d\n", pCritSect, R3STRING(pCritSect->s.pszName),
                             pCritSect->s.Core.NativeThreadOwner, hNativeSelf,
Index: trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp	(revision 90376)
+++ trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp	(revision 90379)
@@ -907,4 +907,5 @@
                         rc = GMMR0InitPerVMData(pGVM);
                         int rc2 = PGMR0InitPerVMData(pGVM);
+                        VMMR0InitPerVMData(pGVM);
                         DBGFR0InitPerVMData(pGVM);
                         PDMR0InitPerVMData(pGVM);
Index: trunk/src/VBox/VMM/VMMR0/HMR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/HMR0.cpp	(revision 90376)
+++ trunk/src/VBox/VMM/VMMR0/HMR0.cpp	(revision 90379)
@@ -1513,4 +1513,8 @@
 /**
  * Thread-context hook for HM.
+ *
+ * This is used together with RTThreadCtxHookCreate() on platforms which
+ * supports it, and directly from VMMR0EmtPrepareForBlocking() and
+ * VMMR0EmtResumeAfterBlocking() on platforms which don't.
  *
  * @param   enmEvent        The thread-context event.
Index: trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 90376)
+++ trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 90379)
@@ -2298,4 +2298,8 @@
  * Thread-context callback for AMD-V.
  *
+ * This is used together with RTThreadCtxHookCreate() on platforms which
+ * supports it, and directly from VMMR0EmtPrepareForBlocking() and
+ * VMMR0EmtResumeAfterBlocking() on platforms which don't.
+ *
  * @param   enmEvent        The thread-context event.
  * @param   pVCpu           The cross context virtual CPU structure.
@@ -2312,5 +2316,4 @@
         {
             Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
-            Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
             VMCPU_ASSERT_EMT(pVCpu);
 
@@ -2337,5 +2340,4 @@
         {
             Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
-            Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
             VMCPU_ASSERT_EMT(pVCpu);
 
Index: trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 90376)
+++ trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 90379)
@@ -9351,5 +9351,9 @@
 
 /**
- * The thread-context callback (only on platforms which support it).
+ * The thread-context callback.
+ *
+ * This is used together with RTThreadCtxHookCreate() on platforms which
+ * supports it, and directly from VMMR0EmtPrepareForBlocking() and
+ * VMMR0EmtResumeAfterBlocking() on platforms which don't.
  *
  * @param   enmEvent        The thread-context event.
@@ -9368,5 +9372,4 @@
         {
             Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
-            Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
             VMCPU_ASSERT_EMT(pVCpu);
 
@@ -9399,5 +9402,4 @@
         {
             Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
-            Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
             VMCPU_ASSERT_EMT(pVCpu);
 
Index: trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 90376)
+++ trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 90379)
@@ -359,4 +359,23 @@
 
 /**
+ * Initializes VMM specific members when the GVM structure is created.
+ *
+ * @param   pGVM        The global (ring-0) VM structure.
+ */
+VMMR0_INT_DECL(void) VMMR0InitPerVMData(PGVM pGVM)
+{
+    for (VMCPUID idCpu = 0; idCpu < pGVM->cCpus; idCpu++)
+    {
+        PGVMCPU pGVCpu = &pGVM->aCpus[idCpu];
+        pGVCpu->vmmr0.s.idHostCpu       = NIL_RTCPUID;
+        pGVCpu->vmmr0.s.iHostCpuSet     = UINT32_MAX;
+        pGVCpu->vmmr0.s.fInHmContext    = false;
+        pGVCpu->vmmr0.s.pPreemptState   = NULL;
+        pGVCpu->vmmr0.s.hCtxHook        = NIL_RTTHREADCTXHOOK;
+    }
+}
+
+
+/**
  * Initiates the R0 driver for a particular VM instance.
  *
@@ -954,4 +973,8 @@
  * callback.
  *
+ * This is used together with RTThreadCtxHookCreate() on platforms which
+ * supports it, and directly from VMMR0EmtPrepareForBlocking() and
+ * VMMR0EmtResumeAfterBlocking() on platforms which don't.
+ *
  * @param   enmEvent    The thread-context event.
  * @param   pvUser      Opaque pointer to the VMCPU.
@@ -983,5 +1006,7 @@
             RTCPUID idHostCpu;
             uint32_t iHostCpuSet = RTMpCurSetIndexAndId(&idHostCpu);
-            pVCpu->iHostCpuSet   = iHostCpuSet;
+            pVCpu->vmmr0.s.iHostCpuSet = iHostCpuSet;
+            ASMAtomicWriteU32(&pVCpu->vmmr0.s.idHostCpu, idHostCpu);
+            pVCpu->iHostCpuSet = iHostCpuSet;
             ASMAtomicWriteU32(&pVCpu->idHostCpu, idHostCpu);
 
@@ -989,5 +1014,7 @@
                rescheduled needs calculating, try force a return to ring-3.
                We unfortunately cannot do the measurements right here. */
-            if (RT_UNLIKELY(SUPIsTscDeltaAvailableForCpuSetIndex(iHostCpuSet)))
+            if (RT_LIKELY(!SUPIsTscDeltaAvailableForCpuSetIndex(iHostCpuSet)))
+            { /* likely */ }
+            else
                 VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
 
@@ -1009,4 +1036,6 @@
              * have the same host CPU associated with it.
              */
+            pVCpu->vmmr0.s.iHostCpuSet = UINT32_MAX;
+            ASMAtomicWriteU32(&pVCpu->vmmr0.s.idHostCpu, NIL_RTCPUID);
             pVCpu->iHostCpuSet = UINT32_MAX;
             ASMAtomicWriteU32(&pVCpu->idHostCpu, NIL_RTCPUID);
@@ -1036,10 +1065,13 @@
 {
     VMCPU_ASSERT_EMT(pVCpu);
-    Assert(pVCpu->vmm.s.hCtxHook == NIL_RTTHREADCTXHOOK);
+    Assert(pVCpu->vmmr0.s.hCtxHook == NIL_RTTHREADCTXHOOK);
 
 #if 1 /* To disable this stuff change to zero. */
-    int rc = RTThreadCtxHookCreate(&pVCpu->vmm.s.hCtxHook, 0, vmmR0ThreadCtxCallback, pVCpu);
+    int rc = RTThreadCtxHookCreate(&pVCpu->vmmr0.s.hCtxHook, 0, vmmR0ThreadCtxCallback, pVCpu);
     if (RT_SUCCESS(rc))
+    {
+        pVCpu->pGVM->vmm.s.fIsUsingContextHooks = true;
         return rc;
+    }
 #else
     RT_NOREF(vmmR0ThreadCtxCallback);
@@ -1047,5 +1079,6 @@
 #endif
 
-    pVCpu->vmm.s.hCtxHook = NIL_RTTHREADCTXHOOK;
+    pVCpu->vmmr0.s.hCtxHook = NIL_RTTHREADCTXHOOK;
+    pVCpu->pGVM->vmm.s.fIsUsingContextHooks = false;
     if (rc == VERR_NOT_SUPPORTED)
         return VINF_SUCCESS;
@@ -1064,7 +1097,7 @@
 VMMR0_INT_DECL(void) VMMR0ThreadCtxHookDestroyForEmt(PVMCPUCC pVCpu)
 {
-    int rc = RTThreadCtxHookDestroy(pVCpu->vmm.s.hCtxHook);
+    int rc = RTThreadCtxHookDestroy(pVCpu->vmmr0.s.hCtxHook);
     AssertRC(rc);
-    pVCpu->vmm.s.hCtxHook = NIL_RTTHREADCTXHOOK;
+    pVCpu->vmmr0.s.hCtxHook = NIL_RTTHREADCTXHOOK;
 }
 
@@ -1101,8 +1134,9 @@
      * Disable the context hook, if we got one.
      */
-    if (pVCpu->vmm.s.hCtxHook != NIL_RTTHREADCTXHOOK)
+    if (pVCpu->vmmr0.s.hCtxHook != NIL_RTTHREADCTXHOOK)
     {
         Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
-        int rc = RTThreadCtxHookDisable(pVCpu->vmm.s.hCtxHook);
+        ASMAtomicWriteU32(&pVCpu->vmmr0.s.idHostCpu, NIL_RTCPUID);
+        int rc = RTThreadCtxHookDisable(pVCpu->vmmr0.s.hCtxHook);
         AssertRC(rc);
     }
@@ -1118,5 +1152,5 @@
 DECLINLINE(bool) vmmR0ThreadCtxHookIsEnabled(PVMCPUCC pVCpu)
 {
-    return RTThreadCtxHookIsEnabled(pVCpu->vmm.s.hCtxHook);
+    return RTThreadCtxHookIsEnabled(pVCpu->vmmr0.s.hCtxHook);
 }
 
@@ -1413,4 +1447,5 @@
                 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
                 RTThreadPreemptDisable(&PreemptState);
+                pGVCpu->vmmr0.s.pPreemptState = &PreemptState;
 
                 /*
@@ -1423,4 +1458,7 @@
                               && SUPIsTscDeltaAvailableForCpuSetIndex(iHostCpuSet)))
                 {
+                    pGVCpu->vmmr0.s.iHostCpuSet = iHostCpuSet;
+                    ASMAtomicWriteU32(&pGVCpu->vmmr0.s.idHostCpu, idHostCpu);
+
                     pGVCpu->iHostCpuSet = iHostCpuSet;
                     ASMAtomicWriteU32(&pGVCpu->idHostCpu, idHostCpu);
@@ -1448,8 +1486,8 @@
                          * Enable the context switching hook.
                          */
-                        if (pGVCpu->vmm.s.hCtxHook != NIL_RTTHREADCTXHOOK)
+                        if (pGVCpu->vmmr0.s.hCtxHook != NIL_RTTHREADCTXHOOK)
                         {
-                            Assert(!RTThreadCtxHookIsEnabled(pGVCpu->vmm.s.hCtxHook));
-                            int rc2 = RTThreadCtxHookEnable(pGVCpu->vmm.s.hCtxHook); AssertRC(rc2);
+                            Assert(!RTThreadCtxHookIsEnabled(pGVCpu->vmmr0.s.hCtxHook));
+                            int rc2 = RTThreadCtxHookEnable(pGVCpu->vmmr0.s.hCtxHook); AssertRC(rc2);
                         }
 
@@ -1460,4 +1498,5 @@
                         if (RT_SUCCESS(rc))
                         {
+                            pGVCpu->vmmr0.s.fInHmContext = true;
                             VMCPU_SET_STATE(pGVCpu, VMCPUSTATE_STARTED_HM);
 
@@ -1469,4 +1508,5 @@
                             {
                                 fPreemptRestored = true;
+                                pGVCpu->vmmr0.s.pPreemptState = NULL;
                                 RTThreadPreemptRestore(&PreemptState);
                             }
@@ -1503,4 +1543,5 @@
 #endif
 
+                            pGVCpu->vmmr0.s.fInHmContext = false;
                             VMCPU_SET_STATE(pGVCpu, VMCPUSTATE_STARTED);
                         }
@@ -1511,4 +1552,7 @@
                          * hook / restore preemption.
                          */
+                        pGVCpu->vmmr0.s.iHostCpuSet = UINT32_MAX;
+                        ASMAtomicWriteU32(&pGVCpu->vmmr0.s.idHostCpu, NIL_RTCPUID);
+
                         pGVCpu->iHostCpuSet = UINT32_MAX;
                         ASMAtomicWriteU32(&pGVCpu->idHostCpu, NIL_RTCPUID);
@@ -1521,8 +1565,8 @@
                          *       when we get here, but the IPRT API handles that.
                          */
-                        if (pGVCpu->vmm.s.hCtxHook != NIL_RTTHREADCTXHOOK)
+                        if (pGVCpu->vmmr0.s.hCtxHook != NIL_RTTHREADCTXHOOK)
                         {
                             ASMAtomicWriteU32(&pGVCpu->idHostCpu, NIL_RTCPUID);
-                            RTThreadCtxHookDisable(pGVCpu->vmm.s.hCtxHook);
+                            RTThreadCtxHookDisable(pGVCpu->vmmr0.s.hCtxHook);
                         }
                     }
@@ -1540,5 +1584,8 @@
                      *        preemption again before the RTThreadCtxHookDisable call. */
                     if (!fPreemptRestored)
+                    {
+                        pGVCpu->vmmr0.s.pPreemptState = NULL;
                         RTThreadPreemptRestore(&PreemptState);
+                    }
 
                     pGVCpu->vmm.s.iLastGZRc = rc;
@@ -1570,4 +1617,7 @@
                 else
                 {
+                    pGVCpu->vmmr0.s.pPreemptState = NULL;
+                    pGVCpu->vmmr0.s.iHostCpuSet = UINT32_MAX;
+                    ASMAtomicWriteU32(&pGVCpu->vmmr0.s.idHostCpu, NIL_RTCPUID);
                     pGVCpu->iHostCpuSet = UINT32_MAX;
                     ASMAtomicWriteU32(&pGVCpu->idHostCpu, NIL_RTCPUID);
@@ -2555,4 +2605,100 @@
 {
     return pVCpu->vmm.s.CallRing3JmpBufR0.fInRing3Call;
+}
+
+
+/**
+ * Locking helper that deals with HM context and checks if the thread can block.
+ *
+ * @returns VINF_SUCCESS if we can block.  Returns @a rcBusy or
+ *          VERR_VMM_CANNOT_BLOCK if not able to block.
+ * @param   pVCpu       The cross context virtual CPU structure of the calling
+ *                      thread.
+ * @param   rcBusy      What to return in case of a blocking problem.  Will IPE
+ *                      if VINF_SUCCESS and we cannot block.
+ * @param   pszCaller   The caller (for logging problems).
+ * @param   pvLock      The lock address (for logging problems).
+ * @param   pCtx        Where to return context info for the resume call.
+ * @thread  EMT(pVCpu)
+ */
+VMMR0_INT_DECL(int) VMMR0EmtPrepareToBlock(PVMCPUCC pVCpu, int rcBusy, const char *pszCaller, void *pvLock,
+                                           PVMMR0EMTBLOCKCTX pCtx)
+{
+    const char *pszMsg;
+
+    /*
+     * Check that we are allowed to block.
+     */
+    if (RT_LIKELY(VMMRZCallRing3IsEnabled(pVCpu)))
+    {
+        /*
+         * Are we in HM context and w/o a context hook?  If so work the context hook.
+         */
+        if (pVCpu->vmmr0.s.idHostCpu != NIL_RTCPUID)
+        {
+            Assert(pVCpu->vmmr0.s.iHostCpuSet != UINT32_MAX);
+            Assert(pVCpu->vmmr0.s.fInHmContext);
+
+            if (pVCpu->vmmr0.s.hCtxHook == NIL_RTTHREADCTXHOOK)
+            {
+                vmmR0ThreadCtxCallback(RTTHREADCTXEVENT_OUT, pVCpu);
+                if (pVCpu->vmmr0.s.pPreemptState)
+                    RTThreadPreemptRestore(pVCpu->vmmr0.s.pPreemptState);
+
+                pCtx->uMagic          = VMMR0EMTBLOCKCTX_MAGIC;
+                pCtx->fWasInHmContext = true;
+                return VINF_SUCCESS;
+            }
+        }
+
+        if (RT_LIKELY(!pVCpu->vmmr0.s.pPreemptState))
+        {
+            /*
+             * Not in HM context or we've got hooks, so just check that preemption
+             * is enabled.
+             */
+            if (RT_LIKELY(RTThreadPreemptIsEnabled(NIL_RTTHREAD)))
+            {
+                pCtx->uMagic          = VMMR0EMTBLOCKCTX_MAGIC;
+                pCtx->fWasInHmContext = false;
+                return VINF_SUCCESS;
+            }
+            pszMsg = "Preemption is disabled!";
+        }
+        else
+            pszMsg = "Preemption state w/o HM state!";
+    }
+    else
+        pszMsg = "Ring-3 calls are disabled!";
+
+    static uint32_t volatile s_cWarnings = 0;
+    if (++s_cWarnings < 50)
+        SUPR0Printf("VMMR0EmtPrepareToBlock: %s pvLock=%p pszCaller=%s rcBusy=%p\n", pszMsg, pvLock, pszCaller, rcBusy);
+    pCtx->uMagic          = VMMR0EMTBLOCKCTX_MAGIC_DEAD;
+    pCtx->fWasInHmContext = false;
+    return rcBusy != VINF_SUCCESS ? rcBusy : VERR_VMM_CANNOT_BLOCK;
+}
+
+
+/**
+ * Counterpart to VMMR0EmtPrepareToBlock.
+ *
+ * @param   pVCpu       The cross context virtual CPU structure of the calling
+ *                      thread.
+ * @param   pCtx        The context structure used with VMMR0EmtPrepareToBlock.
+ * @thread  EMT(pVCpu)
+ */
+VMMR0_INT_DECL(void) VMMR0EmtResumeAfterBlocking(PVMCPUCC pVCpu, PVMMR0EMTBLOCKCTX pCtx)
+{
+    AssertReturnVoid(pCtx->uMagic == VMMR0EMTBLOCKCTX_MAGIC);
+    if (pCtx->fWasInHmContext)
+    {
+        if (pVCpu->vmmr0.s.pPreemptState)
+            RTThreadPreemptDisable(pVCpu->vmmr0.s.pPreemptState);
+
+        pCtx->fWasInHmContext = false;
+        vmmR0ThreadCtxCallback(RTTHREADCTXEVENT_IN, pVCpu);
+    }
+    pCtx->uMagic = VMMR0EMTBLOCKCTX_MAGIC_DEAD;
 }
 
Index: trunk/src/VBox/VMM/VMMR3/PDMCritSect.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/PDMCritSect.cpp	(revision 90376)
+++ trunk/src/VBox/VMM/VMMR3/PDMCritSect.cpp	(revision 90379)
@@ -164,9 +164,10 @@
                 pCritSect->pszName                   = pszName;
 
-                STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLock,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,          NULL, "/PDM/CritSects/%s/ContentionRZLock", pCritSect->pszName);
-                STAMR3RegisterF(pVM, &pCritSect->StatContentionRZUnlock,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,          NULL, "/PDM/CritSects/%s/ContentionRZUnlock", pCritSect->pszName);
-                STAMR3RegisterF(pVM, &pCritSect->StatContentionR3,      STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,          NULL, "/PDM/CritSects/%s/ContentionR3", pCritSect->pszName);
+                STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLock,      STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,          NULL, "/PDM/CritSects/%s/ContentionRZLock", pCritSect->pszName);
+                STAMR3RegisterF(pVM, &pCritSect->StatContentionRZLockBusy,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,          NULL, "/PDM/CritSects/%s/ContentionRZLockBusy", pCritSect->pszName);
+                STAMR3RegisterF(pVM, &pCritSect->StatContentionRZUnlock,    STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,          NULL, "/PDM/CritSects/%s/ContentionRZUnlock", pCritSect->pszName);
+                STAMR3RegisterF(pVM, &pCritSect->StatContentionR3,          STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,          NULL, "/PDM/CritSects/%s/ContentionR3", pCritSect->pszName);
 #ifdef VBOX_WITH_STATISTICS
-                STAMR3RegisterF(pVM, &pCritSect->StatLocked,        STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/Locked", pCritSect->pszName);
+                STAMR3RegisterF(pVM, &pCritSect->StatLocked,            STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, NULL, "/PDM/CritSects/%s/Locked", pCritSect->pszName);
 #endif
 
Index: trunk/src/VBox/VMM/VMMR3/VMM.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/VMM.cpp	(revision 90376)
+++ trunk/src/VBox/VMM/VMMR3/VMM.cpp	(revision 90379)
@@ -627,5 +627,5 @@
 
     /* Log whether thread-context hooks are used (on Linux this can depend on how the kernel is configured). */
-    if (pVM->apCpusR3[0]->vmm.s.hCtxHook != NIL_RTTHREADCTXHOOK)
+    if (pVM->vmm.s.fIsUsingContextHooks)
         LogRel(("VMM: Enabled thread-context hooks\n"));
     else
Index: trunk/src/VBox/VMM/include/PDMInternal.h
===================================================================
--- trunk/src/VBox/VMM/include/PDMInternal.h	(revision 90376)
+++ trunk/src/VBox/VMM/include/PDMInternal.h	(revision 90379)
@@ -438,4 +438,6 @@
     /** R0/RC lock contention. */
     STAMCOUNTER                     StatContentionRZLock;
+    /** R0/RC lock contention, returning rcBusy or VERR_SEM_BUSY (try). */
+    STAMCOUNTER                     StatContentionRZLockBusy;
     /** R0/RC unlock contention. */
     STAMCOUNTER                     StatContentionRZUnlock;
Index: trunk/src/VBox/VMM/include/VMMInternal.h
===================================================================
--- trunk/src/VBox/VMM/include/VMMInternal.h	(revision 90376)
+++ trunk/src/VBox/VMM/include/VMMInternal.h	(revision 90379)
@@ -267,4 +267,6 @@
      * release logging purposes.  */
     bool                        fIsPreemptPossible : 1;
+    /** Set if ring-0 uses context hooks.  */
+    bool                        fIsUsingContextHooks : 1;
 
     bool                        afAlignment2[2]; /**< Alignment padding. */
@@ -379,7 +381,4 @@
     R0PTRTYPE(PVMMR0LOGGER)     pR0RelLoggerR0;
 
-    /** Thread context switching hook (ring-0). */
-    RTTHREADCTXHOOK             hCtxHook;
-
     /** @name Rendezvous
      * @{ */
@@ -387,5 +386,5 @@
      *  attempts at recursive rendezvous. */
     bool volatile               fInRendezvous;
-    bool                        afPadding1[10];
+    bool                        afPadding1[2];
     /** @} */
 
@@ -461,14 +460,30 @@
 typedef struct VMMR0PERVCPU
 {
+    /** Which host CPU ID is this EMT running on.
+     * Only valid when in RC or HMR0 with scheduling disabled. */
+    RTCPUID volatile                    idHostCpu;
+    /** The CPU set index corresponding to idHostCpu, UINT32_MAX if not valid.
+     * @remarks Best to make sure iHostCpuSet shares cache line with idHostCpu! */
+    uint32_t volatile                   iHostCpuSet;
+    /** Set if we've entered HM context. */
+    bool volatile                       fInHmContext;
+
+    bool                                afPadding[7];
+    /** Pointer to the VMMR0EntryFast preemption state structure.
+     * This is used to temporarily restore preemption before blocking.  */
+    R0PTRTYPE(PRTTHREADPREEMPTSTATE)    pPreemptState;
+    /** Thread context switching hook (ring-0). */
+    RTTHREADCTXHOOK                     hCtxHook;
+
     /** @name Arguments passed by VMMR0EntryEx via vmmR0CallRing3SetJmpEx.
      * @note Cannot be put on the stack as the location may change and upset the
      *       validation of resume-after-ring-3-call logic.
      * @{ */
-    PGVM                pGVM;
-    VMCPUID             idCpu;
-    VMMR0OPERATION      enmOperation;
-    PSUPVMMR0REQHDR     pReq;
-    uint64_t            u64Arg;
-    PSUPDRVSESSION      pSession;
+    PGVM                                pGVM;
+    VMCPUID                             idCpu;
+    VMMR0OPERATION                      enmOperation;
+    PSUPVMMR0REQHDR                     pReq;
+    uint64_t                            u64Arg;
+    PSUPDRVSESSION                      pSession;
     /** @} */
 } VMMR0PERVCPU;
Index: trunk/src/VBox/VMM/include/VMMInternal.mac
===================================================================
--- trunk/src/VBox/VMM/include/VMMInternal.mac	(revision 90376)
+++ trunk/src/VBox/VMM/include/VMMInternal.mac	(revision 90379)
@@ -121,8 +121,6 @@
         .pR0RelLoggerR0         RTR0PTR_RES 1
 
-        .hCtxHook               RTR0PTR_RES 1
-
         .fInRendezvous          resb 1
-        .afPadding1             resb 10
+        .afPadding1             resb 2
         .fMayHaltInRing0        resb 1
         .cNsSpinBlockThreshold  resd 1
