/* ********************************************************** * Copyright 2007 - 2009 VMware, Inc. All rights reserved. * **********************************************************/ /* * @VMKAPIMOD_LICENSE@ */ /* *********************************************************************** * Spinlocks */ /** * \defgroup Spinlocks Spin Locks * * \par Lock and Timer Ranks: * All locks are associated with a numeric major rank \em R and a * numeric minor rank \em r. While holding lock \em L1 (ranks: \em R1, * \em r1) a lock \em L2 (ranks: \em R2, \em r2) can be acquired if one * of the following hold true:\n * - \em R2 > \em R1 \n * - \em R2 == \em R1, \em L2 and \em L1 belong to the same class, * and \em r2 > \em r1.\n * \n * The only exception to the above rule is for "unranked locks", which * are applicable only for timers. An unranked timer does not participate * in the ranking rules. Standalone unranked spinlocks are not supported.\n * \n * Two types of spinlocks, with respect to lock ranks are supported:\n * \n * \li Simple Ranked Spinlock: \n * A stand-alone spinlock which has an explicit major rank other * than VMK_SP_RANK_UNRANKED. The minor rank (which is implicitly set) * is always equal to '0'. * \li Class Based Ranked Spinlock:\n * Belongs to a class of spinlocks all of which share the same * explicit major rank other than VMK_SP_RANK_UNRANKED. Members of * the same class differ only with respect to their minor rank, which is * explicitly set to a desired value, other than VMK_SP_RANK_UNRANKED, * during lock initialization. * * \par Timers and Ranks: * Timers also have ranks within the lock ranking system. While a * timer callback is firing, the callback is treated as holding a lock * of the timer's rank, so it is not allowed to acquire locks of lower * rank. A call to vmk_TimerRemoveSync is treated as acquiring (and * releasing) a lock of the timer's rank, and thus is not allowed when * holding locks of higher or equal rank.\n * \n * Timers can only be unranked or simple, not class-based. It is * common to give a timer the rank VMK_SP_RANK_LOWEST; this allows the * callback to acquire any higher-ranked lock, but requires that code * calling vmk_TimerRemoveSync on the timer hold no locks. * * @{ *********************************************************************** */ #ifndef _VMKAPI_SPLOCK_H_ #define _VMKAPI_SPLOCK_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_status.h" #include "base/vmkapi_assert.h" #include "base/vmkapi_module.h" #include "base/vmkapi_lock_rank.h" /** * \brief Recursive flag * * Recursive flag indicates that an instace of lock \em L can be held while * acquiring another instance of lock \em L. It is assumed the caller knows * what they're doing. */ #define VMK_SP_RANK_RECURSIVE_FLAG _VMK_SP_RANK_RECURSIVE_FLAG /** * \brief Mask for rank value */ #define VMK_SP_RANK_NUMERIC_MASK _VMK_SP_RANK_NUMERIC_MASK /** * \brief Lowest rank for locks */ #define VMK_SP_RANK_LOWEST _VMK_SP_RANK_LOWEST /** * \brief highest rank for locks */ #define VMK_SP_RANK_HIGHEST _VMK_SP_RANK_HIGHEST /** * \brief Maximum rank for locks */ #define VMK_SP_RANK_MAX (VMK_SP_RANK_NUMERIC_MASK - 1) /** * \brief Minimum rank for locks */ #define VMK_SP_RANK_MIN (0) /** * \brief Leaf rank for IRQ locks * * To be used for IRQ locks that leafs, except for log/warning * */ #define VMK_SP_RANK_IRQ_LEAF _VMK_SP_RANK_IRQ_LEAF /** * \brief Rank used by calls potentially invoked by timers that need * to manage memory. For instance: an allocator callable by * timers. */ #define VMK_SP_RANK_IRQ_MEMTIMER _VMK_SP_RANK_IRQ_MEMTIMER /** * \brief Block rank for IRQ locks * * To be used for IRQ locks that depend on eventqueue/cpusched locks */ #define VMK_SP_RANK_IRQ_BLOCK _VMK_SP_RANK_IRQ_BLOCK /** * \brief Lowest rank for IRQ locks */ #define VMK_SP_RANK_IRQ_LOWEST _VMK_SP_RANK_IRQ_LOWEST /** * \brief Leaf rank for locks * * Leaf locks are ranked lower than spin locks protecting semaphores, * so that one can grab a semaphore, grab a leaf lock and then call * vmk_SemaIsLocked() on the semaphore. */ #define VMK_SP_RANK_LEAF _VMK_SP_RANK_LEAF /** * \brief Rank for all SCSI locks * */ #define VMK_SP_RANK_SCSI _VMK_SP_RANK_SCSI /** * \brief Rank for all SCSI plugin locks * */ #define VMK_SP_RANK_SCSI_PLUGIN2 _VMK_SP_RANK_SCSI_PLUGIN2 #define VMK_SP_RANK_SCSI_PLUGIN1 _VMK_SP_RANK_SCSI_PLUGIN1 /** * \brief Lowest rank for all SCSI locks * */ #define VMK_SP_RANK_SCSI_LOWEST _VMK_SP_RANK_SCSI_LOWEST /** * \brief Lowest rank for locks in FS Device Switch component * * Lowest possible rank for locks used by FS Device Switch. Modules * operating above the device switch, and calling into the device switch * should use locks ranked lower than this. */ #define VMK_SP_RANK_FDS_LOWEST _VMK_SP_RANK_FDS_LOWEST /** * \brief Lowest rank for locks in VMK FS drivers * * Lowest possible rank for locks used by VMK FS drivers. FSS and everyone * above should use locks ranked lower than this. */ #define VMK_SP_RANK_FSDRIVER_LOWEST _VMK_SP_RANK_FSDRIVER_LOWEST /** * \brief Rank for Network locks * * Usual lock rank used for module internal usage which doesn't imply * vmkapi call. */ #define VMK_SP_RANK_NETWORK _VMK_SP_RANK_NETWORK /** * \brief Lowest Rank for Network locks * * Should be used if the module is intended to hold a lock while calling * a vmkapi function. */ #define VMK_SP_RANK_NETWORK_LOWEST _VMK_SP_RANK_NETWORK_LOWEST /** * \brief Highest Rank for Network locks * * Should be used if the module is intended to hold a lock while calling * a vmkapi function. */ #define VMK_SP_RANK_NETWORK_HIGHEST _VMK_SP_RANK_NETWORK_HIGHEST /** * \brief Tcpip2 stack highest rank. * */ #define VMK_SP_RANK_TCPIP_HIGHEST _VMK_SP_RANK_TCPIP_HIGHEST /** * \brief Unranked timers. */ #define VMK_SP_RANK_UNRANKED_TIMER _VMK_SP_RANK_UNRANKED_TIMER /** * \brief Handle for lock classes */ typedef struct vmk_SpinlockClassInt *vmk_SpinlockClass; /** * \brief Handle for non-IRQ locks */ typedef struct vmk_SpinlockInt *vmk_Spinlock; /** * \brief Handle for IRQ locks */ typedef struct vmk_SpinlockIRQInt *vmk_SpinlockIRQ; /** * \brief Handle for non-IRQ rw locks */ typedef struct vmk_SpinlockRWInt *vmk_SpinlockRW; /** * \brief Rank for locks */ typedef _vmk_SP_Rank vmk_SpinlockRank; /* *********************************************************************** * vmk_SPClassCreate -- */ /** * * \ingroup Spinlocks * \brief Allocate and initialize a spinlock class * * Creates a new spinlock class and initializes it. * * The spinlock class's rank serves as the major rank for the * spinlocks that are members of the class. * * \note Requires that the module heap be initialized. * * \param[out] lockClass Pointer to the new spinlock class. * \param[in] moduleID Module ID who manages the created * spinlock class. * \param[in] name Name of the spinlock class. * \param[in] rank Rank of the spinlock class. * The specified rank must be greater than or * equal to VMK_SP_RANK_LOWEST and less than or * equal to VMK_SP_RANK_HIGHEST. * * \retval VMK_OK The spinlock class was successfully initialized * \retval VMK_NO_MEMORY The spinlock class could not be allocated * \retval VMK_NO_MODULE_HEAP The module has no heap to allocate from * *********************************************************************** */ VMK_ReturnStatus vmk_SPClassCreate( vmk_SpinlockClass *lockClass, vmk_ModuleID moduleID, const char *name, vmk_SpinlockRank rank); /* *********************************************************************** * vmk_SPClassDestroy -- */ /** * * \ingroup Spinlocks * \brief Destroy a spinlock class * * Revert all side effects of vmk_SPClassCreate * * \param[in] lockClass Pointer to the spinlock class to be deleted. * *********************************************************************** */ void vmk_SPClassDestroy(vmk_SpinlockClass *lockClass); /* *********************************************************************** * vmk_SPCreate -- */ /** * * \ingroup Spinlocks * \brief Allocate and initialize a non-IRQ spinlock * * Creates a new non-IRQ spinlock and initializes it. * * \note Requires that the module heap be initialized. * * \param[out] lock Pointer to the new spinlock class. * \param[in] moduleID Module that owns the new spinlock. * \param[in] name Name of the spinlock, * \param[in] lockClass Pointer to a spinlock class, or NULL if the * new spinlock should be a simple (non-classed) * spinlock. * \param[in] rank The spinlock's rank.\n * If lockClass is NULL then this parameter * specifies the lock's major rank. * The specified rank must be greater than or * equal to VMK_SP_RANK_LOWEST and less than or * equal to VMK_SP_RANK_HIGHEST.\n * If lockClass is set to a valid spinlock * class then this parameter specifies the * new spinlock's minor rank with the lock's * major rank being inherited from the * spinlock class. * The specified rank must be greater than or * equal to VMK_SP_RANK_MIN and less than or * equal to VMK_SP_RANK_MAX.\n * * \retval VMK_OK The spinlock was successfully initialized * \retval VMK_NO_MEMORY The spinlock could not be allocated * \retval VMK_NO_MODULE_HEAP The module has no heap to allocate from * *********************************************************************** */ VMK_ReturnStatus vmk_SPCreate( vmk_Spinlock *lock, vmk_ModuleID moduleID, const char *name, vmk_SpinlockClass *lockClass, vmk_SpinlockRank rank); /* *********************************************************************** * vmk_SPIsLocked -- */ /* * * \ingroup Spinlocks * \brief Tests a non-IRQ spinlock to see if it is currently locked. * * \note This call is only available on debug builds. * * \param[in] lock Non-IRQ spinlock to check. * * \retval VMK_OK Lock is unlocked. * \retval VMK_BUSY Lock is locked. * \retval VMK_BAD_PARAM Not a valid lock. * *********************************************************************** */ #ifdef VMX86_DEBUG VMK_ReturnStatus vmk_SPIsLocked( vmk_Spinlock *lock); #endif /* *********************************************************************** * VMK_ASSERT_SPLOCK_LOCKED -- */ /** * * \ingroup Spinlocks * \brief Assert that a spinlock is currently locked. * * \note This call only performs the check on a debug build. * Other builds always succeed. * * \param[in] lock Non-IRQ spinlock to check * *********************************************************************** */ #define VMK_ASSERT_SPLOCK_LOCKED(lock) \ VMK_ASSERT(vmk_SPIsLocked(lock) == VMK_BUSY) /* *********************************************************************** * VMK_ASSERT_SPLOCK_UNLOCKED -- */ /** * * \ingroup Spinlocks * \brief Assert that a spinlock is currently unlocked. * * \note This call only performs the check on a debug build. * Other builds always succeed. * * \param[in] lock Non-IRQ spinlock to check * *********************************************************************** */ #define VMK_ASSERT_SPLOCK_UNLOCKED(lock) \ VMK_ASSERT(vmk_SPIsLocked(lock) == VMK_OK) /* *********************************************************************** * vmk_AssertNoSPLocksHeld -- */ /** * * \ingroup Spinlocks * \brief Assert that no non-IRQ spinlocks are held by this CPU. * * \note This call only performs the check on a debug build. * Other builds always succeed. * *********************************************************************** */ #ifdef VMX86_DEBUG void vmk_AssertNoSPLocksHeld( void); #else static inline void vmk_AssertNoSPLocksHeld( void) {} #endif /* *********************************************************************** * vmk_AssertNoSPLocksHeldIRQ -- */ /** * * \ingroup Spinlocks * \brief Assert that no IRQ spinlocks are held by this CPU. * * \note This call only performs the check on a debug build. * Other builds always succeed. * *********************************************************************** */ #ifdef VMX86_DEBUG void vmk_AssertNoSPLocksHeldIRQ( void); #else static inline void vmk_AssertNoSPLocksHeldIRQ( void) {} #endif /* *********************************************************************** * vmk_SPLock -- */ /** * * \ingroup Spinlocks * \brief Acquire the non-IRQ spinlock * * \pre The caller shall not already hold a spinlock of lower or * equal rank. * * \param[in,out] lock Non-IRQ spinlock to acquire. * * \return None. * *********************************************************************** */ void vmk_SPLock( vmk_Spinlock *lock); /* *********************************************************************** * vmk_SPTryLock -- */ /** * * \ingroup Spinlocks * \brief Try acquire a non-IRQ spinlock * * This function tries to acquire the given spinlock: * - If the given spinlock has not been locked, this function locks it. * - If the given spinlock has been locked already, this function does * nothing and returns immediately. * * \pre This caller shall not already hold a spinlock of lower or * equal rank. * * \param[in,out] lock Non-IRQ spinlock to attempt to acquire. * * \retval VMK_OK The given spinlock is successfully locked by this * call. * \retval VMK_BUSY The given spinlock has been locked already. * *********************************************************************** */ VMK_ReturnStatus vmk_SPTryLock( vmk_Spinlock *lock); /* *********************************************************************** * vmk_SPUnlock -- */ /** * * \ingroup Spinlocks * \brief Release a non-IRQ spinlock * * \pre The caller currently owns the spinlock. * * \param[in,out] lock Non-IRQ spinlock to release. * *********************************************************************** */ void vmk_SPUnlock( vmk_Spinlock *lock); /* *********************************************************************** * vmk_SPDestroy -- */ /** * * \ingroup Spinlocks * \brief Destroy a non-IRQ spinlock * * Revert all side effects of vmk_SPCreate * * \param[in] lock Non-IRQ spinlock to be destroyed. * *********************************************************************** */ void vmk_SPDestroy(vmk_Spinlock *lock); /* *********************************************************************** * vmk_SPCreateIRQ -- */ /** * * \ingroup Spinlocks * \brief Allocate and initialize an IRQ spinlock * * Creates a new IRQ spinlock and initializes it. * * \note Requires that the module heap be initialized. * * \param[out] lock Pointer to the new spinlock class. * \param[in] moduleID Module that owns the new spinlock. * \param[in] name Name of the spinlock, * \param[in] lockClass Pointer to a spinlock class, or NULL if the * new spinlock should be a simple (non-classed) * spinlock. * \param[in] rank The spinlock's rank.\n * If lockClass is NULL then this parameter * specifies the lock's major rank. * The specified rank must be greater than or * equal to VMK_SP_RANK_IRQ_LOWEST and less * than or equal to VMK_SP_RANK_IRQ_HIGHEST.\n * If lockClass is set to a valid spinlock * class then this parameter specifies the * new spinlock's minor rank with the lock's * major rank being inherited from the * spinlock class. * The specified rank must be greater than or * equal to VMK_SP_RANK_MIN and less than or * equal to VMK_SP_RANK_MAX.\n * * \retval VMK_OK The spinlock was successfully initialized * \retval VMK_NO_MEMORY The spinlock could not be allocated * \retval VMK_NO_MODULE_HEAP The module has no heap to allocate from * *********************************************************************** */ VMK_ReturnStatus vmk_SPCreateIRQ( vmk_SpinlockIRQ *lock, vmk_ModuleID moduleID, const char *name, vmk_SpinlockClass *lockClass, vmk_SpinlockRank rank); /* *********************************************************************** * vmk_SPIsLockedIRQ -- */ /* * * \ingroup Spinlocks * \brief Tests an IRQ spinlock to see if it is currently locked. * * \note This call is only available on debug builds. * * \param[in] lock IRQ spinlock to check * * \retval VMK_OK Lock is unlocked. * \retval VMK_BUSY Lock is locked. * \retval VMK_BAD_PARAM Not a valid lock. * *********************************************************************** */ #ifdef VMX86_DEBUG VMK_ReturnStatus vmk_SPIsLockedIRQ( vmk_SpinlockIRQ *lock); #endif /* *********************************************************************** * VMK_ASSERT_SPLOCK_LOCKED_IRQ -- */ /** * * \ingroup Spinlocks * \brief Assert that an IRQ spinlock is currently locked. * * \note This call only performs the check on a debug build. * Other builds always succeed. * * \param[in] lock IRQ spinlock to check * *********************************************************************** */ #define VMK_ASSERT_SPLOCK_LOCKED_IRQ(lock) \ VMK_ASSERT(vmk_SPIsLockedIRQ(lock) == VMK_BUSY) /* *********************************************************************** * VMK_ASSERT_SPLOCKIRQ_UNLOCKED_IRQ -- */ /** * * \ingroup Spinlocks * \brief Assert that an IRQ spinlock is currently unlocked. * * \note This call only performs the check on a debug build. * Other builds always succeed. * * \param[in] lock IRQ spinlock to check * *********************************************************************** */ #define VMK_ASSERT_SPLOCKIRQ_UNLOCKED_IRQ(lock) \ VMK_ASSERT(vmk_SPIsLockedIRQ(lock) == VMK_OK) /* *********************************************************************** * vmk_SPLockIRQ -- */ /** * * \ingroup Spinlocks * \brief Acquire the IRQ spinlock * * Acquires an IRQ spinlock and disable interrupts on the current CPU * if they are not already disabled. * * \pre The caller shall not already hold a spinlock of lower or * equal rank. * * \param[in,out] lock IRQ spinlock to acquire. * * \return Previous IRQ state. * \retval 0 interrupts were enabled. * \retval 1 interrupts were disabled. * *********************************************************************** */ unsigned long vmk_SPLockIRQ( vmk_SpinlockIRQ *lock); /* *********************************************************************** * vmk_SPTryLockIRQ -- */ /** * * \ingroup Spinlocks * \brief Try acquire an IRQ spinlock * * This function tries to acquire the given spinlock: * - If the given IRQ spinlock has not been locked, this function locks it * and disables interrupts on the current CPU if interrupts were not * already disabled. * - If the given IRQ spinlock has been locked already, this function does * nothing and returns immediately. * * \pre This caller shall not already hold a spinlock of lower or * equal rank. * * \param[in,out] lock IRQ spinlock to attempt to acquire. * \param[out] flags Previous IRQ level. 0 if interrupts were enabled. * 1 if interrupts were disabled. * * \retval VMK_OK The given spinlock is successfully locked by this * call. * \retval VMK_BUSY The given spinlock has been locked already. * *********************************************************************** */ VMK_ReturnStatus vmk_SPTryLockIRQ( vmk_SpinlockIRQ *lock, unsigned long *flags); /* *********************************************************************** * vmk_SPUnlockIRQ -- */ /** * * \ingroup Spinlocks * \brief Release an IRQ spinlock * * \pre The caller currently owns the spinlock. * * \param[in,out] lock IRQ spinlock to unlock. * \param[in] prevIRQ IRQ level from returned from vmk_SPLockIRQ * or vmk_SPTryLockIRQ. * *********************************************************************** */ void vmk_SPUnlockIRQ( vmk_SpinlockIRQ *lock, unsigned long prevIRQ); /* *********************************************************************** * vmk_SPDestroyIRQ -- */ /** * * \ingroup Spinlocks * \brief Destroy an IRQ spinlock * * Revert all side effects of vmk_SPCreateIRQ * * \param lock IRQ spinlock to be detroyed. * *********************************************************************** */ void vmk_SPDestroyIRQ(vmk_SpinlockIRQ *lock); /* *********************************************************************** * vmk_RWCreate -- */ /** * * \ingroup Spinlocks * \brief Allocate and initialize a reader/writer spinlock * * Creates a new reader/writer spinlock and initializes it as * ranked spinlock. * * \note Requires that the module heap be initialized. * * \param[out] lock Pointer to the new spinlock class. * \param[in] moduleID Module that owns the new spinlock. * \param[in] name Name of the spinlock, * \param[in] lockClass Pointer to a spinlock class, or NULL if the * new spinlock should be a simple (non-classed) * spinlock. * \param[in] rank The spinlock's rank.\n * If lockClass is NULL then this parameter * specifies the lock's major rank. * The specified rank must be greater than or * equal to VMK_SP_RANK_LOWEST and less than or * equal to VMK_SP_RANK_HIGHEST.\n * If lockClass is set to a valid spinlock * class then this parameter specifies the * new spinlock's minor rank with the lock's * major rank being inherited from the * spinlock class. * The specified rank must be greater than or * equal to VMK_SP_RANK_MIN and less than or * equal to VMK_SP_RANK_MAX.\n * * \retval VMK_OK The spinlock was successfully initialized * \retval VMK_NO_MEMORY The spinlock could not be allocated * \retval VMK_NO_MODULE_HEAP The module has no heap to allocate from * *********************************************************************** */ VMK_ReturnStatus vmk_RWCreate( vmk_SpinlockRW *lock, vmk_ModuleID moduleID, const char *name, vmk_SpinlockClass *lockClass, vmk_SpinlockRank rank); /* *********************************************************************** * vmk_RWReadLock -- */ /** * * \ingroup Spinlocks * \brief Acquire a reader/writer spinlock for reading. * * \pre The caller shall not already hold a spinlock of lower or * equal rank. * * \param[in,out] lock Reader/writer spinlock to acquire. * *********************************************************************** */ void vmk_RWReadLock( vmk_SpinlockRW *lock); /* *********************************************************************** * vmk_RWTryReadLock -- */ /** * * \ingroup Spinlocks * \brief Try acquire the reader/writer spinlock for reading * * This function tries to acquire the given spinlock: * - If the given r/w spinlock has not been locked, this function locks it. * - If the given r/w spinlock has been locked already, this function does * nothing and returns immediately. * * \pre This caller shall not already hold a spinlock of lower or * equal rank. * * \param[in,out] lock Reader/writer spinlock to attempt to acquire. * * \retval VMK_OK The given spinlock is successfully locked by * this call. * \retval VMK_BUSY The given spinlock has been locked already. * *********************************************************************** */ VMK_ReturnStatus vmk_RWTryReadLock( vmk_SpinlockRW *lock); /* *********************************************************************** * vmk_RWIsRLocked -- */ /** * * \ingroup Spinlocks * \brief Tests a reader/writer spinlock to see if it is currently * read-locked. * * \param[in] lock Reader/writer spinlock to check * * \retval VMK_OK Lock is unlocked. * \retval VMK_BUSY Lock is locked. * \retval VMK_BAD_PARAM Not a valid lock. * *********************************************************************** */ VMK_ReturnStatus vmk_RWIsRLocked( vmk_SpinlockRW *lock); /* *********************************************************************** * VMK_ASSERT_RWLOCK_RLOCKED -- */ /** * * \ingroup Spinlocks * \brief Assert that a reader/writer lock is currently read-locked. * * \note This call only performs the check on a debug build. * Other builds always succeed. * * \param[in] lock Reader/writer spinlock to check * *********************************************************************** */ #define VMK_ASSERT_RWLOCK_RLOCKED(lock) \ VMK_ASSERT(vmk_RWIsRLocked(lock) == VMK_BUSY) /* *********************************************************************** * vmk_RWWriteLock -- */ /** * * \ingroup Spinlocks * \brief Acquire a reader/writer spinlock for writing. * * \pre The caller shall not already hold a spinlock of lower or * equal rank. * * \param[in,out] lock Reader/writer spinlock to acquire. * * \return None. * *********************************************************************** */ void vmk_RWWriteLock( vmk_SpinlockRW *lock); /* *********************************************************************** * vmk_RWTryWriteLock -- */ /** * * \ingroup Spinlocks * \brief Try acquire the reader/writer spinlock for writing * * This function tries to acquire the given spinlock: * - If the given r/w spinlock has not been locked, this function locks it. * - If the given r/w spinlock has been locked already, this function does * nothing and returns immediately. * * \pre This caller shall not already hold a spinlock of lower or * equal rank. * * \param[in,out] lock Reader/writer spinlock to attempt to acquire. * * \retval VMK_OK The given spinlock is successfully locked by this * call. * \retval VMK_BUSY The given spinlock has been locked already. * *********************************************************************** */ VMK_ReturnStatus vmk_RWTryWriteLock( vmk_SpinlockRW *lock); /* *********************************************************************** * vmk_RWIsWLocked -- */ /** * * \ingroup Spinlocks * \brief Tests a reader/writer spinlock to see if it is currently * write-locked. * * \param[in] lock Reader/writer spinlock to check * * \retval VMK_OK Lock is unlocked. * \retval VMK_BUSY Lock is locked. * \retval VMK_BAD_PARAM Not a valid lock. * *********************************************************************** */ VMK_ReturnStatus vmk_RWIsWLocked( vmk_SpinlockRW *lock); /* *********************************************************************** * VMK_ASSERT_RWLOCK_WLOCKED -- */ /** * * \ingroup Spinlocks * \brief Assert that a reader/writer lock is currently write-locked. * * \note This call only performs the check on a debug build. * Other builds always succeed. * * \param[in] lock Reader/writer spinlock to check * *********************************************************************** */ #define VMK_ASSERT_RWLOCK_WLOCKED(lock) \ VMK_ASSERT(vmk_RWIsWLocked(lock) == VMK_BUSY) /* *********************************************************************** * vmk_RWReadUnlock -- */ /** * * \ingroup Spinlocks * \brief Release a reader/writer spinlock from a read-lock. * * \pre The caller currently has a read-lock on the spinlock. * * \param[in,out] lock Reader/writer spinlock to release. * *********************************************************************** */ void vmk_RWReadUnlock( vmk_SpinlockRW *lock); /* *********************************************************************** * vmk_RWWriteUnlock -- */ /** * * \ingroup Spinlocks * \brief Release a reader/writer spinlock from a write-lock. * * \pre The caller currently has a write-lock on the spinlock. * * \param[in,out] lock Reader/writer spinlock to release. * *********************************************************************** */ void vmk_RWWriteUnlock( vmk_SpinlockRW *lock); /* *********************************************************************** * vmk_SPDestroy -- */ /** * * \ingroup Spinlocks * \brief Destroy a reader/writer spinlock * * Revert all side effects of vmk_RWCreate * * \param[in] lock Reader/writer spinlock to be destroyed. * *********************************************************************** */ void vmk_RWDestroy(vmk_SpinlockRW *lock); #endif /* _VMKAPI_SPLOCK_H_ */ /** @} */