720 lines
20 KiB
C
720 lines
20 KiB
C
/* semRWLibInlineP.h - inline reader/writer semaphore library header file */
|
|
|
|
/*
|
|
* Copyright (c) 2013 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute or otherwise make use of this software
|
|
* may be licensed only pursuant to the terms of an applicable Wind River
|
|
* license agreement.
|
|
*/
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
01a,27jun13,dlk written.
|
|
*/
|
|
|
|
/*
|
|
* This module is experimental and private. The interfaces it defines
|
|
* are subject to change without notice.
|
|
*
|
|
* Inline implementation of reader/writer semaphores, (somewhat) scalable
|
|
* according to provided semaphore options. Initially only "minimal" and
|
|
* "fully featured" option combinations may be supported.
|
|
*
|
|
* These inline reader/writer semaphore APIs are supported only in the
|
|
* kernel, not from RTPs.
|
|
*/
|
|
|
|
#ifndef __INCsemRWLibInlinePh
|
|
#define __INCsemRWLibInlinePh
|
|
|
|
#include <vxWorks.h>
|
|
#include <semLib.h>
|
|
|
|
#ifndef _ASMLANGUAGE
|
|
#include <vsbConfig.h>
|
|
#include <stdarg.h>
|
|
#include <intLib.h>
|
|
#include <errnoLib.h>
|
|
|
|
/*
|
|
* The following private header files are necessary for the implementation of
|
|
* the inline APIs. The contents of these files are subject to change without
|
|
* notice.
|
|
*/
|
|
|
|
#include <private/qLibP.h>
|
|
#include <private/semLibP.h>
|
|
#include <private/windLibP.h>
|
|
#include <private/kernelLibP.h>
|
|
|
|
#ifndef _WRS_CONFIG_SMP
|
|
#include <private/sigLibP.h>
|
|
#include <private/intLibP.h>
|
|
#endif /* WRS_CONFIG_SMP */
|
|
|
|
#endif /* _ASMLANGUAGE */
|
|
|
|
/*
|
|
* Additional pseudo-options (not stored in semId->options).
|
|
* These must not conflict in value with the options defined in semLibCommon.h.
|
|
* Start from the most-significant bit and work down.
|
|
*/
|
|
|
|
#define SEM_RW_WRITER_CALL ((int)0x80000000)
|
|
#define SEM_RW_READER_CALL (0x40000000)
|
|
|
|
/* option masks for Reader-Writer semaphores*/
|
|
|
|
#define SEM_RW_OPTIONS_MASK_INLINE (SEM_Q_FIFO | \
|
|
SEM_Q_PRIORITY | \
|
|
SEM_DELETE_SAFE | \
|
|
SEM_INVERSION_SAFE | \
|
|
SEM_EVENTSEND_ERR_NOTIFY | \
|
|
SEM_INTERRUPTIBLE | \
|
|
SEM_NO_ID_VALIDATE | \
|
|
SEM_NO_ERROR_CHECK | \
|
|
SEM_NO_EVENT_SEND | \
|
|
SEM_NO_SYSTEM_VIEWER | \
|
|
SEM_NO_RECURSE)
|
|
|
|
/*
|
|
* 'Minimal' reader-writer semaphores have a fast-path that allows
|
|
* them to be given or taken (under certain conditions) without entering
|
|
* the kernel and without fetching the current task ID, but they do not
|
|
* support deletion safety, inversion safety, recursive taking, or VxWorks
|
|
* event sending. Some positive options must be disallowed, and some
|
|
* 'negative' options must be enabled.
|
|
*/
|
|
#define SEM_RW_OPTIONS_MIN_DISALLOWED (SEM_DELETE_SAFE | \
|
|
SEM_INVERSION_SAFE | \
|
|
SEM_EVENTSEND_ERR_NOTIFY)
|
|
/*
|
|
* Required (negative) options for minimal implementation.
|
|
* - Supporting recursion requires the reader task table (or a different API)
|
|
* - Object ID validation requires object lock (entering the kernel in SMP)
|
|
* - Don't want to support EVENT_SEND.
|
|
*/
|
|
#define SEM_RW_OPTIONS_MIN_REQUIRED (SEM_NO_RECURSE | \
|
|
SEM_NO_EVENT_SEND | \
|
|
SEM_NO_ID_VALIDATE)
|
|
|
|
#define SEM_RW_OPTIONS_ARE_MINIMAL(x) \
|
|
(((x) & SEM_RW_OPTIONS_MIN_DISALLOWED) == 0 && \
|
|
((x) & SEM_RW_OPTIONS_MIN_REQUIRED) == SEM_RW_OPTIONS_MIN_REQUIRED)
|
|
|
|
#if !defined (_ASMLANGUAGE)
|
|
|
|
enum SEM_RW_MODE
|
|
{
|
|
SEM_RW_MODE_UNOWNED = 0,
|
|
SEM_RW_MODE_READ,
|
|
SEM_RW_MODE_WRITE
|
|
};
|
|
|
|
#define SEM_RW_INLINE_NDEBUG
|
|
|
|
#ifdef SEM_RW_INLINE_NDEBUG
|
|
#define semrw_kassert(ignore) ((void) 0)
|
|
#else /* turn debugging on */
|
|
|
|
#include <logLib.h>
|
|
#include <taskLib.h>
|
|
|
|
#define _SEMRW_KASSERT_STR(z) _SEMRW_KASSERT_TMP(z)
|
|
#define _SEMRW_KASSERT_TMP(z) #z
|
|
|
|
extern void __semrw_kassert (const char *msg);
|
|
|
|
#define semrw_kassert(test) \
|
|
((void) \
|
|
((test) ? ((void) 0) : \
|
|
__semrw_kassert("Assertion failed: "#test", file " \
|
|
__FILE__ ", line "_SEMRW_KASSERT_STR(__LINE__)"\n")))
|
|
#endif /* SEM_RW_INLINE_NDEBUG */
|
|
|
|
/* function declarations (support routines in semRWMinLib.c) */
|
|
|
|
extern STATUS semRMinTakeHard (SEM_ID semId, int options);
|
|
extern STATUS semWMinTakeHard (SEM_ID semId, int options);
|
|
extern STATUS semRMinGiveHard (SEM_ID semId, int options);
|
|
extern STATUS semWMinGiveHard (SEM_ID semId, int options);
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* _semRWIsrCheck - return ERROR if called from an ISR
|
|
*
|
|
* Returns OK if not called from an ISR, otherwise sets cpu-specific
|
|
* errno value and returns ERROR.
|
|
*
|
|
* RETURNS: OK or ERROR
|
|
* ERRNO: S_intLib_NOT_ISR_CALLABLE
|
|
* NOMANUAL
|
|
*/
|
|
_WRS_INLINE STATUS _semRWIsrCheck (void)
|
|
{
|
|
#ifdef _WRS_CONFIG_SMP
|
|
|
|
int cpuid;
|
|
int intCnt;
|
|
int level;
|
|
|
|
level = KERNEL_INT_CPU_LOCK();
|
|
cpuid = _WRS_CPU_INDEX_GET ();
|
|
intCnt = _WRS_KERNEL_CPU_GLOBAL_GET (cpuid, intCnt);
|
|
if (intCnt != 0)
|
|
{
|
|
_WRS_KERNEL_CPU_GLOBAL_SET (cpuid, errno, S_intLib_NOT_ISR_CALLABLE);
|
|
}
|
|
KERNEL_INT_CPU_UNLOCK(level);
|
|
|
|
return intCnt ? ERROR : 0;
|
|
|
|
#else /* ! _WRS_CONFIG_SMP */
|
|
|
|
return _WRS_INT_RESTRICT ();
|
|
|
|
#endif /* !_WRS_CONFIG_SMP */
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _semRMinGive_inline - give a minimal reader/writer semaphore in read mode
|
|
*
|
|
* This routine is internal and should not be called directly.
|
|
*
|
|
* It handles the case of a call to semRWGive_inline() with 'minimal'
|
|
* options by a reader task owning the semaphore.
|
|
*
|
|
* RETURNS: OK
|
|
* ERRNO: N/A
|
|
* \is
|
|
* \ie
|
|
* NOMANUAL
|
|
*/
|
|
|
|
_WRS_INLINE STATUS _semRMinGive_inline
|
|
(
|
|
SEM_ID semId, /* semaphore ID to give */
|
|
int options /* semaphore options */
|
|
)
|
|
{
|
|
atomic32_t *pSemVal = &SEM_RWMIN_VALUE(semId);
|
|
atomic32Val_t v;
|
|
|
|
/* Note, the required memory barrier was done in semRWGive_inline(). */
|
|
|
|
while (TRUE)
|
|
{
|
|
v = vxAtomic32Get_inline (pSemVal);
|
|
|
|
semrw_kassert ((v & SEM_RWMIN_VAL_W_OWNS) == 0);
|
|
semrw_kassert ((v & ~SEM_RWMIN_VAL_PEND) != 0);
|
|
|
|
/*
|
|
* Note, this is the only case were *pSemVal may be legitimately
|
|
* modified outside of obj/kernel lock when SEM_RWMIN_VAL_PEND is set:
|
|
* a reader-owner other than the last reader-owner may decrement the
|
|
* reader count when giving the semaphore.
|
|
*/
|
|
if (v == (SEM_RWMIN_VAL_R_INC | SEM_RWMIN_VAL_PEND))
|
|
break;
|
|
if (vxAtomic32Cas (pSemVal, v, v - SEM_RWMIN_VAL_R_INC))
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
* This is the last reader-owner and there are tasks pended.
|
|
* Have to enter the kernel.
|
|
*/
|
|
return semRMinGiveHard (semId, options);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* _semWMinGive_inline - give a minimal reader/writer semaphore in write mode
|
|
*
|
|
* This routine is internal and should not be called directly.
|
|
*
|
|
* It handles the case of a call to semRWGive_inline() with 'minimal'
|
|
* options by a writer task owning the semaphore.
|
|
*
|
|
* RETURNS: OK
|
|
* ERRNO: N/A
|
|
* \is
|
|
* \ie
|
|
* NOMANUAL
|
|
*/
|
|
|
|
_WRS_INLINE STATUS _semWMinGive_inline
|
|
(
|
|
SEM_ID semId, /* semaphore ID to give */
|
|
int options /* semaphore options */
|
|
)
|
|
{
|
|
atomic32_t *pSemVal = &SEM_RWMIN_VALUE(semId);
|
|
atomic32Val_t v;
|
|
|
|
/* The required memory barrier was done in semRWGive_inline() */
|
|
|
|
while (TRUE)
|
|
{
|
|
v = vxAtomic32Get_inline (pSemVal);
|
|
|
|
semrw_kassert ((v & SEM_RWMIN_VAL_W_OWNS) != 0);
|
|
semrw_kassert ((v & ~(SEM_RWMIN_VAL_PEND|SEM_RWMIN_VAL_W_OWNS)) == 0);
|
|
|
|
if ((v & SEM_RWMIN_VAL_PEND) != 0)
|
|
break;
|
|
if (vxAtomic32Cas (pSemVal, v, 0))
|
|
return OK;
|
|
}
|
|
|
|
/* There are tasks pended. Have to enter the kernel. */
|
|
|
|
return semWMinGiveHard (semId, options);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* semRWGive_inline - give a reader/writer semaphore (inline version)
|
|
*
|
|
* This routine gives a reader/writer semaphore.
|
|
*
|
|
* The behavior of this routine is similar to that of semRWGive() on a
|
|
* reader/writer semaphore, differing in that an additional parameter,
|
|
* <options>, must be specified. The <options> parameter allows scaling
|
|
* support for particular semaphore features out of the call to this routine.
|
|
*
|
|
* The semaphore specified by <semId> must be of the reader/writer type.
|
|
*
|
|
* The options specified by <options> are called 'minimal' if the following
|
|
* options are not enabled:
|
|
* SEM_DELETE_SAFE
|
|
* SEM_INVERSION_SAFE
|
|
* SEM_EVENTSEND_ERR_NOTIFY
|
|
* and the following (negative) options are enabled:
|
|
* SEM_NO_RECURSE
|
|
* SEM_NO_EVENT_SEND
|
|
* SEM_NO_ID_VALIDATE
|
|
*
|
|
* If the options are 'minimal', one of the special pseudo-options
|
|
* SEM_RW_READER_CALL or SEM_RW_WRITER_CALL may also be specified to omit
|
|
* (compile out) the dynamic test of whether the semaphore is currently
|
|
* reader-owned or writer-owned, provided the calling code knows this.
|
|
*
|
|
* For best scalability, this inline routine should be called with
|
|
* a compile-time-constant options value, so that the compiler may optimize
|
|
* away inapplicable code branches.
|
|
*/
|
|
|
|
_WRS_INLINE STATUS semRWGive_inline
|
|
(
|
|
SEM_ID semId, /* semaphore ID to give */
|
|
int options /* semaphore options */
|
|
)
|
|
{
|
|
int level;
|
|
atomic32_t *pSemVal;
|
|
atomic32Val_t val;
|
|
|
|
if ((options & ~(SEM_RW_OPTIONS_MASK_INLINE |
|
|
SEM_RW_WRITER_CALL | SEM_RW_READER_CALL)) != 0)
|
|
{
|
|
errno = S_semLib_INVALID_OPTION;
|
|
return (ERROR);
|
|
}
|
|
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
if ((options & SEM_NO_SYSTEM_VIEWER) == 0)
|
|
{
|
|
_Vx_usr_arg_t owner;
|
|
_Vx_usr_arg_t recurse;
|
|
|
|
if (SEM_RW_OPTIONS_ARE_MINIMAL(options))
|
|
{
|
|
/*
|
|
* Note: We replace semId->semOwner with *pSemVal,
|
|
* and replace semId->recurse with 0xabadcafe
|
|
* for minimal semaphores. Hopefully sticking
|
|
* with EVT_OBJ_3 (used by semGive()) will lead to less
|
|
* confusion on the system-viewer host side and still
|
|
* provide useful information, even if a couple of the
|
|
* event fields are mislabelled in the display.
|
|
* An alternative might be to introduce a new event type...
|
|
*/
|
|
pSemVal = &SEM_RWMIN_VALUE(semId);
|
|
owner = (_Vx_usr_arg_t)vxAtomic32Get_inline(pSemVal);
|
|
recurse = (_Vx_usr_arg_t)0xabadcafe;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* In the full-featured case, the generic semGive() code
|
|
* would emit the object-level EVENT_SEMGIVE. Since
|
|
* we call semRWGive() directly, we must do it here.
|
|
*/
|
|
owner = (_Vx_usr_arg_t)semId->semOwner;
|
|
recurse = (_Vx_usr_arg_t)semId->recurse;
|
|
}
|
|
|
|
/* system viewer - level 1 event logging */
|
|
EVT_OBJ_3 (semId, semClassId, EVENT_SEMGIVE, semId, owner, recurse);
|
|
}
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
|
|
|
|
if (SEM_RW_OPTIONS_ARE_MINIMAL(options))
|
|
{
|
|
if ((options & SEM_NO_ERROR_CHECK) == 0)
|
|
{
|
|
if (_semRWIsrCheck() != OK)
|
|
return ERROR;
|
|
if (! SEM_IS_MINIMAL (semId))
|
|
{
|
|
errnoSet (S_semLib_INVALID_OPERATION);
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Ensure that loads or stores done while holding the lock
|
|
* are globally seen as occurring before the stores that release
|
|
* the lock.
|
|
*/
|
|
VX_MEM_BARRIER_RW();
|
|
|
|
if ((options & (SEM_RW_READER_CALL | SEM_RW_WRITER_CALL)) == 0)
|
|
{
|
|
/*
|
|
* Will have to determine if the caller is a reader or writer
|
|
* dynamically.
|
|
*/
|
|
pSemVal = &SEM_RWMIN_VALUE(semId);
|
|
val = vxAtomic32Get_inline(pSemVal);
|
|
if ((options & SEM_NO_ERROR_CHECK) == 0)
|
|
{
|
|
if (0 == (val & ~SEM_RWMIN_VAL_PEND))
|
|
{
|
|
/* The semaphore appears unowned. */
|
|
errnoSet (S_semLib_INVALID_OPERATION);
|
|
return ERROR;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
val = 0;
|
|
|
|
if ((options & SEM_RW_WRITER_CALL) != 0
|
|
|| (val & SEM_RWMIN_VAL_W_OWNS) != 0)
|
|
return _semWMinGive_inline (semId, options & ~SEM_RW_WRITER_CALL);
|
|
else
|
|
return _semRMinGive_inline (semId, options & ~SEM_RW_READER_CALL);
|
|
}
|
|
else /* non-minimal options */
|
|
{
|
|
/*
|
|
* For now, we handle only the full-featured case by calling
|
|
* semRWGive().
|
|
*/
|
|
if ((options & SEM_NO_ERROR_CHECK) == 0)
|
|
{
|
|
if (SEM_IS_MINIMAL (semId))
|
|
{
|
|
errnoSet (S_semLib_INVALID_OPERATION);
|
|
return ERROR;
|
|
}
|
|
}
|
|
return semRWGive (semId);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* semWTake_inline - take a reader/writer semaphore in write mode (inline version)
|
|
*
|
|
* This routine takes a reader/writer semaphore in write mode.
|
|
*
|
|
* The behavior of this routine is similar to that of semWTake() on a
|
|
* reader/writer semaphore, differing in that an additional parameter,
|
|
* <options>, must be specified. The <options> parameter allows scaling
|
|
* support for particular semaphore features out of the call to this routine.
|
|
*
|
|
* The semaphore specified by <semId> must be of the reader/writer type.
|
|
*/
|
|
|
|
_WRS_INLINE STATUS semWTake_inline
|
|
(
|
|
SEM_ID semId, /* semaphore ID to take */
|
|
_Vx_ticks_t timeout, /* timeout in ticks */
|
|
int options /* semaphore options */
|
|
)
|
|
{
|
|
if ((options & ~SEM_RW_OPTIONS_MASK_INLINE) != 0)
|
|
{
|
|
errno = S_semLib_INVALID_OPTION;
|
|
return (ERROR);
|
|
}
|
|
|
|
if (SEM_RW_OPTIONS_ARE_MINIMAL(options))
|
|
{
|
|
atomic32_t *pSemVal = &SEM_RWMIN_VALUE(semId);
|
|
atomic32Val_t v;
|
|
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
if (0 == (options & SEM_NO_SYSTEM_VIEWER))
|
|
{
|
|
/* system viewer - level 1 event logging */
|
|
/*
|
|
* Note: We replace semId->semOwner with *pSemVal,
|
|
* and replace semId->recurse with 0xabadcafe
|
|
* for minimal semaphores. Hopefully sticking
|
|
* with EVT_OBJ_3 (used by semWTake()) will lead to less
|
|
* confusion on the system-viewer host side and still
|
|
* provide useful information, even if a couple of the
|
|
* event fields are mislabelled in the display.
|
|
* An alternative might be to introduce a new event type...
|
|
*/
|
|
EVT_OBJ_3 (semId, semClassId, EVENT_SEMWTAKE,
|
|
semId, *pSemVal, 0xabadcafe);
|
|
}
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
|
|
if ((options & SEM_NO_ERROR_CHECK) == 0)
|
|
{
|
|
if (_semRWIsrCheck() != OK)
|
|
return ERROR;
|
|
if (timeout != WAIT_FOREVER || !SEM_IS_MINIMAL (semId))
|
|
{
|
|
errnoSet (S_semLib_INVALID_OPERATION);
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
v = vxAtomic32Get_inline (pSemVal);
|
|
semrw_kassert ((v & SEM_RWMIN_VAL_W_OWNS) == 0 ||
|
|
(v & ~(SEM_RWMIN_VAL_W_OWNS | SEM_RWMIN_VAL_PEND)) == 0);
|
|
|
|
if (v != 0)
|
|
break;
|
|
|
|
if (vxAtomic32Cas (pSemVal, 0, SEM_RWMIN_VAL_W_OWNS))
|
|
{
|
|
VX_INSTR_BARRIER();
|
|
return OK;
|
|
}
|
|
}
|
|
|
|
/* The semaphore appears to be owned; must enter the kernel. */
|
|
return semWMinTakeHard (semId, options);
|
|
}
|
|
else /* non-minimal options */
|
|
{
|
|
/*
|
|
* For now, we handle only the full-featured case by calling
|
|
* semWTake().
|
|
*/
|
|
if ((options & SEM_NO_ERROR_CHECK) == 0)
|
|
{
|
|
if (SEM_IS_MINIMAL (semId))
|
|
{
|
|
errnoSet (S_semLib_INVALID_OPERATION);
|
|
return ERROR;
|
|
}
|
|
}
|
|
return semWTake (semId, timeout);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* semRTake_inline - take a reader/writer semaphore in read mode (inline version)
|
|
*
|
|
* This routine takes a reader/writer semaphore in read mode.
|
|
*
|
|
* The behavior of this routine is similar to that of semRTake() on a
|
|
* reader/writer semaphore, differing in that an additional parameter,
|
|
* <options>, must be specified. The <options> parameter allows scaling
|
|
* support for particular semaphore features out of the call to this routine.
|
|
*
|
|
* The semaphore specified by <semId> must be of the reader/writer type.
|
|
*/
|
|
|
|
_WRS_INLINE STATUS semRTake_inline
|
|
(
|
|
SEM_ID semId, /* semaphore ID to take */
|
|
_Vx_ticks_t timeout, /* timeout in ticks */
|
|
int options /* semaphore options */
|
|
)
|
|
{
|
|
if ((options & ~SEM_RW_OPTIONS_MASK_INLINE) != 0)
|
|
{
|
|
errno = S_semLib_INVALID_OPTION;
|
|
return (ERROR);
|
|
}
|
|
|
|
if (SEM_RW_OPTIONS_ARE_MINIMAL(options))
|
|
{
|
|
atomic32_t *pSemVal = &SEM_RWMIN_VALUE(semId);
|
|
atomic32Val_t v;
|
|
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
if (0 == (options & SEM_NO_SYSTEM_VIEWER))
|
|
{
|
|
/* system viewer - level 1 event logging */
|
|
/*
|
|
* Note: We replace semId->semOwner with *pSemVal,
|
|
* and replace semId->recurse with 0xabadcafe
|
|
* for minimal semaphores. Hopefully sticking
|
|
* with EVT_OBJ_3 (used by semRTake()) will lead to less
|
|
* confusion on the system-viewer host side and still
|
|
* provide useful information, even if a couple of the
|
|
* event fields are mislabelled in the display.
|
|
* An alternative might be to introduce a new event type...
|
|
*/
|
|
EVT_OBJ_3 (semId, semClassId, EVENT_SEMRTAKE,
|
|
semId, *pSemVal, 0xabadcafe);
|
|
}
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
|
|
if ((options & SEM_NO_ERROR_CHECK) == 0)
|
|
{
|
|
if (_semRWIsrCheck() != OK)
|
|
return ERROR;
|
|
if (timeout != WAIT_FOREVER || !SEM_IS_MINIMAL (semId))
|
|
{
|
|
errnoSet (S_semLib_INVALID_OPERATION);
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
v = vxAtomic32Get_inline (pSemVal);
|
|
semrw_kassert ((v & SEM_RWMIN_VAL_W_OWNS) == 0 ||
|
|
(v & ~(SEM_RWMIN_VAL_W_OWNS | SEM_RWMIN_VAL_PEND)) == 0);
|
|
|
|
if ((v & (SEM_RWMIN_VAL_W_OWNS | SEM_RWMIN_VAL_PEND)) != 0)
|
|
break;
|
|
|
|
if (vxAtomic32Cas (pSemVal, v, v + SEM_RWMIN_VAL_R_INC))
|
|
{
|
|
VX_INSTR_BARRIER();
|
|
return OK;
|
|
}
|
|
}
|
|
/*
|
|
* A writer owns the semaphore, or there are pended tasks. Enter
|
|
* the kernel. Note that the minimal case code does not
|
|
* implement timeouts.
|
|
*/
|
|
return semRMinTakeHard (semId, options);
|
|
}
|
|
else /* non-minimal options */
|
|
{
|
|
/* For now, handle the full-featured case by calling semRTake(). */
|
|
if ((options & SEM_NO_ERROR_CHECK) == 0)
|
|
{
|
|
if (SEM_IS_MINIMAL (semId))
|
|
{
|
|
errnoSet (S_semLib_INVALID_OPERATION);
|
|
return ERROR;
|
|
}
|
|
}
|
|
return semRTake (semId, timeout);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* semRWMinOwner_inline - return the owner type of a mimimal reader-writer semaphore
|
|
*
|
|
* This function returns a value that indicates whether the semaphore
|
|
* is currently unowned, held by readers, or owned by a single writer.
|
|
*
|
|
* WARNING:
|
|
* The value returned is only valid and stable if the caller is in fact
|
|
* a task currently owning the semaphore as either a reader or a writer.
|
|
*
|
|
* RETURNS:
|
|
* \is
|
|
* \i 'SEM_RW_MODE_UNOWNED'
|
|
* if the semaphore is currently unheld.
|
|
*
|
|
* \i 'SEM_RW_MODE_READ'
|
|
* if the semaphore is held by one or more reader tasks.
|
|
*
|
|
* \i 'SEM_RW_MODE_WRITE'
|
|
* if the semaphore is owned by a writer task.
|
|
* \ie
|
|
*/
|
|
_WRS_INLINE int semRWOwner_inline
|
|
(
|
|
SEM_ID semId, /* the RW semaphore */
|
|
int options /* semaphore options */
|
|
)
|
|
{
|
|
if ((options & ~SEM_RW_OPTIONS_MASK_INLINE) != 0)
|
|
{
|
|
errno = S_semLib_INVALID_OPTION;
|
|
return (ERROR);
|
|
}
|
|
|
|
if (SEM_RW_OPTIONS_ARE_MINIMAL(options))
|
|
{
|
|
atomic32_t *pSemVal = &SEM_RWMIN_VALUE(semId);
|
|
atomicVal_t v = vxAtomic32Get_inline (pSemVal);
|
|
|
|
if ((options & SEM_NO_ERROR_CHECK) == 0)
|
|
{
|
|
if (! SEM_IS_MINIMAL (semId))
|
|
{
|
|
errnoSet (S_semLib_INVALID_OPERATION);
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
if (v == 0) /* PEND bit will not be set if un-owned... */
|
|
return SEM_RW_MODE_UNOWNED; /* no-one owns it */
|
|
if (v & SEM_RWMIN_VAL_W_OWNS)
|
|
return SEM_RW_MODE_WRITE; /* writer owns it */
|
|
return SEM_RW_MODE_READ; /* reader owns it */
|
|
}
|
|
else
|
|
{
|
|
if ((options & SEM_NO_ERROR_CHECK) == 0)
|
|
{
|
|
if (SEM_IS_MINIMAL (semId))
|
|
{
|
|
errnoSet (S_semLib_INVALID_OPERATION);
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If this task is an owner (either read or write) of the semaphore,
|
|
* then semId->semOwner is stable, even though we have not entered the
|
|
* kernel.
|
|
*/
|
|
if (semId->semOwner != NULL)
|
|
return SEM_RW_MODE_WRITE;
|
|
/*
|
|
* If this task is a read-owner of the semaphore, then
|
|
* SEMRW_READ_CNT(semId) is stably non-zero.
|
|
*/
|
|
if (SEMRW_READ_CNT(semId) != 0)
|
|
return SEM_RW_MODE_READ;
|
|
|
|
return SEM_RW_MODE_UNOWNED;
|
|
}
|
|
}
|
|
|
|
|
|
#endif /* !defined (_ASMLANGUAGE) */
|
|
|
|
#endif /* __INCsemRWLibInlinePh */
|