summaryrefslogtreecommitdiff
path: root/src/VBox/VMM/VMMAll/PDMAllCritSect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/VMMAll/PDMAllCritSect.cpp')
-rw-r--r--src/VBox/VMM/VMMAll/PDMAllCritSect.cpp117
1 files changed, 63 insertions, 54 deletions
diff --git a/src/VBox/VMM/VMMAll/PDMAllCritSect.cpp b/src/VBox/VMM/VMMAll/PDMAllCritSect.cpp
index 55099ecb..db903792 100644
--- a/src/VBox/VMM/VMMAll/PDMAllCritSect.cpp
+++ b/src/VBox/VMM/VMMAll/PDMAllCritSect.cpp
@@ -1,10 +1,10 @@
/* $Id: PDMAllCritSect.cpp $ */
/** @file
- * PDM - Critical Sections, All Contexts.
+ * PDM - Write-Only Critical Section, All Contexts.
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -26,7 +26,7 @@
#include <VBox/vmm/vmm.h>
#include <VBox/vmm/vm.h>
#include <VBox/err.h>
-#include <VBox/vmm/hwaccm.h>
+#include <VBox/vmm/hm.h>
#include <VBox/log.h>
#include <iprt/asm.h>
@@ -111,7 +111,9 @@ DECL_FORCE_INLINE(int) pdmCritSectEnterFirst(PPDMCRITSECT pCritSect, RTNATIVETHR
/**
* Deals with the contended case in ring-3 and ring-0.
*
- * @returns VINF_SUCCESS or VERR_SEM_DESTROYED.
+ * @retval VINF_SUCCESS on success.
+ * @retval VERR_SEM_DESTROYED if destroyed.
+ *
* @param pCritSect The critsect.
* @param hNativeSelf The native thread handle.
*/
@@ -145,25 +147,53 @@ static int pdmR3R0CritSectEnterContended(PPDMCRITSECT pCritSect, RTNATIVETHREAD
# endif
for (;;)
{
-# ifdef PDMCRITSECT_STRICT
+ /*
+ * Do the wait.
+ *
+ * In ring-3 this gets cluttered by lock validation and thread state
+ * maintainence.
+ *
+ * In ring-0 we have to deal with the possibility that the thread has
+ * been signalled and the interruptible wait function returning
+ * immediately. In that case we do normal R0/RC rcBusy handling.
+ */
+# ifdef IN_RING3
+# ifdef PDMCRITSECT_STRICT
int rc9 = RTLockValidatorRecExclCheckBlocking(pCritSect->s.Core.pValidatorRec, hThreadSelf, pSrcPos,
!(pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NO_NESTING),
RT_INDEFINITE_WAIT, RTTHREADSTATE_CRITSECT, true);
if (RT_FAILURE(rc9))
return rc9;
-# elif defined(IN_RING3)
+# else
RTThreadBlocking(hThreadSelf, RTTHREADSTATE_CRITSECT, true);
-# endif
+# endif
int rc = SUPSemEventWaitNoResume(pSession, hEvent, RT_INDEFINITE_WAIT);
-# ifdef IN_RING3
RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_CRITSECT);
-# endif
+# else /* IN_RING0 */
+ int rc = SUPSemEventWaitNoResume(pSession, hEvent, RT_INDEFINITE_WAIT);
+# endif /* IN_RING0 */
+ /*
+ * Deal with the return code and critsect destruction.
+ */
if (RT_UNLIKELY(pCritSect->s.Core.u32Magic != RTCRITSECT_MAGIC))
return VERR_SEM_DESTROYED;
if (rc == VINF_SUCCESS)
return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos);
AssertMsg(rc == VERR_INTERRUPTED, ("rc=%Rrc\n", rc));
+
+# ifdef IN_RING0
+ /* Something is pending (signal, APC, debugger, whatever), just go back
+ to ring-3 so the kernel can deal with it when leaving kernel context.
+
+ Note! We've incremented cLockers already and cannot safely decrement
+ it without creating a race with PDMCritSectLeave, resulting in
+ spurious wakeups. */
+ PVM pVM = pCritSect->s.CTX_SUFF(pVM); AssertPtr(pVM);
+ PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
+ rc = VMMRZCallRing3(pVM, pVCpu, VMMCALLRING3_VM_R0_PREEMPT, NULL);
+ AssertRC(rc);
+# endif
}
/* won't get here */
}
@@ -175,7 +205,8 @@ static int pdmR3R0CritSectEnterContended(PPDMCRITSECT pCritSect, RTNATIVETHREAD
*
* @returns VINF_SUCCESS if entered successfully.
* @returns rcBusy when encountering a busy critical section in GC/R0.
- * @returns VERR_SEM_DESTROYED if the critical section is dead.
+ * @retval VERR_SEM_DESTROYED if the critical section is delete before or
+ * during the operation.
*
* @param pCritSect The PDM critical section to enter.
* @param rcBusy The status code to return when we're in GC or R0
@@ -253,7 +284,7 @@ DECL_FORCE_INLINE(int) pdmCritSectEnter(PPDMCRITSECT pCritSect, int rcBusy, PCRT
* use PDMCritSectTryEnter. */
{
/*
- * Leave HWACCM context while waiting if necessary.
+ * Leave HM context while waiting if necessary.
*/
int rc;
if (RTThreadPreemptIsEnabled(NIL_RTTHREAD))
@@ -266,13 +297,13 @@ DECL_FORCE_INLINE(int) pdmCritSectEnter(PPDMCRITSECT pCritSect, int rcBusy, PCRT
STAM_REL_COUNTER_ADD(&pCritSect->s.StatContentionRZLock, 1000000000);
PVM pVM = pCritSect->s.CTX_SUFF(pVM);
PVMCPU pVCpu = VMMGetCpu(pVM);
- HWACCMR0Leave(pVM, pVCpu);
+ HMR0Leave(pVM, pVCpu);
RTThreadPreemptRestore(NIL_RTTHREAD, ????);
rc = pdmR3R0CritSectEnterContended(pCritSect, hNativeSelf, pSrcPos);
RTThreadPreemptDisable(NIL_RTTHREAD, ????);
- HWACCMR0Enter(pVM, pVCpu);
+ HMR0Enter(pVM, pVCpu);
}
return rc;
}
@@ -311,11 +342,12 @@ DECL_FORCE_INLINE(int) pdmCritSectEnter(PPDMCRITSECT pCritSect, int rcBusy, PCRT
* Enters a PDM critical section.
*
* @returns VINF_SUCCESS if entered successfully.
- * @returns rcBusy when encountering a busy critical section in GC/R0.
- * @returns VERR_SEM_DESTROYED if the critical section is dead.
+ * @returns rcBusy when encountering a busy critical section in RC/R0.
+ * @retval VERR_SEM_DESTROYED if the critical section is delete before or
+ * during the operation.
*
* @param pCritSect The PDM critical section to enter.
- * @param rcBusy The status code to return when we're in GC or R0
+ * @param rcBusy The status code to return when we're in RC or R0
* and the section is busy. Pass VINF_SUCCESS to
* acquired the critical section thru a ring-3
* call if necessary.
@@ -335,11 +367,12 @@ VMMDECL(int) PDMCritSectEnter(PPDMCRITSECT pCritSect, int rcBusy)
* Enters a PDM critical section, with location information for debugging.
*
* @returns VINF_SUCCESS if entered successfully.
- * @returns rcBusy when encountering a busy critical section in GC/R0.
- * @returns VERR_SEM_DESTROYED if the critical section is dead.
+ * @returns rcBusy when encountering a busy critical section in RC/R0.
+ * @retval VERR_SEM_DESTROYED if the critical section is delete before or
+ * during the operation.
*
* @param pCritSect The PDM critical section to enter.
- * @param rcBusy The status code to return when we're in GC or R0
+ * @param rcBusy The status code to return when we're in RC or R0
* and the section is busy. Pass VINF_SUCCESS to
* acquired the critical section thru a ring-3
* call if necessary.
@@ -369,7 +402,8 @@ VMMDECL(int) PDMCritSectEnterDebug(PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTP
* @retval VINF_SUCCESS on success.
* @retval VERR_SEM_BUSY if the critsect was owned.
* @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
- * @retval VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
+ * @retval VERR_SEM_DESTROYED if the critical section is delete before or
+ * during the operation.
*
* @param pCritSect The critical section.
*/
@@ -424,7 +458,8 @@ static int pdmCritSectTryEnter(PPDMCRITSECT pCritSect, PCRTLOCKVALSRCPOS pSrcPos
* @retval VINF_SUCCESS on success.
* @retval VERR_SEM_BUSY if the critsect was owned.
* @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
- * @retval VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
+ * @retval VERR_SEM_DESTROYED if the critical section is delete before or
+ * during the operation.
*
* @param pCritSect The critical section.
*/
@@ -445,7 +480,8 @@ VMMDECL(int) PDMCritSectTryEnter(PPDMCRITSECT pCritSect)
* @retval VINF_SUCCESS on success.
* @retval VERR_SEM_BUSY if the critsect was owned.
* @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
- * @retval VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
+ * @retval VERR_SEM_DESTROYED if the critical section is delete before or
+ * during the operation.
*
* @param pCritSect The critical section.
* @param uId Some kind of locking location ID. Typically a
@@ -474,7 +510,8 @@ VMMDECL(int) PDMCritSectTryEnterDebug(PPDMCRITSECT pCritSect, RTHCUINTPTR uId, R
*
* @returns VINF_SUCCESS if entered successfully.
* @returns rcBusy when encountering a busy critical section in GC/R0.
- * @returns VERR_SEM_DESTROYED if the critical section is dead.
+ * @retval VERR_SEM_DESTROYED if the critical section is delete before or
+ * during the operation.
*
* @param pCritSect The PDM critical section to enter.
* @param fCallRing3 Whether this is a VMMRZCallRing3()request.
@@ -622,8 +659,8 @@ VMMDECL(int) PDMCritSectLeave(PPDMCRITSECT pCritSect)
PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
uint32_t i = pVCpu->pdm.s.cQueuedCritSectLeaves++;
LogFlow(("PDMCritSectLeave: [%d]=%p => R3\n", i, pCritSect));
- AssertFatal(i < RT_ELEMENTS(pVCpu->pdm.s.apQueuedCritSectsLeaves));
- pVCpu->pdm.s.apQueuedCritSectsLeaves[i] = MMHyperCCToR3(pVM, pCritSect);
+ AssertFatal(i < RT_ELEMENTS(pVCpu->pdm.s.apQueuedCritSectLeaves));
+ pVCpu->pdm.s.apQueuedCritSectLeaves[i] = MMHyperCCToR3(pVM, pCritSect);
VMCPU_FF_SET(pVCpu, VMCPU_FF_PDM_CRITSECT);
VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
STAM_REL_COUNTER_INC(&pVM->pdm.s.StatQueuedCritSectLeaves);
@@ -635,35 +672,6 @@ VMMDECL(int) PDMCritSectLeave(PPDMCRITSECT pCritSect)
}
-#if defined(IN_RING3) || defined(IN_RING0)
-/**
- * Process the critical sections queued for ring-3 'leave'.
- *
- * @param pVCpu Pointer to the VMCPU.
- */
-VMMDECL(void) PDMCritSectFF(PVMCPU pVCpu)
-{
- Assert(pVCpu->pdm.s.cQueuedCritSectLeaves > 0);
-
- const RTUINT c = pVCpu->pdm.s.cQueuedCritSectLeaves;
- for (RTUINT i = 0; i < c; i++)
- {
-# ifdef IN_RING3
- PPDMCRITSECT pCritSect = pVCpu->pdm.s.apQueuedCritSectsLeaves[i];
-# else
- PPDMCRITSECT pCritSect = (PPDMCRITSECT)MMHyperR3ToCC(pVCpu->CTX_SUFF(pVM), pVCpu->pdm.s.apQueuedCritSectsLeaves[i]);
-# endif
-
- PDMCritSectLeave(pCritSect);
- LogFlow(("PDMR3CritSectFF: %p\n", pCritSect));
- }
-
- pVCpu->pdm.s.cQueuedCritSectLeaves = 0;
- VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PDM_CRITSECT);
-}
-#endif /* IN_RING3 || IN_RING0 */
-
-
/**
* Checks the caller is the owner of the critical section.
*
@@ -747,3 +755,4 @@ VMMDECL(uint32_t) PDMCritSectGetRecursion(PCPDMCRITSECT pCritSect)
{
return RTCritSectGetRecursion(&pCritSect->s.Core);
}
+