in queue.c [1521:1737]
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
TickType_t xTicksToWait )
{
BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut;
Queue_t * const pxQueue = xQueue;
#if ( configUSE_MUTEXES == 1 )
BaseType_t xInheritanceOccurred = pdFALSE;
#endif
/* Check the queue pointer is not NULL. */
configASSERT( ( pxQueue ) );
/* Check this really is a semaphore, in which case the item size will be
* 0. */
configASSERT( pxQueue->uxItemSize == 0 );
/* Cannot block if the scheduler is suspended. */
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
/*lint -save -e904 This function relaxes the coding standard somewhat to allow return
* statements within the function itself. This is done in the interest
* of execution time efficiency. */
for( ; ; )
{
taskENTER_CRITICAL();
{
/* Semaphores are queues with an item size of 0, and where the
* number of messages in the queue is the semaphore's count value. */
const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting;
/* Is there data in the queue now? To be running the calling task
* must be the highest priority task wanting to access the queue. */
if( uxSemaphoreCount > ( UBaseType_t ) 0 )
{
traceQUEUE_RECEIVE( pxQueue );
/* Semaphores are queues with a data size of zero and where the
* messages waiting is the semaphore's count. Reduce the count. */
pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1;
#if ( configUSE_MUTEXES == 1 )
{
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
{
/* Record the information required to implement
* priority inheritance should it become necessary. */
pxQueue->u.xSemaphore.xMutexHolder = pvTaskIncrementMutexHeldCount();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_MUTEXES */
/* Check to see if other tasks are blocked waiting to give the
* semaphore, and if so, unblock the highest priority such task. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
queueYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
taskEXIT_CRITICAL();
return pdPASS;
}
else
{
if( xTicksToWait == ( TickType_t ) 0 )
{
/* For inheritance to have occurred there must have been an
* initial timeout, and an adjusted timeout cannot become 0, as
* if it were 0 the function would have exited. */
#if ( configUSE_MUTEXES == 1 )
{
configASSERT( xInheritanceOccurred == pdFALSE );
}
#endif /* configUSE_MUTEXES */
/* The semaphore count was 0 and no block time is specified
* (or the block time has expired) so exit now. */
taskEXIT_CRITICAL();
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
}
else if( xEntryTimeSet == pdFALSE )
{
/* The semaphore count was 0 and a block time was specified
* so configure the timeout structure ready to block. */
vTaskInternalSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
else
{
/* Entry time was already set. */
mtCOVERAGE_TEST_MARKER();
}
}
}
taskEXIT_CRITICAL();
/* Interrupts and other tasks can give to and take from the semaphore
* now the critical section has been exited. */
vTaskSuspendAll();
prvLockQueue( pxQueue );
/* Update the timeout state to see if it has expired yet. */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
/* A block time is specified and not expired. If the semaphore
* count is 0 then enter the Blocked state to wait for a semaphore to
* become available. As semaphores are implemented with queues the
* queue being empty is equivalent to the semaphore count being 0. */
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
#if ( configUSE_MUTEXES == 1 )
{
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
{
taskENTER_CRITICAL();
{
xInheritanceOccurred = xTaskPriorityInherit( pxQueue->u.xSemaphore.xMutexHolder );
}
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* if ( configUSE_MUTEXES == 1 ) */
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
prvUnlockQueue( pxQueue );
if( xTaskResumeAll() == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* There was no timeout and the semaphore count was not 0, so
* attempt to take the semaphore again. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
}
}
else
{
/* Timed out. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
/* If the semaphore count is 0 exit now as the timeout has
* expired. Otherwise return to attempt to take the semaphore that is
* known to be available. As semaphores are implemented by queues the
* queue being empty is equivalent to the semaphore count being 0. */
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
#if ( configUSE_MUTEXES == 1 )
{
/* xInheritanceOccurred could only have be set if
* pxQueue->uxQueueType == queueQUEUE_IS_MUTEX so no need to
* test the mutex type again to check it is actually a mutex. */
if( xInheritanceOccurred != pdFALSE )
{
taskENTER_CRITICAL();
{
UBaseType_t uxHighestWaitingPriority;
/* This task blocking on the mutex caused another
* task to inherit this task's priority. Now this task
* has timed out the priority should be disinherited
* again, but only as low as the next highest priority
* task that is waiting for the same mutex. */
uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue );
vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority );
}
taskEXIT_CRITICAL();
}
}
#endif /* configUSE_MUTEXES */
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
} /*lint -restore */
}