]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Source/tasks.c
Changes to core code and port layer:
[freertos] / FreeRTOS / Source / tasks.c
index 7fafd904aceff49bddd7b17731fc86940bb4edb3..f101e258eb422d23e5f9bfa0dbb3782e3b7b3cd2 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-    FreeRTOS V9.0.0rc2 - Copyright (C) 2016 Real Time Engineers Ltd.\r
+    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.\r
     All rights reserved\r
 \r
     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
@@ -117,6 +117,26 @@ functions but without including stdio.h here. */
  */\r
 #define tskSTACK_FILL_BYTE     ( 0xa5U )\r
 \r
+/* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using\r
+dynamically allocated RAM, in which case when any task is deleted it is known\r
+that both the task's stack and TCB need to be freed.  Sometimes the\r
+FreeRTOSConfig.h settings only allow a task to be created using statically\r
+allocated RAM, in which case when any task is deleted it is known that neither\r
+the task's stack or TCB should be freed.  Sometimes the FreeRTOSConfig.h\r
+settings allow a task to be created using either statically or dynamically\r
+allocated RAM, in which case a member of the TCB is used to record whether the\r
+stack and/or TCB were allocated statically or dynamically, so when a task is\r
+deleted the RAM that was allocated dynamically is freed again and no attempt is\r
+made to free the RAM that was allocated statically.\r
+tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a\r
+task to be created using either statically or dynamically allocated RAM.  Note\r
+that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with\r
+a statically allocated stack and a dynamically allocated TCB. */\r
+#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) )\r
+#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB                 ( ( uint8_t ) 0 )\r
+#define tskSTATICALLY_ALLOCATED_STACK_ONLY                     ( ( uint8_t ) 1 )\r
+#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB          ( ( uint8_t ) 2 )\r
+\r
 /*\r
  * Macros used by vListTask to indicate which state a task is in.\r
  */\r
@@ -330,8 +350,10 @@ typedef struct tskTaskControlBlock
                volatile uint8_t ucNotifyState;\r
        #endif\r
 \r
-       #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )\r
-               uint8_t ucStaticallyAllocated; /* Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */\r
+       /* See the comments above the definition of\r
+       tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */\r
+       #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )\r
+               uint8_t ucStaticallyAllocated;          /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */\r
        #endif\r
 \r
        #if( INCLUDE_xTaskAbortDelay == 1 )\r
@@ -542,7 +564,14 @@ static void prvResetNextTaskUnblockTime( void );
  * Called after a Task_t structure has been allocated either statically or\r
  * dynamically to fill in the structure's members.\r
  */\r
-static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */\r
+static void prvInitialiseNewTask(      TaskFunction_t pxTaskCode,\r
+                                                                       const char * const pcName,\r
+                                                                       const uint32_t ulStackDepth,\r
+                                                                       void * const pvParameters,\r
+                                                                       UBaseType_t uxPriority,\r
+                                                                       TaskHandle_t * const pxCreatedTask,\r
+                                                                       TCB_t *pxNewTCB,\r
+                                                                       const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */\r
 \r
 /*\r
  * Called after a new task has been created and initialised to place the task\r
@@ -554,7 +583,13 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 \r
 #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
 \r
-       TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */\r
+       TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,\r
+                                                                       const char * const pcName,\r
+                                                                       const uint32_t ulStackDepth,\r
+                                                                       void * const pvParameters,\r
+                                                                       UBaseType_t uxPriority,\r
+                                                                       StackType_t * const puxStackBuffer,\r
+                                                                       StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */\r
        {\r
        TCB_t *pxNewTCB;\r
        TaskHandle_t xReturn;\r
@@ -569,15 +604,15 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
                        pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */\r
                        pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;\r
 \r
-                       #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )\r
+                       #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )\r
                        {\r
                                /* Tasks can be created statically or dynamically, so note this\r
                                task was created statically in case the task is later deleted. */\r
-                               pxNewTCB->ucStaticallyAllocated = pdTRUE;\r
+                               pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;\r
                        }\r
                        #endif /* configSUPPORT_DYNAMIC_ALLOCATION */\r
 \r
-                       prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB );\r
+                       prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL );\r
                        prvAddNewTaskToReadyList( pxNewTCB );\r
                }\r
                else\r
@@ -591,9 +626,59 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 #endif /* SUPPORT_STATIC_ALLOCATION */\r
 /*-----------------------------------------------------------*/\r
 \r
+#if( portUSING_MPU_WRAPPERS == 1 )\r
+\r
+       BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )\r
+       {\r
+       TCB_t *pxNewTCB;\r
+       BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;\r
+\r
+               configASSERT( pxTaskDefinition->puxStackBuffer );\r
+\r
+               if( pxTaskDefinition->puxStackBuffer != NULL )\r
+               {\r
+                       /* Allocate space for the TCB.  Where the memory comes from depends\r
+                       on the implementation of the port malloc function and whether or\r
+                       not static allocation is being used. */\r
+                       pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );\r
+\r
+                       if( pxNewTCB != NULL )\r
+                       {\r
+                               /* Store the stack location in the TCB. */\r
+                               pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer;\r
+\r
+                               /* Tasks can be created statically or dynamically, so note\r
+                               this task had a statically allocated stack in case it is\r
+                               later deleted.  The TCB was allocated dynamically. */\r
+                               pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY;\r
+\r
+                               prvInitialiseNewTask(   pxTaskDefinition->pvTaskCode,\r
+                                                                               pxTaskDefinition->pcName,\r
+                                                                               ( uint32_t ) pxTaskDefinition->usStackDepth,\r
+                                                                               pxTaskDefinition->pvParameters,\r
+                                                                               pxTaskDefinition->uxPriority,\r
+                                                                               pxCreatedTask, pxNewTCB,\r
+                                                                               pxTaskDefinition->xRegions );\r
+\r
+                               prvAddNewTaskToReadyList( pxNewTCB );\r
+                               xReturn = pdPASS;\r
+                       }\r
+               }\r
+\r
+               return xReturn;\r
+       }\r
+\r
+#endif /* portUSING_MPU_WRAPPERS */\r
+/*-----------------------------------------------------------*/\r
+\r
 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )\r
 \r
-       BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */\r
+       BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,\r
+                                                       const char * const pcName,\r
+                                                       const uint16_t usStackDepth,\r
+                                                       void * const pvParameters,\r
+                                                       UBaseType_t uxPriority,\r
+                                                       TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */\r
        {\r
        TCB_t *pxNewTCB;\r
        BaseType_t xReturn;\r
@@ -656,15 +741,15 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 \r
                if( pxNewTCB != NULL )\r
                {\r
-                       #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
+                       #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )\r
                        {\r
                                /* Tasks can be created statically or dynamically, so note this\r
                                task was created dynamically in case it is later deleted. */\r
-                               pxNewTCB->ucStaticallyAllocated = pdFALSE;\r
+                               pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;\r
                        }\r
                        #endif /* configSUPPORT_STATIC_ALLOCATION */\r
 \r
-                       prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB );\r
+                       prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );\r
                        prvAddNewTaskToReadyList( pxNewTCB );\r
                        xReturn = pdPASS;\r
                }\r
@@ -679,7 +764,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */\r
 /*-----------------------------------------------------------*/\r
 \r
-static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, TCB_t *pxNewTCB ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */\r
+static void prvInitialiseNewTask(      TaskFunction_t pxTaskCode,\r
+                                                                       const char * const pcName,\r
+                                                                       const uint32_t ulStackDepth,\r
+                                                                       void * const pvParameters,\r
+                                                                       UBaseType_t uxPriority,\r
+                                                                       TaskHandle_t * const pxCreatedTask,\r
+                                                                       TCB_t *pxNewTCB,\r
+                                                                       const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */\r
 {\r
 StackType_t *pxTopOfStack;\r
 UBaseType_t x;\r
@@ -805,6 +897,11 @@ UBaseType_t x;
        {\r
                vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, ulStackDepth );\r
        }\r
+       #else\r
+       {\r
+               /* Avoid compiler warning about unreferenced parameter. */\r
+               ( void ) xRegions;\r
+       }\r
        #endif\r
 \r
        #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )\r
@@ -1740,7 +1837,13 @@ BaseType_t xReturn;
                /* The Idle task is created using user provided RAM - obtain the\r
                address of the RAM then create the idle task. */\r
                vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );\r
-               xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, "IDLE", ulIdleTaskStackSize, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), pxIdleTaskStackBuffer, pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */\r
+               xIdleTaskHandle = xTaskCreateStatic(    prvIdleTask,\r
+                                                                                               "IDLE",\r
+                                                                                               ulIdleTaskStackSize,\r
+                                                                                               ( void * ) NULL,\r
+                                                                                               ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),\r
+                                                                                               pxIdleTaskStackBuffer,\r
+                                                                                               pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */\r
 \r
                if( xIdleTaskHandle != NULL )\r
                {\r
@@ -1754,7 +1857,11 @@ BaseType_t xReturn;
        #else\r
        {\r
                /* The Idle task is being created using dynamically allocated RAM. */\r
-               xReturn = xTaskCreate( prvIdleTask, "IDLE", 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. */\r
+               xReturn = xTaskCreate(  prvIdleTask,\r
+                                                               "IDLE", 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
        }\r
        #endif /* configSUPPORT_STATIC_ALLOCATION */\r
 \r
@@ -1794,7 +1901,10 @@ BaseType_t xReturn;
 \r
                /* If configGENERATE_RUN_TIME_STATS is defined then the following\r
                macro must be defined to configure the timer/counter used to generate\r
-               the run time counter time base. */\r
+               the run time counter time base.   NOTE:  If configGENERATE_RUN_TIME_STATS\r
+               is set to 0 and the following line fails to build then ensure you do not\r
+               have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your\r
+               FreeRTOSConfig.h file. */\r
                portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();\r
 \r
                /* Setting up the timer tick is hardware specific and thus in the\r
@@ -1814,7 +1924,7 @@ BaseType_t xReturn;
                /* This line will only be reached if the kernel could not be started,\r
                because there was not enough FreeRTOS heap to create the idle task\r
                or the timer task. */\r
-               configASSERT( xReturn );\r
+               configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );\r
        }\r
 \r
        /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,\r
@@ -2381,7 +2491,7 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
                                mtCOVERAGE_TEST_MARKER();\r
                        }\r
                }\r
-               xTaskResumeAll();\r
+               ( void ) xTaskResumeAll();\r
 \r
                return xReturn;\r
        }\r
@@ -2852,10 +2962,9 @@ BaseType_t xReturn;
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )\r
+void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )\r
 {\r
 TCB_t *pxUnblockedTCB;\r
-BaseType_t xReturn;\r
 \r
        /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED.  It is used by\r
        the event flags implementation. */\r
@@ -2878,22 +2987,12 @@ BaseType_t xReturn;
 \r
        if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )\r
        {\r
-               /* Return true if the task removed from the event list has\r
-               a higher priority than the calling task.  This allows\r
-               the calling task to know if it should force a context\r
-               switch now. */\r
-               xReturn = pdTRUE;\r
-\r
-               /* Mark that a yield is pending in case the user is not using the\r
-               "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */\r
+               /* The unblocked task has a priority above that of the calling task, so\r
+               a context switch is required.  This function is called with the\r
+               scheduler suspended so xYieldPending is set so the context switch\r
+               occurs immediately that the scheduler is resumed (unsuspended). */\r
                xYieldPending = pdTRUE;\r
        }\r
-       else\r
-       {\r
-               xReturn = pdFALSE;\r
-       }\r
-\r
-       return xReturn;\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r
@@ -3328,7 +3427,7 @@ static void prvCheckTasksWaitingTermination( void )
                                                pxTaskStatus->eCurrentState = eBlocked;\r
                                        }\r
                                }\r
-                               xTaskResumeAll();\r
+                               ( void ) xTaskResumeAll();\r
                        }\r
                }\r
                #endif /* INCLUDE_vTaskSuspend */\r
@@ -3392,7 +3491,7 @@ static void prvCheckTasksWaitingTermination( void )
 \r
        static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )\r
        {\r
-       volatile TCB_t *pxNextTCB, *pxFirstTCB;\r
+       configLIST_VOLATILE TCB_t *pxNextTCB, *pxFirstTCB;\r
        UBaseType_t uxTask = 0;\r
 \r
                if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )\r
@@ -3486,24 +3585,36 @@ static void prvCheckTasksWaitingTermination( void )
                }\r
                #endif /* configUSE_NEWLIB_REENTRANT */\r
 \r
-               #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )\r
+               #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) )\r
                {\r
-                       /* The task can only have been allocated dynamically - free it\r
-                       again. */\r
+                       /* The task can only have been allocated dynamically - free both\r
+                       the stack and TCB. */\r
                        vPortFree( pxTCB->pxStack );\r
                        vPortFree( pxTCB );\r
                }\r
-               #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )\r
+               #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 )\r
                {\r
                        /* The task could have been allocated statically or dynamically, so\r
-                       check before attempting to free the memory. */\r
-                       if( pxTCB->ucStaticallyAllocated == ( uint8_t ) pdFALSE )\r
+                       check what was statically allocated before trying to free the\r
+                       memory. */\r
+                       if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB )\r
                        {\r
+                               /* Both the stack and TCB were allocated dynamically, so both\r
+                               must be freed. */\r
                                vPortFree( pxTCB->pxStack );\r
                                vPortFree( pxTCB );\r
                        }\r
+                       else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY )\r
+                       {\r
+                               /* Only the stack was statically allocated, so the TCB is the\r
+                               only memory that must be freed. */\r
+                               vPortFree( pxTCB );\r
+                       }\r
                        else\r
                        {\r
+                               /* Neither the stack nor the TCB were allocated dynamically, so\r
+                               nothing needs to be freed. */\r
+                               configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB     )\r
                                mtCOVERAGE_TEST_MARKER();\r
                        }\r
                }\r