/** @file * IPRT - Critical Sections. */ /* * Copyright (C) 2006-2023 Oracle and/or its affiliates. * * This file is part of VirtualBox base platform packages, as * available from https://www.virtualbox.org. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, in version 3 of the * License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included * in the VirtualBox distribution, in which case the provisions of the * CDDL are applicable instead of those of the GPL. * * You may elect to license modified versions of this file under the * terms and conditions of either the GPL or the CDDL or both. * * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 */ #ifndef IPRT_INCLUDED_critsect_h #define IPRT_INCLUDED_critsect_h #ifndef RT_WITHOUT_PRAGMA_ONCE # pragma once #endif #include #include #include #if defined(IN_RING3) || defined(IN_RING0) # include #endif #ifdef RT_LOCK_STRICT_ORDER # include #endif RT_C_DECLS_BEGIN /** @defgroup grp_rt_critsect RTCritSect - Critical Sections * * "Critical section" synchronization primitives can be used to * protect a section of code or data to which access must be exclusive; * only one thread can hold access to a critical section at one time. * * A critical section is a fast recursive write lock; if the critical * section is not acquired, then entering it is fast (requires no system * call). IPRT uses the Windows terminology here; on other platform, this * might be called a "futex" or a "fast mutex". As opposed to IPRT * "fast mutexes" (see @ref grp_rt_sems_fast_mutex ), critical sections * are recursive. * * Use RTCritSectInit to initialize a critical section; use RTCritSectEnter * and RTCritSectLeave to acquire and release access. * * For an overview of all types of synchronization primitives provided * by IPRT (event, mutex/fast mutex/read-write mutex semaphores), see * @ref grp_rt_sems . * * @ingroup grp_rt * @{ */ /** * Critical section. */ typedef struct RTCRITSECT { /** Magic used to validate the section state. * RTCRITSECT_MAGIC is the value of an initialized & operational section. */ volatile uint32_t u32Magic; /** Number of lockers. * -1 if the section is free. */ volatile int32_t cLockers; /** The owner thread. */ volatile RTNATIVETHREAD NativeThreadOwner; /** Number of nested enter operations performed. * Greater or equal to 1 if owned, 0 when free. */ volatile int32_t cNestings; /** Section flags - the RTCRITSECT_FLAGS_* \#defines. */ uint32_t fFlags; /** The semaphore to block on. */ RTSEMEVENT EventSem; /** Lock validator record. Only used in strict builds. */ R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec; /** Alignment padding. */ RTHCPTR Alignment; } RTCRITSECT; AssertCompileSize(RTCRITSECT, HC_ARCH_BITS == 32 ? 32 : 48); /** RTCRITSECT::u32Magic value. (Hiromi Uehara) */ #define RTCRITSECT_MAGIC UINT32_C(0x19790326) /** @name RTCritSectInitEx flags / RTCRITSECT::fFlags * @{ */ /** If set, nesting(/recursion) is not allowed. */ #define RTCRITSECT_FLAGS_NO_NESTING UINT32_C(0x00000001) /** Disables lock validation. */ #define RTCRITSECT_FLAGS_NO_LOCK_VAL UINT32_C(0x00000002) /** Bootstrap hack for use with certain memory allocator locks only! */ #define RTCRITSECT_FLAGS_BOOTSTRAP_HACK UINT32_C(0x00000004) /** If set, the critical section becomes a dummy that doesn't serialize any * threads. This flag can only be set at creation time. * * The intended use is avoiding lots of conditional code where some component * might or might not require entering a critical section before access. */ #define RTCRITSECT_FLAGS_NOP UINT32_C(0x00000008) /** Indicates that this is a ring-0 critical section. */ #define RTCRITSECT_FLAGS_RING0 UINT32_C(0x00000010) /** @} */ #if defined(IN_RING3) || defined(IN_RING0) /** * Initialize a critical section. */ RTDECL(int) RTCritSectInit(PRTCRITSECT pCritSect); /** * Initialize a critical section with a simple name, */ RTDECL(int) RTCritSectInitNamed(PRTCRITSECT pCritSect, const char *pszName); /** * Initialize a critical section. * * @returns iprt status code. * @param pCritSect Pointer to the critical section structure. * @param fFlags Flags, any combination of the RTCRITSECT_FLAGS * \#defines. * @param hClass The class (no reference consumed). If NIL, no lock * order validation will be performed on this lock. * @param uSubClass The sub-class. This is used to define lock order * within a class. RTLOCKVAL_SUB_CLASS_NONE is the * recommended value here. * @param pszNameFmt Name format string for the lock validator, optional * (NULL). Max length is 32 bytes. * @param ... Format string arguments. */ RTDECL(int) RTCritSectInitEx(PRTCRITSECT pCritSect, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6); /** * Changes the lock validator sub-class of the critical section. * * It is recommended to try make sure that nobody is using this critical section * while changing the value. * * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the * lock validator isn't compiled in or either of the parameters are * invalid. * @param pCritSect The critical section. * @param uSubClass The new sub-class value. */ RTDECL(uint32_t) RTCritSectSetSubClass(PRTCRITSECT pCritSect, uint32_t uSubClass); /** * Enter a critical section. * * @returns VINF_SUCCESS on success. * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * @param pCritSect The critical section. */ RTDECL(int) RTCritSectEnter(PRTCRITSECT pCritSect); /** * Enter a critical section. * * @returns IPRT status code. * @retval VINF_SUCCESS on success. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param pCritSect The critical section. * @param uId Where we're entering the section. * @param SRC_POS The source position where call is being made from. * Use RT_SRC_POS when possible. Optional. */ RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); /** * Try enter a critical section. * * @retval VINF_SUCCESS on success. * @retval VERR_SEM_BUSY if the critsect was owned. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param pCritSect The critical section. */ RTDECL(int) RTCritSectTryEnter(PRTCRITSECT pCritSect); /** * Try enter a critical section. * * @retval VINF_SUCCESS on success. * @retval VERR_SEM_BUSY if the critsect was owned. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param pCritSect The critical section. * @param uId Where we're entering the section. * @param SRC_POS The source position where call is being made from. * Use RT_SRC_POS when possible. Optional. */ RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); # ifdef IN_RING3 /* Crazy APIs: ring-3 only. */ /** * Enter multiple critical sections. * * This function will enter ALL the specified critical sections before returning. * * @returns VINF_SUCCESS on success. * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * @param cCritSects Number of critical sections in the array. * @param papCritSects Array of critical section pointers. * * @remark Please note that this function will not necessarily come out favourable in a * fight with other threads which are using the normal RTCritSectEnter() function. * Therefore, avoid having to enter multiple critical sections! */ RTDECL(int) RTCritSectEnterMultiple(size_t cCritSects, PRTCRITSECT *papCritSects); /** * Enter multiple critical sections. * * This function will enter ALL the specified critical sections before returning. * * @returns VINF_SUCCESS on success. * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param cCritSects Number of critical sections in the array. * @param papCritSects Array of critical section pointers. * @param uId Where we're entering the section. * @param SRC_POS The source position where call is being made from. * Use RT_SRC_POS when possible. Optional. * * @remark See RTCritSectEnterMultiple(). */ RTDECL(int) RTCritSectEnterMultipleDebug(size_t cCritSects, PRTCRITSECT *papCritSects, RTHCUINTPTR uId, RT_SRC_POS_DECL); # endif /* IN_RING3 */ /** * Leave a critical section. * * @returns VINF_SUCCESS. * @param pCritSect The critical section. */ RTDECL(int) RTCritSectLeave(PRTCRITSECT pCritSect); /** * Leave multiple critical sections. * * @returns VINF_SUCCESS. * @param cCritSects Number of critical sections in the array. * @param papCritSects Array of critical section pointers. */ RTDECL(int) RTCritSectLeaveMultiple(size_t cCritSects, PRTCRITSECT *papCritSects); /** * Deletes a critical section. * * @returns VINF_SUCCESS. * @param pCritSect The critical section. */ RTDECL(int) RTCritSectDelete(PRTCRITSECT pCritSect); /** * Checks the caller is the owner of the critical section. * * @returns true if owner. * @returns false if not owner. * @param pCritSect The critical section. */ DECLINLINE(bool) RTCritSectIsOwner(PCRTCRITSECT pCritSect) { return pCritSect->NativeThreadOwner == RTThreadNativeSelf(); } #endif /* IN_RING3 || IN_RING0 */ /** * Checks the section is owned by anyone. * * @returns true if owned. * @returns false if not owned. * @param pCritSect The critical section. */ DECLINLINE(bool) RTCritSectIsOwned(PCRTCRITSECT pCritSect) { return pCritSect->NativeThreadOwner != NIL_RTNATIVETHREAD; } /** * Gets the thread id of the critical section owner. * * @returns Thread id of the owner thread if owned. * @returns NIL_RTNATIVETHREAD is not owned. * @param pCritSect The critical section. */ DECLINLINE(RTNATIVETHREAD) RTCritSectGetOwner(PCRTCRITSECT pCritSect) { return pCritSect->NativeThreadOwner; } /** * Checks if a critical section is initialized or not. * * @returns true if initialized. * @returns false if not initialized. * @param pCritSect The critical section. */ DECLINLINE(bool) RTCritSectIsInitialized(PCRTCRITSECT pCritSect) { return pCritSect->u32Magic == RTCRITSECT_MAGIC; } /** * Gets the recursion depth. * * @returns The recursion depth. * @param pCritSect The Critical section */ DECLINLINE(uint32_t) RTCritSectGetRecursion(PCRTCRITSECT pCritSect) { return (uint32_t)pCritSect->cNestings; } /** * Gets the waiter count * * @returns The waiter count * @param pCritSect The Critical section */ DECLINLINE(int32_t) RTCritSectGetWaiters(PCRTCRITSECT pCritSect) { return pCritSect->cLockers; } /* Lock strict build: Remap the three enter calls to the debug versions. */ #if defined(RT_LOCK_STRICT) && !defined(RTCRITSECT_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) # ifdef IPRT_INCLUDED_asm_h # define RTCritSectEnter(pCritSect) RTCritSectEnterDebug(pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) # define RTCritSectTryEnter(pCritSect) RTCritSectTryEnterDebug(pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) # define RTCritSectEnterMultiple(cCritSects, pCritSect) RTCritSectEnterMultipleDebug((cCritSects), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) # else # define RTCritSectEnter(pCritSect) RTCritSectEnterDebug(pCritSect, 0, RT_SRC_POS) # define RTCritSectTryEnter(pCritSect) RTCritSectTryEnterDebug(pCritSect, 0, RT_SRC_POS) # define RTCritSectEnterMultiple(cCritSects, pCritSect) RTCritSectEnterMultipleDebug((cCritSects), (pCritSect), 0, RT_SRC_POS) # endif #endif /* Strict lock order: Automatically classify locks by init location. */ #if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) && !defined(RTCRITSECT_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) # undef RTCritSectInit # define RTCritSectInit(pCritSect) \ RTCritSectInitEx((pCritSect), 0 /*fFlags*/, \ RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ RTLOCKVAL_SUB_CLASS_NONE, NULL) # undef RTCritSectInitNamed # define RTCritSectInitNamed(a_pCritSect, a_pszName) \ RTCritSectInitEx((a_pCritSect), 0 /*fFlags*/, \ RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ RTLOCKVAL_SUB_CLASS_NONE, "%s", a_pszName) #endif /** @} */ /** @defgroup grp_rt_critsectrw RTCritSectRw - Read/Write Critical Sections * @ingroup grp_rt * @{ */ /** * Union that allows us to atomically update both the state and * exclusive owner if the hardware supports cmpxchg16b or similar. */ typedef union RTCRITSECTRWSTATE { struct { /** The state variable. * All accesses are atomic and it bits are defined like this: * Bits 0..14 - cReads. * Bit 15 - Unused. * Bits 16..31 - cWrites. * Bit 31 - fDirection; 0=Read, 1=Write. * Bits 32..46 - cWaitingReads * Bit 47 - Unused. * Bits 48..62 - cWaitingWrites - doesn't make sense here, not used. * Bit 63 - Unused. */ uint64_t u64State; /** The write owner. */ RTNATIVETHREAD hNativeWriter; } s; RTUINT128U u128; } RTCRITSECTRWSTATE; /** * Read/write critical section. */ typedef struct RTCRITSECTRW { /** Magic used to validate the section state. * RTCRITSECTRW_MAGIC is the value of an initialized & operational section. */ volatile uint32_t u32Magic; /** Indicates whether hEvtRead needs resetting. */ bool volatile fNeedReset; /** Explicit alignment padding. */ bool volatile afPadding[1]; /** Section flags - the RTCRITSECT_FLAGS_* \#defines. */ uint16_t fFlags; /** The number of reads made by the current writer. */ uint32_t volatile cWriterReads; /** The number of recursions made by the current writer. (The initial grabbing * of the lock counts as the first one.) */ uint32_t volatile cWriteRecursions; /** The core state. */ RTCRITSECTRWSTATE volatile u; /** What the writer threads are blocking on. */ RTSEMEVENT hEvtWrite; /** What the read threads are blocking on when waiting for the writer to * finish. */ RTSEMEVENTMULTI hEvtRead; /** The validator record for the writer. */ R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorWrite; /** The validator record for the readers. */ R3R0PTRTYPE(PRTLOCKVALRECSHRD) pValidatorRead; } RTCRITSECTRW; AssertCompileSize(RTCRITSECTRW, HC_ARCH_BITS == 32 ? 48 : 64); /** RTCRITSECTRW::u32Magic value. (Eric Allan Dolphy, Jr.) */ #define RTCRITSECTRW_MAGIC UINT32_C(0x19280620) /** RTCRITSECTRW::u32Magic dead value. */ #define RTCRITSECTRW_MAGIC_DEAD UINT32_C(0x19640629) /** @name RTCRITSECTRW::u64State values. * @note Using RTCSRW instead of RTCRITSECTRW to save space. * @{ */ #define RTCSRW_CNT_BITS 15 #define RTCSRW_CNT_MASK UINT64_C(0x00007fff) #define RTCSRW_CNT_RD_SHIFT 0 #define RTCSRW_CNT_RD_MASK (RTCSRW_CNT_MASK << RTCSRW_CNT_RD_SHIFT) #define RTCSRW_CNT_WR_SHIFT 16 #define RTCSRW_CNT_WR_MASK (RTCSRW_CNT_MASK << RTCSRW_CNT_WR_SHIFT) #define RTCSRW_DIR_SHIFT 31 #define RTCSRW_DIR_MASK RT_BIT_64(RTCSRW_DIR_SHIFT) #define RTCSRW_DIR_READ UINT64_C(0) #define RTCSRW_DIR_WRITE UINT64_C(1) #define RTCSRW_WAIT_CNT_RD_SHIFT 32 #define RTCSRW_WAIT_CNT_RD_MASK (RTCSRW_CNT_MASK << RTCSRW_WAIT_CNT_RD_SHIFT) /* #define RTCSRW_WAIT_CNT_WR_SHIFT 48 */ /* #define RTCSRW_WAIT_CNT_WR_MASK (RTCSRW_CNT_MASK << RTCSRW_WAIT_CNT_WR_SHIFT) */ /** @} */ #if defined(IN_RING3) || defined(IN_RING0) /** * Initialize a read/write critical section. */ RTDECL(int) RTCritSectRwInit(PRTCRITSECTRW pThis); /** * Initialize a read/write critical section with a simple name. */ RTDECL(int) RTCritSectRwInitNamed(PRTCRITSECTRW pThis, const char *pszName); /** * Initialize a read/write critical section. * * @returns IPRT status code. * @param pThis Pointer to the read/write critical section. * @param fFlags Flags, any combination of the RTCRITSECT_FLAGS * \#defines. * @param hClass The class (no reference consumed). If NIL, no lock * order validation will be performed on this lock. * @param uSubClass The sub-class. This is used to define lock order * within a class. RTLOCKVAL_SUB_CLASS_NONE is the * recommended value here. * @param pszNameFmt Name format string for the lock validator, optional * (NULL). Max length is 32 bytes. * @param ... Format string arguments. */ RTDECL(int) RTCritSectRwInitEx(PRTCRITSECTRW pThis, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6); /** * Changes the lock validator sub-class of the critical section. * * It is recommended to try make sure that nobody is using this critical section * while changing the value. * * @returns The old sub-class. RTLOCKVAL_SUB_CLASS_INVALID is returns if the * lock validator isn't compiled in or either of the parameters are * invalid. * @param pThis Pointer to the read/write critical section. * @param uSubClass The new sub-class value. */ RTDECL(uint32_t) RTCritSectRwSetSubClass(PRTCRITSECTRW pThis, uint32_t uSubClass); /** * Enter a critical section with shared (read) access. * * @returns IPRT status code. * @retval VINF_SUCCESS on success. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * @param pThis Pointer to the read/write critical section. */ RTDECL(int) RTCritSectRwEnterShared(PRTCRITSECTRW pThis); /** * Enter a critical section with shared (read) access. * * @returns IPRT status code. * @retval VINF_SUCCESS on success. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param pThis Pointer to the read/write critical section. * @param uId Where we're entering the section. * @param SRC_POS The source position where call is being made from. * Use RT_SRC_POS when possible. Optional. */ RTDECL(int) RTCritSectRwEnterSharedDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); /** * Try enter a critical section with shared (read) access. * * @returns IPRT status code. * @retval VINF_SUCCESS on success. * @retval VERR_SEM_BUSY if the critsect was owned. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param pThis Pointer to the read/write critical section. */ RTDECL(int) RTCritSectRwTryEnterShared(PRTCRITSECTRW pThis); /** * Try enter a critical section with shared (read) access. * * @returns IPRT status code. * @retval VINF_SUCCESS on success. * @retval VERR_SEM_BUSY if the critsect was owned. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param pThis Pointer to the read/write critical section. * @param uId Where we're entering the section. * @param SRC_POS The source position where call is being made from. * Use RT_SRC_POS when possible. Optional. */ RTDECL(int) RTCritSectRwTryEnterSharedDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); /** * Leave a critical section held with shared access. * * @returns IPRT status code. * @param pThis Pointer to the read/write critical section. */ RTDECL(int) RTCritSectRwLeaveShared(PRTCRITSECTRW pThis); /** * Enter a critical section with exclusive (write) access. * * @returns IPRT status code. * @retval VINF_SUCCESS on success. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * @param pThis Pointer to the read/write critical section. */ RTDECL(int) RTCritSectRwEnterExcl(PRTCRITSECTRW pThis); /** * Enter a critical section with exclusive (write) access. * * @retval VINF_SUCCESS on success. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param pThis Pointer to the read/write critical section. * @param uId Where we're entering the section. * @param SRC_POS The source position where call is being made from. * Use RT_SRC_POS when possible. Optional. */ RTDECL(int) RTCritSectRwEnterExclDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); /** * Try enter a critical section with exclusive (write) access. * * @returns IPRT status code. * @retval VINF_SUCCESS on success. * @retval VERR_SEM_BUSY if the critsect was owned. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param pThis Pointer to the read/write critical section. */ RTDECL(int) RTCritSectRwTryEnterExcl(PRTCRITSECTRW pThis); /** * Try enter a critical section with exclusive (write) access. * * @returns IPRT status code. * @retval VINF_SUCCESS on success. * @retval VERR_SEM_BUSY if the critsect was owned. * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) * @retval VERR_SEM_DESTROYED if the critical section is delete before or * during the operation. * * @param pThis Pointer to the read/write critical section. * @param uId Where we're entering the section. * @param SRC_POS The source position where call is being made from. * Use RT_SRC_POS when possible. Optional. */ RTDECL(int) RTCritSectRwTryEnterExclDebug(PRTCRITSECTRW pThis, RTHCUINTPTR uId, RT_SRC_POS_DECL); /** * Leave a critical section held exclusively. * * @returns IPRT status code; VINF_SUCCESS, VERR_NOT_OWNER, VERR_SEM_DESTROYED, * or VERR_WRONG_ORDER. * @param pThis Pointer to the read/write critical section. */ RTDECL(int) RTCritSectRwLeaveExcl(PRTCRITSECTRW pThis); /** * Deletes a critical section. * * @returns VINF_SUCCESS. * @param pThis Pointer to the read/write critical section. */ RTDECL(int) RTCritSectRwDelete(PRTCRITSECTRW pThis); /** * Checks the caller is the exclusive (write) owner of the critical section. * * @retval true if owner. * @retval false if not owner. * @param pThis Pointer to the read/write critical section. */ RTDECL(bool) RTCritSectRwIsWriteOwner(PRTCRITSECTRW pThis); /** * Checks if the caller is one of the read owners of the critical section. * * @note !CAUTION! This API doesn't work reliably if lock validation isn't * enabled. Meaning, the answer is not trustworhty unless * RT_LOCK_STRICT or RTCRITSECTRW_STRICT was defined at build time. * Also, make sure you do not use RTCRITSECTRW_FLAGS_NO_LOCK_VAL when * creating the semaphore. And finally, if you used a locking class, * don't disable deadlock detection by setting cMsMinDeadlock to * RT_INDEFINITE_WAIT. * * In short, only use this for assertions. * * @returns @c true if reader, @c false if not. * @param pThis Pointer to the read/write critical section. * @param fWannaHear What you'd like to hear when lock validation is not * available. (For avoiding asserting all over the * place.) */ RTDECL(bool) RTCritSectRwIsReadOwner(PRTCRITSECTRW pThis, bool fWannaHear); /** * Gets the write recursion count. * * @returns The write recursion count (0 if bad critsect). * @param pThis Pointer to the read/write critical section. */ RTDECL(uint32_t) RTCritSectRwGetWriteRecursion(PRTCRITSECTRW pThis); /** * Gets the read recursion count of the current writer. * * @returns The read recursion count (0 if bad critsect). * @param pThis Pointer to the read/write critical section. */ RTDECL(uint32_t) RTCritSectRwGetWriterReadRecursion(PRTCRITSECTRW pThis); /** * Gets the current number of reads. * * This includes all read recursions, so it might be higher than the number of * read owners. It does not include reads done by the current writer. * * @returns The read count (0 if bad critsect). * @param pThis Pointer to the read/write critical section. */ RTDECL(uint32_t) RTCritSectRwGetReadCount(PRTCRITSECTRW pThis); #endif /* IN_RING3 || IN_RING0 */ /** * Checks if a critical section is initialized or not. * * @retval true if initialized. * @retval false if not initialized. * @param pThis Pointer to the read/write critical section. */ DECLINLINE(bool) RTCritSectRwIsInitialized(PCRTCRITSECTRW pThis) { return pThis->u32Magic == RTCRITSECTRW_MAGIC; } /* Lock strict build: Remap the three enter calls to the debug versions. */ #if defined(RT_LOCK_STRICT) && !defined(RTCRITSECTRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) # ifdef IPRT_INCLUDED_asm_h # define RTCritSectRwEnterExcl(pThis) RTCritSectRwEnterExclDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) # define RTCritSectRwTryEnterExcl(pThis) RTCritSectRwTryEnterExclDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) # define RTCritSectRwEnterShared(pThis) RTCritSectRwEnterSharedDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) # define RTCritSectRwTryEnterShared(pThis) RTCritSectRwTryEnterSharedDebug(pThis, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) # else # define RTCritSectRwEnterExcl(pThis) RTCritSectRwEnterExclDebug(pThis, 0, RT_SRC_POS) # define RTCritSectRwTryEnterExcl(pThis) RTCritSectRwTryEnterExclDebug(pThis, 0, RT_SRC_POS) # define RTCritSectRwEnterShared(pThis) RTCritSectRwEnterSharedDebug(pThis, 0, RT_SRC_POS) # define RTCritSectRwTryEnterShared(pThis) RTCritSectRwTryEnterSharedDebug(pThis, 0, RT_SRC_POS) # endif #endif /* Strict lock order: Automatically classify locks by init location. */ #if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3) && !defined(RTCRITSECTRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING) # define RTCritSectRwInit(a_pThis) \ RTCritSectRwInitEx((a_pThis), 0 /*fFlags*/, \ RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ RTLOCKVAL_SUB_CLASS_NONE, NULL) # define RTCritSectRwInitNamed(a_pThis, a_pszName) \ RTCritSectRwInitEx((a_pThis), 0 /*fFlags*/, \ RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \ RTLOCKVAL_SUB_CLASS_NONE, "%s", a_pszName) #endif /** @} */ RT_C_DECLS_END #endif /* !IPRT_INCLUDED_critsect_h */