mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-19 21:11:57 -04:00
Enhanced priority dis-inheritance functionality in the case where a task that caused another task to inherit its priority times out before obtain a mutex.
Added test code to GenQTest to test the new priority dis-inheritance functionality. Allow the default names given to the Idle and Timer tasks to be overwridden by definitions in FreeRTOSConfig.h.
This commit is contained in:
parent
883541bc8e
commit
d67dcf9c74
|
@ -91,6 +91,7 @@
|
||||||
|
|
||||||
#define genqQUEUE_LENGTH ( 5 )
|
#define genqQUEUE_LENGTH ( 5 )
|
||||||
#define intsemNO_BLOCK ( 0 )
|
#define intsemNO_BLOCK ( 0 )
|
||||||
|
#define genqSHORT_BLOCK ( pdMS_TO_TICKS( 2 ) )
|
||||||
|
|
||||||
#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
|
#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
|
||||||
#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||||
|
@ -125,6 +126,27 @@ static void prvLowPriorityMutexTask( void *pvParameters );
|
||||||
static void prvMediumPriorityMutexTask( void *pvParameters );
|
static void prvMediumPriorityMutexTask( void *pvParameters );
|
||||||
static void prvHighPriorityMutexTask( void *pvParameters );
|
static void prvHighPriorityMutexTask( void *pvParameters );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tests the behaviour when a low priority task inherits the priority of a
|
||||||
|
* higher priority task when taking two mutexes, and returns the mutexes in
|
||||||
|
* first the same order as the two mutexes were obtained, and second the
|
||||||
|
* opposite order as the two mutexes were obtained.
|
||||||
|
*/
|
||||||
|
static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex );
|
||||||
|
static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex );
|
||||||
|
|
||||||
|
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||||
|
|
||||||
|
#if( configUSE_PREEMPTION == 0 )
|
||||||
|
#error The additional tests included when INCLUDE_xTaskAbortDelay is 1 expect preemption to be used.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Tests the behaviour when a low priority task inherits the priority of a
|
||||||
|
high priority task only for the high priority task to timeout before
|
||||||
|
obtaining the mutex. */
|
||||||
|
static void prvHighPriorityTimeout( SemaphoreHandle_t xMutex );
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||||
|
@ -143,6 +165,17 @@ static volatile uint32_t ulGuardedVariable = 0;
|
||||||
priority mutex test tasks. */
|
priority mutex test tasks. */
|
||||||
static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask;
|
static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask;
|
||||||
|
|
||||||
|
/* If INCLUDE_xTaskAbortDelay is 1 additional tests are performed, requiring an
|
||||||
|
additional task. */
|
||||||
|
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||||
|
static TaskHandle_t xSecondMediumPriorityMutexTask;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Lets the high priority semaphore task know that its wait for the semaphore
|
||||||
|
was aborted, in which case not being able to obtain the semaphore is not to be
|
||||||
|
considered an error. */
|
||||||
|
static volatile BaseType_t xBlockWasAborted = pdFALSE;
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vStartGenericQueueTasks( UBaseType_t uxPriority )
|
void vStartGenericQueueTasks( UBaseType_t uxPriority )
|
||||||
|
@ -189,13 +222,21 @@ SemaphoreHandle_t xMutex;
|
||||||
xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
|
xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
|
||||||
xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
|
xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
|
||||||
xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
|
xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
|
||||||
|
|
||||||
|
/* If INCLUDE_xTaskAbortDelay is set then additional tests are performed,
|
||||||
|
requiring two instances of prvHighPriorityMutexTask(). */
|
||||||
|
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||||
|
{
|
||||||
|
xTaskCreate( prvHighPriorityMutexTask, "MuHigh2", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_MEDIUM_PRIORITY, &xSecondMediumPriorityMutexTask );
|
||||||
|
}
|
||||||
|
#endif /* INCLUDE_xTaskAbortDelay */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
static void prvSendFrontAndBackTest( void *pvParameters )
|
static void prvSendFrontAndBackTest( void *pvParameters )
|
||||||
{
|
{
|
||||||
uint32_t ulData, ulData2;
|
uint32_t ulData, ulData2, ulLoopCounterSnapshot;
|
||||||
QueueHandle_t xQueue;
|
QueueHandle_t xQueue;
|
||||||
|
|
||||||
#ifdef USE_STDIO
|
#ifdef USE_STDIO
|
||||||
|
@ -215,7 +256,8 @@ QueueHandle_t xQueue;
|
||||||
should have the same efect as sending it to the front of the queue.
|
should have the same efect as sending it to the front of the queue.
|
||||||
|
|
||||||
First send to the front and check everything is as expected. */
|
First send to the front and check everything is as expected. */
|
||||||
xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );
|
ulLoopCounterSnapshot = ulLoopCounter;
|
||||||
|
xQueueSendToFront( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK );
|
||||||
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||||
{
|
{
|
||||||
|
@ -241,7 +283,8 @@ QueueHandle_t xQueue;
|
||||||
xErrorDetected = pdTRUE;
|
xErrorDetected = pdTRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );
|
ulLoopCounterSnapshot = ulLoopCounter;
|
||||||
|
xQueueSendToBack( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK );
|
||||||
|
|
||||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||||
{
|
{
|
||||||
|
@ -258,8 +301,8 @@ QueueHandle_t xQueue;
|
||||||
xErrorDetected = pdTRUE;
|
xErrorDetected = pdTRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The data we sent to the queue should equal the data we just received
|
/* The data sent to the queue should equal the data just received from
|
||||||
from the queue. */
|
the queue. */
|
||||||
if( ulLoopCounter != ulData )
|
if( ulLoopCounter != ulData )
|
||||||
{
|
{
|
||||||
xErrorDetected = pdTRUE;
|
xErrorDetected = pdTRUE;
|
||||||
|
@ -416,11 +459,204 @@ QueueHandle_t xQueue;
|
||||||
xErrorDetected = pdTRUE;
|
xErrorDetected = pdTRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Increment the loop counter to indicate these tasks are still
|
||||||
|
executing. */
|
||||||
ulLoopCounter++;
|
ulLoopCounter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||||
|
|
||||||
|
static void prvHighPriorityTimeout( SemaphoreHandle_t xMutex )
|
||||||
|
{
|
||||||
|
static UBaseType_t uxLoopCount = 0;
|
||||||
|
|
||||||
|
/* The tests in this function are very similar, the slight variations
|
||||||
|
are for code coverage purposes. */
|
||||||
|
|
||||||
|
/* Take the mutex. It should be available now. */
|
||||||
|
if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This task's priority should be as per that assigned when the task was
|
||||||
|
created. */
|
||||||
|
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now unsuspend the high priority task. This will attempt to take the
|
||||||
|
mutex, and block when it finds it cannot obtain it. */
|
||||||
|
vTaskResume( xHighPriorityMutexTask );
|
||||||
|
|
||||||
|
/* This task should now have inherited the priority of the high priority
|
||||||
|
task as by now the high priority task will have attempted to obtain the
|
||||||
|
mutex. */
|
||||||
|
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unblock a second medium priority task. It too will attempt to take
|
||||||
|
the mutex and enter the Blocked state - it won't run yet though as this
|
||||||
|
task has inherited a priority above it. */
|
||||||
|
vTaskResume( xSecondMediumPriorityMutexTask );
|
||||||
|
|
||||||
|
/* This task should still have the priority of the high priority task as
|
||||||
|
that had already been inherited as is the highest priority of the three
|
||||||
|
tasks using the mutex. */
|
||||||
|
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* On some loops, block for a short while to provide additional
|
||||||
|
code coverage. Blocking here will allow the medium priority task to
|
||||||
|
execute and so also block on the mutex so when the high priority task
|
||||||
|
causes this task to disinherit the high priority it is inherited down to
|
||||||
|
the priority of the medium priority task. When there is no delay the
|
||||||
|
medium priority task will not run until after the disinheritance, so
|
||||||
|
this task will disinherit back to its base priority, then only up to the
|
||||||
|
medium priority after the medium priority has executed. */
|
||||||
|
vTaskDelay( uxLoopCount & ( UBaseType_t ) 0x07 );
|
||||||
|
|
||||||
|
/* Now force the high priority task to unblock. It will fail to obtain
|
||||||
|
the mutex and go back to the suspended state - allowing this task to
|
||||||
|
execute again. xBlockWasAborted is set to pdTRUE so the higher priority
|
||||||
|
task knows that its failure to obtain the semaphore is not an error. */
|
||||||
|
xBlockWasAborted = pdTRUE;
|
||||||
|
if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This task has inherited the priority of xHighPriorityMutexTask so
|
||||||
|
could still be running even though xHighPriorityMutexTask is no longer
|
||||||
|
blocked. Delay for a short while to ensure xHighPriorityMutexTask gets
|
||||||
|
a chance to run - indicated by this task changing priority. It should
|
||||||
|
disinherit the high priority task, but then inherit the priority of the
|
||||||
|
medium priority task that is waiting for the same mutex. */
|
||||||
|
while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )
|
||||||
|
{
|
||||||
|
/* If this task gets stuck here then the check variables will stop
|
||||||
|
incrementing and the check task will detect the error. */
|
||||||
|
vTaskDelay( genqSHORT_BLOCK );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now force the medium priority task to unblock. xBlockWasAborted is
|
||||||
|
set to pdTRUE so the medium priority task knows that its failure to
|
||||||
|
obtain the semaphore is not an error. */
|
||||||
|
xBlockWasAborted = pdTRUE;
|
||||||
|
if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This time no other tasks are waiting for the mutex, so this task
|
||||||
|
should return to its base priority. This might not happen straight
|
||||||
|
away as it is running at the same priority as the task it just
|
||||||
|
unblocked. */
|
||||||
|
while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
|
||||||
|
{
|
||||||
|
/* If this task gets stuck here then the check variables will stop
|
||||||
|
incrementing and the check task will detect the error. */
|
||||||
|
vTaskDelay( genqSHORT_BLOCK );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Give the semaphore back ready for the next test. */
|
||||||
|
xSemaphoreGive( xMutex );
|
||||||
|
|
||||||
|
configASSERT( xErrorDetected == pdFALSE );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Now do the same again, but this time unsuspend the tasks in the
|
||||||
|
opposite order. This takes a different path though the code because
|
||||||
|
when the high priority task has its block aborted there is already
|
||||||
|
another task in the list of tasks waiting for the mutex, and the
|
||||||
|
low priority task drops down to that priority, rather than dropping
|
||||||
|
down to its base priority before inheriting the priority of the medium
|
||||||
|
priority task. */
|
||||||
|
if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This time unsuspend the medium priority task first. This will
|
||||||
|
attempt to take the mutex, and block when it finds it cannot obtain it. */
|
||||||
|
vTaskResume( xSecondMediumPriorityMutexTask );
|
||||||
|
|
||||||
|
/* This time this task should now have inherited the priority of the
|
||||||
|
medium task. */
|
||||||
|
if( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This time the high priority task in unsuspended second. */
|
||||||
|
vTaskResume( xHighPriorityMutexTask );
|
||||||
|
|
||||||
|
/* The high priority task should already have run, causing this task to
|
||||||
|
inherit a priority for the second time. */
|
||||||
|
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This time, when the high priority task has its delay aborted and it
|
||||||
|
fails to obtain the mutex this task will immediately have its priority
|
||||||
|
lowered down to that of the highest priority task waiting on the mutex,
|
||||||
|
which is the medium priority task. */
|
||||||
|
xBlockWasAborted = pdTRUE;
|
||||||
|
if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )
|
||||||
|
{
|
||||||
|
/* If this task gets stuck here then the check variables will stop
|
||||||
|
incrementing and the check task will detect the error. */
|
||||||
|
vTaskDelay( genqSHORT_BLOCK );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And finally, when the medium priority task also have its delay
|
||||||
|
aborted there are no other tasks waiting for the mutex so this task
|
||||||
|
returns to its base priority. */
|
||||||
|
xBlockWasAborted = pdTRUE;
|
||||||
|
if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS )
|
||||||
|
{
|
||||||
|
xErrorDetected = pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
|
||||||
|
{
|
||||||
|
/* If this task gets stuck here then the check variables will stop
|
||||||
|
incrementing and the check task will detect the error. */
|
||||||
|
vTaskDelay( genqSHORT_BLOCK );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Give the semaphore back ready for the next test. */
|
||||||
|
xSemaphoreGive( xMutex );
|
||||||
|
|
||||||
|
configASSERT( xErrorDetected == pdFALSE );
|
||||||
|
|
||||||
|
/* uxLoopCount is used to add a variable delay, and in-so-doing provide
|
||||||
|
additional code coverage. */
|
||||||
|
uxLoopCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* INCLUDE_xTaskAbortDelay == 1 */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )
|
static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )
|
||||||
{
|
{
|
||||||
/* Take the mutex. It should be available now. */
|
/* Take the mutex. It should be available now. */
|
||||||
|
@ -455,8 +691,9 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S
|
||||||
}
|
}
|
||||||
#endif /* INCLUDE_eTaskGetState */
|
#endif /* INCLUDE_eTaskGetState */
|
||||||
|
|
||||||
/* The priority of the high priority task should now have been inherited
|
/* This task should now have inherited the priority of the high priority
|
||||||
as by now it will have attempted to get the mutex. */
|
task as by now the high priority task will have attempted to obtain the
|
||||||
|
mutex. */
|
||||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||||
{
|
{
|
||||||
xErrorDetected = pdTRUE;
|
xErrorDetected = pdTRUE;
|
||||||
|
@ -585,8 +822,9 @@ static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, Semaph
|
||||||
}
|
}
|
||||||
#endif /* INCLUDE_eTaskGetState */
|
#endif /* INCLUDE_eTaskGetState */
|
||||||
|
|
||||||
/* The priority of the high priority task should now have been inherited
|
/* This task should now have inherited the priority of the high priority
|
||||||
as by now it will have attempted to get the mutex. */
|
task as by now the high priority task will have attempted to obtain the
|
||||||
|
mutex. */
|
||||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||||
{
|
{
|
||||||
xErrorDetected = pdTRUE;
|
xErrorDetected = pdTRUE;
|
||||||
|
@ -708,6 +946,15 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;
|
||||||
#if configUSE_PREEMPTION == 0
|
#if configUSE_PREEMPTION == 0
|
||||||
taskYIELD();
|
taskYIELD();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||||
|
{
|
||||||
|
/* Tests the behaviour when a low priority task inherits the
|
||||||
|
priority of a high priority task only for the high priority task to
|
||||||
|
timeout before obtaining the mutex. */
|
||||||
|
prvHighPriorityTimeout( xMutex );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
@ -740,14 +987,24 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;
|
||||||
priority task will unsuspend this task when required. */
|
priority task will unsuspend this task when required. */
|
||||||
vTaskSuspend( NULL );
|
vTaskSuspend( NULL );
|
||||||
|
|
||||||
/* When this task unsuspends all it does is attempt to obtain
|
/* When this task unsuspends all it does is attempt to obtain the
|
||||||
the mutex. It should find the mutex is not available so a
|
mutex. It should find the mutex is not available so a block time is
|
||||||
block time is specified. */
|
specified. */
|
||||||
if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
|
if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
|
||||||
|
{
|
||||||
|
/* This task would expect to obtain the mutex unless its wait for
|
||||||
|
the mutex was aborted. */
|
||||||
|
if( xBlockWasAborted == pdFALSE )
|
||||||
{
|
{
|
||||||
xErrorDetected = pdTRUE;
|
xErrorDetected = pdTRUE;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xBlockWasAborted = pdFALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* When the mutex is eventually obtained it is just given back before
|
/* When the mutex is eventually obtained it is just given back before
|
||||||
returning to suspend ready for the next cycle. */
|
returning to suspend ready for the next cycle. */
|
||||||
if( xSemaphoreGive( xMutex ) != pdPASS )
|
if( xSemaphoreGive( xMutex ) != pdPASS )
|
||||||
|
@ -755,6 +1012,7 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;
|
||||||
xErrorDetected = pdTRUE;
|
xErrorDetected = pdTRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,7 @@ static void prvRecursiveMutexPollingTask( void *pvParameters )
|
||||||
|
|
||||||
for( ;; )
|
for( ;; )
|
||||||
{
|
{
|
||||||
/* Keep attempting to obtain the mutex. We should only obtain it when
|
/* Keep attempting to obtain the mutex. It should only be obtained when
|
||||||
the blocking task has suspended itself, which in turn should only
|
the blocking task has suspended itself, which in turn should only
|
||||||
happen when the controlling task is also suspended. */
|
happen when the controlling task is also suspended. */
|
||||||
if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )
|
if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )
|
||||||
|
|
|
@ -205,7 +205,7 @@ typedef struct xMINI_LIST_ITEM MiniListItem_t;
|
||||||
typedef struct xLIST
|
typedef struct xLIST
|
||||||
{
|
{
|
||||||
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
configLIST_VOLATILE UBaseType_t uxNumberOfItems;
|
volatile UBaseType_t uxNumberOfItems;
|
||||||
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
|
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
|
||||||
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
|
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
|
||||||
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
|
|
|
@ -2311,6 +2311,16 @@ BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_F
|
||||||
*/
|
*/
|
||||||
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
|
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a higher priority task attempting to obtain a mutex caused a lower
|
||||||
|
* priority task to inherit the higher priority task's priority - but the higher
|
||||||
|
* priority task then timed out without obtaining the mutex, then the lower
|
||||||
|
* priority task will disinherit the priority again - but only down as far as
|
||||||
|
* the highest priority task that is still waiting for the mutex (if there were
|
||||||
|
* more than one task waiting for the mutex).
|
||||||
|
*/
|
||||||
|
void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the uxTCBNumber assigned to the task referenced by the xTask parameter.
|
* Get the uxTCBNumber assigned to the task referenced by the xTask parameter.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -255,6 +255,16 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
|
||||||
static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION;
|
static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if( configUSE_MUTEXES == 1 )
|
||||||
|
/*
|
||||||
|
* If a task waiting for a mutex causes the mutex holder to inherit a
|
||||||
|
* priority, but the waiting task times out, then the holder should
|
||||||
|
* disinherit the priority - but only down to the highest priority of any
|
||||||
|
* other tasks that are waiting for the same mutex. This function returns
|
||||||
|
* that priority.
|
||||||
|
*/
|
||||||
|
static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1408,6 +1418,10 @@ BaseType_t xEntryTimeSet = pdFALSE;
|
||||||
TimeOut_t xTimeOut;
|
TimeOut_t xTimeOut;
|
||||||
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
|
|
||||||
|
#if( configUSE_MUTEXES == 1 )
|
||||||
|
BaseType_t xInheritanceOccurred = pdFALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Check the queue pointer is not NULL. */
|
/* Check the queue pointer is not NULL. */
|
||||||
configASSERT( ( pxQueue ) );
|
configASSERT( ( pxQueue ) );
|
||||||
|
|
||||||
|
@ -1485,6 +1499,11 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
{
|
{
|
||||||
if( xTicksToWait == ( TickType_t ) 0 )
|
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. */
|
||||||
|
configASSERT( xInheritanceOccurred == pdFALSE );
|
||||||
|
|
||||||
/* The semaphore count was 0 and no block time is specified
|
/* The semaphore count was 0 and no block time is specified
|
||||||
(or the block time has expired) so exit now. */
|
(or the block time has expired) so exit now. */
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
|
@ -1530,7 +1549,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
{
|
{
|
||||||
taskENTER_CRITICAL();
|
taskENTER_CRITICAL();
|
||||||
{
|
{
|
||||||
xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
|
xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
|
||||||
}
|
}
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
}
|
}
|
||||||
|
@ -1572,6 +1591,30 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
queue being empty is equivalent to the semaphore count being 0. */
|
queue being empty is equivalent to the semaphore count being 0. */
|
||||||
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
|
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( ( void * ) pxQueue->pxMutexHolder, uxHighestWaitingPriority );
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configUSE_MUTEXES */
|
||||||
|
|
||||||
traceQUEUE_RECEIVE_FAILED( pxQueue );
|
traceQUEUE_RECEIVE_FAILED( pxQueue );
|
||||||
return errQUEUE_EMPTY;
|
return errQUEUE_EMPTY;
|
||||||
}
|
}
|
||||||
|
@ -1997,6 +2040,33 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
#endif /* configUSE_TRACE_FACILITY */
|
#endif /* configUSE_TRACE_FACILITY */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( configUSE_MUTEXES == 1 )
|
||||||
|
|
||||||
|
static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue )
|
||||||
|
{
|
||||||
|
UBaseType_t uxHighestPriorityOfWaitingTasks;
|
||||||
|
|
||||||
|
/* If a task waiting for a mutex causes the mutex holder to inherit a
|
||||||
|
priority, but the waiting task times out, then the holder should
|
||||||
|
disinherit the priority - but only down to the highest priority of any
|
||||||
|
other tasks that are waiting for the same mutex. For this purpose,
|
||||||
|
return the priority of the highest priority task that is waiting for the
|
||||||
|
mutex. */
|
||||||
|
if( listCURRENT_LIST_LENGTH( &( pxQueue->xTasksWaitingToReceive ) ) > 0 )
|
||||||
|
{
|
||||||
|
uxHighestPriorityOfWaitingTasks = configMAX_PRIORITIES - listGET_ITEM_VALUE_OF_HEAD_ENTRY( &( pxQueue->xTasksWaitingToReceive ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uxHighestPriorityOfWaitingTasks = tskIDLE_PRIORITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uxHighestPriorityOfWaitingTasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configUSE_MUTEXES */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition )
|
static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition )
|
||||||
{
|
{
|
||||||
BaseType_t xReturn = pdFALSE;
|
BaseType_t xReturn = pdFALSE;
|
||||||
|
|
|
@ -164,6 +164,12 @@ set then don't fill the stack so there is no unnecessary dependency on memset. *
|
||||||
#define static
|
#define static
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* The name allocated to the Idle task. This can be overridden by defining
|
||||||
|
tskIDLE_TASK_NAME in FreeRTOSConfig.h. */
|
||||||
|
#ifndef tskIDLE_TASK_NAME
|
||||||
|
#define tskIDLE_TASK_NAME "IDLE"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
|
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
|
||||||
|
|
||||||
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
|
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
|
||||||
|
@ -713,7 +719,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
|
#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) )
|
||||||
|
|
||||||
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
|
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
|
||||||
{
|
{
|
||||||
|
@ -1610,14 +1616,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the task is in the blocked or suspended list we need do
|
/* If the task is in the blocked or suspended list we need do
|
||||||
nothing more than change it's priority variable. However, if
|
nothing more than change its priority variable. However, if
|
||||||
the task is in a ready list it needs to be removed and placed
|
the task is in a ready list it needs to be removed and placed
|
||||||
in the list appropriate to its new priority. */
|
in the list appropriate to its new priority. */
|
||||||
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
|
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
|
||||||
{
|
{
|
||||||
/* The task is currently in its ready list - remove before adding
|
/* The task is currently in its ready list - remove before
|
||||||
it to it's new ready list. As we are in a critical section we
|
adding it to it's new ready list. As we are in a critical
|
||||||
can do this even if the scheduler is suspended. */
|
section we can do this even if the scheduler is suspended. */
|
||||||
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
||||||
{
|
{
|
||||||
/* It is known that the task is in its ready list so
|
/* It is known that the task is in its ready list so
|
||||||
|
@ -1944,7 +1950,7 @@ BaseType_t xReturn;
|
||||||
address of the RAM then create the idle task. */
|
address of the RAM then create the idle task. */
|
||||||
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
|
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
|
||||||
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
|
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
|
||||||
"IDLE",
|
tskIDLE_TASK_NAME,
|
||||||
ulIdleTaskStackSize,
|
ulIdleTaskStackSize,
|
||||||
( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
|
( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
|
||||||
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
|
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
|
||||||
|
@ -1964,7 +1970,8 @@ BaseType_t xReturn;
|
||||||
{
|
{
|
||||||
/* The Idle task is being created using dynamically allocated RAM. */
|
/* The Idle task is being created using dynamically allocated RAM. */
|
||||||
xReturn = xTaskCreate( prvIdleTask,
|
xReturn = xTaskCreate( prvIdleTask,
|
||||||
"IDLE", configMINIMAL_STACK_SIZE,
|
tskIDLE_TASK_NAME,
|
||||||
|
configMINIMAL_STACK_SIZE,
|
||||||
( void * ) NULL,
|
( void * ) NULL,
|
||||||
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
|
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
|
||||||
&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
|
&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
|
||||||
|
@ -2545,7 +2552,7 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
|
||||||
BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
|
BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
|
||||||
{
|
{
|
||||||
TCB_t *pxTCB = ( TCB_t * ) xTask;
|
TCB_t *pxTCB = ( TCB_t * ) xTask;
|
||||||
BaseType_t xReturn = pdFALSE;
|
BaseType_t xReturn;
|
||||||
|
|
||||||
configASSERT( pxTCB );
|
configASSERT( pxTCB );
|
||||||
|
|
||||||
|
@ -2555,6 +2562,8 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
|
||||||
it is actually in the Blocked state. */
|
it is actually in the Blocked state. */
|
||||||
if( eTaskGetState( xTask ) == eBlocked )
|
if( eTaskGetState( xTask ) == eBlocked )
|
||||||
{
|
{
|
||||||
|
xReturn = pdPASS;
|
||||||
|
|
||||||
/* Remove the reference to the task from the blocked list. An
|
/* Remove the reference to the task from the blocked list. An
|
||||||
interrupt won't touch the xStateListItem because the
|
interrupt won't touch the xStateListItem because the
|
||||||
scheduler is suspended. */
|
scheduler is suspended. */
|
||||||
|
@ -2603,7 +2612,7 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mtCOVERAGE_TEST_MARKER();
|
xReturn = pdFAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
( void ) xTaskResumeAll();
|
( void ) xTaskResumeAll();
|
||||||
|
@ -3130,6 +3139,7 @@ BaseType_t xReturn;
|
||||||
{
|
{
|
||||||
/* Minor optimisation. The tick count cannot change in this block. */
|
/* Minor optimisation. The tick count cannot change in this block. */
|
||||||
const TickType_t xConstTickCount = xTickCount;
|
const TickType_t xConstTickCount = xTickCount;
|
||||||
|
const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering;
|
||||||
|
|
||||||
#if( INCLUDE_xTaskAbortDelay == 1 )
|
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||||
if( pxCurrentTCB->ucDelayAborted != pdFALSE )
|
if( pxCurrentTCB->ucDelayAborted != pdFALSE )
|
||||||
|
@ -3162,10 +3172,10 @@ BaseType_t xReturn;
|
||||||
was called. */
|
was called. */
|
||||||
xReturn = pdTRUE;
|
xReturn = pdTRUE;
|
||||||
}
|
}
|
||||||
else if( ( ( TickType_t ) ( xConstTickCount - pxTimeOut->xTimeOnEntering ) ) < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */
|
else if( xElapsedTime < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */
|
||||||
{
|
{
|
||||||
/* Not a genuine timeout. Adjust parameters for time remaining. */
|
/* Not a genuine timeout. Adjust parameters for time remaining. */
|
||||||
*pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering );
|
*pxTicksToWait -= xElapsedTime;
|
||||||
vTaskSetTimeOutState( pxTimeOut );
|
vTaskSetTimeOutState( pxTimeOut );
|
||||||
xReturn = pdFALSE;
|
xReturn = pdFALSE;
|
||||||
}
|
}
|
||||||
|
@ -3817,25 +3827,25 @@ TCB_t *pxTCB;
|
||||||
|
|
||||||
BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
|
BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
|
||||||
{
|
{
|
||||||
TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
|
TCB_t * const pxMutexHolderTCB = ( TCB_t * ) pxMutexHolder;
|
||||||
BaseType_t xReturn = pdFALSE;
|
BaseType_t xReturn = pdFALSE;
|
||||||
|
|
||||||
/* If the mutex was given back by an interrupt while the queue was
|
/* If the mutex was given back by an interrupt while the queue was
|
||||||
locked then the mutex holder might now be NULL. _RB_ Is this still
|
locked then the mutex holder might now be NULL. _RB_ Is this still
|
||||||
needed as interrupt can no longer use mutexes? */
|
needed as interrupts can no longer use mutexes? */
|
||||||
if( pxMutexHolder != NULL )
|
if( pxMutexHolder != NULL )
|
||||||
{
|
{
|
||||||
/* If the holder of the mutex has a priority below the priority of
|
/* If the holder of the mutex has a priority below the priority of
|
||||||
the task attempting to obtain the mutex then it will temporarily
|
the task attempting to obtain the mutex then it will temporarily
|
||||||
inherit the priority of the task attempting to obtain the mutex. */
|
inherit the priority of the task attempting to obtain the mutex. */
|
||||||
if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
|
if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority )
|
||||||
{
|
{
|
||||||
/* Adjust the mutex holder state to account for its new
|
/* Adjust the mutex holder state to account for its new
|
||||||
priority. Only reset the event list item value if the value is
|
priority. Only reset the event list item value if the value is
|
||||||
not being used for anything else. */
|
not being used for anything else. */
|
||||||
if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
|
if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
|
||||||
{
|
{
|
||||||
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3844,11 +3854,11 @@ TCB_t *pxTCB;
|
||||||
|
|
||||||
/* If the task being modified is in the ready state it will need
|
/* If the task being modified is in the ready state it will need
|
||||||
to be moved into a new list. */
|
to be moved into a new list. */
|
||||||
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
|
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE )
|
||||||
{
|
{
|
||||||
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
||||||
{
|
{
|
||||||
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
|
taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3856,25 +3866,39 @@ TCB_t *pxTCB;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inherit the priority before being moved into the new list. */
|
/* Inherit the priority before being moved into the new list. */
|
||||||
pxTCB->uxPriority = pxCurrentTCB->uxPriority;
|
pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
|
||||||
prvAddTaskToReadyList( pxTCB );
|
prvAddTaskToReadyList( pxMutexHolderTCB );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Just inherit the priority. */
|
/* Just inherit the priority. */
|
||||||
pxTCB->uxPriority = pxCurrentTCB->uxPriority;
|
pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );
|
traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCB->uxPriority );
|
||||||
|
|
||||||
/* Inheritance occurred. */
|
/* Inheritance occurred. */
|
||||||
xReturn = pdTRUE;
|
xReturn = pdTRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority )
|
||||||
|
{
|
||||||
|
/* The base priority of the mutex holder is lower than the
|
||||||
|
priority of the task attempting to take the mutex, but the
|
||||||
|
current priority of the mutex holder is not lower than the
|
||||||
|
priority of the task attempting to take the mutex.
|
||||||
|
Therefore the mutex holder must have already inherited a
|
||||||
|
priority, but inheritance would have occurred if that had
|
||||||
|
not been the case. */
|
||||||
|
xReturn = pdTRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
mtCOVERAGE_TEST_MARKER();
|
mtCOVERAGE_TEST_MARKER();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mtCOVERAGE_TEST_MARKER();
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
@ -3900,7 +3924,6 @@ TCB_t *pxTCB;
|
||||||
interrupt, and if a mutex is given by the holding task then it must
|
interrupt, and if a mutex is given by the holding task then it must
|
||||||
be the running state task. */
|
be the running state task. */
|
||||||
configASSERT( pxTCB == pxCurrentTCB );
|
configASSERT( pxTCB == pxCurrentTCB );
|
||||||
|
|
||||||
configASSERT( pxTCB->uxMutexesHeld );
|
configASSERT( pxTCB->uxMutexesHeld );
|
||||||
( pxTCB->uxMutexesHeld )--;
|
( pxTCB->uxMutexesHeld )--;
|
||||||
|
|
||||||
|
@ -3967,6 +3990,108 @@ TCB_t *pxTCB;
|
||||||
#endif /* configUSE_MUTEXES */
|
#endif /* configUSE_MUTEXES */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configUSE_MUTEXES == 1 )
|
||||||
|
|
||||||
|
void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask )
|
||||||
|
{
|
||||||
|
TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
|
||||||
|
UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse;
|
||||||
|
const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1;
|
||||||
|
|
||||||
|
if( pxMutexHolder != NULL )
|
||||||
|
{
|
||||||
|
/* If pxMutexHolder is not NULL then the holder must hold at least
|
||||||
|
one mutex. */
|
||||||
|
configASSERT( pxTCB->uxMutexesHeld );
|
||||||
|
|
||||||
|
/* Determine the priority to which the priority of the task that
|
||||||
|
holds the mutex should be set. This will be the greater of the
|
||||||
|
holding task's base priority and the priority of the highest
|
||||||
|
priority task that is waiting to obtain the mutex. */
|
||||||
|
if( pxTCB->uxBasePriority < uxHighestPriorityWaitingTask )
|
||||||
|
{
|
||||||
|
uxPriorityToUse = uxHighestPriorityWaitingTask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uxPriorityToUse = pxTCB->uxBasePriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does the priority need to change? */
|
||||||
|
if( pxTCB->uxPriority != uxPriorityToUse )
|
||||||
|
{
|
||||||
|
/* Only disinherit if no other mutexes are held. This is a
|
||||||
|
simplification in the priority inheritance implementation. If
|
||||||
|
the task that holds the mutex is also holding other mutexes then
|
||||||
|
the other mutexes may have caused the priority inheritance. */
|
||||||
|
if( pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld )
|
||||||
|
{
|
||||||
|
/* If a task has timed out because it already holds the
|
||||||
|
mutex it was trying to obtain then it cannot of inherited
|
||||||
|
its own priority. */
|
||||||
|
configASSERT( pxTCB != pxCurrentTCB );
|
||||||
|
|
||||||
|
/* Disinherit the priority, remembering the previous
|
||||||
|
priority to facilitate determining the subject task's
|
||||||
|
state. */
|
||||||
|
traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
|
||||||
|
uxPriorityUsedOnEntry = pxTCB->uxPriority;
|
||||||
|
pxTCB->uxPriority = uxPriorityToUse;
|
||||||
|
|
||||||
|
/* Only reset the event list item value if the value is not
|
||||||
|
being used for anything else. */
|
||||||
|
if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
|
||||||
|
{
|
||||||
|
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriorityToUse ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the running task is not the task that holds the mutex
|
||||||
|
then the task that holds the mutex could be in either the
|
||||||
|
Ready, Blocked or Suspended states. Only remove the task
|
||||||
|
from its current state list if it is in the Ready state as
|
||||||
|
the task's priority is going to change and there is one
|
||||||
|
Ready list per priority. */
|
||||||
|
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
|
||||||
|
{
|
||||||
|
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
||||||
|
{
|
||||||
|
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
prvAddTaskToReadyList( pxTCB );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configUSE_MUTEXES */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||||
|
|
||||||
void vTaskEnterCritical( void )
|
void vTaskEnterCritical( void )
|
||||||
|
|
|
@ -100,6 +100,12 @@ configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
|
||||||
/* Misc definitions. */
|
/* Misc definitions. */
|
||||||
#define tmrNO_DELAY ( TickType_t ) 0U
|
#define tmrNO_DELAY ( TickType_t ) 0U
|
||||||
|
|
||||||
|
/* The name assigned to the timer service task. This can be overridden by
|
||||||
|
defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
|
||||||
|
#ifndef tmrTIMER_SERVICE_TASK_NAME
|
||||||
|
#define tmrTIMER_SERVICE_TASK_NAME "Tmr Svc"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The definition of the timers themselves. */
|
/* The definition of the timers themselves. */
|
||||||
typedef struct tmrTimerControl
|
typedef struct tmrTimerControl
|
||||||
{
|
{
|
||||||
|
@ -276,7 +282,7 @@ BaseType_t xReturn = pdFAIL;
|
||||||
|
|
||||||
vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
|
vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
|
||||||
xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
|
xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
|
||||||
"Tmr Svc",
|
tmrTIMER_SERVICE_TASK_NAME,
|
||||||
ulTimerTaskStackSize,
|
ulTimerTaskStackSize,
|
||||||
NULL,
|
NULL,
|
||||||
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
||||||
|
@ -291,7 +297,7 @@ BaseType_t xReturn = pdFAIL;
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
xReturn = xTaskCreate( prvTimerTask,
|
xReturn = xTaskCreate( prvTimerTask,
|
||||||
"Tmr Svc",
|
tmrTIMER_SERVICE_TASK_NAME,
|
||||||
configTIMER_TASK_STACK_DEPTH,
|
configTIMER_TASK_STACK_DEPTH,
|
||||||
NULL,
|
NULL,
|
||||||
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
||||||
|
|
Loading…
Reference in a new issue