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:
Richard Barry 2017-01-16 03:58:51 +00:00
parent 883541bc8e
commit d67dcf9c74
7 changed files with 521 additions and 52 deletions

View File

@ -91,6 +91,7 @@
#define genqQUEUE_LENGTH ( 5 )
#define intsemNO_BLOCK ( 0 )
#define genqSHORT_BLOCK ( pdMS_TO_TICKS( 2 ) )
#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
@ -125,6 +126,27 @@ static void prvLowPriorityMutexTask( void *pvParameters );
static void prvMediumPriorityMutexTask( 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
@ -143,6 +165,17 @@ static volatile uint32_t ulGuardedVariable = 0;
priority mutex test tasks. */
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 )
@ -189,13 +222,21 @@ SemaphoreHandle_t xMutex;
xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
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 )
{
uint32_t ulData, ulData2;
uint32_t ulData, ulData2, ulLoopCounterSnapshot;
QueueHandle_t xQueue;
#ifdef USE_STDIO
@ -215,7 +256,8 @@ QueueHandle_t xQueue;
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. */
xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );
ulLoopCounterSnapshot = ulLoopCounter;
xQueueSendToFront( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK );
if( uxQueueMessagesWaiting( xQueue ) != 1 )
{
@ -241,7 +283,8 @@ QueueHandle_t xQueue;
xErrorDetected = pdTRUE;
}
xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );
ulLoopCounterSnapshot = ulLoopCounter;
xQueueSendToBack( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK );
if( uxQueueMessagesWaiting( xQueue ) != 1 )
{
@ -258,8 +301,8 @@ QueueHandle_t xQueue;
xErrorDetected = pdTRUE;
}
/* The data we sent to the queue should equal the data we just received
from the queue. */
/* The data sent to the queue should equal the data just received from
the queue. */
if( ulLoopCounter != ulData )
{
xErrorDetected = pdTRUE;
@ -416,11 +459,204 @@ QueueHandle_t xQueue;
xErrorDetected = pdTRUE;
}
/* Increment the loop counter to indicate these tasks are still
executing. */
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 )
{
/* Take the mutex. It should be available now. */
@ -455,15 +691,16 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S
}
#endif /* INCLUDE_eTaskGetState */
/* The priority of the high priority task should now have been inherited
as by now it will have attempted to get the mutex. */
/* 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;
}
/* Attempt to set the priority of this task to the test priority -
between the idle priority and the medium/high test priorities, but the
between the idle priority and the medium/high test priorities, but the
actual priority should remain at the high priority. */
vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
@ -585,8 +822,9 @@ static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, Semaph
}
#endif /* INCLUDE_eTaskGetState */
/* The priority of the high priority task should now have been inherited
as by now it will have attempted to get the mutex. */
/* 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;
@ -708,6 +946,15 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;
#if configUSE_PREEMPTION == 0
taskYIELD();
#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,19 +987,30 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;
priority task will unsuspend this task when required. */
vTaskSuspend( NULL );
/* When this task unsuspends all it does is attempt to obtain
the mutex. It should find the mutex is not available so a
block time is specified. */
/* When this task unsuspends all it does is attempt to obtain the
mutex. It should find the mutex is not available so a block time is
specified. */
if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
{
xErrorDetected = pdTRUE;
/* This task would expect to obtain the mutex unless its wait for
the mutex was aborted. */
if( xBlockWasAborted == pdFALSE )
{
xErrorDetected = pdTRUE;
}
else
{
xBlockWasAborted = pdFALSE;
}
}
/* When the mutex is eventually obtained it is just given back before
returning to suspend ready for the next cycle. */
if( xSemaphoreGive( xMutex ) != pdPASS )
else
{
xErrorDetected = pdTRUE;
/* When the mutex is eventually obtained it is just given back before
returning to suspend ready for the next cycle. */
if( xSemaphoreGive( xMutex ) != pdPASS )
{
xErrorDetected = pdTRUE;
}
}
}
}

View File

@ -314,7 +314,7 @@ static void prvRecursiveMutexPollingTask( void *pvParameters )
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
happen when the controlling task is also suspended. */
if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )

View File

@ -205,7 +205,7 @@ typedef struct xMINI_LIST_ITEM MiniListItem_t;
typedef struct xLIST
{
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 (). */
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. */

View File

@ -2311,6 +2311,16 @@ BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_F
*/
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.
*/

View File

@ -255,6 +255,16 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION;
#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;
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
#if( configUSE_MUTEXES == 1 )
BaseType_t xInheritanceOccurred = pdFALSE;
#endif
/* Check the queue pointer is not NULL. */
configASSERT( ( pxQueue ) );
@ -1485,6 +1499,11 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
{
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
(or the block time has expired) so exit now. */
taskEXIT_CRITICAL();
@ -1530,7 +1549,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
{
taskENTER_CRITICAL();
{
xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
}
taskEXIT_CRITICAL();
}
@ -1572,6 +1591,30 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
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( ( void * ) pxQueue->pxMutexHolder, uxHighestWaitingPriority );
}
taskEXIT_CRITICAL();
}
}
#endif /* configUSE_MUTEXES */
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
}
@ -1997,6 +2040,33 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
#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 )
{
BaseType_t xReturn = pdFALSE;

View File

@ -164,6 +164,12 @@ set then don't fill the stack so there is no unnecessary dependency on memset. *
#define static
#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 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 ) */
/*-----------------------------------------------------------*/
#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 )
{
@ -1610,14 +1616,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
}
/* 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
in the list appropriate to its new priority. */
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
{
/* The task is currently in its ready list - remove before adding
it to it's new ready list. As we are in a critical section we
can do this even if the scheduler is suspended. */
/* The task is currently in its ready list - remove before
adding it to it's new ready list. As we are in a critical
section we can do this even if the scheduler is suspended. */
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
/* 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. */
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
"IDLE",
tskIDLE_TASK_NAME,
ulIdleTaskStackSize,
( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
@ -1964,7 +1970,8 @@ BaseType_t xReturn;
{
/* The Idle task is being created using dynamically allocated RAM. */
xReturn = xTaskCreate( prvIdleTask,
"IDLE", configMINIMAL_STACK_SIZE,
tskIDLE_TASK_NAME,
configMINIMAL_STACK_SIZE,
( void * ) NULL,
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
&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 )
{
TCB_t *pxTCB = ( TCB_t * ) xTask;
BaseType_t xReturn = pdFALSE;
BaseType_t xReturn;
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. */
if( eTaskGetState( xTask ) == eBlocked )
{
xReturn = pdPASS;
/* Remove the reference to the task from the blocked list. An
interrupt won't touch the xStateListItem because the
scheduler is suspended. */
@ -2603,7 +2612,7 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
}
else
{
mtCOVERAGE_TEST_MARKER();
xReturn = pdFAIL;
}
}
( void ) xTaskResumeAll();
@ -3130,6 +3139,7 @@ BaseType_t xReturn;
{
/* Minor optimisation. The tick count cannot change in this block. */
const TickType_t xConstTickCount = xTickCount;
const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering;
#if( INCLUDE_xTaskAbortDelay == 1 )
if( pxCurrentTCB->ucDelayAborted != pdFALSE )
@ -3162,10 +3172,10 @@ BaseType_t xReturn;
was called. */
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. */
*pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering );
*pxTicksToWait -= xElapsedTime;
vTaskSetTimeOutState( pxTimeOut );
xReturn = pdFALSE;
}
@ -3817,25 +3827,25 @@ TCB_t *pxTCB;
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;
/* 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
needed as interrupt can no longer use mutexes? */
needed as interrupts can no longer use mutexes? */
if( pxMutexHolder != NULL )
{
/* If the holder of the mutex has a priority below the priority of
the task attempting to obtain the mutex then it will temporarily
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
priority. 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 )
not being used for anything else. */
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
{
@ -3844,11 +3854,11 @@ TCB_t *pxTCB;
/* If the task being modified is in the ready state it will need
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
{
@ -3856,23 +3866,37 @@ TCB_t *pxTCB;
}
/* Inherit the priority before being moved into the new list. */
pxTCB->uxPriority = pxCurrentTCB->uxPriority;
prvAddTaskToReadyList( pxTCB );
pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
prvAddTaskToReadyList( pxMutexHolderTCB );
}
else
{
/* 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. */
xReturn = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
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();
}
}
}
else
@ -3900,7 +3924,6 @@ TCB_t *pxTCB;
interrupt, and if a mutex is given by the holding task then it must
be the running state task. */
configASSERT( pxTCB == pxCurrentTCB );
configASSERT( pxTCB->uxMutexesHeld );
( pxTCB->uxMutexesHeld )--;
@ -3914,8 +3937,8 @@ TCB_t *pxTCB;
/* A task can only have an inherited priority if it holds
the mutex. If the mutex is held by a task then it cannot be
given from an interrupt, and if a mutex is given by the
holding task then it must be the running state task. Remove
the holding task from the ready list. */
holding task then it must be the running state task. Remove
the holding task from the ready list. */
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
@ -3967,6 +3990,108 @@ TCB_t *pxTCB;
#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 )
void vTaskEnterCritical( void )

View File

@ -100,6 +100,12 @@ configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
/* Misc definitions. */
#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. */
typedef struct tmrTimerControl
{
@ -276,7 +282,7 @@ BaseType_t xReturn = pdFAIL;
vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
"Tmr Svc",
tmrTIMER_SERVICE_TASK_NAME,
ulTimerTaskStackSize,
NULL,
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
@ -291,7 +297,7 @@ BaseType_t xReturn = pdFAIL;
#else
{
xReturn = xTaskCreate( prvTimerTask,
"Tmr Svc",
tmrTIMER_SERVICE_TASK_NAME,
configTIMER_TASK_STACK_DEPTH,
NULL,
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,