/** @file * IPRT - Semaphore. */ /* * Copyright (C) 2006-2007 Sun Microsystems, Inc. * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the * VirtualBox OSE 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. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 USA or visit http://www.sun.com if you need * additional information or have any questions. */ #ifndef ___iprt_semaphore_h #define ___iprt_semaphore_h #include #include __BEGIN_DECLS /** @defgroup grp_rt_sems RTSem - Semaphores * @ingroup grp_rt * @{ */ /** * Create a event semaphore. * * @returns iprt status code. * @param pEventSem Where to store the event semaphore handle. */ RTDECL(int) RTSemEventCreate(PRTSEMEVENT pEventSem); /** * Destroy an event semaphore. * * @returns iprt status code. * @param EventSem Handle of the */ RTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem); /** * 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 EventSem The event semaphore to signal. */ RTDECL(int) RTSemEventSignal(RTSEMEVENT EventSem); /** * 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 EventSem The event semaphore to wait on. * @param cMillies Number of milliseconds to wait. */ RTDECL(int) RTSemEventWait(RTSEMEVENT EventSem, unsigned 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 EventSem The event semaphore to wait on. * @param cMillies Number of milliseconds to wait. */ RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies); /** * Create a event multi semaphore. * * @returns iprt status code. * @param pEventMultiSem Where to store the event multi semaphore handle. */ RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem); /** * Destroy an event multi semaphore. * * @returns iprt status code. * @param EventMultiSem The event multi sempahore to destroy. */ RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem); /** * Signal an event multi semaphore. * * @returns iprt status code. * @param EventMultiSem The event multi semaphore to signal. */ RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem); /** * Resets an event multi semaphore to non-signaled state. * * @returns iprt status code. * @param EventMultiSem The event multi semaphore to reset. */ RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem); /** * 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 EventMultiSem The event multi semaphore to wait on. * @param cMillies Number of milliseconds to wait. */ RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned 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 EventMultiSem The event multi semaphore to wait on. * @param cMillies Number of milliseconds to wait. */ RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies); /** * Create a mutex semaphore. * * @returns iprt status code. * @param pMutexSem Where to store the mutex semaphore handle. */ RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX pMutexSem); /** * Destroy a mutex semaphore. * * @returns iprt status code. * @param MutexSem The mutex semaphore to destroy. */ RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX MutexSem); /** * 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 MutexSem The mutex semaphore to request ownership over. * @param cMillies The number of milliseconds to wait. */ RTDECL(int) RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned 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 MutexSem The mutex semaphore to request ownership over. * @param cMillies The number of milliseconds to wait. */ RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies); /** * Release the ownership of a mutex semaphore. * * @returns iprt status code. * @param MutexSem The mutex to release the ownership of. * It goes without saying the the calling thread must own it. */ RTDECL(int) RTSemMutexRelease(RTSEMMUTEX MutexSem); /** * Create a fast mutex semaphore. * * @returns iprt status code. * @param pMutexSem Where to store the mutex semaphore handle. * * @remarks Fast mutex semaphores are not recursive. */ RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX pMutexSem); /** * Destroy a fast mutex semaphore. * * @returns iprt status code. * @param MutexSem The mutex semaphore to destroy. */ RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX MutexSem); /** * Request ownership of a fast mutex semaphore. * * 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 MutexSem The mutex semaphore to request ownership over. */ RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX MutexSem); /** * Release the ownership of a fast mutex semaphore. * * @returns iprt status code. * @param MutexSem The mutex to release the ownership of. * It goes without saying the the calling thread must own it. */ RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX MutexSem); /** * Creates a read/write semaphore. * * @returns iprt status code. * @param pRWSem Where to store the handle to the created RW semaphore. */ RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem); /** * Destroys a read/write semaphore. * * @returns iprt status code. * @param RWSem The Read/Write semaphore to destroy. */ RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem); /** * 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 RWSem is invalid. * * @param RWSem The Read/Write semaphore to request read access to. * @param cMillies The number of milliseconds to wait. */ RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned 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 RWSem is invalid. * * @param RWSem The Read/Write semaphore to request read access to. * @param cMillies The number of milliseconds to wait. */ RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies); /** * Release read access to a read/write semaphore. * * @returns iprt status code. * @param RWSem The Read/Write sempahore to release read access to. * Goes without saying that caller must have read access to the sem. */ RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem); /** * 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 RWSem is invalid. * * @param RWSem The Read/Write semaphore to request write access to. * @param cMillies The number of milliseconds to wait. */ RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned 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 RWSem is invalid. * * @param RWSem The Read/Write semaphore to request write access to. * @param cMillies The number of milliseconds to wait. */ RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies); /** * Release write access to a read/write semaphore. * * @returns iprt status code. * @param RWSem The Read/Write sempahore to release read access to. * Goes without saying that caller must have write access to the sem. */ RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem); /** * Checks if the caller is the exclusive semaphore owner. * * @returns true / false accoringly. * @param RWSem The Read/Write semaphore in question. */ RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW RWSem); /** * Gets the write recursion count. * * @returns The write recursion count (0 if bad semaphore handle). * @param RWSem The Read/Write semaphore in question. */ RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem); /** * Gets the read recursion count of the current writer. * * @returns The read recursion count (0 if bad semaphore handle). * @param RWSem The Read/Write semaphore in question. */ RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem); /** * 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, unsigned 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, unsigned 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; } /** @} */ __END_DECLS #endif