Core kernel code:

+ Introduce xSemaphoreGenericGiveFromISR() as an optimisation when giving semaphores and mutexes from an interrupt.

Demo applications:
+ Update IntSemTest.c to provide more code coverage in xSemaphoreGenericGiveFromISR().
+ Ensure the MMU is turned on in the RZ IAR demo.  It was already on in the RZ ARM demo.
This commit is contained in:
Richard Barry 2014-09-16 14:54:32 +00:00
parent b3c040fc27
commit 3b0854bf96
9 changed files with 509 additions and 179 deletions

View file

@ -1074,20 +1074,12 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
{
traceQUEUE_SEND_FROM_ISR( pxQueue );
if( prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ) != pdFALSE )
{
/* This is a special case that can only be executed if a task
holds multiple mutexes and then gives the mutexes back in an
order that is different to that in which they were taken. */
if( pxHigherPriorityTaskWoken != NULL )
{
*pxHigherPriorityTaskWoken = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* A task can only have an inherited priority if it is a mutex
holder - and if there is a mutex holder then the mutex cannot be
given from an ISR. Therefore, unlike the xQueueGenericGive()
function, there is no need to determine the need for priority
disinheritance here or to clear the mutex holder TCB member. */
( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
/* The event list is not altered if the queue is locked. This will
be done when the queue is unlocked later. */
@ -1194,6 +1186,160 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
}
/*-----------------------------------------------------------*/
BaseType_t xQueueGenericGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken )
{
BaseType_t xReturn;
UBaseType_t uxSavedInterruptStatus;
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
configASSERT( pxQueue );
/* xQueueGenericSendFromISR() should be used in the item size is not 0. */
configASSERT( pxQueue->uxItemSize == 0 );
/* RTOS ports that support interrupt nesting have the concept of a maximum
system call (or maximum API call) interrupt priority. Interrupts that are
above the maximum system call priority are kept permanently enabled, even
when the RTOS kernel is in a critical section, but cannot make any calls to
FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h
then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
failure if a FreeRTOS API function is called from an interrupt that has been
assigned a priority above the configured maximum system call priority.
Only FreeRTOS functions that end in FromISR can be called from interrupts
that have been assigned a priority at or (logically) below the maximum
system call interrupt priority. FreeRTOS maintains a separate interrupt
safe API to ensure interrupt entry is as fast and as simple as possible.
More information (albeit Cortex-M specific) is provided on the following
link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */
portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
/* Similar to xQueueGenericSendFromISR() but used with semaphores where the
item size is 0. Don't directly wake a task that was blocked on a queue
read, instead return a flag to say whether a context switch is required or
not (i.e. has a task with a higher priority than us been woken by this
post). */
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
{
/* When the queue is used to implement a semaphore no data is ever
moved through the queue but it is still valid to see if the queue 'has
space'. */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
traceQUEUE_SEND_FROM_ISR( pxQueue );
/* A task can only have an inherited priority if it is a mutex
holder - and if there is a mutex holder then the mutex cannot be
given from an ISR. Therefore, unlike the xQueueGenericGive()
function, there is no need to determine the need for priority
disinheritance here or to clear the mutex holder TCB member. */
++( pxQueue->uxMessagesWaiting );
/* The event list is not altered if the queue is locked. This will
be done when the queue is unlocked later. */
if( pxQueue->xTxLock == queueUNLOCKED )
{
#if ( configUSE_QUEUE_SETS == 1 )
{
if( pxQueue->pxQueueSetContainer != NULL )
{
if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE )
{
/* The semaphore is a member of a queue set, and
posting to the queue set caused a higher priority
task to unblock. A context switch is required. */
if( pxHigherPriorityTaskWoken != NULL )
{
*pxHigherPriorityTaskWoken = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority so
record that a context switch is required. */
if( pxHigherPriorityTaskWoken != NULL )
{
*pxHigherPriorityTaskWoken = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
#else /* configUSE_QUEUE_SETS */
{
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority so record that a
context switch is required. */
if( pxHigherPriorityTaskWoken != NULL )
{
*pxHigherPriorityTaskWoken = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_QUEUE_SETS */
}
else
{
/* Increment the lock count so the task that unlocks the queue
knows that data was posted while it was locked. */
++( pxQueue->xTxLock );
}
xReturn = pdPASS;
}
else
{
traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );
xReturn = errQUEUE_FULL;
}
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); //0.36
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )
{
BaseType_t xEntryTimeSet = pdFALSE;