int sem_timedwait()

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;
}