in FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_semaphore.c [129:201]
int sem_timedwait( sem_t * sem,
const struct timespec * abstime )
{
int iStatus = 0;
sem_internal_t * pxSem = ( sem_internal_t * ) ( sem );
TickType_t xDelay = portMAX_DELAY;
int iPreviousValue = Atomic_Decrement_u32( ( uint32_t * ) &pxSem->value );
if( abstime != NULL )
{
/* If the provided timespec is invalid, still attempt to take the
* semaphore without blocking, per POSIX spec. */
if( UTILS_ValidateTimespec( abstime ) == false )
{
xDelay = 0;
iStatus = EINVAL;
}
else
{
struct timespec xCurrentTime = { 0 };
/* Get current time */
if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
{
iStatus = EINVAL;
}
else
{
iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay );
}
/* If abstime was in the past, still attempt to take the semaphore without
* blocking, per POSIX spec. */
if( iStatus == ETIMEDOUT )
{
xDelay = 0;
}
}
}
/* If previous semaphore value is larger than zero, the thread entering this function call
* can take the semaphore without yielding. Else (<=0), calling into FreeRTOS API to yield.
*/
if( iPreviousValue > 0 )
{
/* Under no circumstance shall the function fail with a timeout if the semaphore can be locked immediately. */
iStatus = 0;
}
else
{
/* Take the semaphore using the FreeRTOS API. */
if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxSem->xSemaphore,
xDelay ) != pdTRUE )
{
if( iStatus == 0 )
{
errno = ETIMEDOUT;
}
else
{
errno = iStatus;
}
iStatus = -1;
}
else
{
iStatus = 0;
}
}
return iStatus;
}