diff --git a/FreeRTOS/Source/include/mpu_wrappers.h b/FreeRTOS/Source/include/mpu_wrappers.h index 95a52c29d..2681ca82a 100644 --- a/FreeRTOS/Source/include/mpu_wrappers.h +++ b/FreeRTOS/Source/include/mpu_wrappers.h @@ -1,5 +1,5 @@ /* - FreeRTOS V8.0.0:rc1 - Copyright (C) 2014 Real Time Engineers Ltd. + FreeRTOS V8.0.0:rc1 - Copyright (C) 2014 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -84,7 +84,6 @@ only for ports that are using the MPU. */ #define vTaskPrioritySet MPU_vTaskPrioritySet #define eTaskGetState MPU_eTaskGetState #define vTaskSuspend MPU_vTaskSuspend - #define xTaskIsTaskSuspended MPU_xTaskIsTaskSuspended #define vTaskResume MPU_vTaskResume #define vTaskSuspendAll MPU_vTaskSuspendAll #define xTaskResumeAll MPU_xTaskResumeAll diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h index d559e2dca..fbbff3115 100644 --- a/FreeRTOS/Source/include/queue.h +++ b/FreeRTOS/Source/include/queue.h @@ -173,8 +173,8 @@ typedef void * QueueSetMemberHandle_t; *
BaseType_t xQueueSendToToFront( QueueHandle_t xQueue, - const void * pvItemToQueue, - TickType_t xTicksToWait + const void *pvItemToQueue, + TickType_t xTicksToWait ); ** diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index 614565b88..b0d53a811 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -1028,17 +1028,6 @@ void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION; */ BaseType_t xTaskResumeAll( void ) PRIVILEGED_FUNCTION; -/** - * task. h - *
BaseType_t xTaskIsTaskSuspended( const TaskHandle_t xTask );- * - * Utility task that simply returns pdTRUE if the task referenced by xTask is - * currently in the Suspended state, or pdFALSE if the task referenced by xTask - * is in any other state. - * - */ -BaseType_t xTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; - /*----------------------------------------------------------- * TASK UTILITIES *----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c index 06f5949aa..d7d4dd684 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c @@ -179,7 +179,6 @@ UBaseType_t MPU_uxTaskPriorityGet( TaskHandle_t pxTask ); void MPU_vTaskPrioritySet( TaskHandle_t pxTask, UBaseType_t uxNewPriority ); eTaskState MPU_eTaskGetState( TaskHandle_t pxTask ); void MPU_vTaskSuspend( TaskHandle_t pxTaskToSuspend ); -BaseType_t MPU_xTaskIsTaskSuspended( TaskHandle_t xTask ); void MPU_vTaskResume( TaskHandle_t pxTaskToResume ); void MPU_vTaskSuspendAll( void ); BaseType_t MPU_xTaskResumeAll( void ); @@ -787,19 +786,6 @@ BaseType_t xRunningPrivileged = prvRaisePrivilege(); #endif /*-----------------------------------------------------------*/ -#if ( INCLUDE_vTaskSuspend == 1 ) - BaseType_t MPU_xTaskIsTaskSuspended( TaskHandle_t xTask ) - { - BaseType_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xTaskIsTaskSuspended( xTask ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - #if ( INCLUDE_vTaskSuspend == 1 ) void MPU_vTaskResume( TaskHandle_t pxTaskToResume ) { diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c index 61f907852..6a3acc984 100644 --- a/FreeRTOS/Source/queue.c +++ b/FreeRTOS/Source/queue.c @@ -86,7 +86,7 @@ privileged Vs unprivileged linkage and placement. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ -/* Constants used with the cRxLock and xTxLock structure members. */ +/* Constants used with the xRxLock and xTxLock structure members. */ #define queueUNLOCKED ( ( BaseType_t ) -1 ) #define queueLOCKED_UNMODIFIED ( ( BaseType_t ) 0 ) @@ -1038,11 +1038,11 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - /* Similar to xQueueGenericSend, except we don't block if there is no room - in the queue. Also we don't directly wake a task that was blocked on a - queue read, instead we return a flag to say whether a context switch is - required or not (i.e. has a task with a higher priority than us been woken - by this post). */ + /* Similar to xQueueGenericSend, except without blocking if there is no room + in the queue. Also don't directly wake a task that was blocked on a queue + read, instead return a flag to say whether a context switch is required or + not (i.e. has a task with a higher priority than us been woken by this + post). */ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) @@ -1051,7 +1051,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); - /* If the queue is locked we do not alter the event list. This will + /* The event list is not altered if the queue is locked. This will be done when the queue is unlocked later. */ if( pxQueue->xTxLock == queueUNLOCKED ) { @@ -2349,6 +2349,8 @@ BaseType_t xReturn; Queue_t *pxQueueSetContainer = pxQueue->pxQueueSetContainer; BaseType_t xReturn = pdFALSE; + /* This function must be called form a critical section. */ + configASSERT( pxQueueSetContainer ); configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ); diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index 51747b5e6..fc06935d8 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -214,13 +214,22 @@ PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseTyp PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U; PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; -PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE; PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U; PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE; PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = portMAX_DELAY; +/* Context switches are held pending while the scheduler is suspended. Also, +interrupts must not manipulate the xStateListItem of a TCB, or any of the +lists the xStateListItem can be referenced from, if the scheduler is suspended. +If an interrupt needs to unblock a task while the scheduler is suspended then it +moves the task's event list item into the xPendingReadyList, ready for the +kernel to move the task from the pending ready list into the real ready list +when the scheduler is unsuspended. The pending ready list itself can only be +accessed from a critical section. */ +PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE; + #if ( configGENERATE_RUN_TIME_STATS == 1 ) PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ @@ -393,6 +402,13 @@ to its original value when it is released. */ */ static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +/** + * Utility task that simply returns pdTRUE if the task referenced by xTask is + * currently in the Suspended state, or pdFALSE if the task referenced by xTask + * is in any other state. + */ +static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + /* * Utility to ready all the lists used by the scheduler. This is called * automatically upon the creation of the first task. @@ -806,9 +822,8 @@ TCB_t * pxNewTCB; { traceTASK_DELAY_UNTIL(); - /* We must remove ourselves from the ready list before adding - ourselves to the blocked list as the same list item is used for - both lists. */ + /* Remove the task from the ready list before adding it to the + blocked list as the same list item is used for both lists. */ if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) { /* The current task must be in a ready list, so there is @@ -1254,25 +1269,25 @@ TCB_t * pxNewTCB; #if ( INCLUDE_vTaskSuspend == 1 ) - BaseType_t xTaskIsTaskSuspended( const TaskHandle_t xTask ) + static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) { BaseType_t xReturn = pdFALSE; const TCB_t * const pxTCB = ( TCB_t * ) xTask; + /* Accesses xPendingReadyList so must be called from a critical + section. */ + /* It does not make sense to check if the calling task is suspended. */ configASSERT( xTask ); - /* Is the task we are attempting to resume actually in the - suspended list? */ + /* Is the task being resumed actually in the suspended list? */ if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE ) { /* Has the task already been resumed from within an ISR? */ if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) { - /* Is it in the suspended list because it is in the - Suspended state? It is possible to be in the suspended - list because it is blocked on a task with no timeout - specified. */ + /* Is it in the suspended list because it is in the Suspended + state, or because is is blocked with no timeout? */ if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) { xReturn = pdTRUE; @@ -1313,7 +1328,7 @@ TCB_t * pxNewTCB; { taskENTER_CRITICAL(); { - if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE ) + if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE ) { traceTASK_RESUME( pxTCB ); @@ -1382,12 +1397,15 @@ TCB_t * pxNewTCB; uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { - if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE ) + if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE ) { traceTASK_RESUME_FROM_ISR( pxTCB ); + /* Check the ready lists can be accessed. */ if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) { + /* Ready lists can be accessed so move the task from the + suspended list to the ready list directly. */ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) { xYieldRequired = pdTRUE; @@ -1402,9 +1420,9 @@ TCB_t * pxNewTCB; } else { - /* We cannot access the delayed or ready lists, so will hold this - task pending until the scheduler is resumed, at which point a - yield will be performed if necessary. */ + /* The delayed or ready lists cannot be accessed so the task + is held in the pending ready list until the scheduler is + unsuspended. */ vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); } } @@ -2144,17 +2162,18 @@ TickType_t xTimeToWake; configASSERT( pxEventList ); - /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE - SCHEDULER SUSPENDED. */ + /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE + SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */ /* Place the event list item of the TCB in the appropriate event list. This is placed in the list in priority order so the highest priority task - is the first to be woken by the event. */ + is the first to be woken by the event. The queue that contains the event + list is locked, preventing simultaneous access from interrupts. */ vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) ); - /* We must remove ourselves from the ready list before adding ourselves - to the blocked list as the same list item is used for both lists. We have - exclusive access to the ready lists as the scheduler is locked. */ + /* The task must be removed from from the ready list before it is added to + the blocked list as the same list item is used for both lists. Exclusive + access to the ready lists guaranteed because the scheduler is locked. */ if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) { /* The current task must be in a ready list, so there is no need to @@ -2170,15 +2189,16 @@ TickType_t xTimeToWake; { if( xTicksToWait == portMAX_DELAY ) { - /* Add ourselves to the suspended task list instead of a delayed task - list to ensure we are not woken by a timing event. We will block - indefinitely. */ + /* Add the task to the suspended task list instead of a delayed task + list to ensure the task is not woken by a timing event. It will + block indefinitely. */ vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); } else { - /* Calculate the time at which the task should be woken if the event does - not occur. This may overflow but this doesn't matter. */ + /* Calculate the time at which the task should be woken if the event + does not occur. This may overflow but this doesn't matter, the + scheduler will handle it. */ xTimeToWake = xTickCount + xTicksToWait; prvAddCurrentTaskToDelayedList( xTimeToWake ); } @@ -2186,7 +2206,8 @@ TickType_t xTimeToWake; #else /* INCLUDE_vTaskSuspend */ { /* Calculate the time at which the task should be woken if the event does - not occur. This may overflow but this doesn't matter. */ + not occur. This may overflow but this doesn't matter, the scheduler + will handle it. */ xTimeToWake = xTickCount + xTicksToWait; prvAddCurrentTaskToDelayedList( xTimeToWake ); } @@ -2200,14 +2221,20 @@ TickType_t xTimeToWake; configASSERT( pxEventList ); - /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE - SCHEDULER SUSPENDED. */ + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by + the event groups implementation. */ + configASSERT( uxSchedulerSuspended != 0 ); - /* Store the item value in the event list item. */ + /* Store the item value in the event list item. It is safe to access the + event list item here as interrupts won't access the event list item of a + task that is not in the Blocked state. */ listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); /* Place the event list item of the TCB at the end of the appropriate event - list. */ + list. It is safe to access the event list here because it is part of an + event group implementation - and interrupts don't access event groups + directly (instead they access them indirectly by pending function calls to + the task level). */ vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); /* The task must be removed from the ready list before it is added to the @@ -2235,8 +2262,9 @@ TickType_t xTimeToWake; } else { - /* Calculate the time at which the task should be woken if the event does - not occur. This may overflow but this doesn't matter. */ + /* Calculate the time at which the task should be woken if the event + does not occur. This may overflow but this doesn't matter, the + kernel will manage it correctly. */ xTimeToWake = xTickCount + xTicksToWait; prvAddCurrentTaskToDelayedList( xTimeToWake ); } @@ -2244,7 +2272,8 @@ TickType_t xTimeToWake; #else /* INCLUDE_vTaskSuspend */ { /* Calculate the time at which the task should be woken if the event does - not occur. This may overflow but this doesn't matter. */ + not occur. This may overflow but this doesn't matter, the kernel + will manage it correctly. */ xTimeToWake = xTickCount + xTicksToWait; prvAddCurrentTaskToDelayedList( xTimeToWake ); } @@ -2302,16 +2331,16 @@ BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) TCB_t *pxUnblockedTCB; BaseType_t xReturn; - /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE - SCHEDULER SUSPENDED. It can also be called from within an ISR. */ + /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be + called from a critical section within an ISR. */ - /* The event list is sorted in priority order, so we can remove the - first in the list, remove the TCB from the delayed list, and add - it to the ready list. + /* The event list is sorted in priority order, so the first in the list can + be removed as it is known to be the highest priority. Remove the TCB from + the delayed list, and add it to the ready list. If an event is for a queue that is locked then this function will never get called - the lock count on the queue will get modified instead. This - means we can always expect exclusive access to the event list here. + means exclusive access to the event list is guaranteed here. This function assumes that a check has already been made to ensure that pxEventList is not empty. */ @@ -2333,10 +2362,9 @@ BaseType_t xReturn; if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) { - /* Return true if the task removed from the event list has - a higher priority than the calling task. This allows - the calling task to know if it should force a context - switch now. */ + /* Return true if the task removed from the event list has a higher + priority than the calling task. This allows the calling task to know if + it should force a context switch now. */ xReturn = pdTRUE; /* Mark that a yield is pending in case the user is not using the @@ -2357,29 +2385,24 @@ BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, cons TCB_t *pxUnblockedTCB; BaseType_t xReturn; - /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE - SCHEDULER SUSPENDED. It can also be called from within an ISR. */ + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by + the event flags implementation. */ + configASSERT( uxSchedulerSuspended != pdFALSE ); /* Store the new item value in the event list. */ listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); - /* Remove the TCB from the delayed list, and add it to the ready list. */ - + /* Remove the event list form the event flag. Interrupts do not access + event flags. */ pxUnblockedTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxEventListItem ); configASSERT( pxUnblockedTCB ); ( void ) uxListRemove( pxEventListItem ); - if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) - { - ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); - prvAddTaskToReadyList( pxUnblockedTCB ); - } - else - { - /* Cannot access the delayed or ready lists, so will hold this task - pending until the scheduler is resumed. */ - vListInsertEnd( &( xPendingReadyList ), pxEventListItem ); - } + /* Remove the task from the delayed list and add it to the ready list. The + scheduler is suspended so interrupts will not be accessing the ready + lists. */ + ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) { @@ -2812,7 +2835,9 @@ static void prvCheckTasksWaitingTermination( void ) while( uxTasksDeleted > ( UBaseType_t ) 0U ) { vTaskSuspendAll(); + { xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); + } ( void ) xTaskResumeAll(); if( xListIsEmpty == pdFALSE ) @@ -2932,6 +2957,21 @@ TCB_t *pxNewTCB; pxTaskStatusArray[ uxTask ].eCurrentState = eState; pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority; + #if ( INCLUDE_vTaskSuspend == 1 ) + { + /* If the task is in the suspended list then there is a chance + it is actually just blocked indefinitely - so really it should + be reported as being in the Blocked state. */ + if( eState == eSuspended ) + { + if( listLIST_ITEM_CONTAINER( &( pxNextTCB->xEventListItem ) ) != NULL ) + { + pxTaskStatusArray[ uxTask ].eCurrentState = eBlocked; + } + } + } + #endif /* INCLUDE_vTaskSuspend */ + #if ( configUSE_MUTEXES == 1 ) { pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority;