\r
#define genqQUEUE_LENGTH ( 5 )\r
#define intsemNO_BLOCK ( 0 )\r
+#define genqSHORT_BLOCK ( pdMS_TO_TICKS( 2 ) )\r
\r
#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )\r
#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
static void prvMediumPriorityMutexTask( void *pvParameters );\r
static void prvHighPriorityMutexTask( void *pvParameters );\r
\r
+/*\r
+ * Tests the behaviour when a low priority task inherits the priority of a\r
+ * higher priority task when taking two mutexes, and returns the mutexes in\r
+ * first the same order as the two mutexes were obtained, and second the\r
+ * opposite order as the two mutexes were obtained.\r
+ */\r
+static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex );\r
+static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex );\r
+\r
+#if( INCLUDE_xTaskAbortDelay == 1 )\r
+\r
+ #if( configUSE_PREEMPTION == 0 )\r
+ #error The additional tests included when INCLUDE_xTaskAbortDelay is 1 expect preemption to be used.\r
+ #endif\r
+\r
+ /* Tests the behaviour when a low priority task inherits the priority of a\r
+ high priority task only for the high priority task to timeout before\r
+ obtaining the mutex. */\r
+ static void prvHighPriorityTimeout( SemaphoreHandle_t xMutex );\r
+#endif\r
+\r
/*-----------------------------------------------------------*/\r
\r
/* Flag that will be latched to pdTRUE should any unexpected behaviour be\r
priority mutex test tasks. */\r
static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask;\r
\r
+/* If INCLUDE_xTaskAbortDelay is 1 additional tests are performed, requiring an\r
+additional task. */\r
+#if( INCLUDE_xTaskAbortDelay == 1 )\r
+ static TaskHandle_t xSecondMediumPriorityMutexTask;\r
+#endif\r
+\r
+/* Lets the high priority semaphore task know that its wait for the semaphore\r
+was aborted, in which case not being able to obtain the semaphore is not to be\r
+considered an error. */\r
+static volatile BaseType_t xBlockWasAborted = pdFALSE;\r
+\r
/*-----------------------------------------------------------*/\r
\r
void vStartGenericQueueTasks( UBaseType_t uxPriority )\r
xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );\r
xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );\r
xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );\r
+\r
+ /* If INCLUDE_xTaskAbortDelay is set then additional tests are performed,\r
+ requiring two instances of prvHighPriorityMutexTask(). */\r
+ #if( INCLUDE_xTaskAbortDelay == 1 )\r
+ {\r
+ xTaskCreate( prvHighPriorityMutexTask, "MuHigh2", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_MEDIUM_PRIORITY, &xSecondMediumPriorityMutexTask );\r
+ }\r
+ #endif /* INCLUDE_xTaskAbortDelay */\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
static void prvSendFrontAndBackTest( void *pvParameters )\r
{\r
-uint32_t ulData, ulData2;\r
+uint32_t ulData, ulData2, ulLoopCounterSnapshot;\r
QueueHandle_t xQueue;\r
\r
#ifdef USE_STDIO\r
should have the same efect as sending it to the front of the queue.\r
\r
First send to the front and check everything is as expected. */\r
- xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );\r
+ ulLoopCounterSnapshot = ulLoopCounter;\r
+ xQueueSendToFront( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK );\r
\r
if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
\r
- xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );\r
+ ulLoopCounterSnapshot = ulLoopCounter;\r
+ xQueueSendToBack( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK );\r
\r
if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
\r
- /* The data we sent to the queue should equal the data we just received\r
- from the queue. */\r
+ /* The data sent to the queue should equal the data just received from\r
+ the queue. */\r
if( ulLoopCounter != ulData )\r
{\r
xErrorDetected = pdTRUE;\r
xErrorDetected = pdTRUE;\r
}\r
\r
+ /* Increment the loop counter to indicate these tasks are still\r
+ executing. */\r
ulLoopCounter++;\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
+#if( INCLUDE_xTaskAbortDelay == 1 )\r
+\r
+ static void prvHighPriorityTimeout( SemaphoreHandle_t xMutex )\r
+ {\r
+ static UBaseType_t uxLoopCount = 0;\r
+\r
+ /* The tests in this function are very similar, the slight variations\r
+ are for code coverage purposes. */\r
+\r
+ /* Take the mutex. It should be available now. */\r
+ if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* This task's priority should be as per that assigned when the task was\r
+ created. */\r
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* Now unsuspend the high priority task. This will attempt to take the\r
+ mutex, and block when it finds it cannot obtain it. */\r
+ vTaskResume( xHighPriorityMutexTask );\r
+\r
+ /* This task should now have inherited the priority of the high priority\r
+ task as by now the high priority task will have attempted to obtain the\r
+ mutex. */\r
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* Unblock a second medium priority task. It too will attempt to take\r
+ the mutex and enter the Blocked state - it won't run yet though as this\r
+ task has inherited a priority above it. */\r
+ vTaskResume( xSecondMediumPriorityMutexTask );\r
+\r
+ /* This task should still have the priority of the high priority task as\r
+ that had already been inherited as is the highest priority of the three\r
+ tasks using the mutex. */\r
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* On some loops, block for a short while to provide additional\r
+ code coverage. Blocking here will allow the medium priority task to\r
+ execute and so also block on the mutex so when the high priority task\r
+ causes this task to disinherit the high priority it is inherited down to\r
+ the priority of the medium priority task. When there is no delay the\r
+ medium priority task will not run until after the disinheritance, so\r
+ this task will disinherit back to its base priority, then only up to the\r
+ medium priority after the medium priority has executed. */\r
+ vTaskDelay( uxLoopCount & ( UBaseType_t ) 0x07 );\r
+\r
+ /* Now force the high priority task to unblock. It will fail to obtain\r
+ the mutex and go back to the suspended state - allowing this task to\r
+ execute again. xBlockWasAborted is set to pdTRUE so the higher priority\r
+ task knows that its failure to obtain the semaphore is not an error. */\r
+ xBlockWasAborted = pdTRUE;\r
+ if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* This task has inherited the priority of xHighPriorityMutexTask so\r
+ could still be running even though xHighPriorityMutexTask is no longer\r
+ blocked. Delay for a short while to ensure xHighPriorityMutexTask gets\r
+ a chance to run - indicated by this task changing priority. It should\r
+ disinherit the high priority task, but then inherit the priority of the\r
+ medium priority task that is waiting for the same mutex. */\r
+ while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )\r
+ {\r
+ /* If this task gets stuck here then the check variables will stop\r
+ incrementing and the check task will detect the error. */\r
+ vTaskDelay( genqSHORT_BLOCK );\r
+ }\r
+\r
+ /* Now force the medium priority task to unblock. xBlockWasAborted is\r
+ set to pdTRUE so the medium priority task knows that its failure to\r
+ obtain the semaphore is not an error. */\r
+ xBlockWasAborted = pdTRUE;\r
+ if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* This time no other tasks are waiting for the mutex, so this task\r
+ should return to its base priority. This might not happen straight\r
+ away as it is running at the same priority as the task it just\r
+ unblocked. */\r
+ while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
+ {\r
+ /* If this task gets stuck here then the check variables will stop\r
+ incrementing and the check task will detect the error. */\r
+ vTaskDelay( genqSHORT_BLOCK );\r
+ }\r
+\r
+ /* Give the semaphore back ready for the next test. */\r
+ xSemaphoreGive( xMutex );\r
+\r
+ configASSERT( xErrorDetected == pdFALSE );\r
+\r
+\r
+\r
+ /* Now do the same again, but this time unsuspend the tasks in the\r
+ opposite order. This takes a different path though the code because\r
+ when the high priority task has its block aborted there is already\r
+ another task in the list of tasks waiting for the mutex, and the\r
+ low priority task drops down to that priority, rather than dropping\r
+ down to its base priority before inheriting the priority of the medium\r
+ priority task. */\r
+ if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* This time unsuspend the medium priority task first. This will\r
+ attempt to take the mutex, and block when it finds it cannot obtain it. */\r
+ vTaskResume( xSecondMediumPriorityMutexTask );\r
+\r
+ /* This time this task should now have inherited the priority of the\r
+ medium task. */\r
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* This time the high priority task in unsuspended second. */\r
+ vTaskResume( xHighPriorityMutexTask );\r
+\r
+ /* The high priority task should already have run, causing this task to\r
+ inherit a priority for the second time. */\r
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* This time, when the high priority task has its delay aborted and it\r
+ fails to obtain the mutex this task will immediately have its priority\r
+ lowered down to that of the highest priority task waiting on the mutex,\r
+ which is the medium priority task. */\r
+ xBlockWasAborted = pdTRUE;\r
+ if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )\r
+ {\r
+ /* If this task gets stuck here then the check variables will stop\r
+ incrementing and the check task will detect the error. */\r
+ vTaskDelay( genqSHORT_BLOCK );\r
+ }\r
+\r
+ /* And finally, when the medium priority task also have its delay\r
+ aborted there are no other tasks waiting for the mutex so this task\r
+ returns to its base priority. */\r
+ xBlockWasAborted = pdTRUE;\r
+ if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
+ {\r
+ /* If this task gets stuck here then the check variables will stop\r
+ incrementing and the check task will detect the error. */\r
+ vTaskDelay( genqSHORT_BLOCK );\r
+ }\r
+\r
+ /* Give the semaphore back ready for the next test. */\r
+ xSemaphoreGive( xMutex );\r
+\r
+ configASSERT( xErrorDetected == pdFALSE );\r
+\r
+ /* uxLoopCount is used to add a variable delay, and in-so-doing provide\r
+ additional code coverage. */\r
+ uxLoopCount++;\r
+ }\r
+\r
+#endif /* INCLUDE_xTaskAbortDelay == 1 */\r
+/*-----------------------------------------------------------*/\r
+\r
static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )\r
{\r
/* Take the mutex. It should be available now. */\r
}\r
#endif /* INCLUDE_eTaskGetState */\r
\r
- /* The priority of the high priority task should now have been inherited\r
- as by now it will have attempted to get the mutex. */\r
+ /* This task should now have inherited the priority of the high priority\r
+ task as by now the high priority task will have attempted to obtain the\r
+ mutex. */\r
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
\r
/* Attempt to set the priority of this task to the test priority -\r
- between the idle priority and the medium/high test priorities, but the\r
+ between the idle priority and the medium/high test priorities, but the\r
actual priority should remain at the high priority. */\r
vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );\r
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
}\r
#endif /* INCLUDE_eTaskGetState */\r
\r
- /* The priority of the high priority task should now have been inherited\r
- as by now it will have attempted to get the mutex. */\r
+ /* This task should now have inherited the priority of the high priority\r
+ task as by now the high priority task will have attempted to obtain the\r
+ mutex. */\r
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
{\r
xErrorDetected = pdTRUE;\r
#if configUSE_PREEMPTION == 0\r
taskYIELD();\r
#endif\r
+\r
+ #if( INCLUDE_xTaskAbortDelay == 1 )\r
+ {\r
+ /* Tests the behaviour when a low priority task inherits the\r
+ priority of a high priority task only for the high priority task to\r
+ timeout before obtaining the mutex. */\r
+ prvHighPriorityTimeout( xMutex );\r
+ }\r
+ #endif\r
}\r
}\r
/*-----------------------------------------------------------*/\r
priority task will unsuspend this task when required. */\r
vTaskSuspend( NULL );\r
\r
- /* When this task unsuspends all it does is attempt to obtain\r
- the mutex. It should find the mutex is not available so a\r
- block time is specified. */\r
+ /* When this task unsuspends all it does is attempt to obtain the\r
+ mutex. It should find the mutex is not available so a block time is\r
+ specified. */\r
if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )\r
{\r
- xErrorDetected = pdTRUE;\r
+ /* This task would expect to obtain the mutex unless its wait for\r
+ the mutex was aborted. */\r
+ if( xBlockWasAborted == pdFALSE )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+ else\r
+ {\r
+ xBlockWasAborted = pdFALSE;\r
+ }\r
}\r
-\r
- /* When the mutex is eventually obtained it is just given back before\r
- returning to suspend ready for the next cycle. */\r
- if( xSemaphoreGive( xMutex ) != pdPASS )\r
+ else\r
{\r
- xErrorDetected = pdTRUE;\r
+ /* When the mutex is eventually obtained it is just given back before\r
+ returning to suspend ready for the next cycle. */\r
+ if( xSemaphoreGive( xMutex ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
}\r
}\r
}\r
\r
for( ;; )\r
{\r
- /* Keep attempting to obtain the mutex. We should only obtain it when\r
+ /* Keep attempting to obtain the mutex. It should only be obtained when\r
the blocking task has suspended itself, which in turn should only\r
happen when the controlling task is also suspended. */\r
if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )\r
typedef struct xLIST\r
{\r
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */\r
- configLIST_VOLATILE UBaseType_t uxNumberOfItems;\r
+ volatile UBaseType_t uxNumberOfItems;\r
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 (). */\r
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. */\r
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */\r
*/\r
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;\r
\r
+/*\r
+ * If a higher priority task attempting to obtain a mutex caused a lower\r
+ * priority task to inherit the higher priority task's priority - but the higher\r
+ * priority task then timed out without obtaining the mutex, then the lower\r
+ * priority task will disinherit the priority again - but only down as far as\r
+ * the highest priority task that is still waiting for the mutex (if there were\r
+ * more than one task waiting for the mutex).\r
+ */\r
+void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask ) PRIVILEGED_FUNCTION;\r
+\r
/*\r
* Get the uxTCBNumber assigned to the task referenced by the xTask parameter.\r
*/\r
static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION;\r
#endif\r
\r
+#if( configUSE_MUTEXES == 1 )\r
+ /*\r
+ * If a task waiting for a mutex causes the mutex holder to inherit a\r
+ * priority, but the waiting task times out, then the holder should\r
+ * disinherit the priority - but only down to the highest priority of any\r
+ * other tasks that are waiting for the same mutex. This function returns\r
+ * that priority.\r
+ */\r
+ static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;\r
+#endif\r
/*-----------------------------------------------------------*/\r
\r
/*\r
TimeOut_t xTimeOut;\r
Queue_t * const pxQueue = ( Queue_t * ) xQueue;\r
\r
+#if( configUSE_MUTEXES == 1 )\r
+ BaseType_t xInheritanceOccurred = pdFALSE;\r
+#endif\r
+\r
/* Check the queue pointer is not NULL. */\r
configASSERT( ( pxQueue ) );\r
\r
{\r
if( xTicksToWait == ( TickType_t ) 0 )\r
{\r
+ /* For inheritance to have occurred there must have been an\r
+ initial timeout, and an adjusted timeout cannot become 0, as\r
+ if it were 0 the function would have exited. */\r
+ configASSERT( xInheritanceOccurred == pdFALSE );\r
+\r
/* The semaphore count was 0 and no block time is specified\r
(or the block time has expired) so exit now. */\r
taskEXIT_CRITICAL();\r
{\r
taskENTER_CRITICAL();\r
{\r
- xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
+ xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
}\r
taskEXIT_CRITICAL();\r
}\r
queue being empty is equivalent to the semaphore count being 0. */\r
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )\r
{\r
+ #if ( configUSE_MUTEXES == 1 )\r
+ {\r
+ /* xInheritanceOccurred could only have be set if\r
+ pxQueue->uxQueueType == queueQUEUE_IS_MUTEX so no need to\r
+ test the mutex type again to check it is actually a mutex. */\r
+ if( xInheritanceOccurred != pdFALSE )\r
+ {\r
+ taskENTER_CRITICAL();\r
+ {\r
+ UBaseType_t uxHighestWaitingPriority;\r
+\r
+ /* This task blocking on the mutex caused another\r
+ task to inherit this task's priority. Now this task\r
+ has timed out the priority should be disinherited\r
+ again, but only as low as the next highest priority\r
+ task that is waiting for the same mutex. */\r
+ uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue );\r
+ vTaskPriorityDisinheritAfterTimeout( ( void * ) pxQueue->pxMutexHolder, uxHighestWaitingPriority );\r
+ }\r
+ taskEXIT_CRITICAL();\r
+ }\r
+ }\r
+ #endif /* configUSE_MUTEXES */\r
+\r
traceQUEUE_RECEIVE_FAILED( pxQueue );\r
return errQUEUE_EMPTY;\r
}\r
#endif /* configUSE_TRACE_FACILITY */\r
/*-----------------------------------------------------------*/\r
\r
+#if( configUSE_MUTEXES == 1 )\r
+\r
+ static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue )\r
+ {\r
+ UBaseType_t uxHighestPriorityOfWaitingTasks;\r
+\r
+ /* If a task waiting for a mutex causes the mutex holder to inherit a\r
+ priority, but the waiting task times out, then the holder should\r
+ disinherit the priority - but only down to the highest priority of any\r
+ other tasks that are waiting for the same mutex. For this purpose,\r
+ return the priority of the highest priority task that is waiting for the\r
+ mutex. */\r
+ if( listCURRENT_LIST_LENGTH( &( pxQueue->xTasksWaitingToReceive ) ) > 0 )\r
+ {\r
+ uxHighestPriorityOfWaitingTasks = configMAX_PRIORITIES - listGET_ITEM_VALUE_OF_HEAD_ENTRY( &( pxQueue->xTasksWaitingToReceive ) );\r
+ }\r
+ else\r
+ {\r
+ uxHighestPriorityOfWaitingTasks = tskIDLE_PRIORITY;\r
+ }\r
+\r
+ return uxHighestPriorityOfWaitingTasks;\r
+ }\r
+\r
+#endif /* configUSE_MUTEXES */\r
+/*-----------------------------------------------------------*/\r
+\r
static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition )\r
{\r
BaseType_t xReturn = pdFALSE;\r
#define static\r
#endif\r
\r
+/* The name allocated to the Idle task. This can be overridden by defining\r
+tskIDLE_TASK_NAME in FreeRTOSConfig.h. */\r
+#ifndef tskIDLE_TASK_NAME\r
+ #define tskIDLE_TASK_NAME "IDLE"\r
+#endif\r
+\r
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )\r
\r
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is\r
#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */\r
/*-----------------------------------------------------------*/\r
\r
-#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )\r
+#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) )\r
\r
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )\r
{\r
}\r
\r
/* If the task is in the blocked or suspended list we need do\r
- nothing more than change it's priority variable. However, if\r
+ nothing more than change its priority variable. However, if\r
the task is in a ready list it needs to be removed and placed\r
in the list appropriate to its new priority. */\r
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )\r
{\r
- /* The task is currently in its ready list - remove before adding\r
- it to it's new ready list. As we are in a critical section we\r
- can do this even if the scheduler is suspended. */\r
+ /* The task is currently in its ready list - remove before\r
+ adding it to it's new ready list. As we are in a critical\r
+ section we can do this even if the scheduler is suspended. */\r
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )\r
{\r
/* It is known that the task is in its ready list so\r
address of the RAM then create the idle task. */\r
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );\r
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,\r
- "IDLE",\r
+ tskIDLE_TASK_NAME,\r
ulIdleTaskStackSize,\r
( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */\r
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),\r
{\r
/* The Idle task is being created using dynamically allocated RAM. */\r
xReturn = xTaskCreate( prvIdleTask,\r
- "IDLE", configMINIMAL_STACK_SIZE,\r
+ tskIDLE_TASK_NAME,\r
+ configMINIMAL_STACK_SIZE,\r
( void * ) NULL,\r
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),\r
&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */\r
BaseType_t xTaskAbortDelay( TaskHandle_t xTask )\r
{\r
TCB_t *pxTCB = ( TCB_t * ) xTask;\r
- BaseType_t xReturn = pdFALSE;\r
+ BaseType_t xReturn;\r
\r
configASSERT( pxTCB );\r
\r
it is actually in the Blocked state. */\r
if( eTaskGetState( xTask ) == eBlocked )\r
{\r
+ xReturn = pdPASS;\r
+\r
/* Remove the reference to the task from the blocked list. An\r
interrupt won't touch the xStateListItem because the\r
scheduler is suspended. */\r
}\r
else\r
{\r
- mtCOVERAGE_TEST_MARKER();\r
+ xReturn = pdFAIL;\r
}\r
}\r
( void ) xTaskResumeAll();\r
{\r
/* Minor optimisation. The tick count cannot change in this block. */\r
const TickType_t xConstTickCount = xTickCount;\r
+ const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering;\r
\r
#if( INCLUDE_xTaskAbortDelay == 1 )\r
if( pxCurrentTCB->ucDelayAborted != pdFALSE )\r
was called. */\r
xReturn = pdTRUE;\r
}\r
- 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. */\r
+ else if( xElapsedTime < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */\r
{\r
/* Not a genuine timeout. Adjust parameters for time remaining. */\r
- *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering );\r
+ *pxTicksToWait -= xElapsedTime;\r
vTaskSetTimeOutState( pxTimeOut );\r
xReturn = pdFALSE;\r
}\r
\r
BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder )\r
{\r
- TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;\r
+ TCB_t * const pxMutexHolderTCB = ( TCB_t * ) pxMutexHolder;\r
BaseType_t xReturn = pdFALSE;\r
\r
/* If the mutex was given back by an interrupt while the queue was\r
locked then the mutex holder might now be NULL. _RB_ Is this still\r
- needed as interrupt can no longer use mutexes? */\r
+ needed as interrupts can no longer use mutexes? */\r
if( pxMutexHolder != NULL )\r
{\r
/* If the holder of the mutex has a priority below the priority of\r
the task attempting to obtain the mutex then it will temporarily\r
inherit the priority of the task attempting to obtain the mutex. */\r
- if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )\r
+ if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority )\r
{\r
/* Adjust the mutex holder state to account for its new\r
priority. Only reset the event list item value if the value is\r
- not being used for anything else. */\r
- if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )\r
+ not being used for anything else. */\r
+ if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )\r
{\r
- 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. */\r
+ 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. */\r
}\r
else\r
{\r
\r
/* If the task being modified is in the ready state it will need\r
to be moved into a new list. */\r
- if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )\r
+ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE )\r
{\r
- if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )\r
+ if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )\r
{\r
- taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
+ taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority );\r
}\r
else\r
{\r
}\r
\r
/* Inherit the priority before being moved into the new list. */\r
- pxTCB->uxPriority = pxCurrentTCB->uxPriority;\r
- prvAddTaskToReadyList( pxTCB );\r
+ pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;\r
+ prvAddTaskToReadyList( pxMutexHolderTCB );\r
}\r
else\r
{\r
/* Just inherit the priority. */\r
- pxTCB->uxPriority = pxCurrentTCB->uxPriority;\r
+ pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;\r
}\r
\r
- traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );\r
+ traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCB->uxPriority );\r
\r
/* Inheritance occurred. */\r
xReturn = pdTRUE;\r
}\r
else\r
{\r
- mtCOVERAGE_TEST_MARKER();\r
+ if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority )\r
+ {\r
+ /* The base priority of the mutex holder is lower than the\r
+ priority of the task attempting to take the mutex, but the\r
+ current priority of the mutex holder is not lower than the\r
+ priority of the task attempting to take the mutex.\r
+ Therefore the mutex holder must have already inherited a\r
+ priority, but inheritance would have occurred if that had\r
+ not been the case. */\r
+ xReturn = pdTRUE;\r
+ }\r
+ else\r
+ {\r
+ mtCOVERAGE_TEST_MARKER();\r
+ }\r
}\r
}\r
else\r
interrupt, and if a mutex is given by the holding task then it must\r
be the running state task. */\r
configASSERT( pxTCB == pxCurrentTCB );\r
-\r
configASSERT( pxTCB->uxMutexesHeld );\r
( pxTCB->uxMutexesHeld )--;\r
\r
/* A task can only have an inherited priority if it holds\r
the mutex. If the mutex is held by a task then it cannot be\r
given from an interrupt, and if a mutex is given by the\r
- holding task then it must be the running state task. Remove\r
- the holding task from the ready list. */\r
+ holding task then it must be the running state task. Remove\r
+ the holding task from the ready list. */\r
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )\r
{\r
taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
#endif /* configUSE_MUTEXES */\r
/*-----------------------------------------------------------*/\r
\r
+#if ( configUSE_MUTEXES == 1 )\r
+\r
+ void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask )\r
+ {\r
+ TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;\r
+ UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse;\r
+ const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1;\r
+\r
+ if( pxMutexHolder != NULL )\r
+ {\r
+ /* If pxMutexHolder is not NULL then the holder must hold at least\r
+ one mutex. */\r
+ configASSERT( pxTCB->uxMutexesHeld );\r
+\r
+ /* Determine the priority to which the priority of the task that\r
+ holds the mutex should be set. This will be the greater of the\r
+ holding task's base priority and the priority of the highest\r
+ priority task that is waiting to obtain the mutex. */\r
+ if( pxTCB->uxBasePriority < uxHighestPriorityWaitingTask )\r
+ {\r
+ uxPriorityToUse = uxHighestPriorityWaitingTask;\r
+ }\r
+ else\r
+ {\r
+ uxPriorityToUse = pxTCB->uxBasePriority;\r
+ }\r
+\r
+ /* Does the priority need to change? */\r
+ if( pxTCB->uxPriority != uxPriorityToUse )\r
+ {\r
+ /* Only disinherit if no other mutexes are held. This is a\r
+ simplification in the priority inheritance implementation. If\r
+ the task that holds the mutex is also holding other mutexes then\r
+ the other mutexes may have caused the priority inheritance. */\r
+ if( pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld )\r
+ {\r
+ /* If a task has timed out because it already holds the\r
+ mutex it was trying to obtain then it cannot of inherited\r
+ its own priority. */\r
+ configASSERT( pxTCB != pxCurrentTCB );\r
+\r
+ /* Disinherit the priority, remembering the previous\r
+ priority to facilitate determining the subject task's\r
+ state. */\r
+ traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );\r
+ uxPriorityUsedOnEntry = pxTCB->uxPriority;\r
+ pxTCB->uxPriority = uxPriorityToUse;\r
+\r
+ /* Only reset the event list item value if the value is not\r
+ being used for anything else. */\r
+ if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )\r
+ {\r
+ 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. */\r
+ }\r
+ else\r
+ {\r
+ mtCOVERAGE_TEST_MARKER();\r
+ }\r
+\r
+ /* If the running task is not the task that holds the mutex\r
+ then the task that holds the mutex could be in either the\r
+ Ready, Blocked or Suspended states. Only remove the task\r
+ from its current state list if it is in the Ready state as\r
+ the task's priority is going to change and there is one\r
+ Ready list per priority. */\r
+ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )\r
+ {\r
+ if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )\r
+ {\r
+ taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
+ }\r
+ else\r
+ {\r
+ mtCOVERAGE_TEST_MARKER();\r
+ }\r
+\r
+ prvAddTaskToReadyList( pxTCB );\r
+ }\r
+ else\r
+ {\r
+ mtCOVERAGE_TEST_MARKER();\r
+ }\r
+ }\r
+ else\r
+ {\r
+ mtCOVERAGE_TEST_MARKER();\r
+ }\r
+ }\r
+ else\r
+ {\r
+ mtCOVERAGE_TEST_MARKER();\r
+ }\r
+ }\r
+ else\r
+ {\r
+ mtCOVERAGE_TEST_MARKER();\r
+ }\r
+ }\r
+\r
+#endif /* configUSE_MUTEXES */\r
+/*-----------------------------------------------------------*/\r
+\r
#if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
\r
void vTaskEnterCritical( void )\r
/* Misc definitions. */\r
#define tmrNO_DELAY ( TickType_t ) 0U\r
\r
+/* The name assigned to the timer service task. This can be overridden by\r
+defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */\r
+#ifndef tmrTIMER_SERVICE_TASK_NAME\r
+ #define tmrTIMER_SERVICE_TASK_NAME "Tmr Svc"\r
+#endif\r
+\r
/* The definition of the timers themselves. */\r
typedef struct tmrTimerControl\r
{\r
\r
vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );\r
xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,\r
- "Tmr Svc",\r
+ tmrTIMER_SERVICE_TASK_NAME,\r
ulTimerTaskStackSize,\r
NULL,\r
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,\r
#else\r
{\r
xReturn = xTaskCreate( prvTimerTask,\r
- "Tmr Svc",\r
+ tmrTIMER_SERVICE_TASK_NAME,\r
configTIMER_TASK_STACK_DEPTH,\r
NULL,\r
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,\r