1450 lines
55 KiB
C
1450 lines
55 KiB
C
/** @file
|
|
* IPRT - Semaphore.
|
|
*/
|
|
|
|
/*
|
|
* 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 <https://www.gnu.org/licenses>.
|
|
*
|
|
* 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_semaphore_h
|
|
#define IPRT_INCLUDED_semaphore_h
|
|
#ifndef RT_WITHOUT_PRAGMA_ONCE
|
|
# pragma once
|
|
#endif
|
|
|
|
#include <iprt/cdefs.h>
|
|
#include <iprt/types.h>
|
|
#if defined(RT_LOCK_STRICT_ORDER) && defined(IN_RING3)
|
|
# include <iprt/lockvalidator.h>
|
|
#endif
|
|
|
|
|
|
RT_C_DECLS_BEGIN
|
|
|
|
/** @defgroup grp_rt_sems RTSem - Semaphores
|
|
*
|
|
* This module implements all kinds of event and mutex semaphores; in addition
|
|
* to these, IPRT implements "critical sections", which are fast recursive
|
|
* mutexes (see @ref grp_rt_critsect ). C++ users may find @ref grp_rt_cpp_lock
|
|
* interesting.
|
|
*
|
|
* @ingroup grp_rt
|
|
* @{
|
|
*/
|
|
|
|
|
|
/** @name Generic Semaphore Wait Flags.
|
|
*
|
|
* @remarks Exactly one of RTSEMWAIT_FLAGS_RELATIVE and
|
|
* RTSEMWAIT_FLAGS_ABSOLUTE must be set, unless
|
|
* RTSEMWAIT_FLAGS_INDEFINITE is used.
|
|
*
|
|
* Exactly one of RTSEMWAIT_FLAGS_NANOSECS and
|
|
* RTSEMWAIT_FLAGS_MILLISECS must be set, unless
|
|
* RTSEMWAIT_FLAGS_INDEFINITE is used.
|
|
*
|
|
* Exactly one of RTSEMWAIT_FLAGS_RESUME and RTSEMWAIT_FLAGS_NORESUME
|
|
* must be set.
|
|
*
|
|
* The interruptible vs resume stuff is ring-0 vs ring-3 semantics.
|
|
*
|
|
* @{ */
|
|
/** The timeout is relative. */
|
|
#define RTSEMWAIT_FLAGS_RELATIVE RT_BIT_32(0)
|
|
/** The timeout is absolute. */
|
|
#define RTSEMWAIT_FLAGS_ABSOLUTE RT_BIT_32(1)
|
|
/** The timeout is specified in nanoseconds. */
|
|
#define RTSEMWAIT_FLAGS_NANOSECS RT_BIT_32(2)
|
|
/** The timeout is specified in milliseconds. */
|
|
#define RTSEMWAIT_FLAGS_MILLISECS RT_BIT_32(3)
|
|
/** Indefinite wait.
|
|
* The relative/absolute and nano-/millisecond flags are ignored. */
|
|
#define RTSEMWAIT_FLAGS_INDEFINITE RT_BIT_32(4)
|
|
/** Mask covering the time related bits. */
|
|
#define RTSEMWAIT_FLAGS_TIME_MASK UINT32_C(0x0000001f)
|
|
|
|
/** Interruptible wait. */
|
|
#define RTSEMWAIT_FLAGS_INTERRUPTIBLE RT_BIT_32(5)
|
|
/** No automatic resume, same as interruptible. */
|
|
#define RTSEMWAIT_FLAGS_NORESUME RTSEMWAIT_FLAGS_INTERRUPTIBLE
|
|
/** Uninterruptible wait. */
|
|
#define RTSEMWAIT_FLAGS_UNINTERRUPTIBLE RT_BIT_32(6)
|
|
/** Resume on interrupt, same as uninterruptible. */
|
|
#define RTSEMWAIT_FLAGS_RESUME RTSEMWAIT_FLAGS_UNINTERRUPTIBLE
|
|
|
|
/** Macro for validate the flags. */
|
|
#define RTSEMWAIT_FLAGS_ARE_VALID(fFlags) \
|
|
( !((fFlags) & UINT32_C(0xffffff80)) \
|
|
&& ( ((fFlags) & RTSEMWAIT_FLAGS_INDEFINITE) \
|
|
? ( (((fFlags) & UINT32_C(0x20))) ^ (((fFlags) >> 1) & UINT32_C(0x20)) ) == UINT32_C(0x20) \
|
|
: ( (((fFlags) & UINT32_C(0x25))) ^ (((fFlags) >> 1) & UINT32_C(0x25)) ) == UINT32_C(0x25) ))
|
|
/** @} */
|
|
|
|
|
|
|
|
/** @defgroup grp_rt_sems_event RTSemEvent - Single Release Event Semaphores
|
|
*
|
|
* Event semaphores can be used for inter-thread communication when one thread
|
|
* wants to notify another thread that something happened. A thread can block
|
|
* ("wait") on an event semaphore until it is signalled by another thread; see
|
|
* RTSemEventCreate, RTSemEventSignal and RTSemEventWait.
|
|
*
|
|
* @{ */
|
|
|
|
/**
|
|
* Create an event semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param phEventSem Where to store the handle to the newly created
|
|
* event semaphore.
|
|
*/
|
|
RTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem);
|
|
|
|
/**
|
|
* Create an event semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param phEventSem Where to store the handle to the newly created
|
|
* event semaphore.
|
|
* @param fFlags Flags, any combination of the
|
|
* RTSEMEVENT_FLAGS_XXX \#defines.
|
|
* @param hClass The class (no reference consumed). Since we
|
|
* don't do order checks on event semaphores, the
|
|
* use of the class is limited to controlling the
|
|
* timeout threshold for deadlock detection.
|
|
* @param pszNameFmt Name format string for the lock validator,
|
|
* optional (NULL). Max length is 32 bytes.
|
|
* @param ... Format string arguments.
|
|
*/
|
|
RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
|
|
const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(4, 5);
|
|
|
|
/** @name RTSemMutexCreateEx flags
|
|
* @{ */
|
|
/** Disables lock validation. */
|
|
#define RTSEMEVENT_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001)
|
|
/** Bootstrap hack for use with certain memory allocator locks only! */
|
|
#define RTSEMEVENT_FLAGS_BOOTSTRAP_HACK UINT32_C(0x00000004)
|
|
/** @} */
|
|
|
|
/**
|
|
* Destroy an event semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hEventSem Handle of the event semaphore. NIL_RTSEMEVENT
|
|
* is quietly ignored (VINF_SUCCESS).
|
|
*/
|
|
RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem);
|
|
|
|
/**
|
|
* Signal an event semaphore.
|
|
*
|
|
* The event semaphore will be signaled and automatically reset after exactly
|
|
* one thread have successfully returned from RTSemEventWait() after
|
|
* waiting/polling on that semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hEventSem The event semaphore to signal.
|
|
*
|
|
* @remarks ring-0: This works when preemption is disabled. However it is
|
|
* system specific whether it works in interrupt context or with
|
|
* interrupts disabled.
|
|
*
|
|
* ring-0/Darwin: This works when interrupts are disabled and thereby
|
|
* in interrupt context, except it cannot race semaphore destruction as
|
|
* the allocator does not work under these circumstances.
|
|
*/
|
|
RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem);
|
|
|
|
/**
|
|
* Whether RTSemEventSignal can be safely called w/o risk of preemption.
|
|
*
|
|
* Checks whether the caller can safely signal a single release semaphore
|
|
* without any risk of getting preempted on locks or similar while doing so.
|
|
* This also checks whether the context is suitable in general.
|
|
*
|
|
* @returns true if safe, false if not.
|
|
* @remarks Only ring-0.
|
|
*/
|
|
RTR0DECL(bool) RTSemEventIsSignalSafe(void);
|
|
|
|
/**
|
|
* Wait for the event semaphore to be signaled, resume on interruption.
|
|
*
|
|
* This function will resume if the wait is interrupted by an async system event
|
|
* (like a unix signal) or similar.
|
|
*
|
|
* @returns iprt status code.
|
|
* Will not return VERR_INTERRUPTED.
|
|
* @param hEventSem The event semaphore to wait on.
|
|
* @param cMillies Number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Wait for the event semaphore to be signaled, return on interruption.
|
|
*
|
|
* This function will not resume the wait if interrupted.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hEventSem The event semaphore to wait on.
|
|
* @param cMillies Number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Extended API for waiting on an event semaphore to be signaled.
|
|
*
|
|
* @returns IPRT status code.
|
|
* @param hEventSem The event semaphore to wait on.
|
|
* @param fFlags Combination of RTSEMWAIT_FLAGS_XXX.
|
|
* @param uTimeout The timeout, ignored if
|
|
* RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags.
|
|
* Whether this is absolute or relative,
|
|
* milliseconds or nanoseconds depends on the @a
|
|
* fFlags value. Do not pass RT_INDEFINITE_WAIT
|
|
* here, use RTSEMWAIT_FLAGS_INDEFINITE instead.
|
|
*/
|
|
RTDECL(int) RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout);
|
|
|
|
/**
|
|
* Debug version of RTSemEventWaitEx that tracks the location.
|
|
*
|
|
* @returns IPRT status code, see RTSemEventWaitEx.
|
|
* @param hEventSem The event semaphore to wait on.
|
|
* @param fFlags See RTSemEventWaitEx.
|
|
* @param uTimeout See RTSemEventWaitEx.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
|
|
RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Gets the best timeout resolution that RTSemEventWaitEx can do.
|
|
*
|
|
* @returns The resolution in nanoseconds.
|
|
*/
|
|
RTDECL(uint32_t) RTSemEventGetResolution(void);
|
|
|
|
/**
|
|
* Sets the signaller thread to one specific thread.
|
|
*
|
|
* This is only used for validating usage and deadlock detection. When used
|
|
* after calls to RTSemEventAddSignaller, the specified thread will be the only
|
|
* signalling thread.
|
|
*
|
|
* @param hEventSem The event semaphore.
|
|
* @param hThread The thread that will signal it. Pass
|
|
* NIL_RTTHREAD to indicate that there is no
|
|
* special signalling thread.
|
|
*/
|
|
RTDECL(void) RTSemEventSetSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread);
|
|
|
|
/**
|
|
* To add more signalling threads.
|
|
*
|
|
* First call RTSemEventSetSignaller then add further threads with this.
|
|
*
|
|
* @param hEventSem The event semaphore.
|
|
* @param hThread The thread that will signal it. NIL_RTTHREAD is
|
|
* not accepted.
|
|
*/
|
|
RTDECL(void) RTSemEventAddSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread);
|
|
|
|
/**
|
|
* To remove a signalling thread.
|
|
*
|
|
* Reverts work done by RTSemEventAddSignaller and RTSemEventSetSignaller.
|
|
*
|
|
* @param hEventSem The event semaphore.
|
|
* @param hThread A previously added thread.
|
|
*/
|
|
RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread);
|
|
|
|
/** @} */
|
|
|
|
|
|
/** @defgroup grp_rt_sems_event_multi RTSemEventMulti - Multiple Release Event Semaphores
|
|
*
|
|
* A variant of @ref grp_rt_sems_event where all threads will be unblocked when
|
|
* signalling the semaphore.
|
|
*
|
|
* @{ */
|
|
|
|
/**
|
|
* Creates a multiple release event semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param phEventMultiSem Where to store the handle to the newly created
|
|
* multiple release event semaphore.
|
|
*/
|
|
RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem);
|
|
|
|
/**
|
|
* Creates a multiple release event semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param phEventMultiSem Where to store the handle to the newly created
|
|
* multiple release event semaphore.
|
|
* @param fFlags Flags, any combination of the
|
|
* RTSEMEVENTMULTI_FLAGS_XXX \#defines.
|
|
* @param hClass The class (no reference consumed). Since we
|
|
* don't do order checks on event semaphores, the
|
|
* use of the class is limited to controlling the
|
|
* timeout threshold for deadlock detection.
|
|
* @param pszNameFmt Name format string for the lock validator,
|
|
* optional (NULL). Max length is 32 bytes.
|
|
* @param ... Format string arguments.
|
|
*/
|
|
RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
|
|
const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(4, 5);
|
|
|
|
/** @name RTSemMutexCreateEx flags
|
|
* @{ */
|
|
/** Disables lock validation. */
|
|
#define RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001)
|
|
/** @} */
|
|
|
|
/**
|
|
* Destroy an event multi semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hEventMultiSem The multiple release event semaphore. NIL is
|
|
* quietly ignored (VINF_SUCCESS).
|
|
*/
|
|
RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem);
|
|
|
|
/**
|
|
* Signal an event multi semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hEventMultiSem The multiple release event semaphore.
|
|
*
|
|
* @remarks ring-0: This works when preemption is disabled. However it is
|
|
* system specific whether it works in interrupt context or with
|
|
* interrupts disabled.
|
|
*
|
|
* ring-0/Darwin: This works when interrupts are disabled and thereby
|
|
* in interrupt context, except it cannot race semaphore destruction as
|
|
* the allocator does not work under these circumstances.
|
|
*/
|
|
RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem);
|
|
|
|
/**
|
|
* Whether RTSemEventMultiSignal can be safely called w/o risk of preemption.
|
|
*
|
|
* Checks whether the caller can safely signal a multiple release semaphore
|
|
* without any risk of getting preempted on locks or similar while doing so.
|
|
* This also checks whether the context is suitable in general.
|
|
*
|
|
* @returns true if safe, false if not.
|
|
* @remarks Only ring-0.
|
|
*/
|
|
RTR0DECL(bool) RTSemEventMultiIsSignalSafe(void);
|
|
|
|
/**
|
|
* Resets an event multi semaphore to non-signaled state.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hEventMultiSem The multiple release event semaphore.
|
|
*/
|
|
RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem);
|
|
|
|
/**
|
|
* Wait for the event multi semaphore to be signaled, resume on interruption.
|
|
*
|
|
* This function will resume if the wait is interrupted by an async
|
|
* system event (like a unix signal) or similar.
|
|
*
|
|
* @returns iprt status code.
|
|
* Will not return VERR_INTERRUPTED.
|
|
* @param hEventMultiSem The multiple release event semaphore.
|
|
* @param cMillies Number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Wait for the event multi semaphore to be signaled, return on interruption.
|
|
*
|
|
* This function will not resume the wait if interrupted.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hEventMultiSem The multiple release event semaphore.
|
|
* @param cMillies Number of milliseconds to wait.
|
|
* @todo Rename to RTSemEventMultiWaitIntr since it is mainly for
|
|
* ring-0 consumption.
|
|
*/
|
|
RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Extended API for waiting on an event semaphore to be signaled.
|
|
*
|
|
* @returns IPRT status code.
|
|
* @param hEventMultiSem The multiple release event semaphore to wait
|
|
* on.
|
|
* @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX.
|
|
* @param uTimeout The timeout, ignored if
|
|
* RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags.
|
|
* Whether this is absolute or relative,
|
|
* milliseconds or nanoseconds depends on the @a
|
|
* fFlags value. Do not pass RT_INDEFINITE_WAIT
|
|
* here, use RTSEMWAIT_FLAGS_INDEFINITE instead.
|
|
*/
|
|
RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout);
|
|
|
|
/**
|
|
* Debug version of RTSemEventMultiWaitEx that tracks the location.
|
|
|
|
* @returns IPRT status code, see RTSemEventMultiWaitEx.
|
|
* @param hEventMultiSem The multiple release event semaphore handle.
|
|
* @param fFlags See RTSemEventMultiWaitEx.
|
|
* @param uTimeout See RTSemEventMultiWaitEx.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
|
|
RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Gets the best timeout resolution that RTSemEventMultiWaitEx can do.
|
|
*
|
|
* @returns The resolution in nanoseconds.
|
|
*/
|
|
RTDECL(uint32_t) RTSemEventMultiGetResolution(void);
|
|
|
|
/**
|
|
* Sets the signaller thread to one specific thread.
|
|
*
|
|
* This is only used for validating usage and deadlock detection. When used
|
|
* after calls to RTSemEventAddSignaller, the specified thread will be the only
|
|
* signalling thread.
|
|
*
|
|
* @param hEventMultiSem The multiple release event semaphore.
|
|
* @param hThread The thread that will signal it. Pass
|
|
* NIL_RTTHREAD to indicate that there is no
|
|
* special signalling thread.
|
|
*/
|
|
RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread);
|
|
|
|
/**
|
|
* To add more signalling threads.
|
|
*
|
|
* First call RTSemEventSetSignaller then add further threads with this.
|
|
*
|
|
* @param hEventMultiSem The multiple release event semaphore.
|
|
* @param hThread The thread that will signal it. NIL_RTTHREAD is
|
|
* not accepted.
|
|
*/
|
|
RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread);
|
|
|
|
/**
|
|
* To remove a signalling thread.
|
|
*
|
|
* Reverts work done by RTSemEventAddSignaller and RTSemEventSetSignaller.
|
|
*
|
|
* @param hEventMultiSem The multiple release event semaphore.
|
|
* @param hThread A previously added thread.
|
|
*/
|
|
RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread);
|
|
|
|
/** @} */
|
|
|
|
|
|
/** @defgroup grp_rt_sems_mutex RTSemMutex - Mutex semaphores.
|
|
*
|
|
* Mutex semaphores 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. See RTSemMutexCreate, RTSemMutexRequest and RTSemMutexRelease.
|
|
*
|
|
* @remarks These are less efficient than "fast mutexes" and "critical
|
|
* sections", which IPRT implements as well; see @ref
|
|
* grp_rt_sems_fast_mutex and @ref grp_rt_critsect .
|
|
*
|
|
* @{ */
|
|
|
|
/**
|
|
* Create a mutex semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param phMutexSem Where to store the mutex semaphore handle.
|
|
*/
|
|
RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem);
|
|
|
|
/**
|
|
* Creates a read/write semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param phMutexSem Where to store the handle to the newly created
|
|
* mutex semaphore.
|
|
* @param fFlags Flags, any combination of the
|
|
* RTSEMMUTEX_FLAGS_XXX \#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) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass,
|
|
const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6);
|
|
|
|
/** @name RTSemMutexCreateEx flags
|
|
* @{ */
|
|
/** Disables lock validation. */
|
|
#define RTSEMMUTEX_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001)
|
|
/** @} */
|
|
|
|
|
|
/**
|
|
* Destroy a mutex semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hMutexSem The mutex semaphore to destroy. NIL is quietly
|
|
* ignored (VINF_SUCCESS).
|
|
*/
|
|
RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem);
|
|
|
|
/**
|
|
* Changes the lock validator sub-class of the mutex semaphore.
|
|
*
|
|
* It is recommended to try make sure that nobody is using this semaphore 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 hMutexSem The handle to the mutex semaphore.
|
|
* @param uSubClass The new sub-class value.
|
|
*/
|
|
RTDECL(uint32_t) RTSemMutexSetSubClass(RTSEMMUTEX hMutexSem, uint32_t uSubClass);
|
|
|
|
/**
|
|
* Request ownership of a mutex semaphore, resume on interruption.
|
|
*
|
|
* This function will resume if the wait is interrupted by an async
|
|
* system event (like a unix signal) or similar.
|
|
*
|
|
* The same thread may request a mutex semaphore multiple times,
|
|
* a nested counter is kept to make sure it's released on the right
|
|
* RTSemMutexRelease() call.
|
|
*
|
|
* @returns iprt status code.
|
|
* Will not return VERR_INTERRUPTED.
|
|
* @param hMutexSem The mutex semaphore to request ownership over.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Request ownership of a mutex semaphore, return on interruption.
|
|
*
|
|
* This function will not resume the wait if interrupted.
|
|
*
|
|
* The same thread may request a mutex semaphore multiple times,
|
|
* a nested counter is kept to make sure it's released on the right
|
|
* RTSemMutexRelease() call.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hMutexSem The mutex semaphore to request ownership over.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Debug version of RTSemMutexRequest that tracks the location.
|
|
*
|
|
* @returns iprt status code.
|
|
* Will not return VERR_INTERRUPTED.
|
|
* @param hMutexSem The mutex semaphore to request ownership over.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Debug version of RTSemMutexRequestNoResume that tracks the location.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hMutexSem The mutex semaphore to request ownership over.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Request ownership of a mutex semaphore, extended edition.
|
|
*
|
|
* The same thread may request a mutex semaphore multiple times,
|
|
* a nested counter is kept to make sure it's released on the right
|
|
* RTSemMutexRelease() call.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hMutexSem The mutex semaphore to request ownership over.
|
|
* @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX.
|
|
* @param uTimeout The timeout, ignored if
|
|
* RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags.
|
|
* Whether this is absolute or relative,
|
|
* milliseconds or nanoseconds depends on the @a
|
|
* fFlags value. Do not pass RT_INDEFINITE_WAIT
|
|
* here, use RTSEMWAIT_FLAGS_INDEFINITE instead.
|
|
*/
|
|
RTDECL(int) RTSemMutexRequestEx(RTSEMMUTEX hMutexSem, uint32_t fFlags, uint64_t uTimeout);
|
|
|
|
/**
|
|
* Debug version of RTSemMutexRequestEx that tracks the location.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hMutexSem The mutex semaphore to request ownership over.
|
|
* @param fFlags See RTSemMutexRequestEx.
|
|
* @param uTimeout See RTSemMutexRequestEx.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemMutexRequestExDebug(RTSEMMUTEX hMutexSem, uint32_t fFlags, uint64_t uTimeout,
|
|
RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Release the ownership of a mutex semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hMutexSem The mutex to release the ownership of. It goes
|
|
* without saying the the calling thread must own
|
|
* it.
|
|
*/
|
|
RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem);
|
|
|
|
/**
|
|
* Checks if the mutex semaphore is owned or not.
|
|
*
|
|
* @returns true if owned, false if not.
|
|
* @param hMutexSem The mutex semaphore.
|
|
*/
|
|
RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem);
|
|
|
|
/* Strict build: Remap the two request calls to the debug versions. */
|
|
#if defined(RT_STRICT) && !defined(RTSEMMUTEX_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING)
|
|
# ifdef IPRT_INCLUDED_asm_h
|
|
# define RTSemMutexRequest(hMutexSem, cMillies) RTSemMutexRequestDebug((hMutexSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
|
|
# define RTSemMutexRequestNoResume(hMutexSem, cMillies) RTSemMutexRequestNoResumeDebug((hMutexSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
|
|
# define RTSemMutexRequestEx(hMutexSem, fFlags, uTimeout) RTSemMutexRequestExDebug((hMutexSem), (fFlags), (uTimeout), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
|
|
# else
|
|
# define RTSemMutexRequest(hMutexSem, cMillies) RTSemMutexRequestDebug((hMutexSem), (cMillies), 0, RT_SRC_POS)
|
|
# define RTSemMutexRequestNoResume(hMutexSem, cMillies) RTSemMutexRequestNoResumeDebug((hMutexSem), (cMillies), 0, RT_SRC_POS)
|
|
# define RTSemMutexRequestEx(hMutexSem, fFlags, uTimeout) RTSemMutexRequestExDebug((hMutexSem), (fFlags), (uTimeout), 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(RTSEMMUTEX_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING)
|
|
# define RTSemMutexCreate(phMutexSem) \
|
|
RTSemMutexCreateEx((phMutexSem), 0 /*fFlags*/, \
|
|
RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \
|
|
RTLOCKVAL_SUB_CLASS_NONE, NULL)
|
|
#endif
|
|
|
|
/** @} */
|
|
|
|
|
|
/** @defgroup grp_rt_sems_fast_mutex RTSemFastMutex - Fast Mutex Semaphores
|
|
*
|
|
* Fast mutexes work like regular mutexes in that they allow only a single
|
|
* thread access to a critical piece of code or data. As opposed to mutexes,
|
|
* they require no syscall if the fast mutex is not held (like critical
|
|
* sections). Unlike critical sections however, they are *not* recursive.
|
|
*
|
|
* @remarks The fast mutexes has sideeffects on IRQL on Windows hosts. So use
|
|
* with care and test on windows with the driver verifier enabled.
|
|
*
|
|
* @{ */
|
|
|
|
/**
|
|
* Create a fast mutex semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param phFastMtx Where to store the handle to the newly created
|
|
* fast mutex semaphore.
|
|
*
|
|
* @remarks Fast mutex semaphores are not recursive.
|
|
*/
|
|
RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx);
|
|
|
|
/**
|
|
* Destroy a fast mutex semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hFastMtx Handle to the fast mutex semaphore. NIL is
|
|
* quietly ignored (VINF_SUCCESS).
|
|
*/
|
|
RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx);
|
|
|
|
/**
|
|
* Request ownership of a fast mutex semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hFastMtx Handle to the fast mutex semaphore.
|
|
*/
|
|
RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx);
|
|
|
|
/**
|
|
* Release the ownership of a fast mutex semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hFastMtx Handle to the fast mutex semaphore. It goes
|
|
* without saying the the calling thread must own
|
|
* it.
|
|
*/
|
|
RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx);
|
|
|
|
/** @} */
|
|
|
|
|
|
/** @defgroup grp_rt_sems_spin_mutex RTSemSpinMutex - Spinning Mutex Semaphores
|
|
*
|
|
* A very adaptive variant of mutex semaphore that is tailored for the ring-0
|
|
* logger.
|
|
*
|
|
* @{ */
|
|
|
|
/**
|
|
* Creates a spinning mutex semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VERR_INVALID_PARAMETER on invalid flags.
|
|
* @retval VERR_NO_MEMORY if out of memory for the semaphore structure and
|
|
* handle.
|
|
*
|
|
* @param phSpinMtx Where to return the handle to the create semaphore.
|
|
* @param fFlags Flags, see RTSEMSPINMUTEX_FLAGS_XXX.
|
|
*/
|
|
RTDECL(int) RTSemSpinMutexCreate(PRTSEMSPINMUTEX phSpinMtx, uint32_t fFlags);
|
|
|
|
/** @name RTSemSpinMutexCreate flags.
|
|
* @{ */
|
|
/** Always take the semaphore in a IRQ safe way.
|
|
* (In plain words: always disable interrupts.) */
|
|
#define RTSEMSPINMUTEX_FLAGS_IRQ_SAFE RT_BIT_32(0)
|
|
/** Mask of valid flags. */
|
|
#define RTSEMSPINMUTEX_FLAGS_VALID_MASK UINT32_C(0x00000001)
|
|
/** @} */
|
|
|
|
/**
|
|
* Destroys a spinning mutex semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VERR_INVALID_HANDLE (or crash) if the handle is invalid. (NIL will
|
|
* not cause this status.)
|
|
*
|
|
* @param hSpinMtx The semaphore handle. NIL_RTSEMSPINMUTEX is ignored
|
|
* quietly (VINF_SUCCESS).
|
|
*/
|
|
RTDECL(int) RTSemSpinMutexDestroy(RTSEMSPINMUTEX hSpinMtx);
|
|
|
|
/**
|
|
* Request the spinning mutex semaphore.
|
|
*
|
|
* This may block if the context we're called in allows this. If not it will
|
|
* spin. If called in an interrupt context, we will only spin if the current
|
|
* owner isn't interrupted. Also, on some systems it is not always possible to
|
|
* wake up blocking threads in all contexts, so, which will either be indicated
|
|
* by returning VERR_SEM_BAD_CONTEXT or by temporarily switching the semaphore
|
|
* into pure spinlock state.
|
|
*
|
|
* Preemption will be disabled upon return. IRQs may also be disabled.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VERR_SEM_BAD_CONTEXT if the context it's called in isn't suitable
|
|
* for releasing it if someone is sleeping on it.
|
|
* @retval VERR_SEM_DESTROYED if destroyed.
|
|
* @retval VERR_SEM_NESTED if held by the caller. Asserted.
|
|
* @retval VERR_INVALID_HANDLE if the handle is invalid. Asserted
|
|
*
|
|
* @param hSpinMtx The semaphore handle.
|
|
*/
|
|
RTDECL(int) RTSemSpinMutexRequest(RTSEMSPINMUTEX hSpinMtx);
|
|
|
|
/**
|
|
* Like RTSemSpinMutexRequest but it won't block or spin if the semaphore is
|
|
* held by someone else.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VERR_SEM_BUSY if held by someone else.
|
|
* @retval VERR_SEM_DESTROYED if destroyed.
|
|
* @retval VERR_SEM_NESTED if held by the caller. Asserted.
|
|
* @retval VERR_INVALID_HANDLE if the handle is invalid. Asserted
|
|
*
|
|
* @param hSpinMtx The semaphore handle.
|
|
*/
|
|
RTDECL(int) RTSemSpinMutexTryRequest(RTSEMSPINMUTEX hSpinMtx);
|
|
|
|
/**
|
|
* Releases the semaphore previously acquired by RTSemSpinMutexRequest or
|
|
* RTSemSpinMutexTryRequest.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VERR_SEM_DESTROYED if destroyed.
|
|
* @retval VERR_NOT_OWNER if not owner. Asserted.
|
|
* @retval VERR_INVALID_HANDLE if the handle is invalid. Asserted.
|
|
*
|
|
* @param hSpinMtx The semaphore handle.
|
|
*/
|
|
RTDECL(int) RTSemSpinMutexRelease(RTSEMSPINMUTEX hSpinMtx);
|
|
|
|
/** @} */
|
|
|
|
|
|
/** @defgroup grp_rt_sem_rw RTSemRW - Read / Write Semaphores
|
|
*
|
|
* Read/write semaphores are a fancier version of mutexes in that they grant
|
|
* read access to the protected data to several threads at the same time but
|
|
* allow only one writer at a time. This can make code scale better at the
|
|
* expense of slightly more overhead in mutex management.
|
|
*
|
|
* @{ */
|
|
|
|
/**
|
|
* Creates a read/write semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param phRWSem Where to store the handle to the newly created
|
|
* RW semaphore.
|
|
*/
|
|
RTDECL(int) RTSemRWCreate(PRTSEMRW phRWSem);
|
|
|
|
/**
|
|
* Creates a read/write semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param phRWSem Where to store the handle to the newly created
|
|
* RW semaphore.
|
|
* @param fFlags Flags, any combination of the RTSEMRW_FLAGS_XXX
|
|
* \#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) RTSemRWCreateEx(PRTSEMRW phRWSem, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass,
|
|
const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(5, 6);
|
|
|
|
/** @name RTSemRWCreateEx flags
|
|
* @{ */
|
|
/** Disables lock validation. */
|
|
#define RTSEMRW_FLAGS_NO_LOCK_VAL UINT32_C(0x00000001)
|
|
/** @} */
|
|
|
|
/**
|
|
* Destroys a read/write semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hRWSem Handle to the read/write semaphore. NIL is
|
|
* quietly ignored (VINF_SUCCESS).
|
|
*/
|
|
RTDECL(int) RTSemRWDestroy(RTSEMRW hRWSem);
|
|
|
|
/**
|
|
* Changes the lock validator sub-class of the read/write semaphore.
|
|
*
|
|
* It is recommended to try make sure that nobody is using this semaphore 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 hRWSem Handle to the read/write semaphore.
|
|
* @param uSubClass The new sub-class value.
|
|
*/
|
|
RTDECL(uint32_t) RTSemRWSetSubClass(RTSEMRW hRWSem, uint32_t uSubClass);
|
|
|
|
/**
|
|
* Request read access to a read/write semaphore, resume on interruption
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VINF_SUCCESS on success.
|
|
* @retval VERR_INTERRUPT if the wait was interrupted.
|
|
* @retval VERR_INVALID_HANDLE if hRWSem is invalid.
|
|
*
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestRead(RTSEMRW hRWSem, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Request read access to a read/write semaphore, return on interruption
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VINF_SUCCESS on success.
|
|
* @retval VERR_INTERRUPT if the wait was interrupted.
|
|
* @retval VERR_INVALID_HANDLE if hRWSem is invalid.
|
|
*
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW hRWSem, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Debug version of RTSemRWRequestRead that tracks the location.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VINF_SUCCESS on success.
|
|
* @retval VERR_INTERRUPT if the wait was interrupted.
|
|
* @retval VERR_INVALID_HANDLE if hRWSem is invalid.
|
|
*
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestReadDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Debug version of RTSemRWRequestWriteNoResume that tracks the location.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VINF_SUCCESS on success.
|
|
* @retval VERR_INTERRUPT if the wait was interrupted.
|
|
* @retval VERR_INVALID_HANDLE if hRWSem is invalid.
|
|
*
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestReadNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Request read access to a read/write semaphore, extended edition.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VINF_SUCCESS on success.
|
|
* @retval VERR_INTERRUPT if the wait was interrupted.
|
|
* @retval VERR_TIMEOUT if the wait timed out.
|
|
* @retval VERR_INVALID_HANDLE if hRWSem is invalid.
|
|
*
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX.
|
|
* @param uTimeout The timeout, ignored if
|
|
* RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags.
|
|
* Whether this is absolute or relative,
|
|
* milliseconds or nanoseconds depends on the @a
|
|
* fFlags value. Do not pass RT_INDEFINITE_WAIT
|
|
* here, use RTSEMWAIT_FLAGS_INDEFINITE instead.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestReadEx(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout);
|
|
|
|
|
|
/**
|
|
* Debug version of RTSemRWRequestReadEx that tracks the location.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VINF_SUCCESS on success.
|
|
* @retval VERR_INTERRUPT if the wait was interrupted.
|
|
* @retval VERR_TIMEOUT if the wait timed out.
|
|
* @retval VERR_INVALID_HANDLE if hRWSem is invalid.
|
|
*
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param fFlags See RTSemRWRequestReadEx.
|
|
* @param uTimeout See RTSemRWRequestReadEx.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestReadExDebug(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout,
|
|
RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Release read access to a read/write semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hRWSem Handle to the read/write semaphore. It goes
|
|
* without saying that caller must own read
|
|
* privileges to the semaphore.
|
|
*/
|
|
RTDECL(int) RTSemRWReleaseRead(RTSEMRW hRWSem);
|
|
|
|
/**
|
|
* Request write access to a read/write semaphore, resume on interruption.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VINF_SUCCESS on success.
|
|
* @retval VERR_DEADLOCK if the caller owned the read lock.
|
|
* @retval VERR_INVALID_HANDLE if hRWSem is invalid.
|
|
*
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestWrite(RTSEMRW hRWSem, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Request write access to a read/write semaphore, return on interruption.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VINF_SUCCESS on success.
|
|
* @retval VERR_INTERRUPT if the wait was interrupted.
|
|
* @retval VERR_DEADLOCK if the caller owned the read lock.
|
|
* @retval VERR_INVALID_HANDLE if hRWSem is invalid.
|
|
*
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW hRWSem, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Debug version of RTSemRWRequestWrite that tracks the location.
|
|
*
|
|
* @returns IPRT status code, see RTSemRWRequestWrite.
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Debug version of RTSemRWRequestWriteNoResume that tracks the location.
|
|
*
|
|
* @returns IPRT status code, see RTSemRWRequestWriteNoResume.
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param cMillies The number of milliseconds to wait.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW hRWSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Request write access to a read/write semaphore, extended edition.
|
|
*
|
|
* @returns iprt status code.
|
|
* @retval VINF_SUCCESS on success.
|
|
* @retval VERR_INTERRUPTED if the wait was interrupted.
|
|
* @retval VERR_TIMEOUT if the wait timed out.
|
|
* @retval VERR_DEADLOCK if the caller owned the read lock. Do not depend on
|
|
* this as it is implementation specific.
|
|
* @retval VERR_INVALID_HANDLE if hRWSem is invalid.
|
|
*
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param fFlags Combination of the RTSEMWAIT_FLAGS_XXX.
|
|
* @param uTimeout The timeout, ignored if
|
|
* RTSEMWAIT_FLAGS_INDEFINITE is set in @a flags.
|
|
* Whether this is absolute or relative,
|
|
* milliseconds or nanoseconds depends on the @a
|
|
* fFlags value. Do not pass RT_INDEFINITE_WAIT
|
|
* here, use RTSEMWAIT_FLAGS_INDEFINITE instead.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestWriteEx(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout);
|
|
|
|
/**
|
|
* Debug version of RTSemRWRequestWriteEx that tracks the location.
|
|
*
|
|
* @returns IPRT status code, see RTSemRWRequestWriteEx.
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param fFlags See RTSemRWRequestWriteEx.
|
|
* @param uTimeout See RTSemRWRequestWriteEx.
|
|
* @param uId Some kind of locking location ID. Typically a
|
|
* return address up the stack. Optional (0).
|
|
* @param SRC_POS The source position where call is being made
|
|
* from. Use RT_SRC_POS when possible. Optional.
|
|
*/
|
|
RTDECL(int) RTSemRWRequestWriteExDebug(RTSEMRW hRWSem, uint32_t fFlags, uint64_t uTimeout,
|
|
RTHCUINTPTR uId, RT_SRC_POS_DECL);
|
|
|
|
/**
|
|
* Release write access to a read/write semaphore.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param hRWSem Handle to the read/write semaphore. Goes
|
|
* without saying that caller must have write
|
|
* access to the semaphore.
|
|
*/
|
|
RTDECL(int) RTSemRWReleaseWrite(RTSEMRW hRWSem);
|
|
|
|
/**
|
|
* Checks if the caller is the exclusive semaphore owner.
|
|
*
|
|
* @returns true / false accoringly.
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
*/
|
|
RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW hRWSem);
|
|
|
|
/**
|
|
* Checks if the caller is one of the read owners of the semaphore.
|
|
*
|
|
* @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 RTSEMRW_STRICT was defined at build time. Also,
|
|
* make sure you do not use RTSEMRW_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 true if reader, false if not.
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
* @param fWannaHear What you'd like to hear when lock validation is
|
|
* not available. (For avoiding asserting all over
|
|
* the place.)
|
|
*/
|
|
RTDECL(bool) RTSemRWIsReadOwner(RTSEMRW hRWSem, bool fWannaHear);
|
|
|
|
/**
|
|
* Gets the write recursion count.
|
|
*
|
|
* @returns The write recursion count (0 if bad semaphore handle).
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
*/
|
|
RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW hRWSem);
|
|
|
|
/**
|
|
* Gets the read recursion count of the current writer.
|
|
*
|
|
* @returns The read recursion count (0 if bad semaphore handle).
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
*/
|
|
RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW hRWSem);
|
|
|
|
/**
|
|
* 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 semaphore handle).
|
|
* @param hRWSem Handle to the read/write semaphore.
|
|
*/
|
|
RTDECL(uint32_t) RTSemRWGetReadCount(RTSEMRW hRWSem);
|
|
|
|
/* Strict build: Remap the four request calls to the debug versions. */
|
|
#if defined(RT_STRICT) && !defined(RTSEMRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING)
|
|
# ifdef IPRT_INCLUDED_asm_h
|
|
# define RTSemRWRequestRead(hRWSem, cMillies) RTSemRWRequestReadDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
|
|
# define RTSemRWRequestReadNoResume(hRWSem, cMillies) RTSemRWRequestReadNoResumeDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
|
|
# define RTSemRWRequestWrite(hRWSem, cMillies) RTSemRWRequestWriteDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
|
|
# define RTSemRWRequestWriteNoResume(hRWSem, cMillies) RTSemRWRequestWriteNoResumeDebug((hRWSem), (cMillies), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
|
|
# define RTSemRWRequestWriteEx(hRWSem, fFlags, uTimeout) RTSemRWRequestWriteExDebug((hRWSem), (fFlags), (uTimeout), (uintptr_t)ASMReturnAddress(), RT_SRC_POS)
|
|
# else
|
|
# define RTSemRWRequestRead(hRWSem, cMillies) RTSemRWRequestReadDebug((hRWSem), (cMillies), 0, RT_SRC_POS)
|
|
# define RTSemRWRequestReadNoResume(hRWSem, cMillies) RTSemRWRequestReadNoResumeDebug((hRWSem), (cMillies), 0, RT_SRC_POS)
|
|
# define RTSemRWRequestWrite(hRWSem, cMillies) RTSemRWRequestWriteDebug((hRWSem), (cMillies), 0, RT_SRC_POS)
|
|
# define RTSemRWRequestWriteNoResume(hRWSem, cMillies) RTSemRWRequestWriteNoResumeDebug((hRWSem), (cMillies), 0, RT_SRC_POS)
|
|
# define RTSemRWRequestWriteEx(hRWSem, fFlags, uTimeout) RTSemRWRequestWriteExDebug((hRWSem), (fFlags), (uTimeout), 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(RTSEMRW_WITHOUT_REMAPPING) && !defined(RT_WITH_MANGLING)
|
|
# define RTSemRWCreate(phSemRW) \
|
|
RTSemRWCreateEx((phSemRW), 0 /*fFlags*/, \
|
|
RTLockValidatorClassForSrcPos(RT_SRC_POS, NULL), \
|
|
RTLOCKVAL_SUB_CLASS_NONE, NULL)
|
|
#endif
|
|
|
|
/** @} */
|
|
|
|
|
|
/** @defgroup grp_rt_sems_pingpong RTSemPingPong - Ping-Pong Construct
|
|
*
|
|
* Serialization of a two way communication.
|
|
*
|
|
* @{ */
|
|
|
|
/**
|
|
* Ping-pong speaker
|
|
*/
|
|
typedef enum RTPINGPONGSPEAKER
|
|
{
|
|
/** Not initialized. */
|
|
RTPINGPONGSPEAKER_UNINITIALIZE = 0,
|
|
/** Ping is speaking, Pong is waiting. */
|
|
RTPINGPONGSPEAKER_PING,
|
|
/** Pong is signaled, Ping is waiting. */
|
|
RTPINGPONGSPEAKER_PONG_SIGNALED,
|
|
/** Pong is speaking, Ping is waiting. */
|
|
RTPINGPONGSPEAKER_PONG,
|
|
/** Ping is signaled, Pong is waiting. */
|
|
RTPINGPONGSPEAKER_PING_SIGNALED,
|
|
/** Hack to ensure that it's at least 32-bits wide. */
|
|
RTPINGPONGSPEAKER_HACK = 0x7fffffff
|
|
} RTPINGPONGSPEAKER;
|
|
|
|
/**
|
|
* Ping-Pong construct.
|
|
*
|
|
* Two threads, one saying Ping and the other saying Pong. The construct
|
|
* makes sure they don't speak out of turn and that they can wait and poll
|
|
* on the conversation.
|
|
*/
|
|
typedef struct RTPINGPONG
|
|
{
|
|
/** The semaphore the Ping thread waits on. */
|
|
RTSEMEVENT Ping;
|
|
/** The semaphore the Pong thread waits on. */
|
|
RTSEMEVENT Pong;
|
|
/** The current speaker. */
|
|
volatile RTPINGPONGSPEAKER enmSpeaker;
|
|
#if HC_ARCH_BITS == 64
|
|
/** Padding the structure to become a multiple of sizeof(RTHCPTR). */
|
|
uint32_t u32Padding;
|
|
#endif
|
|
} RTPINGPONG;
|
|
/** Pointer to Ping-Pong construct. */
|
|
typedef RTPINGPONG *PRTPINGPONG;
|
|
|
|
/**
|
|
* Init a Ping-Pong construct.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param pPP Pointer to the ping-pong structure which needs initialization.
|
|
*/
|
|
RTDECL(int) RTSemPingPongInit(PRTPINGPONG pPP);
|
|
|
|
/**
|
|
* Deletes a Ping-Pong construct.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param pPP Pointer to the ping-pong structure which is to be destroyed.
|
|
* (I.e. put into uninitialized state.)
|
|
*/
|
|
RTDECL(int) RTSemPingPongDelete(PRTPINGPONG pPP);
|
|
|
|
/**
|
|
* Signals the pong thread in a ping-pong construct. (I.e. sends ping.)
|
|
* This is called by the ping thread.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param pPP Pointer to the ping-pong structure to ping.
|
|
*/
|
|
RTDECL(int) RTSemPing(PRTPINGPONG pPP);
|
|
|
|
/**
|
|
* Signals the ping thread in a ping-pong construct. (I.e. sends pong.)
|
|
* This is called by the pong thread.
|
|
*
|
|
* @returns iprt status code.
|
|
* @param pPP Pointer to the ping-pong structure to pong.
|
|
*/
|
|
RTDECL(int) RTSemPong(PRTPINGPONG pPP);
|
|
|
|
/**
|
|
* Wait function for the ping thread.
|
|
*
|
|
* @returns iprt status code.
|
|
* Will not return VERR_INTERRUPTED.
|
|
* @param pPP Pointer to the ping-pong structure to wait on.
|
|
* @param cMillies Number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemPingWait(PRTPINGPONG pPP, RTMSINTERVAL cMillies);
|
|
|
|
/**
|
|
* Wait function for the pong thread.
|
|
*
|
|
* @returns iprt status code.
|
|
* Will not return VERR_INTERRUPTED.
|
|
* @param pPP Pointer to the ping-pong structure to wait on.
|
|
* @param cMillies Number of milliseconds to wait.
|
|
*/
|
|
RTDECL(int) RTSemPongWait(PRTPINGPONG pPP, RTMSINTERVAL cMillies);
|
|
|
|
|
|
/**
|
|
* Checks if the pong thread is speaking.
|
|
*
|
|
* @returns true / false.
|
|
* @param pPP Pointer to the ping-pong structure.
|
|
* @remark This is NOT the same as !RTSemPongIsSpeaker().
|
|
*/
|
|
DECLINLINE(bool) RTSemPingIsSpeaker(PRTPINGPONG pPP)
|
|
{
|
|
RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker;
|
|
return enmSpeaker == RTPINGPONGSPEAKER_PING;
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks if the pong thread is speaking.
|
|
*
|
|
* @returns true / false.
|
|
* @param pPP Pointer to the ping-pong structure.
|
|
* @remark This is NOT the same as !RTSemPingIsSpeaker().
|
|
*/
|
|
DECLINLINE(bool) RTSemPongIsSpeaker(PRTPINGPONG pPP)
|
|
{
|
|
RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker;
|
|
return enmSpeaker == RTPINGPONGSPEAKER_PONG;
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks whether the ping thread should wait.
|
|
*
|
|
* @returns true / false.
|
|
* @param pPP Pointer to the ping-pong structure.
|
|
* @remark This is NOT the same as !RTSemPongShouldWait().
|
|
*/
|
|
DECLINLINE(bool) RTSemPingShouldWait(PRTPINGPONG pPP)
|
|
{
|
|
RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker;
|
|
return enmSpeaker == RTPINGPONGSPEAKER_PONG
|
|
|| enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED
|
|
|| enmSpeaker == RTPINGPONGSPEAKER_PING_SIGNALED;
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks whether the pong thread should wait.
|
|
*
|
|
* @returns true / false.
|
|
* @param pPP Pointer to the ping-pong structure.
|
|
* @remark This is NOT the same as !RTSemPingShouldWait().
|
|
*/
|
|
DECLINLINE(bool) RTSemPongShouldWait(PRTPINGPONG pPP)
|
|
{
|
|
RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker;
|
|
return enmSpeaker == RTPINGPONGSPEAKER_PING
|
|
|| enmSpeaker == RTPINGPONGSPEAKER_PING_SIGNALED
|
|
|| enmSpeaker == RTPINGPONGSPEAKER_PONG_SIGNALED;
|
|
}
|
|
|
|
/** @} */
|
|
|
|
|
|
/** @defgroup grp_rt_sems_xroads RTSemXRoads - Crossroads
|
|
*
|
|
* The crossroads semaphore is intended to prevent two classes of incompatible
|
|
* events from occurring simultaneously, like south/north bound traffic and
|
|
* west/east bound traffic at a 4-way junction.
|
|
*
|
|
* @remarks In order to simplify the implementation, the current flow is always
|
|
* given priority. So, it won't work at all well when busy!
|
|
*
|
|
* @remarks "XRoads" is used as a name because it is briefer than "crossroads"
|
|
* and it slightly stresses that is a 4 way crossing to the users of
|
|
* American English.
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Creates a crossroads semaphore.
|
|
*
|
|
* @returns IPRT status code.
|
|
*
|
|
* @param phXRoads Where to return the handle to the newly created
|
|
* crossroads semaphore.
|
|
*/
|
|
RTDECL(int) RTSemXRoadsCreate(PRTSEMXROADS phXRoads);
|
|
|
|
/**
|
|
* Destroys a crossroads semaphore.
|
|
*
|
|
* @returns IPRT status code.
|
|
*
|
|
* @param hXRoads Handle to the crossroads semaphore that is to be
|
|
* destroyed. NIL_RTSEMXROADS is quitetly ignored
|
|
* (VINF_SUCCESS).
|
|
*/
|
|
RTDECL(int) RTSemXRoadsDestroy(RTSEMXROADS hXRoads);
|
|
|
|
/**
|
|
* Enter the crossroads from the south or north.
|
|
*
|
|
* (Coupled with RTSemXRoadsNSLeave.)
|
|
*
|
|
* @returns IPRT status code.
|
|
* @param hXRoads Handle to the crossroads semaphore.
|
|
*/
|
|
RTDECL(int) RTSemXRoadsNSEnter(RTSEMXROADS hXRoads);
|
|
|
|
/**
|
|
* Leave the crossroads to the north or south.
|
|
*
|
|
* (Coupled with RTSemXRoadsNSEnter.)
|
|
*
|
|
* @returns IPRT status code.
|
|
* @param hXRoads Handle to the crossroads semaphore.
|
|
*/
|
|
RTDECL(int) RTSemXRoadsNSLeave(RTSEMXROADS hXRoads);
|
|
|
|
/**
|
|
* Leave the crossroads from the east or west.
|
|
*
|
|
* (Coupled with RTSemXRoadsEWLeave.)
|
|
*
|
|
* @returns IPRT status code.
|
|
* @param hXRoads Handle to the crossroads semaphore.
|
|
*/
|
|
RTDECL(int) RTSemXRoadsEWEnter(RTSEMXROADS hXRoads);
|
|
|
|
/**
|
|
* Leave the crossroads to the west or east.
|
|
*
|
|
* (Coupled with RTSemXRoadsEWEnter.)
|
|
*
|
|
* @returns IPRT status code.
|
|
* @param hXRoads Handle to the crossroads semaphore.
|
|
*/
|
|
RTDECL(int) RTSemXRoadsEWLeave(RTSEMXROADS hXRoads);
|
|
|
|
/** @} */
|
|
|
|
/** @} */
|
|
|
|
RT_C_DECLS_END
|
|
|
|
#endif /* !IPRT_INCLUDED_semaphore_h */
|
|
|