564 lines
18 KiB
C
564 lines
18 KiB
C
|
/* **********************************************************
|
||
|
* Copyright 2004 - 2009 VMware, Inc. All rights reserved.
|
||
|
* **********************************************************/
|
||
|
|
||
|
/*
|
||
|
* @VMKAPIMOD_LICENSE@
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* Semaphores */ /**
|
||
|
* \defgroup Semaphores Semaphores
|
||
|
*
|
||
|
* \par Binary Semaphore Ranks:
|
||
|
* Binary semaphores are semaphores which may be treated like blocking
|
||
|
* locks. As such, they take a rank and sub-rank in a manner analogous
|
||
|
* the the lock ranking used for spinlocks.\n
|
||
|
* \n
|
||
|
* When a world locks a binary semaphore \em BS1 with major rank \em R1 and
|
||
|
* minor rank \em r1, it may only lock another binary semaphore BS2 with
|
||
|
* major rank \em R2 and minor rank \em r2 when:
|
||
|
* \n
|
||
|
* \em R2 > \em R1 \n
|
||
|
* or \n
|
||
|
* \em R2 == \em R1 and \em r2 > \em r1 \n
|
||
|
* \n
|
||
|
* Be aware that rank checking is only performed on debug builds.
|
||
|
* @{
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
|
||
|
#ifndef _VMKAPI_SEM_H_
|
||
|
#define _VMKAPI_SEM_H_
|
||
|
|
||
|
/** \cond never */
|
||
|
#ifndef VMK_HEADER_INCLUDED_FROM_VMKAPI_H
|
||
|
#error This vmkapi file should never be included directly but only via vmkapi.h
|
||
|
#endif
|
||
|
/** \endcond never */
|
||
|
|
||
|
#include "base/vmkapi_types.h"
|
||
|
#include "base/vmkapi_module.h"
|
||
|
#include "base/vmkapi_status.h"
|
||
|
|
||
|
/** \cond nodoc */
|
||
|
/* Private definitions */
|
||
|
#define _VMK_SEMA_RANK_UNRANKED 0x10000
|
||
|
#define _VMK_SEMA_RANK_MAX 0xffff
|
||
|
#define _VMK_SEMA_RANK_MIN 0
|
||
|
|
||
|
#define _VMK_SEMA_RANK_LEAF _VMK_SEMA_RANK_MAX
|
||
|
#define _VMK_SEMA_RANK_STORAGE 0x8000
|
||
|
|
||
|
typedef vmk_uint32 _vmk_SemaRank, _vmk_SemaRankMinor;
|
||
|
/** \endcond nodoc */
|
||
|
|
||
|
/**
|
||
|
* \brief unranked rank
|
||
|
*/
|
||
|
#define VMK_SEMA_RANK_UNRANKED _VMK_SEMA_RANK_UNRANKED
|
||
|
|
||
|
/**
|
||
|
* \brief Leaf rank for semaphores
|
||
|
*/
|
||
|
#define VMK_SEMA_RANK_LEAF _VMK_SEMA_RANK_LEAF
|
||
|
|
||
|
/**
|
||
|
* \brief Maximum rank for semaphores
|
||
|
*/
|
||
|
#define VMK_SEMA_RANK_MAX _VMK_SEMA_RANK_MAX
|
||
|
|
||
|
/**
|
||
|
* \brief Minimum rank for semaphores
|
||
|
*/
|
||
|
#define VMK_SEMA_RANK_MIN _VMK_SEMA_RANK_MIN
|
||
|
|
||
|
/**
|
||
|
* \brief Rank for semaphores in storage components
|
||
|
*/
|
||
|
#define VMK_SEMA_RANK_STORAGE _VMK_SEMA_RANK_STORAGE
|
||
|
|
||
|
/**
|
||
|
* \brief Rank for semaphores
|
||
|
*/
|
||
|
typedef _vmk_SemaRank vmk_SemaphoreRank;
|
||
|
|
||
|
/**
|
||
|
* \brief Sub rank for semaphores
|
||
|
*/
|
||
|
typedef _vmk_SemaRankMinor vmk_SemaphoreRankMinor;
|
||
|
|
||
|
/**
|
||
|
* \brief Opaque handle for semaphores
|
||
|
*/
|
||
|
typedef struct vmk_SemaphoreInt *vmk_Semaphore;
|
||
|
|
||
|
/**
|
||
|
* \brief Opaque handle for readers-writers semaphores
|
||
|
*/
|
||
|
typedef struct vmk_SemaphoreRWInt *vmk_SemaphoreRW;
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_SemaCreate -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Allocate and initialize a counting semaphore
|
||
|
*
|
||
|
* \note Requires that the module heap be initialized.
|
||
|
*
|
||
|
* \param[out] sema New counting semaphore.
|
||
|
* \param[in] moduleID Module on whose behalf the semaphore
|
||
|
* is created.
|
||
|
* \param[in] name Human-readable name of the semaphore.
|
||
|
* \param[in] value Initial count.
|
||
|
*
|
||
|
* \retval VMK_OK The semaphore was successfully created
|
||
|
* \retval VMK_NO_MEMORY The semaphore could not be allocated
|
||
|
* \retval VMK_NO_MODULE_HEAP The module has no heap to allocate from
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
VMK_ReturnStatus vmk_SemaCreate(
|
||
|
vmk_Semaphore *sema,
|
||
|
vmk_ModuleID moduleID,
|
||
|
const char *name,
|
||
|
vmk_int32 value);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_BinarySemaCreate -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Allocate and initialize a binary semaphore
|
||
|
*
|
||
|
* \note Requires that the module heap be initialized.
|
||
|
*
|
||
|
* \param[out] sema New counting semaphore.
|
||
|
* \param[in] moduleID Module on whose behalf the semaphore
|
||
|
* is created.
|
||
|
* \param[in] name Human-readable name of the semaphore.
|
||
|
* \param[in] majorRank Major rank of the semaphore.
|
||
|
* The rank value must be greater than or
|
||
|
* equal to VMK_SEMA_RANK_MIN and less than
|
||
|
* or equal to VMK_SEMA_RANK_MAX.
|
||
|
* \param[in] minorRank Minor rank of the semaphore.
|
||
|
* The rank value must be greater than or
|
||
|
* equal to VMK_SEMA_RANK_MIN and less than
|
||
|
* or equal to VMK_SEMA_RANK_MAX.
|
||
|
*
|
||
|
* \retval VMK_OK The semaphore was successfully created
|
||
|
* \retval VMK_NO_MEMORY The semaphore could not be allocated
|
||
|
* \retval VMK_NO_MODULE_HEAP The module has no heap to allocate from
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
VMK_ReturnStatus vmk_BinarySemaCreate(
|
||
|
vmk_Semaphore *sema,
|
||
|
vmk_ModuleID moduleID,
|
||
|
const char *name,
|
||
|
vmk_SemaphoreRank majorRank,
|
||
|
vmk_SemaphoreRankMinor minorRank);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* _vmkSemaIsLocked
|
||
|
*
|
||
|
* This is used by VMK_ASSERT_SEMA_LOCKED and VMK_ASSERT_SEMA_UNLOCKED.
|
||
|
* VMKAPI users should not call this function directly.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
/** \cond nodoc */
|
||
|
VMK_ReturnStatus _vmkSemaIsLocked(
|
||
|
vmk_Semaphore *sema,
|
||
|
vmk_Bool *isLocked);
|
||
|
/** \endcond */
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* VMK_ASSERT_SEMA_LOCKED -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Assert that a semaphore is currently locked only in
|
||
|
* debug builds.
|
||
|
*
|
||
|
* \param[in] sema Semaphore to check.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
#if defined(VMX86_DEBUG)
|
||
|
#define VMK_ASSERT_SEMA_LOCKED(sema) \
|
||
|
do { \
|
||
|
vmk_Bool _vmkCheckLockState ; \
|
||
|
VMK_ASSERT(_vmkSemaIsLocked((sema),&_vmkCheckLockState) == \
|
||
|
VMK_OK); \
|
||
|
VMK_ASSERT(_vmkCheckLockState); \
|
||
|
} while(0)
|
||
|
#else
|
||
|
#define VMK_ASSERT_SEMA_LOCKED(sema)
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* VMK_ASSERT_SEMA_UNLOCKED -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Assert that a semaphore is currently unlocked only in
|
||
|
* debug builds.
|
||
|
*
|
||
|
* \param[in] sema Semaphore to check.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
#if defined(VMX86_DEBUG)
|
||
|
#define VMK_ASSERT_SEMA_UNLOCKED(sema) \
|
||
|
do { \
|
||
|
vmk_Bool _vmkCheckLockState ; \
|
||
|
VMK_ASSERT(_vmkSemaIsLocked((sema),&_vmkCheckLockState) == \
|
||
|
VMK_OK); \
|
||
|
VMK_ASSERT(!_vmkCheckLockState); \
|
||
|
} while(0)
|
||
|
#else
|
||
|
#define VMK_ASSERT_SEMA_UNLOCKED(sema)
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_SemaLock -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Acquire a semaphore
|
||
|
*
|
||
|
* \pre Shall be called from a blockable context.
|
||
|
* \pre The caller shall not already hold a semaphore of lower or equal
|
||
|
* rank if the semaphore is a binary semaphore.
|
||
|
*
|
||
|
* \param[in] sema The semaphore to acquire.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
void vmk_SemaLock(
|
||
|
vmk_Semaphore *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_SemaTryLock -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Try to acquire a semaphore.
|
||
|
*
|
||
|
* This tries to acquire the given semaphore once.
|
||
|
* If the semaphore is already locked, it returns immediately.
|
||
|
*
|
||
|
* \pre Shall be called from a blockable context.
|
||
|
*
|
||
|
* \param[in] sema Semaphore to attempt to acquire.
|
||
|
*
|
||
|
* \retval VMK_OK The semaphore was successfully acquired.
|
||
|
* \retval VMK_BUSY The semaphore is currently locked.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
VMK_ReturnStatus vmk_SemaTryLock(
|
||
|
vmk_Semaphore *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_SemaUnlock -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Release a semaphore
|
||
|
*
|
||
|
* \param[in] sema Semaphore to unlock.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
void vmk_SemaUnlock(
|
||
|
vmk_Semaphore *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_SemaDestroy -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Destroy a semaphore
|
||
|
*
|
||
|
* Revert all side effects of vmk_SemaCreate or vmk_BinarySemaCreate.
|
||
|
*
|
||
|
* \param[in] sema Semaphore to destroy.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
void vmk_SemaDestroy(vmk_Semaphore *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* VMK_ASSERT_RWSEMA_HAS_READERS -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Assert that a readers-writers semaphore has at least one
|
||
|
* shared reader only in debug builds.
|
||
|
*
|
||
|
* \param[in] sema Semaphore to check.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
#if defined(VMX86_DEBUG)
|
||
|
#define VMK_ASSERT_RWSEMA_HAS_READERS(sema) \
|
||
|
do { \
|
||
|
VMK_ASSERT(vmk_RWSemaHasReaders(sema) == VMK_TRUE); \
|
||
|
} while(0)
|
||
|
#else
|
||
|
#define VMK_ASSERT_RWSEMA_HAS_READERS(sema)
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* VMK_ASSERT_RWSEMA_HAS_WRITER -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Assert that a readers-writers semaphore has a writer only in
|
||
|
* debug builds.
|
||
|
*
|
||
|
* \param[in] sema Semaphore to check.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
#if defined(VMX86_DEBUG)
|
||
|
#define VMK_ASSERT_RWSEMA_HAS_WRITER(sema) \
|
||
|
do { \
|
||
|
VMK_ASSERT(vmk_RWSemaHasWriter(sema) == VMK_TRUE); \
|
||
|
} while(0)
|
||
|
#else
|
||
|
#define VMK_ASSERT_RWSEMA_HAS_WRITER(sema)
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* VMK_ASSERT_RWSEMA_HAS_READERS_WRITERS -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Assert that a readers-writers semaphore has a writer only in
|
||
|
* debug builds.
|
||
|
*
|
||
|
* \param[in] sema Semaphore to check.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
#if defined(VMX86_DEBUG)
|
||
|
#define VMK_ASSERT_RWSEMA_HAS_READERS_WRITERS(sema) \
|
||
|
do { \
|
||
|
VMK_ASSERT(vmk_RWSemaHasReadersWriters(sema) == VMK_TRUE); \
|
||
|
} while(0)
|
||
|
#else
|
||
|
#define VMK_ASSERT_RWSEMA_HAS_READERS_WRITERS(sema)
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_RWSemaCreate -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Allocate and initialize a readers-writers semaphore
|
||
|
*
|
||
|
* \param[out] sema New readers-writers semaphore.
|
||
|
* \param[in] moduleID Module on whose behalf the semaphore
|
||
|
* is created.
|
||
|
* \param[in] name Human-readable name of the semaphore.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
VMK_ReturnStatus vmk_RWSemaCreate(
|
||
|
vmk_SemaphoreRW *sema,
|
||
|
vmk_ModuleID moduleID,
|
||
|
const char *name);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_RWSemaDestroy -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Destroy a readers-writers semaphore
|
||
|
*
|
||
|
* Revert all side effects of vmk_RWSemaCreate.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to destroy.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
void vmk_RWSemaDestroy(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_RWSemaReadLock -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Acquire a readers-writers semaphore for shared read access.
|
||
|
*
|
||
|
* \pre Shall be called from a blockable context.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to acquire.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
void vmk_RWSemaReadLock(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_RWSemaWriteLock -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Acquire a readers-writers semaphore for exclusive write
|
||
|
* access.
|
||
|
*
|
||
|
* \pre Shall be called from a blockable context.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to acquire.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
void vmk_RWSemaWriteLock(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_RWSemaReadUnlock -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Release a readers-writers semaphore from shared read access.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to release.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
void vmk_RWSemaReadUnlock(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_RWSemaWriteUnlock -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Release a readers-writers semaphore from exclusive write
|
||
|
* access.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to release.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
void vmk_RWSemaWriteUnlock(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_RWSemaUpgradeFromRead -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Upgrade a readers-writers semaphore to exclusive write access.
|
||
|
*
|
||
|
* This requests an upgrade to exclusive writers access for the
|
||
|
* readers-writers semaphore while already holding shared reader access.
|
||
|
* If the upgrade is not immediately available, only the first caller
|
||
|
* can block waiting for the upgrade. Others fail, but they retain
|
||
|
* shared reader access.
|
||
|
*
|
||
|
* \pre Shall be called from a blockable context.
|
||
|
* \pre Shall already have read access to the semaphore.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to upgrade.
|
||
|
*
|
||
|
* \retval VMK_OK The semaphore was upgraded.
|
||
|
* \retval VMK_BUSY The semaphore could not be upgraded.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
VMK_ReturnStatus vmk_RWSemaUpgradeFromRead(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_RWSemaTryUpgradeFromRead -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Attempt to upgrade a readers-writers semaphore to
|
||
|
* exclusive write access.
|
||
|
*
|
||
|
* This attempts to obtain exclusive writers access to the
|
||
|
* readers-writers semaphore while already holding shared reader access.
|
||
|
* If the upgrade is not immediately available, shared reader access
|
||
|
* is retained.
|
||
|
*
|
||
|
* \pre Shall already have read access to the semaphore.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to upgrade.
|
||
|
*
|
||
|
* \retval VMK_OK The semaphore was upgraded.
|
||
|
* \retval VMK_BUSY The semaphore could not be upgraded.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
VMK_ReturnStatus vmk_RWSemaTryUpgradeFromRead(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_RWSemaDowngradeToRead -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Downgrade a readers-writers semaphore from exclusive
|
||
|
* write access to shared read access.
|
||
|
*
|
||
|
* \pre Shall already have write access to the semaphore.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to downgrade.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
void vmk_RWSemaDowngradeToRead(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_RWSemaHasReaders -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Determine if a readers-writers semaphore currently has one or
|
||
|
* more readers.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to inspect.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
vmk_Bool vmk_RWSemaHasReaders(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_SemaHasWriter -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Determine if a readers-writers semaphore currently has
|
||
|
* a writer.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to inspect.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
vmk_Bool vmk_RWSemaHasWriter(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
/*
|
||
|
***********************************************************************
|
||
|
* vmk_SemaHasReadersWriters -- */ /**
|
||
|
*
|
||
|
* \ingroup Semaphores
|
||
|
* \brief Determine if a readers-writers semaphore currently has any
|
||
|
* readers or an exclusive writer.
|
||
|
*
|
||
|
* \param[in] sema Readers-writers semaphore to inspect.
|
||
|
*
|
||
|
***********************************************************************
|
||
|
*/
|
||
|
vmk_Bool vmk_RWSemaHasReadersWriters(vmk_SemaphoreRW *sema);
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#endif /* _VMKAPI_SEM_H_ */
|
||
|
/** @} */
|