a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/* $Id$ */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/** @file
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * IPRT - Read/Write Critical Section, Generic.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Copyright (C) 2009-2013 Oracle Corporation
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * available from http://www.virtualbox.org. This file is free software;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * General Public License (GPL) as published by the Free Software
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/*******************************************************************************
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync* Header Files *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync*******************************************************************************/
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#define LOG_GROUP LOG_GROUP_PDM//_CRITSECT
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include "PDMInternal.h"
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include <VBox/vmm/pdmcritsectrw.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include <VBox/vmm/mm.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include <VBox/vmm/vmm.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include <VBox/vmm/vm.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include <VBox/err.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include <VBox/vmm/hm.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include <VBox/log.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include <iprt/asm.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include <iprt/asm-amd64-x86.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#include <iprt/assert.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#ifdef IN_RING3
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync# include <iprt/lockvalidator.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync# include <iprt/semaphore.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#if defined(IN_RING3) || defined(IN_RING0)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync# include <iprt/thread.h>
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/*******************************************************************************
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync* Defined Constants And Macros *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync*******************************************************************************/
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/** The number loops to spin for shared access in ring-3. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#define PDMCRITSECTRW_SHRD_SPIN_COUNT_R3 20
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/** The number loops to spin for shared access in ring-0. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#define PDMCRITSECTRW_SHRD_SPIN_COUNT_R0 128
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/** The number loops to spin for shared access in the raw-mode context. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#define PDMCRITSECTRW_SHRD_SPIN_COUNT_RC 128
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/** The number loops to spin for exclusive access in ring-3. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#define PDMCRITSECTRW_EXCL_SPIN_COUNT_R3 20
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/** The number loops to spin for exclusive access in ring-0. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#define PDMCRITSECTRW_EXCL_SPIN_COUNT_R0 256
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/** The number loops to spin for exclusive access in the raw-mode context. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#define PDMCRITSECTRW_EXCL_SPIN_COUNT_RC 256
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/* Undefine the automatic VBOX_STRICT API mappings. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#undef PDMCritSectRwEnterExcl
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#undef PDMCritSectRwTryEnterExcl
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#undef PDMCritSectRwEnterShared
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#undef PDMCritSectRwTryEnterShared
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Gets the ring-3 native thread handle of the calling thread.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns native thread handle (ring-3).
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis The read/write critical section. This is only used in
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * R0 and RC.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncDECL_FORCE_INLINE(RTNATIVETHREAD) pdmCritSectRwGetNativeSelf(PCPDMCRITSECTRW pThis)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#ifdef IN_RING3
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync NOREF(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#else
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync AssertMsgReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, ("%RX32\n", pThis->s.Core.u32Magic),
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync NIL_RTNATIVETHREAD);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync PVM pVM = pThis->s.CTX_SUFF(pVM); AssertPtr(pVM);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeSelf = pVCpu->hNativeThread; Assert(hNativeSelf != NIL_RTNATIVETHREAD);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return hNativeSelf;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#ifdef IN_RING3
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Changes the lock validator sub-class of the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * It is recommended to try make sure that nobody is using this critical section
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * while changing the value.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * lock validator isn't compiled in or either of the parameters are
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * invalid.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param uSubClass The new sub-class value.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(uint32_t) PDMR3CritSectRwSetSubClass(PPDMCRITSECTRW pThis, uint32_t uSubClass)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtrReturn(pThis, RTLOCKVAL_SUB_CLASS_INVALID);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(!(pThis->s.Core.fFlags & RTCRITSECT_FLAGS_NOP), RTLOCKVAL_SUB_CLASS_INVALID);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTLockValidatorRecSharedSetSubClass(pThis->s.Core.pValidatorRead, uSubClass);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return RTLockValidatorRecExclSetSubClass(pThis->s.Core.pValidatorWrite, uSubClass);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync# else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync NOREF(uSubClass);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return RTLOCKVAL_SUB_CLASS_INVALID;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync# endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif /* IN_RING3 */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync#ifdef IN_RING0
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync/**
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync * Go back to ring-3 so the kernel can do signals, APCs and other fun things.
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync *
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync * @param pThis Pointer to the read/write critical section.
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync */
081c3b36a07589055ec98579ea9d22d2074c8164vboxsyncstatic void pdmR0CritSectRwYieldToRing3(PPDMCRITSECTRW pThis)
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync{
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync PVM pVM = pThis->s.CTX_SUFF(pVM); AssertPtr(pVM);
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync int rc = VMMRZCallRing3(pVM, pVCpu, VMMCALLRING3_VM_R0_PREEMPT, NULL);
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync AssertRC(rc);
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync}
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync#endif /* IN_RING0 */
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync/**
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * Worker that enters a read/write critical section with shard access.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync *
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @returns VBox status code.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param pThis Pointer to the read/write critical section.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param rcBusy The busy return code for ring-0 and ring-3.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param fTryOnly Only try enter it, don't wait.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param pSrcPos The source position. (Can be NULL.)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param fNoVal No validation records.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsyncstatic int pdmCritSectRwEnterShared(PPDMCRITSECTRW pThis, int rcBusy, bool fTryOnly, PCRTLOCKVALSRCPOS pSrcPos, bool fNoVal)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Validate input.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtr(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (!fTryOnly)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync int rc9;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeWriter;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicUoReadHandle(&pThis->s.Core.hNativeWriter, &hNativeWriter);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (hNativeWriter != NIL_RTTHREAD && hNativeWriter == pdmCritSectRwGetNativeSelf(pThis))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync rc9 = RTLockValidatorRecExclCheckOrder(pThis->s.Core.pValidatorWrite, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync rc9 = RTLockValidatorRecSharedCheckOrder(pThis->s.Core.pValidatorRead, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (RT_FAILURE(rc9))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return rc9;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Get cracking...
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t u64OldState = u64State;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync for (;;)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /* It flows in the right direction, try follow it before it changes. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync c++;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert(c < RTCSRW_CNT_MASK / 2);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State &= ~RTCSRW_CNT_RD_MASK;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State |= c << RTCSRW_CNT_RD_SHIFT;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (!fNoVal)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync RTLockValidatorRecSharedAddOwner(pThis->s.Core.pValidatorRead, hThreadSelf, pSrcPos);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync else if ((u64State & (RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK)) == 0)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /* Wrong direction, but we're alone here and can simply try switch the direction. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK | RTCSRW_DIR_MASK);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State |= (UINT64_C(1) << RTCSRW_CNT_RD_SHIFT) | (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert(!pThis->s.Core.fNeedReset);
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (!fNoVal)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync RTLockValidatorRecSharedAddOwner(pThis->s.Core.pValidatorRead, hThreadSelf, pSrcPos);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /* Is the writer perhaps doing a read recursion? */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeSelf = pdmCritSectRwGetNativeSelf(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeWriter;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicUoReadHandle(&pThis->s.Core.hNativeWriter, &hNativeWriter);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (hNativeSelf == hNativeWriter)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (!fNoVal)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync int rc9 = RTLockValidatorRecExclRecursionMixed(pThis->s.Core.pValidatorWrite, &pThis->s.Core.pValidatorRead->Core, pSrcPos);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (RT_FAILURE(rc9))
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return rc9;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert(pThis->s.Core.cWriterReads < UINT32_MAX / 2);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicIncU32(&pThis->s.Core.cWriterReads);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync STAM_REL_COUNTER_INC(&pThis->s.CTX_MID_Z(Stat,EnterShared));
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return VINF_SUCCESS; /* don't break! */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync /*
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * If we're only trying, return already.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (fTryOnly)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync STAM_REL_COUNTER_INC(&pThis->s.CTX_MID_Z(StatContention,EnterShared));
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return VERR_SEM_BUSY;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#if defined(IN_RING3) || defined(IN_RING0)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING0
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if ( RTThreadPreemptIsEnabled(NIL_RTTHREAD)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync && ASMIntAreEnabled())
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync /*
09266e7b8337832578fd14f5103f9b663d74930bvboxsync * Add ourselves to the queue and wait for the direction to change.
09266e7b8337832578fd14f5103f9b663d74930bvboxsync */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync uint64_t c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync c++;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync Assert(c < RTCSRW_CNT_MASK / 2);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync uint64_t cWait = (u64State & RTCSRW_WAIT_CNT_RD_MASK) >> RTCSRW_WAIT_CNT_RD_SHIFT;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync cWait++;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync Assert(cWait <= c);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync Assert(cWait < RTCSRW_CNT_MASK / 2);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_WAIT_CNT_RD_MASK);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State |= (c << RTCSRW_CNT_RD_SHIFT) | (cWait << RTCSRW_WAIT_CNT_RD_SHIFT);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync for (uint32_t iLoop = 0; ; iLoop++)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync int rc;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING3
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync rc = RTLockValidatorRecSharedCheckBlocking(pThis->s.Core.pValidatorRead, hThreadSelf, pSrcPos, true,
09266e7b8337832578fd14f5103f9b663d74930bvboxsync RT_INDEFINITE_WAIT, RTTHREADSTATE_RW_READ, false);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (RT_SUCCESS(rc))
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# else
09266e7b8337832578fd14f5103f9b663d74930bvboxsync RTTHREAD hThreadSelf = RTThreadSelf();
09266e7b8337832578fd14f5103f9b663d74930bvboxsync RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ, false);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync for (;;)
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync rc = SUPSemEventMultiWaitNoResume(pThis->s.CTX_SUFF(pVM)->pSession,
09266e7b8337832578fd14f5103f9b663d74930bvboxsync (SUPSEMEVENTMULTI)pThis->s.Core.hEvtRead,
09266e7b8337832578fd14f5103f9b663d74930bvboxsync RT_INDEFINITE_WAIT);
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync if ( rc != VERR_INTERRUPTED
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync || pThis->s.Core.u32Magic != RTCRITSECTRW_MAGIC)
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync break;
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync# ifdef IN_RING0
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync pdmR0CritSectRwYieldToRing3(pThis);
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync# endif
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING3
09266e7b8337832578fd14f5103f9b663d74930bvboxsync RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (pThis->s.Core.u32Magic != RTCRITSECTRW_MAGIC)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync return VERR_SEM_DESTROYED;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (RT_FAILURE(rc))
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync /* Decrement the counts and return the error. */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync for (;;)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64OldState = u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT; Assert(c > 0);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync c--;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync cWait = (u64State & RTCSRW_WAIT_CNT_RD_MASK) >> RTCSRW_WAIT_CNT_RD_SHIFT; Assert(cWait > 0);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync cWait--;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_WAIT_CNT_RD_MASK);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State |= (c << RTCSRW_CNT_RD_SHIFT) | (cWait << RTCSRW_WAIT_CNT_RD_SHIFT);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
09266e7b8337832578fd14f5103f9b663d74930bvboxsync break;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync return rc;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync Assert(pThis->s.Core.fNeedReset);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
09266e7b8337832578fd14f5103f9b663d74930bvboxsync break;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync AssertMsg(iLoop < 1, ("%u\n", iLoop));
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync /* Decrement the wait count and maybe reset the semaphore (if we're last). */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync for (;;)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64OldState = u64State;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync cWait = (u64State & RTCSRW_WAIT_CNT_RD_MASK) >> RTCSRW_WAIT_CNT_RD_SHIFT;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync Assert(cWait > 0);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync cWait--;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State &= ~RTCSRW_WAIT_CNT_RD_MASK;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State |= cWait << RTCSRW_WAIT_CNT_RD_SHIFT;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (cWait == 0)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (ASMAtomicXchgBool(&pThis->s.Core.fNeedReset, false))
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync int rc = SUPSemEventMultiReset(pThis->s.CTX_SUFF(pVM)->pSession,
09266e7b8337832578fd14f5103f9b663d74930bvboxsync (SUPSEMEVENTMULTI)pThis->s.Core.hEvtRead);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync AssertRCReturn(rc, rc);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync# if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (!fNoVal)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync RTLockValidatorRecSharedAddOwner(pThis->s.Core.pValidatorRead, hThreadSelf, pSrcPos);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync# endif
09266e7b8337832578fd14f5103f9b663d74930bvboxsync break;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#endif /* IN_RING3 || IN_RING3 */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#ifndef IN_RING3
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING0
09266e7b8337832578fd14f5103f9b663d74930bvboxsync else
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync /*
09266e7b8337832578fd14f5103f9b663d74930bvboxsync * We cannot call SUPSemEventMultiWaitNoResume in this context. Go
09266e7b8337832578fd14f5103f9b663d74930bvboxsync * back to ring-3 and do it there or return rcBusy.
09266e7b8337832578fd14f5103f9b663d74930bvboxsync */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync STAM_REL_COUNTER_INC(&pThis->s.CTX_MID_Z(StatContention,EnterShared));
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (rcBusy == VINF_SUCCESS)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync PVM pVM = pThis->s.CTX_SUFF(pVM); AssertPtr(pVM);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync /** @todo Should actually do this in via VMMR0.cpp instead of going all the way
09266e7b8337832578fd14f5103f9b663d74930bvboxsync * back to ring-3. Goes for both kind of crit sects. */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync return VMMRZCallRing3(pVM, pVCpu, VMMCALLRING3_PDM_CRIT_SECT_RW_ENTER_SHARED, MMHyperCCToR3(pVM, pThis));
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync return rcBusy;
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#endif /* !IN_RING3 */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (pThis->s.Core.u32Magic != RTCRITSECTRW_MAGIC)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return VERR_SEM_DESTROYED;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMNopPause();
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64OldState = u64State;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /* got it! */
1e492a1641955148d5024f44aa35a2084bcc47d3vboxsync STAM_REL_COUNTER_INC(&pThis->s.CTX_MID_Z(Stat,EnterShared));
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert((ASMAtomicReadU64(&pThis->s.Core.u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT));
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return VINF_SUCCESS;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Enter a critical section with shared (read) access.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns VBox status code.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VINF_SUCCESS on success.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval @a rcBusy if in ring-0 or raw-mode context and it is busy.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * during the operation.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param rcBusy The status code to return when we're in RC or R0 and the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * section is busy. Pass VINF_SUCCESS to acquired the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * critical section thru a ring-3 call if necessary.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param uId Where we're entering the section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFile The source position - file.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param iLine The source position - line.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFunction The source position - function.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwEnterSharedDebug, PDMCritSectRwTryEnterShared,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectRwTryEnterSharedDebug, PDMCritSectRwLeaveShared,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwEnterShared.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(int) PDMCritSectRwEnterShared(PPDMCRITSECTRW pThis, int rcBusy)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#if !defined(PDMCRITSECTRW_STRICT) || !defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterShared(pThis, rcBusy, false /*fTryOnly*/, NULL, false /*fNoVal*/);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterShared(pThis, rcBusy, false /*fTryOnly*/, &SrcPos, false /*fNoVal*/);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Enter a critical section with shared (read) access.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns VBox status code.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VINF_SUCCESS on success.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval @a rcBusy if in ring-0 or raw-mode context and it is busy.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * during the operation.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param rcBusy The status code to return when we're in RC or R0 and the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * section is busy. Pass VINF_SUCCESS to acquired the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * critical section thru a ring-3 call if necessary.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param uId Where we're entering the section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFile The source position - file.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param iLine The source position - line.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFunction The source position - function.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwEnterShared, PDMCritSectRwTryEnterShared,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectRwTryEnterSharedDebug, PDMCritSectRwLeaveShared,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwEnterSharedDebug.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(int) PDMCritSectRwEnterSharedDebug(PPDMCRITSECTRW pThis, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
2b7595fc8faa08b58ffdccce425e7417ba755d2fvboxsync NOREF(uId); NOREF(pszFile); NOREF(iLine); NOREF(pszFunction);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#if !defined(PDMCRITSECTRW_STRICT) || !defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterShared(pThis, rcBusy, false /*fTryOnly*/, NULL, false /*fNoVal*/);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterShared(pThis, rcBusy, false /*fTryOnly*/, &SrcPos, false /*fNoVal*/);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Try enter a critical section with shared (read) access.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns VBox status code.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VINF_SUCCESS on success.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_BUSY if the critsect was owned.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * during the operation.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param uId Where we're entering the section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFile The source position - file.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param iLine The source position - line.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFunction The source position - function.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwTryEnterSharedDebug, PDMCritSectRwEnterShared,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectRwEnterSharedDebug, PDMCritSectRwLeaveShared,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwTryEnterShared.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(int) PDMCritSectRwTryEnterShared(PPDMCRITSECTRW pThis)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#if !defined(PDMCRITSECTRW_STRICT) || !defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterShared(pThis, VERR_SEM_BUSY, true /*fTryOnly*/, NULL, false /*fNoVal*/);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterShared(pThis, VERR_SEM_BUSY, true /*fTryOnly*/, &SrcPos, false /*fNoVal*/);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Try enter a critical section with shared (read) access.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns VBox status code.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VINF_SUCCESS on success.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_BUSY if the critsect was owned.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * during the operation.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param uId Where we're entering the section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFile The source position - file.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param iLine The source position - line.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFunction The source position - function.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwTryEnterShared, PDMCritSectRwEnterShared,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectRwEnterSharedDebug, PDMCritSectRwLeaveShared,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwTryEnterSharedDebug.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(int) PDMCritSectRwTryEnterSharedDebug(PPDMCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
2b7595fc8faa08b58ffdccce425e7417ba755d2fvboxsync NOREF(uId); NOREF(pszFile); NOREF(iLine); NOREF(pszFunction);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#if !defined(PDMCRITSECTRW_STRICT) || !defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterShared(pThis, VERR_SEM_BUSY, true /*fTryOnly*/, NULL, false /*fNoVal*/);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterShared(pThis, VERR_SEM_BUSY, true /*fTryOnly*/, &SrcPos, false /*fNoVal*/);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#endif
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync}
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#ifdef IN_RING3
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync/**
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * Enters a PDM read/write critical section with shared (read) access.
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync *
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * @returns VINF_SUCCESS if entered successfully.
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * during the operation.
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync *
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * @param pThis Pointer to the read/write critical section.
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * @param fCallRing3 Whether this is a VMMRZCallRing3()request.
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync */
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsyncVMMR3DECL(int) PDMR3CritSectRwEnterSharedEx(PPDMCRITSECTRW pThis, bool fCallRing3)
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync{
59851790061a61c1ebb30683ba14240c4f813356vboxsync return pdmCritSectRwEnterShared(pThis, VERR_SEM_BUSY, false /*fTryAgain*/, NULL, fCallRing3);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Leave a critical section held with shared access.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns VBox status code.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * during the operation.
91dbfb6e2654dd783968343fd50e102e8e28d214vboxsync * @param pThis Pointer to the read/write critical section.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param fNoVal No validation records (i.e. queued release).
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwEnterShared, PDMCritSectRwTryEnterShared,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectRwEnterSharedDebug, PDMCritSectRwTryEnterSharedDebug,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectRwLeaveExcl, RTCritSectRwLeaveShared.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsyncstatic int pdmCritSectRwLeaveSharedWorker(PPDMCRITSECTRW pThis, bool fNoVal)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Validate handle.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtr(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Check the direction and take action accordingly.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t u64OldState = u64State;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (fNoVal)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync Assert(!RTLockValidatorRecSharedIsOwner(pThis->s.Core.pValidatorRead, NIL_RTTHREAD));
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync else
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync int rc9 = RTLockValidatorRecSharedCheckAndRelease(pThis->s.Core.pValidatorRead, NIL_RTTHREAD);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (RT_FAILURE(rc9))
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return rc9;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync for (;;)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t c = (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(c > 0, VERR_NOT_OWNER);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync c--;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if ( c > 0
310c472beee97db0bd77c2dfee62a902f0474580vboxsync || (u64State & RTCSRW_CNT_WR_MASK) == 0)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /* Don't change the direction. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State &= ~RTCSRW_CNT_RD_MASK;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State |= c << RTCSRW_CNT_RD_SHIFT;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#if defined(IN_RING3) || defined(IN_RING0)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING0
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if ( RTThreadPreemptIsEnabled(NIL_RTTHREAD)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync && ASMIntAreEnabled())
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync /* Reverse the direction and signal the writer threads. */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_DIR_MASK);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State |= RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync int rc = SUPSemEventSignal(pThis->s.CTX_SUFF(pVM)->pSession, (SUPSEMEVENT)pThis->s.Core.hEvtWrite);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync AssertRC(rc);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync break;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#endif /* IN_RING3 || IN_RING0 */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#ifndef IN_RING3
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING0
09266e7b8337832578fd14f5103f9b663d74930bvboxsync else
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync /* Queue the exit request (ring-3). */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync PVM pVM = pThis->s.CTX_SUFF(pVM); AssertPtr(pVM);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync uint32_t i = pVCpu->pdm.s.cQueuedCritSectRwShrdLeaves++;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync LogFlow(("PDMCritSectRwLeaveShared: [%d]=%p => R3 c=%d (%#llx)\n", i, pThis, c, u64State));
09266e7b8337832578fd14f5103f9b663d74930bvboxsync AssertFatal(i < RT_ELEMENTS(pVCpu->pdm.s.apQueuedCritSectRwShrdLeaves));
09266e7b8337832578fd14f5103f9b663d74930bvboxsync pVCpu->pdm.s.apQueuedCritSectRwShrdLeaves[i] = MMHyperCCToR3(pVM, pThis);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync VMCPU_FF_SET(pVCpu, VMCPU_FF_PDM_CRITSECT);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync STAM_REL_COUNTER_INC(&pVM->pdm.s.StatQueuedCritSectLeaves);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync STAM_REL_COUNTER_INC(&pThis->s.StatContentionRZLeaveShared);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMNopPause();
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64OldState = u64State;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeSelf = pdmCritSectRwGetNativeSelf(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeWriter;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicUoReadHandle(&pThis->s.Core.hNativeWriter, &hNativeWriter);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(hNativeSelf == hNativeWriter, VERR_NOT_OWNER);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.cWriterReads > 0, VERR_NOT_OWNER);
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (!fNoVal)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync int rc = RTLockValidatorRecExclUnwindMixed(pThis->s.Core.pValidatorWrite, &pThis->s.Core.pValidatorRead->Core);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (RT_FAILURE(rc))
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return rc;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicDecU32(&pThis->s.Core.cWriterReads);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return VINF_SUCCESS;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync/**
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * Leave a critical section held with shared access.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync *
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @returns VBox status code.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * during the operation.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param pThis Pointer to the read/write critical section.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @sa PDMCritSectRwEnterShared, PDMCritSectRwTryEnterShared,
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * PDMCritSectRwEnterSharedDebug, PDMCritSectRwTryEnterSharedDebug,
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * PDMCritSectRwLeaveExcl, RTCritSectRwLeaveShared.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsyncVMMDECL(int) PDMCritSectRwLeaveShared(PPDMCRITSECTRW pThis)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync{
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwLeaveSharedWorker(pThis, false /*fNoVal*/);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync}
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync#if defined(IN_RING3) || defined(IN_RING0)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync/**
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * PDMCritSectBothFF interface.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync *
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param pThis Pointer to the read/write critical section.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsyncvoid pdmCritSectRwLeaveSharedQueued(PPDMCRITSECTRW pThis)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync{
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync pdmCritSectRwLeaveSharedWorker(pThis, true /*fNoVal*/);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync}
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync#endif
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync/**
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * Worker that enters a read/write critical section with exclusive access.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync *
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @returns VBox status code.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param pThis Pointer to the read/write critical section.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param rcBusy The busy return code for ring-0 and ring-3.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param fTryOnly Only try enter it, don't wait.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param pSrcPos The source position. (Can be NULL.)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param fNoVal No validation records.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsyncstatic int pdmCritSectRwEnterExcl(PPDMCRITSECTRW pThis, int rcBusy, bool fTryOnly, PCRTLOCKVALSRCPOS pSrcPos, bool fNoVal)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Validate input.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtr(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTTHREAD hThreadSelf = NIL_RTTHREAD;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (!fTryOnly)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync hThreadSelf = RTThreadSelfAutoAdopt();
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync int rc9 = RTLockValidatorRecExclCheckOrder(pThis->s.Core.pValidatorWrite, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (RT_FAILURE(rc9))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return rc9;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Check if we're already the owner and just recursing.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeSelf = pdmCritSectRwGetNativeSelf(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeWriter;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicUoReadHandle(&pThis->s.Core.hNativeWriter, &hNativeWriter);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (hNativeSelf == hNativeWriter)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert((ASMAtomicReadU64(&pThis->s.Core.u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT));
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (!fNoVal)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync int rc9 = RTLockValidatorRecExclRecursion(pThis->s.Core.pValidatorWrite, pSrcPos);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (RT_FAILURE(rc9))
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return rc9;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert(pThis->s.Core.cWriteRecursions < UINT32_MAX / 2);
1e492a1641955148d5024f44aa35a2084bcc47d3vboxsync STAM_REL_COUNTER_INC(&pThis->s.CTX_MID_Z(Stat,EnterExcl));
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicIncU32(&pThis->s.Core.cWriteRecursions);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return VINF_SUCCESS;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Get cracking.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t u64OldState = u64State;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync for (;;)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if ( (u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync || (u64State & (RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK)) != 0)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /* It flows in the right direction, try follow it before it changes. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync c++;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert(c < RTCSRW_CNT_MASK / 2);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State &= ~RTCSRW_CNT_WR_MASK;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State |= c << RTCSRW_CNT_WR_SHIFT;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync else if ((u64State & (RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK)) == 0)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /* Wrong direction, but we're alone here and can simply try switch the direction. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State &= ~(RTCSRW_CNT_RD_MASK | RTCSRW_CNT_WR_MASK | RTCSRW_DIR_MASK);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State |= (UINT64_C(1) << RTCSRW_CNT_WR_SHIFT) | (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync else if (fTryOnly)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /* Wrong direction and we're not supposed to wait, just return. */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync STAM_REL_COUNTER_INC(&pThis->s.CTX_MID_Z(StatContention,EnterExcl));
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return VERR_SEM_BUSY;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /* Add ourselves to the write count and break out to do the wait. */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync c++;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert(c < RTCSRW_CNT_MASK / 2);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State &= ~RTCSRW_CNT_WR_MASK;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State |= c << RTCSRW_CNT_WR_SHIFT;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (pThis->s.Core.u32Magic != RTCRITSECTRW_MAGIC)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return VERR_SEM_DESTROYED;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMNopPause();
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync u64OldState = u64State;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * If we're in write mode now try grab the ownership. Play fair if there
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * are threads already waiting.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync bool fDone = (u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT)
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#if defined(IN_RING3)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync && ( ((u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT) == 1
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync || fTryOnly)
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#endif
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync ;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (fDone)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicCmpXchgHandle(&pThis->s.Core.hNativeWriter, hNativeSelf, NIL_RTNATIVETHREAD, fDone);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (!fDone)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync STAM_REL_COUNTER_INC(&pThis->s.CTX_MID_Z(StatContention,EnterExcl));
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#if defined(IN_RING3) || defined(IN_RING0)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if ( !fTryOnly
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING0
09266e7b8337832578fd14f5103f9b663d74930bvboxsync && RTThreadPreemptIsEnabled(NIL_RTTHREAD)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync && ASMIntAreEnabled()
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
09266e7b8337832578fd14f5103f9b663d74930bvboxsync )
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync /*
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * Wait for our turn.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync for (uint32_t iLoop = 0; ; iLoop++)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync int rc;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING3
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef PDMCRITSECTRW_STRICT
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (hThreadSelf == NIL_RTTHREAD)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync hThreadSelf = RTThreadSelfAutoAdopt();
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync rc = RTLockValidatorRecExclCheckBlocking(pThis->s.Core.pValidatorWrite, hThreadSelf, pSrcPos, true,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RT_INDEFINITE_WAIT, RTTHREADSTATE_RW_WRITE, false);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (RT_SUCCESS(rc))
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# else
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync RTTHREAD hThreadSelf = RTThreadSelf();
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE, false);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync# endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync for (;;)
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync rc = SUPSemEventWaitNoResume(pThis->s.CTX_SUFF(pVM)->pSession,
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync (SUPSEMEVENT)pThis->s.Core.hEvtWrite,
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync RT_INDEFINITE_WAIT);
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync if ( rc != VERR_INTERRUPTED
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync || pThis->s.Core.u32Magic != RTCRITSECTRW_MAGIC)
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync break;
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync# ifdef IN_RING0
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync pdmR0CritSectRwYieldToRing3(pThis);
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync# endif
081c3b36a07589055ec98579ea9d22d2074c8164vboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING3
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (pThis->s.Core.u32Magic != RTCRITSECTRW_MAGIC)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return VERR_SEM_DESTROYED;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (RT_FAILURE(rc))
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync /* Decrement the counts and return the error. */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync for (;;)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync u64OldState = u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT; Assert(c > 0);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync c--;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync u64State &= ~RTCSRW_CNT_WR_MASK;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync u64State |= c << RTCSRW_CNT_WR_SHIFT;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync break;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return rc;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT))
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync ASMAtomicCmpXchgHandle(&pThis->s.Core.hNativeWriter, hNativeSelf, NIL_RTNATIVETHREAD, fDone);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (fDone)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync AssertMsg(iLoop < 1000, ("%u\n", iLoop)); /* may loop a few times here... */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync else
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#endif /* IN_RING3 || IN_RING0 */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync#ifdef IN_RING3
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync /* TryEnter call - decrement the number of (waiting) writers. */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync#else
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync /* We cannot call SUPSemEventWaitNoResume in this context. Go back to
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync ring-3 and do it there or return rcBusy. */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync#endif
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync for (;;)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync u64OldState = u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT; Assert(c > 0);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync c--;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync u64State &= ~RTCSRW_CNT_WR_MASK;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync u64State |= c << RTCSRW_CNT_WR_SHIFT;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync#ifdef IN_RING3
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return VERR_SEM_BUSY;
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#else
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (rcBusy == VINF_SUCCESS)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync Assert(!fTryOnly);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync PVM pVM = pThis->s.CTX_SUFF(pVM); AssertPtr(pVM);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync /** @todo Should actually do this in via VMMR0.cpp instead of going all the way
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * back to ring-3. Goes for both kind of crit sects. */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return VMMRZCallRing3(pVM, pVCpu, VMMCALLRING3_PDM_CRIT_SECT_RW_ENTER_EXCL, MMHyperCCToR3(pVM, pThis));
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return rcBusy;
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#endif
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Got it!
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert((ASMAtomicReadU64(&pThis->s.Core.u64State) & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT));
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicWriteU32(&pThis->s.Core.cWriteRecursions, 1);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert(pThis->s.Core.cWriterReads == 0);
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (!fNoVal)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync RTLockValidatorRecExclSetOwner(pThis->s.Core.pValidatorWrite, hThreadSelf, pSrcPos, true);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
1e492a1641955148d5024f44aa35a2084bcc47d3vboxsync STAM_REL_COUNTER_INC(&pThis->s.CTX_MID_Z(Stat,EnterExcl));
1e492a1641955148d5024f44aa35a2084bcc47d3vboxsync STAM_PROFILE_ADV_START(&pThis->s.StatWriteLocked, swl);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return VINF_SUCCESS;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Try enter a critical section with exclusive (write) access.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns VBox status code.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VINF_SUCCESS on success.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval @a rcBusy if in ring-0 or raw-mode context and it is busy.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * during the operation.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param rcBusy The status code to return when we're in RC or R0 and the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * section is busy. Pass VINF_SUCCESS to acquired the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * critical section thru a ring-3 call if necessary.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwEnterExclDebug, PDMCritSectRwTryEnterExcl,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectRwTryEnterExclDebug,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectEnterDebug, PDMCritSectEnter,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwEnterExcl.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(int) PDMCritSectRwEnterExcl(PPDMCRITSECTRW pThis, int rcBusy)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#if !defined(PDMCRITSECTRW_STRICT) || !defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterExcl(pThis, rcBusy, false /*fTryAgain*/, NULL, false /*fNoVal*/);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterExcl(pThis, rcBusy, false /*fTryAgain*/, &SrcPos, false /*fNoVal*/);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Try enter a critical section with exclusive (write) access.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns VBox status code.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VINF_SUCCESS on success.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval @a rcBusy if in ring-0 or raw-mode context and it is busy.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * during the operation.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param rcBusy The status code to return when we're in RC or R0 and the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * section is busy. Pass VINF_SUCCESS to acquired the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * critical section thru a ring-3 call if necessary.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param uId Where we're entering the section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFile The source position - file.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param iLine The source position - line.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFunction The source position - function.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwEnterExcl, PDMCritSectRwTryEnterExcl,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectRwTryEnterExclDebug,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectEnterDebug, PDMCritSectEnter,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwEnterExclDebug.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(int) PDMCritSectRwEnterExclDebug(PPDMCRITSECTRW pThis, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
2b7595fc8faa08b58ffdccce425e7417ba755d2fvboxsync NOREF(uId); NOREF(pszFile); NOREF(iLine); NOREF(pszFunction);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#if !defined(PDMCRITSECTRW_STRICT) || !defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterExcl(pThis, rcBusy, false /*fTryAgain*/, NULL, false /*fNoVal*/);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterExcl(pThis, rcBusy, false /*fTryAgain*/, &SrcPos, false /*fNoVal*/);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Try enter a critical section with exclusive (write) access.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VINF_SUCCESS on success.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_BUSY if the critsect was owned.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * during the operation.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwEnterExcl, PDMCritSectRwTryEnterExclDebug,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectRwEnterExclDebug,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectTryEnter, PDMCritSectTryEnterDebug,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwTryEnterExcl.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(int) PDMCritSectRwTryEnterExcl(PPDMCRITSECTRW pThis)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#if !defined(PDMCRITSECTRW_STRICT) || !defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterExcl(pThis, VERR_SEM_BUSY, true /*fTryAgain*/, NULL, false /*fNoVal*/);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterExcl(pThis, VERR_SEM_BUSY, true /*fTryAgain*/, &SrcPos, false /*fNoVal*/);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Try enter a critical section with exclusive (write) access.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VINF_SUCCESS on success.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_BUSY if the critsect was owned.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * during the operation.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param uId Where we're entering the section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFile The source position - file.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param iLine The source position - line.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pszFunction The source position - function.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwTryEnterExcl, PDMCritSectRwEnterExcl,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectRwEnterExclDebug,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * PDMCritSectTryEnterDebug, PDMCritSectTryEnter,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwTryEnterExclDebug.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(int) PDMCritSectRwTryEnterExclDebug(PPDMCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
2b7595fc8faa08b58ffdccce425e7417ba755d2fvboxsync NOREF(uId); NOREF(pszFile); NOREF(iLine); NOREF(pszFunction);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#if !defined(PDMCRITSECTRW_STRICT) || !defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterExcl(pThis, VERR_SEM_BUSY, true /*fTryAgain*/, NULL, false /*fNoVal*/);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwEnterExcl(pThis, VERR_SEM_BUSY, true /*fTryAgain*/, &SrcPos, false /*fNoVal*/);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#ifdef IN_RING3
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync/**
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * Enters a PDM read/write critical section with exclusive (write) access.
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync *
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * @returns VINF_SUCCESS if entered successfully.
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * during the operation.
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync *
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * @param pThis Pointer to the read/write critical section.
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync * @param fCallRing3 Whether this is a VMMRZCallRing3()request.
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync */
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsyncVMMR3DECL(int) PDMR3CritSectRwEnterExclEx(PPDMCRITSECTRW pThis, bool fCallRing3)
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync{
59851790061a61c1ebb30683ba14240c4f813356vboxsync return pdmCritSectRwEnterExcl(pThis, VERR_SEM_BUSY, false /*fTryAgain*/, NULL, fCallRing3 /*fNoVal*/);
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync}
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#endif /* IN_RING3 */
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Leave a critical section held exclusively.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns VBox status code.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * during the operation.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param fNoVal No validation records (i.e. queued release).
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwLeaveShared, RTCritSectRwLeaveExcl.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsyncstatic int pdmCritSectRwLeaveExclWorker(PPDMCRITSECTRW pThis, bool fNoVal)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Validate handle.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtr(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, VERR_SEM_DESTROYED);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeSelf = pdmCritSectRwGetNativeSelf(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeWriter;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicUoReadHandle(&pThis->s.Core.hNativeWriter, &hNativeWriter);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(hNativeSelf == hNativeWriter, VERR_NOT_OWNER);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync * Unwind one recursion. Is it the final one?
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (pThis->s.Core.cWriteRecursions == 1)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.cWriterReads == 0, VERR_WRONG_ORDER); /* (must release all read recursions before the final write.) */
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (fNoVal)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync Assert(pThis->s.Core.pValidatorWrite->hThread == NIL_RTTHREAD);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync else
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync int rc9 = RTLockValidatorRecExclReleaseOwner(pThis->s.Core.pValidatorWrite, true);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (RT_FAILURE(rc9))
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return rc9;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Update the state.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#if defined(IN_RING3) || defined(IN_RING0)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING0
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if ( RTThreadPreemptIsEnabled(NIL_RTTHREAD)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync && ASMIntAreEnabled())
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync ASMAtomicWriteU32(&pThis->s.Core.cWriteRecursions, 0);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync STAM_PROFILE_ADV_STOP(&pThis->s.StatWriteLocked, swl);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync ASMAtomicWriteHandle(&pThis->s.Core.hNativeWriter, NIL_RTNATIVETHREAD);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync for (;;)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync uint64_t u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync uint64_t u64OldState = u64State;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync uint64_t c = (u64State & RTCSRW_CNT_WR_MASK) >> RTCSRW_CNT_WR_SHIFT;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync Assert(c > 0);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync c--;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if ( c > 0
09266e7b8337832578fd14f5103f9b663d74930bvboxsync || (u64State & RTCSRW_CNT_RD_MASK) == 0)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync /* Don't change the direction, wake up the next writer if any. */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State &= ~RTCSRW_CNT_WR_MASK;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State |= c << RTCSRW_CNT_WR_SHIFT;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (c > 0)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync int rc = SUPSemEventSignal(pThis->s.CTX_SUFF(pVM)->pSession, (SUPSEMEVENT)pThis->s.Core.hEvtWrite);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync AssertRC(rc);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync break;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync /* Reverse the direction and signal the reader threads. */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State &= ~(RTCSRW_CNT_WR_MASK | RTCSRW_DIR_MASK);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync u64State |= RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (ASMAtomicCmpXchgU64(&pThis->s.Core.u64State, u64State, u64OldState))
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync Assert(!pThis->s.Core.fNeedReset);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync ASMAtomicWriteBool(&pThis->s.Core.fNeedReset, true);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync int rc = SUPSemEventMultiSignal(pThis->s.CTX_SUFF(pVM)->pSession, (SUPSEMEVENTMULTI)pThis->s.Core.hEvtRead);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync AssertRC(rc);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync break;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
09266e7b8337832578fd14f5103f9b663d74930bvboxsync ASMNopPause();
09266e7b8337832578fd14f5103f9b663d74930bvboxsync if (pThis->s.Core.u32Magic != RTCRITSECTRW_MAGIC)
09266e7b8337832578fd14f5103f9b663d74930bvboxsync return VERR_SEM_DESTROYED;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync }
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#endif /* IN_RING3 || IN_RING0 */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync#ifndef IN_RING3
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# ifdef IN_RING0
09266e7b8337832578fd14f5103f9b663d74930bvboxsync else
09266e7b8337832578fd14f5103f9b663d74930bvboxsync# endif
09266e7b8337832578fd14f5103f9b663d74930bvboxsync {
09266e7b8337832578fd14f5103f9b663d74930bvboxsync /*
09266e7b8337832578fd14f5103f9b663d74930bvboxsync * We cannot call neither SUPSemEventSignal nor SUPSemEventMultiSignal,
09266e7b8337832578fd14f5103f9b663d74930bvboxsync * so queue the exit request (ring-3).
09266e7b8337832578fd14f5103f9b663d74930bvboxsync */
09266e7b8337832578fd14f5103f9b663d74930bvboxsync PVM pVM = pThis->s.CTX_SUFF(pVM); AssertPtr(pVM);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync PVMCPU pVCpu = VMMGetCpu(pVM); AssertPtr(pVCpu);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync uint32_t i = pVCpu->pdm.s.cQueuedCritSectRwExclLeaves++;
09266e7b8337832578fd14f5103f9b663d74930bvboxsync LogFlow(("PDMCritSectRwLeaveShared: [%d]=%p => R3\n", i, pThis));
09266e7b8337832578fd14f5103f9b663d74930bvboxsync AssertFatal(i < RT_ELEMENTS(pVCpu->pdm.s.apQueuedCritSectLeaves));
09266e7b8337832578fd14f5103f9b663d74930bvboxsync pVCpu->pdm.s.apQueuedCritSectRwExclLeaves[i] = MMHyperCCToR3(pVM, pThis);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync VMCPU_FF_SET(pVCpu, VMCPU_FF_PDM_CRITSECT);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync STAM_REL_COUNTER_INC(&pVM->pdm.s.StatQueuedCritSectLeaves);
09266e7b8337832578fd14f5103f9b663d74930bvboxsync STAM_REL_COUNTER_INC(&pThis->s.StatContentionRZLeaveExcl);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
8c7f1eb426ed2259c4ed882d80af2666b2490867vboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync /*
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync * Not the final recursion.
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync Assert(pThis->s.Core.cWriteRecursions != 0);
36ac4f28a411bfbbf9bcb0f1e6c5cd2d4ae9f80evboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (fNoVal)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync Assert(pThis->s.Core.pValidatorWrite->hThread == NIL_RTTHREAD);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync else
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync {
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync int rc9 = RTLockValidatorRecExclUnwind(pThis->s.Core.pValidatorWrite);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync if (RT_FAILURE(rc9))
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return rc9;
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicDecU32(&pThis->s.Core.cWriteRecursions);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return VINF_SUCCESS;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync/**
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * Leave a critical section held exclusively.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync *
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @returns VBox status code.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @retval VERR_SEM_DESTROYED if the critical section is delete before or
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * during the operation.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param pThis Pointer to the read/write critical section.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @sa PDMCritSectRwLeaveShared, RTCritSectRwLeaveExcl.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsyncVMMDECL(int) PDMCritSectRwLeaveExcl(PPDMCRITSECTRW pThis)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync{
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync return pdmCritSectRwLeaveExclWorker(pThis, false /*fNoVal*/);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync}
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync#if defined(IN_RING3) || defined(IN_RING0)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync/**
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * PDMCritSectBothFF interface.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync *
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync * @param pThis Pointer to the read/write critical section.
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync */
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsyncvoid pdmCritSectRwLeaveExclQueued(PPDMCRITSECTRW pThis)
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync{
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync pdmCritSectRwLeaveExclWorker(pThis, true /*fNoVal*/);
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync}
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync#endif
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync
9d39cf70a53b3411e29d332d9997cb691df1b5f6vboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Checks the caller is the exclusive (write) owner of the critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval @c true if owner.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval @c false if not owner.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwIsReadOwner, PDMCritSectIsOwner,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwIsWriteOwner.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(bool) PDMCritSectRwIsWriteOwner(PPDMCRITSECTRW pThis)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Validate handle.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtr(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, false);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Check ownership.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hNativeWriter;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicUoReadHandle(&pThis->s.Core.hNativeWriter, &hNativeWriter);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (hNativeWriter == NIL_RTNATIVETHREAD)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return false;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return hNativeWriter == pdmCritSectRwGetNativeSelf(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Checks if the caller is one of the read owners of the critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @note !CAUTION! This API doesn't work reliably if lock validation isn't
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * enabled. Meaning, the answer is not trustworhty unless
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RT_LOCK_STRICT or PDMCRITSECTRW_STRICT was defined at build time.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Also, make sure you do not use RTCRITSECTRW_FLAGS_NO_LOCK_VAL when
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * creating the semaphore. And finally, if you used a locking class,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * don't disable deadlock detection by setting cMsMinDeadlock to
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RT_INDEFINITE_WAIT.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * In short, only use this for assertions.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns @c true if reader, @c false if not.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param fWannaHear What you'd like to hear when lock validation is not
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * available. (For avoiding asserting all over the place.)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwIsWriteOwner, RTCritSectRwIsReadOwner.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(bool) PDMCritSectRwIsReadOwner(PPDMCRITSECTRW pThis, bool fWannaHear)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Validate handle.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtr(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, false);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Inspect the state.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if ((u64State & RTCSRW_DIR_MASK) == (RTCSRW_DIR_WRITE << RTCSRW_DIR_SHIFT))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync {
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * It's in write mode, so we can only be a reader if we're also the
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * current writer.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync RTNATIVETHREAD hWriter;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync ASMAtomicUoReadHandle(&pThis->s.Core.hNativeWriter, &hWriter);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (hWriter == NIL_RTNATIVETHREAD)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return false;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return hWriter == pdmCritSectRwGetNativeSelf(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync }
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Read mode. If there are no current readers, then we cannot be a reader.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if (!(u64State & RTCSRW_CNT_RD_MASK))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return false;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#if defined(PDMCRITSECTRW_STRICT) && defined(IN_RING3)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Ask the lock validator.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Note! It doesn't know everything, let's deal with that if it becomes an issue...
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return RTLockValidatorRecSharedIsOwner(pThis->s.Core.pValidatorRead, NIL_RTTHREAD);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#else
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Ok, we don't know, just tell the caller what he want to hear.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return fWannaHear;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync#endif
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Gets the write recursion count.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns The write recursion count (0 if bad critsect).
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwGetWriterReadRecursion, PDMCritSectRwGetReadCount,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwGetWriteRecursion.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(uint32_t) PDMCritSectRwGetWriteRecursion(PPDMCRITSECTRW pThis)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Validate handle.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtr(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, 0);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Return the requested data.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return pThis->s.Core.cWriteRecursions;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Gets the read recursion count of the current writer.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns The read recursion count (0 if bad critsect).
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwGetWriteRecursion, PDMCritSectRwGetReadCount,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwGetWriterReadRecursion.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(uint32_t) PDMCritSectRwGetWriterReadRecursion(PPDMCRITSECTRW pThis)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Validate handle.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtr(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, 0);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Return the requested data.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return pThis->s.Core.cWriterReads;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Gets the current number of reads.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * This includes all read recursions, so it might be higher than the number of
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * read owners. It does not include reads done by the current writer.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @returns The read count (0 if bad critsect).
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectRwGetWriteRecursion, PDMCritSectRwGetWriterReadRecursion,
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * RTCritSectRwGetReadCount.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(uint32_t) PDMCritSectRwGetReadCount(PPDMCRITSECTRW pThis)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Validate input.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtr(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertReturn(pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC, 0);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync /*
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Return the requested data.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync uint64_t u64State = ASMAtomicReadU64(&pThis->s.Core.u64State);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync if ((u64State & RTCSRW_DIR_MASK) != (RTCSRW_DIR_READ << RTCSRW_DIR_SHIFT))
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return 0;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return (u64State & RTCSRW_CNT_RD_MASK) >> RTCSRW_CNT_RD_SHIFT;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync/**
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * Checks if the read/write critical section is initialized or not.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync *
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval @c true if initialized.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @retval @c false if not initialized.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @param pThis Pointer to the read/write critical section.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync * @sa PDMCritSectIsInitialized, RTCritSectRwIsInitialized.
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync */
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsyncVMMDECL(bool) PDMCritSectRwIsInitialized(PCPDMCRITSECTRW pThis)
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync{
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync AssertPtr(pThis);
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync return pThis->s.Core.u32Magic == RTCRITSECTRW_MAGIC;
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync}
a0352d06ef77cf45a08eb08b4d65d570b7b294cbvboxsync