diff options
author | Nicolas Royer <nroyer@baylibre.com> | 2020-09-27 17:06:50 +0200 |
---|---|---|
committer | nicola-mazzucato-arm <42373140+nicola-mazzucato-arm@users.noreply.github.com> | 2020-10-15 17:45:38 +0100 |
commit | 084f9d4edade54160d16265b0108942709b2e7aa (patch) | |
tree | 2867fb045d52e03f2ddd36fc4820005a5872afd1 /product/rcar/src/CMSIS-FreeRTOS/Source/tasks.c | |
parent | db2d011984a280afbfdcde930ba1965db0d2b8d5 (diff) |
rcar: add rcar platform
This patch adds support for the rcar platform running on FreeRTOS.
FreeRTOS source code is temporarily included into rcar product directory
until armv8-a support is added to CMSIS-FreeRTOS repository.
Change-Id: Ia828f903d52df236922fe7f6f548bce06ee131cc
Signed-off-by: Tsutomu Muroya <tsutomu.muroya.jy@bp.renesas.com>
Signed-off-by: Nicolas Royer <nroyer@baylibre.com>
Diffstat (limited to 'product/rcar/src/CMSIS-FreeRTOS/Source/tasks.c')
-rw-r--r-- | product/rcar/src/CMSIS-FreeRTOS/Source/tasks.c | 5356 |
1 files changed, 5356 insertions, 0 deletions
diff --git a/product/rcar/src/CMSIS-FreeRTOS/Source/tasks.c b/product/rcar/src/CMSIS-FreeRTOS/Source/tasks.c new file mode 100644 index 00000000..ea565032 --- /dev/null +++ b/product/rcar/src/CMSIS-FreeRTOS/Source/tasks.c @@ -0,0 +1,5356 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* Standard includes. */ +#include <stdlib.h> +#include <string.h> + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "stack_macros.h" +#include "task.h" +#include "timers.h" + +/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified +because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined +for the header files above, but not in this file, in order to generate the +correct privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ + +/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting +functions but without including stdio.h here. */ +#if (configUSE_STATS_FORMATTING_FUNCTIONS == 1) +/* At the bottom of this file are two optional functions that can be used +to generate human readable text from the raw data generated by the +uxTaskGetSystemState() function. Note the formatting functions are provided +for convenience only, and are NOT considered part of the kernel. */ +# include <stdio.h> +#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */ + +#if (configUSE_PREEMPTION == 0) +/* If the cooperative scheduler is being used then a yield should not be +performed just because a higher priority task has been woken. */ +# define taskYIELD_IF_USING_PREEMPTION() +#else +# define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() +#endif + +/* Values that can be assigned to the ucNotifyState member of the TCB. */ +#define taskNOT_WAITING_NOTIFICATION ((uint8_t)0) +#define taskWAITING_NOTIFICATION ((uint8_t)1) +#define taskNOTIFICATION_RECEIVED ((uint8_t)2) + +/* + * The value used to fill the stack of a task when the task is created. This + * is used purely for checking the high water mark for tasks. + */ +#define tskSTACK_FILL_BYTE (0xa5U) + +/* Bits used to recored how a task's stack and TCB were allocated. */ +#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ((uint8_t)0) +#define tskSTATICALLY_ALLOCATED_STACK_ONLY ((uint8_t)1) +#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ((uint8_t)2) + +/* If any of the following are set then task stacks are filled with a known +value so the high water mark can be determined. If none of the following are +set then don't fill the stack so there is no unnecessary dependency on memset. +*/ +#if ( \ + (configCHECK_FOR_STACK_OVERFLOW > 1) || (configUSE_TRACE_FACILITY == 1) || \ + (INCLUDE_uxTaskGetStackHighWaterMark == 1) || \ + (INCLUDE_uxTaskGetStackHighWaterMark2 == 1)) +# define tskSET_NEW_STACKS_TO_KNOWN_VALUE 1 +#else +# define tskSET_NEW_STACKS_TO_KNOWN_VALUE 0 +#endif + +/* + * Macros used by vListTask to indicate which state a task is in. + */ +#define tskRUNNING_CHAR ('X') +#define tskBLOCKED_CHAR ('B') +#define tskREADY_CHAR ('R') +#define tskDELETED_CHAR ('D') +#define tskSUSPENDED_CHAR ('S') + +/* + * Some kernel aware debuggers require the data the debugger needs access to be + * global, rather than file scope. + */ +#ifdef portREMOVE_STATIC_QUALIFIER +# define static +#endif + +/* The name allocated to the Idle task. This can be overridden by defining +configIDLE_TASK_NAME in FreeRTOSConfig.h. */ +#ifndef configIDLE_TASK_NAME +# define configIDLE_TASK_NAME "IDLE" +#endif + +#if (configUSE_PORT_OPTIMISED_TASK_SELECTION == 0) + +/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is +performed in a generic way that is not optimised to any particular +microcontroller architecture. */ + +/* uxTopReadyPriority holds the priority of the highest priority ready +state task. */ +# define taskRECORD_READY_PRIORITY(uxPriority) \ + { \ + if ((uxPriority) > uxTopReadyPriority) { \ + uxTopReadyPriority = (uxPriority); \ + } \ + } /* taskRECORD_READY_PRIORITY */ + +/*-----------------------------------------------------------*/ + +# define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + UBaseType_t uxTopPriority = uxTopReadyPriority; \ +\ + /* Find the highest priority queue that contains ready tasks. */ \ + while (listLIST_IS_EMPTY(&(pxReadyTasksLists[uxTopPriority]))) { \ + configASSERT(uxTopPriority); \ + --uxTopPriority; \ + } \ +\ + /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the \ + tasks of \ + the same priority get an equal share of the processor time. */ \ + listGET_OWNER_OF_NEXT_ENTRY( \ + pxCurrentTCB, &(pxReadyTasksLists[uxTopPriority])); \ + uxTopReadyPriority = uxTopPriority; \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK */ + +/*-----------------------------------------------------------*/ + +/* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as +they are only required when a port optimised method of task selection is +being used. */ +# define taskRESET_READY_PRIORITY(uxPriority) +# define portRESET_READY_PRIORITY(uxPriority, uxTopReadyPriority) + +#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + +/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is +performed in a way that is tailored to the particular microcontroller +architecture being used. */ + +/* A port optimised version is provided. Call the port defined macros. */ +# define taskRECORD_READY_PRIORITY(uxPriority) \ + portRECORD_READY_PRIORITY(uxPriority, uxTopReadyPriority) + +/*-----------------------------------------------------------*/ + +# define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + UBaseType_t uxTopPriority; \ +\ + /* Find the highest priority list that contains ready tasks. */ \ + portGET_HIGHEST_PRIORITY(uxTopPriority, uxTopReadyPriority); \ + configASSERT( \ + listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[uxTopPriority])) > \ + 0); \ + listGET_OWNER_OF_NEXT_ENTRY( \ + pxCurrentTCB, &(pxReadyTasksLists[uxTopPriority])); \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ + +/*-----------------------------------------------------------*/ + +/* A port optimised version is provided, call it only if the TCB being reset +is being referenced from a ready list. If it is referenced from a delayed +or suspended list then it won't be in a ready list. */ +# define taskRESET_READY_PRIORITY(uxPriority) \ + { \ + if (listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[(uxPriority)])) == \ + (UBaseType_t)0) { \ + portRESET_READY_PRIORITY((uxPriority), (uxTopReadyPriority)); \ + } \ + } + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + +/*-----------------------------------------------------------*/ + +/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick +count overflows. */ +#define taskSWITCH_DELAYED_LISTS() \ + { \ + List_t *pxTemp; \ +\ + /* The delayed tasks list should be empty when the lists are switched. \ + */ \ + configASSERT((listLIST_IS_EMPTY(pxDelayedTaskList))); \ +\ + pxTemp = pxDelayedTaskList; \ + pxDelayedTaskList = pxOverflowDelayedTaskList; \ + pxOverflowDelayedTaskList = pxTemp; \ + xNumOfOverflows++; \ + prvResetNextTaskUnblockTime(); \ + } + +/*-----------------------------------------------------------*/ + +/* + * Place the task represented by pxTCB into the appropriate ready list for + * the task. It is inserted at the end of the list. + */ +#define prvAddTaskToReadyList(pxTCB) \ + traceMOVED_TASK_TO_READY_STATE(pxTCB); \ + taskRECORD_READY_PRIORITY((pxTCB)->uxPriority); \ + vListInsertEnd( \ + &(pxReadyTasksLists[(pxTCB)->uxPriority]), \ + &((pxTCB)->xStateListItem)); \ + tracePOST_MOVED_TASK_TO_READY_STATE(pxTCB) +/*-----------------------------------------------------------*/ + +/* + * Several functions take an TaskHandle_t parameter that can optionally be NULL, + * where NULL is used to indicate that the handle of the currently executing + * task should be used in place of the parameter. This macro simply checks to + * see if the parameter is NULL and returns a pointer to the appropriate TCB. + */ +#define prvGetTCBFromHandle(pxHandle) \ + (((pxHandle) == NULL) ? pxCurrentTCB : (pxHandle)) + +/* The item value of the event list item is normally used to hold the priority +of the task to which it belongs (coded to allow it to be held in reverse +priority order). However, it is occasionally borrowed for other purposes. It +is important its value is not updated due to a task priority change while it is +being used for another purpose. The following bit definition is used to inform +the scheduler that the value should not be changed - in which case it is the +responsibility of whichever module is using the value to ensure it gets set back +to its original value when it is released. */ +#if (configUSE_16_BIT_TICKS == 1) +# define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U +#else +# define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL +#endif + +/* + * Task control block. A task control block (TCB) is allocated for each task, + * and stores task state information, including a pointer to the task's context + * (the task's run time environment, including register values) + */ +typedef struct tskTaskControlBlock /* The old naming convention is used to + prevent breaking kernel aware debuggers. + */ +{ + volatile StackType_t + *pxTopOfStack; /*< Points to the location of the last item placed on the + tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB + STRUCT. */ + +#if (portUSING_MPU_WRAPPERS == 1) + xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the + port layer. THIS MUST BE THE SECOND MEMBER + OF THE TCB STRUCT. */ +#endif + + ListItem_t xStateListItem; /*< The list that the state list item of a task + is reference from denotes the state of that + task (Ready, Blocked, Suspended ). */ + ListItem_t + xEventListItem; /*< Used to reference a task from an event list. */ + UBaseType_t + uxPriority; /*< The priority of the task. 0 is the lowest priority. */ + StackType_t *pxStack; /*< Points to the start of the stack. */ + char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +#if ((portSTACK_GROWTH > 0) || (configRECORD_STACK_HIGH_ADDRESS == 1)) + StackType_t + *pxEndOfStack; /*< Points to the highest valid address for the stack. */ +#endif + +#if (portCRITICAL_NESTING_IN_TCB == 1) + UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth + for ports that do not maintain their own + count in the port layer. */ +#endif + +#if (configUSE_TRACE_FACILITY == 1) + UBaseType_t + uxTCBNumber; /*< Stores a number that increments each time a TCB is + created. It allows debuggers to determine when a task + has been deleted and then recreated. */ + UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third + party trace code. */ +#endif + +#if (configUSE_MUTEXES == 1) + UBaseType_t + uxBasePriority; /*< The priority last assigned to the task - used by the + priority inheritance mechanism. */ + UBaseType_t uxMutexesHeld; +#endif + +#if (configUSE_APPLICATION_TASK_TAG == 1) + TaskHookFunction_t pxTaskTag; +#endif + +#if (configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0) + void *pvThreadLocalStoragePointers[configNUM_THREAD_LOCAL_STORAGE_POINTERS]; +#endif + +#if (configGENERATE_RUN_TIME_STATS == 1) + uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent + in the Running state. */ +#endif + +#if (configUSE_NEWLIB_REENTRANT == 1) + /* Allocate a Newlib reent structure that is specific to this task. + Note Newlib support has been included by popular demand, but is not + used by the FreeRTOS maintainers themselves. FreeRTOS is not + responsible for resulting newlib operation. User must be familiar with + newlib and must provide system-wide implementations of the necessary + stubs. Be warned that (at the time of writing) the current newlib design + implements a system-wide malloc() that must be provided with locks. + + See the third party link + http://www.nadler.com/embedded/newlibAndFreeRTOS.html for additional + information. */ + struct _reent xNewLib_reent; +#endif + +#if (configUSE_TASK_NOTIFICATIONS == 1) + volatile uint32_t ulNotifiedValue; + volatile uint8_t ucNotifyState; +#endif + +/* See the comments in FreeRTOS.h with the definition of +tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ +#if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0) /*lint !e731 !e9029 Macro \ + has been consolidated \ + for readability \ + reasons. */ + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically + allocated to ensure no attempt is made to + free the memory. */ +#endif + +#if (INCLUDE_xTaskAbortDelay == 1) + uint8_t ucDelayAborted; +#endif + +#if (configUSE_POSIX_ERRNO == 1) + int iTaskErrno; +#endif + +} tskTCB; + +/* The old tskTCB name is maintained above then typedefed to the new TCB_t name +below to enable the use of older kernel aware debuggers. */ +typedef tskTCB TCB_t; + +/*lint -save -e956 A manual analysis and inspection has been used to determine +which static variables must be declared volatile. */ +PRIVILEGED_DATA TCB_t *volatile pxCurrentTCB = NULL; + +/* Lists for ready and blocked tasks. -------------------- +xDelayedTaskList1 and xDelayedTaskList2 could be move to function scople but +doing so breaks some kernel aware debuggers and debuggers that rely on removing +the static qualifier. */ +PRIVILEGED_DATA static List_t + pxReadyTasksLists[configMAX_PRIORITIES]; /*< Prioritised ready tasks. */ +PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */ +PRIVILEGED_DATA static List_t + xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays + that have overflowed the current tick count. */ +PRIVILEGED_DATA static List_t + *volatile pxDelayedTaskList; /*< Points to the delayed task list currently + being used. */ +PRIVILEGED_DATA static List_t + *volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list + currently being used to hold tasks + that have overflowed the current + tick count. */ +PRIVILEGED_DATA static List_t + xPendingReadyList; /*< Tasks that have been readied while the scheduler was + suspended. They will be moved to the ready list when + the scheduler is resumed. */ + +#if (INCLUDE_vTaskDelete == 1) + +PRIVILEGED_DATA static List_t + xTasksWaitingTermination; /*< Tasks that have been deleted - but their + memory not yet freed. */ +PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = + (UBaseType_t)0U; + +#endif + +#if (INCLUDE_vTaskSuspend == 1) + +PRIVILEGED_DATA static List_t + xSuspendedTaskList; /*< Tasks that are currently suspended. */ + +#endif + +/* Global POSIX errno. Its value is changed upon context switching to match +the errno of the currently running task. */ +#if (configUSE_POSIX_ERRNO == 1) +int FreeRTOS_errno = 0; +#endif + +/* Other file private variables. --------------------------------*/ +PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = + (UBaseType_t)0U; +PRIVILEGED_DATA static volatile TickType_t xTickCount = + (TickType_t)configINITIAL_TICK_COUNT; +PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = + tskIDLE_PRIORITY; +PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; +PRIVILEGED_DATA static volatile TickType_t xPendedTicks = (TickType_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 = + (TickType_t)0U; /* Initialised to portMAX_DELAY before the scheduler starts. + */ +PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = + NULL; /*< Holds the handle of the idle task. The idle task is created + automatically when the scheduler is started. */ + +/* 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) + +/* Do not move these variables to function scope as doing so prevents the +code working with debuggers that need to remove the static qualifier. */ +PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = + 0UL; /*< Holds the value of a timer/counter the last time a task was + switched in. */ +PRIVILEGED_DATA static uint32_t ulTotalRunTime = + 0UL; /*< Holds the total amount of execution time as defined by the run time + counter clock. */ + +#endif + +/*lint -restore */ + +/*-----------------------------------------------------------*/ + +/* Callback function prototypes. --------------------------*/ +#if (configCHECK_FOR_STACK_OVERFLOW > 0) + +extern void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName); + +#endif + +#if (configUSE_TICK_HOOK > 0) + +extern void vApplicationTickHook( + void); /*lint !e526 Symbol not defined as it is an application callback. */ + +#endif + +#if (configSUPPORT_STATIC_ALLOCATION == 1) + +extern void vApplicationGetIdleTaskMemory( + StaticTask_t **ppxIdleTaskTCBBuffer, + StackType_t **ppxIdleTaskStackBuffer, + uint32_t *pulIdleTaskStackSize); /*lint !e526 Symbol not defined as it is an + application callback. */ + +#endif + +/* File private functions. --------------------------------*/ + +/** + * 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. + */ +#if (INCLUDE_vTaskSuspend == 1) + +static BaseType_t prvTaskIsTaskSuspended(const TaskHandle_t xTask) + PRIVILEGED_FUNCTION; + +#endif /* INCLUDE_vTaskSuspend */ + +/* + * Utility to ready all the lists used by the scheduler. This is called + * automatically upon the creation of the first task. + */ +static void prvInitialiseTaskLists(void) PRIVILEGED_FUNCTION; + +/* + * The idle task, which as all tasks is implemented as a never ending loop. + * The idle task is automatically created and added to the ready lists upon + * creation of the first user task. + * + * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific + * language extensions. The equivalent prototype for this function is: + * + * void prvIdleTask( void *pvParameters ); + * + */ +static portTASK_FUNCTION_PROTO(prvIdleTask, pvParameters); + +/* + * Utility to free all memory allocated by the scheduler to hold a TCB, + * including the stack pointed to by the TCB. + * + * This does not free memory allocated by the task itself (i.e. memory + * allocated by calls to pvPortMalloc from within the tasks application code). + */ +#if (INCLUDE_vTaskDelete == 1) + +static void prvDeleteTCB(TCB_t *pxTCB) PRIVILEGED_FUNCTION; + +#endif + +/* + * Used only by the idle task. This checks to see if anything has been placed + * in the list of tasks waiting to be deleted. If so the task is cleaned up + * and its TCB deleted. + */ +static void prvCheckTasksWaitingTermination(void) PRIVILEGED_FUNCTION; + +/* + * The currently executing task is entering the Blocked state. Add the task to + * either the current or the overflow delayed task list. + */ +static void prvAddCurrentTaskToDelayedList( + TickType_t xTicksToWait, + const BaseType_t xCanBlockIndefinitely) PRIVILEGED_FUNCTION; + +/* + * Fills an TaskStatus_t structure with information on each task that is + * referenced from the pxList list (which may be a ready list, a delayed list, + * a suspended list, etc.). + * + * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM + * NORMAL APPLICATION CODE. + */ +#if (configUSE_TRACE_FACILITY == 1) + +static UBaseType_t prvListTasksWithinSingleList( + TaskStatus_t *pxTaskStatusArray, + List_t *pxList, + eTaskState eState) PRIVILEGED_FUNCTION; + +#endif + +/* + * Searches pxList for a task with name pcNameToQuery - returning a handle to + * the task if it is found, or NULL if the task is not found. + */ +#if (INCLUDE_xTaskGetHandle == 1) + +static TCB_t *prvSearchForNameWithinSingleList( + List_t *pxList, + const char pcNameToQuery[]) PRIVILEGED_FUNCTION; + +#endif + +/* + * When a task is created, the stack of the task is filled with a known value. + * This function determines the 'high water mark' of the task stack by + * determining how much of the stack remains at the original preset value. + */ +#if ( \ + (configUSE_TRACE_FACILITY == 1) || \ + (INCLUDE_uxTaskGetStackHighWaterMark == 1) || \ + (INCLUDE_uxTaskGetStackHighWaterMark2 == 1)) + +static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( + const uint8_t *pucStackByte) PRIVILEGED_FUNCTION; + +#endif + +/* + * Return the amount of time, in ticks, that will pass before the kernel will + * next move a task from the Blocked state to the Running state. + * + * This conditional compilation should use inequality to 0, not equality to 1. + * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user + * defined low power mode implementations require configUSE_TICKLESS_IDLE to be + * set to a value other than 1. + */ +#if (configUSE_TICKLESS_IDLE != 0) + +static TickType_t prvGetExpectedIdleTime(void) PRIVILEGED_FUNCTION; + +#endif + +/* + * Set xNextTaskUnblockTime to the time at which the next Blocked state task + * will exit the Blocked state. + */ +static void prvResetNextTaskUnblockTime(void); + +#if ( \ + (configUSE_TRACE_FACILITY == 1) && \ + (configUSE_STATS_FORMATTING_FUNCTIONS > 0)) + +/* + * Helper function used to pad task names with spaces when printing out + * human readable tables of task information. + */ +static char *prvWriteNameToBuffer(char *pcBuffer, const char *pcTaskName) + PRIVILEGED_FUNCTION; + +#endif + +/* + * Called after a Task_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewTask( + TaskFunction_t pxTaskCode, + const char *const pcName, /*lint !e971 Unqualified char types are allowed + for strings and single characters only. */ + const uint32_t ulStackDepth, + void *const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t *const pxCreatedTask, + TCB_t *pxNewTCB, + const MemoryRegion_t *const xRegions) PRIVILEGED_FUNCTION; + +/* + * Called after a new task has been created and initialised to place the task + * under the control of the scheduler. + */ +static void prvAddNewTaskToReadyList(TCB_t *pxNewTCB) PRIVILEGED_FUNCTION; + +/* + * freertos_tasks_c_additions_init() should only be called if the user definable + * macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro + * called by the function. + */ +#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT + +static void freertos_tasks_c_additions_init(void) PRIVILEGED_FUNCTION; + +#endif + +/*-----------------------------------------------------------*/ + +#if (configSUPPORT_STATIC_ALLOCATION == 1) + +TaskHandle_t xTaskCreateStatic( + TaskFunction_t pxTaskCode, + const char *const pcName, /*lint !e971 Unqualified char types are allowed + for strings and single characters only. */ + const uint32_t ulStackDepth, + void *const pvParameters, + UBaseType_t uxPriority, + StackType_t *const puxStackBuffer, + StaticTask_t *const pxTaskBuffer) +{ + TCB_t *pxNewTCB; + TaskHandle_t xReturn; + + configASSERT(puxStackBuffer != NULL); + configASSERT(pxTaskBuffer != NULL); + +# if (configASSERT_DEFINED == 1) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticTask_t equals the size of the real task + structure. */ + volatile size_t xSize = sizeof(StaticTask_t); + configASSERT(xSize == sizeof(TCB_t)); + (void)xSize; /* Prevent lint warning when configASSERT() is not used. */ + } +# endif /* configASSERT_DEFINED */ + + if ((pxTaskBuffer != NULL) && (puxStackBuffer != NULL)) { + /* The memory used for the task's TCB and stack are passed into this + function - use them. */ + pxNewTCB = (TCB_t *) + pxTaskBuffer; /*lint !e740 !e9087 Unusual cast is ok as the + structures are designed to have the same alignment, + and the size is checked by an assert. */ + pxNewTCB->pxStack = (StackType_t *)puxStackBuffer; + +# if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0) /*lint !e731 !e9029 \ + Macro has been \ + consolidated for \ + readability \ + reasons. */ + { + /* Tasks can be created statically or dynamically, so note this + task was created statically in case the task is later deleted. */ + pxNewTCB->ucStaticallyAllocated = + tskSTATICALLY_ALLOCATED_STACK_AND_TCB; + } +# endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ + + prvInitialiseNewTask( + pxTaskCode, + pcName, + ulStackDepth, + pvParameters, + uxPriority, + &xReturn, + pxNewTCB, + NULL); + prvAddNewTaskToReadyList(pxNewTCB); + } else { + xReturn = NULL; + } + + return xReturn; +} + +#endif /* SUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if ((portUSING_MPU_WRAPPERS == 1) && (configSUPPORT_STATIC_ALLOCATION == 1)) + +BaseType_t xTaskCreateRestrictedStatic( + const TaskParameters_t *const pxTaskDefinition, + TaskHandle_t *pxCreatedTask) +{ + TCB_t *pxNewTCB; + BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + + configASSERT(pxTaskDefinition->puxStackBuffer != NULL); + configASSERT(pxTaskDefinition->pxTaskBuffer != NULL); + + if ((pxTaskDefinition->puxStackBuffer != NULL) && + (pxTaskDefinition->pxTaskBuffer != NULL)) { + /* Allocate space for the TCB. Where the memory comes from depends + on the implementation of the port malloc function and whether or + not static allocation is being used. */ + pxNewTCB = (TCB_t *)pxTaskDefinition->pxTaskBuffer; + + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer; + +# if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0) + { + /* Tasks can be created statically or dynamically, so note this + task was created statically in case the task is later deleted. */ + pxNewTCB->ucStaticallyAllocated = + tskSTATICALLY_ALLOCATED_STACK_AND_TCB; + } +# endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ + + prvInitialiseNewTask( + pxTaskDefinition->pvTaskCode, + pxTaskDefinition->pcName, + (uint32_t)pxTaskDefinition->usStackDepth, + pxTaskDefinition->pvParameters, + pxTaskDefinition->uxPriority, + pxCreatedTask, + pxNewTCB, + pxTaskDefinition->xRegions); + + prvAddNewTaskToReadyList(pxNewTCB); + xReturn = pdPASS; + } + + return xReturn; +} + +#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION \ + == 1 ) */ +/*-----------------------------------------------------------*/ + +#if ((portUSING_MPU_WRAPPERS == 1) && (configSUPPORT_DYNAMIC_ALLOCATION == 1)) + +BaseType_t xTaskCreateRestricted( + const TaskParameters_t *const pxTaskDefinition, + TaskHandle_t *pxCreatedTask) +{ + TCB_t *pxNewTCB; + BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + + configASSERT(pxTaskDefinition->puxStackBuffer); + + if (pxTaskDefinition->puxStackBuffer != NULL) { + /* Allocate space for the TCB. Where the memory comes from depends + on the implementation of the port malloc function and whether or + not static allocation is being used. */ + pxNewTCB = (TCB_t *)pvPortMalloc(sizeof(TCB_t)); + + if (pxNewTCB != NULL) { + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer; + +# if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0) + { + /* Tasks can be created statically or dynamically, so note + this task had a statically allocated stack in case it is + later deleted. The TCB was allocated dynamically. */ + pxNewTCB->ucStaticallyAllocated = + tskSTATICALLY_ALLOCATED_STACK_ONLY; + } +# endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ + + prvInitialiseNewTask( + pxTaskDefinition->pvTaskCode, + pxTaskDefinition->pcName, + (uint32_t)pxTaskDefinition->usStackDepth, + pxTaskDefinition->pvParameters, + pxTaskDefinition->uxPriority, + pxCreatedTask, + pxNewTCB, + pxTaskDefinition->xRegions); + + prvAddNewTaskToReadyList(pxNewTCB); + xReturn = pdPASS; + } + } + + return xReturn; +} + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ + +#if (configSUPPORT_DYNAMIC_ALLOCATION == 1) + +BaseType_t xTaskCreate( + TaskFunction_t pxTaskCode, + const char *const pcName, /*lint !e971 Unqualified char types are allowed + for strings and single characters only. */ + const configSTACK_DEPTH_TYPE usStackDepth, + void *const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t *const pxCreatedTask) +{ + TCB_t *pxNewTCB; + BaseType_t xReturn; + +/* If the stack grows down then allocate the stack then the TCB so the stack +does not grow into the TCB. Likewise if the stack grows up then allocate +the TCB then the stack. */ +# if (portSTACK_GROWTH > 0) + { + /* Allocate space for the TCB. Where the memory comes from depends on + the implementation of the port malloc function and whether or not static + allocation is being used. */ + pxNewTCB = (TCB_t *)pvPortMalloc(sizeof(TCB_t)); + + if (pxNewTCB != NULL) { + /* Allocate space for the stack used by the task being created. + The base of the stack memory stored in the TCB so the task can + be deleted later if required. */ + pxNewTCB->pxStack = (StackType_t *)pvPortMalloc(( + ((size_t)usStackDepth) * + sizeof(StackType_t))); /*lint !e961 MISRA exception as the casts + are only redundant for some ports. */ + + if (pxNewTCB->pxStack == NULL) { + /* Could not allocate the stack. Delete the allocated TCB. */ + vPortFree(pxNewTCB); + pxNewTCB = NULL; + } + } + } +# else /* portSTACK_GROWTH */ + { + StackType_t *pxStack; + + /* Allocate space for the stack used by the task being created. */ + pxStack = pvPortMalloc( + (((size_t)usStackDepth) * + sizeof(StackType_t))); /*lint !e9079 All values returned by + pvPortMalloc() have at least the + alignment required by the MCU's stack and + this allocation is the stack. */ + + if (pxStack != NULL) { + /* Allocate space for the TCB. */ + pxNewTCB = (TCB_t *)pvPortMalloc(sizeof( + TCB_t)); /*lint !e9087 !e9079 All values returned by + pvPortMalloc() have at least the alignment required + by the MCU's stack, and the first member of TCB_t is + always a pointer to the task's stack. */ + + if (pxNewTCB != NULL) { + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxStack; + } else { + /* The stack cannot be used as the TCB was not created. Free + it again. */ + vPortFree(pxStack); + } + } else { + pxNewTCB = NULL; + } + } +# endif /* portSTACK_GROWTH */ + + if (pxNewTCB != NULL) { +# if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0) /*lint !e9029 !e731 \ + Macro has been \ + consolidated for \ + readability \ + reasons. */ + { + /* Tasks can be created statically or dynamically, so note this + task was created dynamically in case it is later deleted. */ + pxNewTCB->ucStaticallyAllocated = + tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB; + } +# endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ + + prvInitialiseNewTask( + pxTaskCode, + pcName, + (uint32_t)usStackDepth, + pvParameters, + uxPriority, + pxCreatedTask, + pxNewTCB, + NULL); + prvAddNewTaskToReadyList(pxNewTCB); + xReturn = pdPASS; + } else { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } + + return xReturn; +} + +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewTask( + TaskFunction_t pxTaskCode, + const char *const pcName, /*lint !e971 Unqualified char types are allowed + for strings and single characters only. */ + const uint32_t ulStackDepth, + void *const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t *const pxCreatedTask, + TCB_t *pxNewTCB, + const MemoryRegion_t *const xRegions) +{ + StackType_t *pxTopOfStack; + UBaseType_t x; + +#if (portUSING_MPU_WRAPPERS == 1) + /* Should the task be created in privileged mode? */ + BaseType_t xRunPrivileged; + if ((uxPriority & portPRIVILEGE_BIT) != 0U) { + xRunPrivileged = pdTRUE; + } else { + xRunPrivileged = pdFALSE; + } + uxPriority &= ~portPRIVILEGE_BIT; +#endif /* portUSING_MPU_WRAPPERS == 1 */ + +/* Avoid dependency on memset() if it is not required. */ +#if (tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1) + { + /* Fill the stack with a known value to assist debugging. */ + (void)memset( + pxNewTCB->pxStack, + (int)tskSTACK_FILL_BYTE, + (size_t)ulStackDepth * sizeof(StackType_t)); + } +#endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */ + +/* Calculate the top of stack address. This depends on whether the stack +grows from high memory to low (as per the 80x86) or vice versa. +portSTACK_GROWTH is used to make the result positive or negative as required +by the port. */ +#if (portSTACK_GROWTH < 0) + { + pxTopOfStack = &(pxNewTCB->pxStack[ulStackDepth - (uint32_t)1]); + pxTopOfStack = + (StackType_t + *)(((portPOINTER_SIZE_TYPE)pxTopOfStack) & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK))); /*lint !e923 !e9033 !e9078 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. Checked by assert(). */ + + /* Check the alignment of the calculated top of stack is correct. */ + configASSERT( + (((portPOINTER_SIZE_TYPE)pxTopOfStack & + (portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK) == 0UL)); + +# if (configRECORD_STACK_HIGH_ADDRESS == 1) + { + /* Also record the stack's high address, which may assist + debugging. */ + pxNewTCB->pxEndOfStack = pxTopOfStack; + } +# endif /* configRECORD_STACK_HIGH_ADDRESS */ + } +#else /* portSTACK_GROWTH */ + { + pxTopOfStack = pxNewTCB->pxStack; + + /* Check the alignment of the stack buffer is correct. */ + configASSERT( + (((portPOINTER_SIZE_TYPE)pxNewTCB->pxStack & + (portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK) == 0UL)); + + /* The other extreme of the stack space is required if stack checking is + performed. */ + pxNewTCB->pxEndOfStack = + pxNewTCB->pxStack + (ulStackDepth - (uint32_t)1); + } +#endif /* portSTACK_GROWTH */ + + /* Store the task name in the TCB. */ + if (pcName != NULL) { + for (x = (UBaseType_t)0; x < (UBaseType_t)configMAX_TASK_NAME_LEN; + x++) { + pxNewTCB->pcTaskName[x] = pcName[x]; + + /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter + than configMAX_TASK_NAME_LEN characters just in case the memory + after the string is not accessible (extremely unlikely). */ + if (pcName[x] == (char)0x00) { + break; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Ensure the name string is terminated in the case that the string + length was greater or equal to configMAX_TASK_NAME_LEN. */ + pxNewTCB->pcTaskName[configMAX_TASK_NAME_LEN - 1] = '\0'; + } else { + /* The task has not been given a name, so just ensure there is a NULL + terminator when it is read out. */ + pxNewTCB->pcTaskName[0] = 0x00; + } + + /* This is used as an array index so must ensure it's not too large. First + remove the privilege bit if one is present. */ + if (uxPriority >= (UBaseType_t)configMAX_PRIORITIES) { + uxPriority = (UBaseType_t)configMAX_PRIORITIES - (UBaseType_t)1U; + } else { + mtCOVERAGE_TEST_MARKER(); + } + + pxNewTCB->uxPriority = uxPriority; +#if (configUSE_MUTEXES == 1) + { + pxNewTCB->uxBasePriority = uxPriority; + pxNewTCB->uxMutexesHeld = 0; + } +#endif /* configUSE_MUTEXES */ + + vListInitialiseItem(&(pxNewTCB->xStateListItem)); + vListInitialiseItem(&(pxNewTCB->xEventListItem)); + + /* Set the pxNewTCB as a link back from the ListItem_t. This is so we can + get back to the containing TCB from a generic item in a list. */ + listSET_LIST_ITEM_OWNER(&(pxNewTCB->xStateListItem), pxNewTCB); + + /* Event lists are always in priority order. */ + listSET_LIST_ITEM_VALUE( + &(pxNewTCB->xEventListItem), + (TickType_t)configMAX_PRIORITIES - + (TickType_t)uxPriority); /*lint !e961 MISRA exception as the casts + are only redundant for some ports. */ + listSET_LIST_ITEM_OWNER(&(pxNewTCB->xEventListItem), pxNewTCB); + +#if (portCRITICAL_NESTING_IN_TCB == 1) + { + pxNewTCB->uxCriticalNesting = (UBaseType_t)0U; + } +#endif /* portCRITICAL_NESTING_IN_TCB */ + +#if (configUSE_APPLICATION_TASK_TAG == 1) + { + pxNewTCB->pxTaskTag = NULL; + } +#endif /* configUSE_APPLICATION_TASK_TAG */ + +#if (configGENERATE_RUN_TIME_STATS == 1) + { + pxNewTCB->ulRunTimeCounter = 0UL; + } +#endif /* configGENERATE_RUN_TIME_STATS */ + +#if (portUSING_MPU_WRAPPERS == 1) + { + vPortStoreTaskMPUSettings( + &(pxNewTCB->xMPUSettings), + xRegions, + pxNewTCB->pxStack, + ulStackDepth); + } +#else + { + /* Avoid compiler warning about unreferenced parameter. */ + (void)xRegions; + } +#endif + +#if (configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0) + { + for (x = 0; x < (UBaseType_t)configNUM_THREAD_LOCAL_STORAGE_POINTERS; + x++) { + pxNewTCB->pvThreadLocalStoragePointers[x] = NULL; + } + } +#endif + +#if (configUSE_TASK_NOTIFICATIONS == 1) + { + pxNewTCB->ulNotifiedValue = 0; + pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } +#endif + +#if (configUSE_NEWLIB_REENTRANT == 1) + { + /* Initialise this task's Newlib reent structure. + See the third party link + http://www.nadler.com/embedded/newlibAndFreeRTOS.html for additional + information. */ + _REENT_INIT_PTR((&(pxNewTCB->xNewLib_reent))); + } +#endif + +#if (INCLUDE_xTaskAbortDelay == 1) + { + pxNewTCB->ucDelayAborted = pdFALSE; + } +#endif + +/* Initialize the TCB stack to look as if the task was already running, +but had been interrupted by the scheduler. The return address is set +to the start of the task function. Once the stack has been initialised +the top of stack variable is updated. */ +#if (portUSING_MPU_WRAPPERS == 1) + { +/* If the port has capability to detect stack overflow, +pass the stack end address to the stack initialization +function as well. */ +# if (portHAS_STACK_OVERFLOW_CHECKING == 1) + { +# if (portSTACK_GROWTH < 0) + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( + pxTopOfStack, + pxNewTCB->pxStack, + pxTaskCode, + pvParameters, + xRunPrivileged); + } +# else /* portSTACK_GROWTH */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( + pxTopOfStack, + pxNewTCB->pxEndOfStack, + pxTaskCode, + pvParameters, + xRunPrivileged); + } +# endif /* portSTACK_GROWTH */ + } +# else /* portHAS_STACK_OVERFLOW_CHECKING */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( + pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged); + } +# endif /* portHAS_STACK_OVERFLOW_CHECKING */ + } +#else /* portUSING_MPU_WRAPPERS */ + { +/* If the port has capability to detect stack overflow, +pass the stack end address to the stack initialization +function as well. */ +# if (portHAS_STACK_OVERFLOW_CHECKING == 1) + { +# if (portSTACK_GROWTH < 0) + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( + pxTopOfStack, pxNewTCB->pxStack, pxTaskCode, pvParameters); + } +# else /* portSTACK_GROWTH */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( + pxTopOfStack, + pxNewTCB->pxEndOfStack, + pxTaskCode, + pvParameters); + } +# endif /* portSTACK_GROWTH */ + } +# else /* portHAS_STACK_OVERFLOW_CHECKING */ + { + pxNewTCB->pxTopOfStack = + pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters); + } +# endif /* portHAS_STACK_OVERFLOW_CHECKING */ + } +#endif /* portUSING_MPU_WRAPPERS */ + + if (pxCreatedTask != NULL) { + /* Pass the handle out in an anonymous way. The handle can be used to + change the created task's priority, delete the created task, etc.*/ + *pxCreatedTask = (TaskHandle_t)pxNewTCB; + } else { + mtCOVERAGE_TEST_MARKER(); + } +} +/*-----------------------------------------------------------*/ + +static void prvAddNewTaskToReadyList(TCB_t *pxNewTCB) +{ + /* Ensure interrupts don't access the task lists while the lists are being + updated. */ + taskENTER_CRITICAL(); + { + uxCurrentNumberOfTasks++; + if (pxCurrentTCB == NULL) { + /* There are no other tasks, or all the other tasks are in + the suspended state - make this the current task. */ + pxCurrentTCB = pxNewTCB; + + if (uxCurrentNumberOfTasks == (UBaseType_t)1) { + /* This is the first task to be created so do the preliminary + initialisation required. We will not recover if this call + fails, but we will report the failure. */ + prvInitialiseTaskLists(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + /* If the scheduler is not already running, make this task the + current task if it is the highest priority task to be created + so far. */ + if (xSchedulerRunning == pdFALSE) { + if (pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority) { + pxCurrentTCB = pxNewTCB; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + + uxTaskNumber++; + +#if (configUSE_TRACE_FACILITY == 1) + { + /* Add a counter into the TCB for tracing only. */ + pxNewTCB->uxTCBNumber = uxTaskNumber; + } +#endif /* configUSE_TRACE_FACILITY */ + traceTASK_CREATE(pxNewTCB); + + prvAddTaskToReadyList(pxNewTCB); + + portSETUP_TCB(pxNewTCB); + } + taskEXIT_CRITICAL(); + + if (xSchedulerRunning != pdFALSE) { + /* If the created task is of a higher priority than the current task + then it should run now. */ + if (pxCurrentTCB->uxPriority < pxNewTCB->uxPriority) { + taskYIELD_IF_USING_PREEMPTION(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } +} +/*-----------------------------------------------------------*/ + +#if (INCLUDE_vTaskDelete == 1) + +void vTaskDelete(TaskHandle_t xTaskToDelete) +{ + TCB_t *pxTCB; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the calling task that is + being deleted. */ + pxTCB = prvGetTCBFromHandle(xTaskToDelete); + + /* Remove task from the ready/delayed list. */ + if (uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0) { + taskRESET_READY_PRIORITY(pxTCB->uxPriority); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* Is the task waiting on an event also? */ + if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != NULL) { + (void)uxListRemove(&(pxTCB->xEventListItem)); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* Increment the uxTaskNumber also so kernel aware debuggers can + detect that the task lists need re-generating. This is done before + portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will + not return. */ + uxTaskNumber++; + + if (pxTCB == pxCurrentTCB) { + /* A task is deleting itself. This cannot complete within the + task itself, as a context switch to another task is required. + Place the task in the termination list. The idle task will + check the termination list and free up any memory allocated by + the scheduler for the TCB and stack of the deleted task. */ + vListInsertEnd(&xTasksWaitingTermination, &(pxTCB->xStateListItem)); + + /* Increment the ucTasksDeleted variable so the idle task knows + there is a task that has been deleted and that it should therefore + check the xTasksWaitingTermination list. */ + ++uxDeletedTasksWaitingCleanUp; + + /* Call the delete hook before portPRE_TASK_DELETE_HOOK() as + portPRE_TASK_DELETE_HOOK() does not return in the Win32 port. */ + traceTASK_DELETE(pxTCB); + + /* The pre-delete hook is primarily for the Windows simulator, + in which Windows specific clean up operations are performed, + after which it is not possible to yield away from this task - + hence xYieldPending is used to latch that a context switch is + required. */ + portPRE_TASK_DELETE_HOOK(pxTCB, &xYieldPending); + } else { + --uxCurrentNumberOfTasks; + traceTASK_DELETE(pxTCB); + prvDeleteTCB(pxTCB); + + /* Reset the next expected unblock time in case it referred to + the task that has just been deleted. */ + prvResetNextTaskUnblockTime(); + } + } + taskEXIT_CRITICAL(); + + /* Force a reschedule if it is the currently running task that has just + been deleted. */ + if (xSchedulerRunning != pdFALSE) { + if (pxTCB == pxCurrentTCB) { + configASSERT(uxSchedulerSuspended == 0); + portYIELD_WITHIN_API(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } +} + +#endif /* INCLUDE_vTaskDelete */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_vTaskDelayUntil == 1) + +void vTaskDelayUntil( + TickType_t *const pxPreviousWakeTime, + const TickType_t xTimeIncrement) +{ + TickType_t xTimeToWake; + BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE; + + configASSERT(pxPreviousWakeTime); + configASSERT((xTimeIncrement > 0U)); + configASSERT(uxSchedulerSuspended == 0); + + vTaskSuspendAll(); + { + /* Minor optimisation. The tick count cannot change in this + block. */ + const TickType_t xConstTickCount = xTickCount; + + /* Generate the tick time at which the task wants to wake. */ + xTimeToWake = *pxPreviousWakeTime + xTimeIncrement; + + if (xConstTickCount < *pxPreviousWakeTime) { + /* The tick count has overflowed since this function was + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ + if ((xTimeToWake < *pxPreviousWakeTime) && + (xTimeToWake > xConstTickCount)) { + xShouldDelay = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ + if ((xTimeToWake < *pxPreviousWakeTime) || + (xTimeToWake > xConstTickCount)) { + xShouldDelay = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Update the wake time ready for the next call. */ + *pxPreviousWakeTime = xTimeToWake; + + if (xShouldDelay != pdFALSE) { + traceTASK_DELAY_UNTIL(xTimeToWake); + + /* prvAddCurrentTaskToDelayedList() needs the block time, not + the time to wake, so subtract the current tick count. */ + prvAddCurrentTaskToDelayedList( + xTimeToWake - xConstTickCount, pdFALSE); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + xAlreadyYielded = xTaskResumeAll(); + + /* Force a reschedule if xTaskResumeAll has not already done so, we may + have put ourselves to sleep. */ + if (xAlreadyYielded == pdFALSE) { + portYIELD_WITHIN_API(); + } else { + mtCOVERAGE_TEST_MARKER(); + } +} + +#endif /* INCLUDE_vTaskDelayUntil */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_vTaskDelay == 1) + +void vTaskDelay(const TickType_t xTicksToDelay) +{ + BaseType_t xAlreadyYielded = pdFALSE; + + /* A delay time of zero just forces a reschedule. */ + if (xTicksToDelay > (TickType_t)0U) { + configASSERT(uxSchedulerSuspended == 0); + vTaskSuspendAll(); + { + traceTASK_DELAY(); + + /* A task that is removed from the event list while the + scheduler is suspended will not get placed in the ready + list or removed from the blocked list until the scheduler + is resumed. + + This task cannot be in an event list as it is the currently + executing task. */ + prvAddCurrentTaskToDelayedList(xTicksToDelay, pdFALSE); + } + xAlreadyYielded = xTaskResumeAll(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* Force a reschedule if xTaskResumeAll has not already done so, we may + have put ourselves to sleep. */ + if (xAlreadyYielded == pdFALSE) { + portYIELD_WITHIN_API(); + } else { + mtCOVERAGE_TEST_MARKER(); + } +} + +#endif /* INCLUDE_vTaskDelay */ +/*-----------------------------------------------------------*/ + +#if ( \ + (INCLUDE_eTaskGetState == 1) || (configUSE_TRACE_FACILITY == 1) || \ + (INCLUDE_xTaskAbortDelay == 1)) + +eTaskState eTaskGetState(TaskHandle_t xTask) +{ + eTaskState eReturn; + List_t const *pxStateList, *pxDelayedList, *pxOverflowedDelayedList; + const TCB_t *const pxTCB = xTask; + + configASSERT(pxTCB); + + if (pxTCB == pxCurrentTCB) { + /* The task calling this function is querying its own state. */ + eReturn = eRunning; + } else { + taskENTER_CRITICAL(); + { + pxStateList = listLIST_ITEM_CONTAINER(&(pxTCB->xStateListItem)); + pxDelayedList = pxDelayedTaskList; + pxOverflowedDelayedList = pxOverflowDelayedTaskList; + } + taskEXIT_CRITICAL(); + + if ((pxStateList == pxDelayedList) || + (pxStateList == pxOverflowedDelayedList)) { + /* The task being queried is referenced from one of the Blocked + lists. */ + eReturn = eBlocked; + } +# if (INCLUDE_vTaskSuspend == 1) + else if (pxStateList == &xSuspendedTaskList) { + /* The task being queried is referenced from the suspended + list. Is it genuinely suspended or is it blocked + indefinitely? */ + if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) == NULL) { +# if (configUSE_TASK_NOTIFICATIONS == 1) + { + /* The task does not appear on the event list item of + and of the RTOS objects, but could still be in the + blocked state if it is waiting on its notification + rather than waiting on an object. */ + if (pxTCB->ucNotifyState == taskWAITING_NOTIFICATION) { + eReturn = eBlocked; + } else { + eReturn = eSuspended; + } + } +# else + { + eReturn = eSuspended; + } +# endif + } else { + eReturn = eBlocked; + } + } +# endif + +# if (INCLUDE_vTaskDelete == 1) + else if ( + (pxStateList == &xTasksWaitingTermination) || + (pxStateList == NULL)) { + /* The task being queried is referenced from the deleted + tasks list, or it is not referenced from any lists at + all. */ + eReturn = eDeleted; + } +# endif + + else /*lint !e525 Negative indentation is intended to make use of + pre-processor clearer. */ + { + /* If the task is not in any other state, it must be in the + Ready (including pending ready) state. */ + eReturn = eReady; + } + } + + return eReturn; +} /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ + +#endif /* INCLUDE_eTaskGetState */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_uxTaskPriorityGet == 1) + +UBaseType_t uxTaskPriorityGet(const TaskHandle_t xTask) +{ + TCB_t const *pxTCB; + UBaseType_t uxReturn; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the priority of the task + that called uxTaskPriorityGet() that is being queried. */ + pxTCB = prvGetTCBFromHandle(xTask); + uxReturn = pxTCB->uxPriority; + } + taskEXIT_CRITICAL(); + + return uxReturn; +} + +#endif /* INCLUDE_uxTaskPriorityGet */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_uxTaskPriorityGet == 1) + +UBaseType_t uxTaskPriorityGetFromISR(const TaskHandle_t xTask) +{ + TCB_t const *pxTCB; + UBaseType_t uxReturn, uxSavedInterruptState; + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + https://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR(); + { + /* If null is passed in here then it is the priority of the calling + task that is being queried. */ + pxTCB = prvGetTCBFromHandle(xTask); + uxReturn = pxTCB->uxPriority; + } + portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptState); + + return uxReturn; +} + +#endif /* INCLUDE_uxTaskPriorityGet */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_vTaskPrioritySet == 1) + +void vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority) +{ + TCB_t *pxTCB; + UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry; + BaseType_t xYieldRequired = pdFALSE; + + configASSERT((uxNewPriority < configMAX_PRIORITIES)); + + /* Ensure the new priority is valid. */ + if (uxNewPriority >= (UBaseType_t)configMAX_PRIORITIES) { + uxNewPriority = (UBaseType_t)configMAX_PRIORITIES - (UBaseType_t)1U; + } else { + mtCOVERAGE_TEST_MARKER(); + } + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the priority of the calling + task that is being changed. */ + pxTCB = prvGetTCBFromHandle(xTask); + + traceTASK_PRIORITY_SET(pxTCB, uxNewPriority); + +# if (configUSE_MUTEXES == 1) + { + uxCurrentBasePriority = pxTCB->uxBasePriority; + } +# else + { + uxCurrentBasePriority = pxTCB->uxPriority; + } +# endif + + if (uxCurrentBasePriority != uxNewPriority) { + /* The priority change may have readied a task of higher + priority than the calling task. */ + if (uxNewPriority > uxCurrentBasePriority) { + if (pxTCB != pxCurrentTCB) { + /* The priority of a task other than the currently + running task is being raised. Is the priority being + raised above that of the running task? */ + if (uxNewPriority >= pxCurrentTCB->uxPriority) { + xYieldRequired = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + /* The priority of the running task is being raised, + but the running task must already be the highest + priority task able to run so no yield is required. */ + } + } else if (pxTCB == pxCurrentTCB) { + /* Setting the priority of the running task down means + there may now be another task of higher priority that + is ready to execute. */ + xYieldRequired = pdTRUE; + } else { + /* Setting the priority of any other task down does not + require a yield as the running task must be above the + new priority of the task being modified. */ + } + + /* Remember the ready list the task might be referenced from + before its uxPriority member is changed so the + taskRESET_READY_PRIORITY() macro can function correctly. */ + uxPriorityUsedOnEntry = pxTCB->uxPriority; + +# if (configUSE_MUTEXES == 1) + { + /* Only change the priority being used if the task is not + currently using an inherited priority. */ + if (pxTCB->uxBasePriority == pxTCB->uxPriority) { + pxTCB->uxPriority = uxNewPriority; + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* The base priority gets set whatever. */ + pxTCB->uxBasePriority = uxNewPriority; + } +# else + { + pxTCB->uxPriority = uxNewPriority; + } +# endif + + /* 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) + uxNewPriority)); /*lint !e961 MISRA exception as the + casts are only redundant for some + ports. */ + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* If the task is in the blocked or suspended list we need do + 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. */ + if (uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0) { + /* It is known that the task is in its ready list so + there is no need to check again and the port level + reset macro can be called directly. */ + portRESET_READY_PRIORITY( + uxPriorityUsedOnEntry, uxTopReadyPriority); + } else { + mtCOVERAGE_TEST_MARKER(); + } + prvAddTaskToReadyList(pxTCB); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + if (xYieldRequired != pdFALSE) { + taskYIELD_IF_USING_PREEMPTION(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* Remove compiler warning about unused variables when the port + optimised task selection is not being used. */ + (void)uxPriorityUsedOnEntry; + } + } + taskEXIT_CRITICAL(); +} + +#endif /* INCLUDE_vTaskPrioritySet */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_vTaskSuspend == 1) + +void vTaskSuspend(TaskHandle_t xTaskToSuspend) +{ + TCB_t *pxTCB; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the running task that is + being suspended. */ + pxTCB = prvGetTCBFromHandle(xTaskToSuspend); + + traceTASK_SUSPEND(pxTCB); + + /* Remove task from the ready/delayed list and place in the + suspended list. */ + if (uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0) { + taskRESET_READY_PRIORITY(pxTCB->uxPriority); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* Is the task waiting on an event also? */ + if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != NULL) { + (void)uxListRemove(&(pxTCB->xEventListItem)); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + vListInsertEnd(&xSuspendedTaskList, &(pxTCB->xStateListItem)); + +# if (configUSE_TASK_NOTIFICATIONS == 1) + { + if (pxTCB->ucNotifyState == taskWAITING_NOTIFICATION) { + /* The task was blocked to wait for a notification, but is + now suspended, so no notification was received. */ + pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + } +# endif + } + taskEXIT_CRITICAL(); + + if (xSchedulerRunning != pdFALSE) { + /* Reset the next expected unblock time in case it referred to the + task that is now in the Suspended state. */ + taskENTER_CRITICAL(); + { + prvResetNextTaskUnblockTime(); + } + taskEXIT_CRITICAL(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + if (pxTCB == pxCurrentTCB) { + if (xSchedulerRunning != pdFALSE) { + /* The current task has just been suspended. */ + configASSERT(uxSchedulerSuspended == 0); + portYIELD_WITHIN_API(); + } else { + /* The scheduler is not running, but the task that was pointed + to by pxCurrentTCB has just been suspended and pxCurrentTCB + must be adjusted to point to a different task. */ + if (listCURRENT_LIST_LENGTH(&xSuspendedTaskList) == + uxCurrentNumberOfTasks) /*lint !e931 Right has no side effect, + just volatile. */ + { + /* No other tasks are ready, so set pxCurrentTCB back to + NULL so when the next task is created pxCurrentTCB will + be set to point to it no matter what its relative priority + is. */ + pxCurrentTCB = NULL; + } else { + vTaskSwitchContext(); + } + } + } else { + mtCOVERAGE_TEST_MARKER(); + } +} + +#endif /* INCLUDE_vTaskSuspend */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_vTaskSuspend == 1) + +static BaseType_t prvTaskIsTaskSuspended(const TaskHandle_t xTask) +{ + BaseType_t xReturn = pdFALSE; + const TCB_t *const pxTCB = 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 being resumed actually in the suspended list? */ + if (listIS_CONTAINED_WITHIN( + &xSuspendedTaskList, &(pxTCB->xStateListItem)) != 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, or because is is blocked with no timeout? */ + if (listIS_CONTAINED_WITHIN(NULL, &(pxTCB->xEventListItem)) != + pdFALSE) /*lint !e961. The cast is only redundant when NULL is + used. */ + { + xReturn = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; +} /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ + +#endif /* INCLUDE_vTaskSuspend */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_vTaskSuspend == 1) + +void vTaskResume(TaskHandle_t xTaskToResume) +{ + TCB_t *const pxTCB = xTaskToResume; + + /* It does not make sense to resume the calling task. */ + configASSERT(xTaskToResume); + + /* The parameter cannot be NULL as it is impossible to resume the + currently executing task. */ + if ((pxTCB != pxCurrentTCB) && (pxTCB != NULL)) { + taskENTER_CRITICAL(); + { + if (prvTaskIsTaskSuspended(pxTCB) != pdFALSE) { + traceTASK_RESUME(pxTCB); + + /* The ready list can be accessed even if the scheduler is + suspended because this is inside a critical section. */ + (void)uxListRemove(&(pxTCB->xStateListItem)); + prvAddTaskToReadyList(pxTCB); + + /* A higher priority task may have just been resumed. */ + if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority) { + /* This yield may not cause the task just resumed to run, + but will leave the lists in the correct state for the + next yield. */ + taskYIELD_IF_USING_PREEMPTION(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + } else { + mtCOVERAGE_TEST_MARKER(); + } +} + +#endif /* INCLUDE_vTaskSuspend */ + +/*-----------------------------------------------------------*/ + +#if ((INCLUDE_xTaskResumeFromISR == 1) && (INCLUDE_vTaskSuspend == 1)) + +BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume) +{ + BaseType_t xYieldRequired = pdFALSE; + TCB_t *const pxTCB = xTaskToResume; + UBaseType_t uxSavedInterruptStatus; + + configASSERT(xTaskToResume); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + https://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + if (prvTaskIsTaskSuspended(pxTCB) != pdFALSE) { + 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; + } else { + mtCOVERAGE_TEST_MARKER(); + } + + (void)uxListRemove(&(pxTCB->xStateListItem)); + prvAddTaskToReadyList(pxTCB); + } else { + /* 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)); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus); + + return xYieldRequired; +} + +#endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 \ + ) ) */ +/*-----------------------------------------------------------*/ + +void vTaskStartScheduler(void) +{ + BaseType_t xReturn; + +/* Add the idle task at the lowest priority. */ +#if (configSUPPORT_STATIC_ALLOCATION == 1) + { + StaticTask_t *pxIdleTaskTCBBuffer = NULL; + StackType_t *pxIdleTaskStackBuffer = NULL; + uint32_t ulIdleTaskStackSize; + + /* The Idle task is created using user provided RAM - obtain the + address of the RAM then create the idle task. */ + vApplicationGetIdleTaskMemory( + &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize); + xIdleTaskHandle = xTaskCreateStatic( + prvIdleTask, + configIDLE_TASK_NAME, + ulIdleTaskStackSize, + (void *)NULL, /*lint !e961. The cast is not redundant for all + compilers. */ + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | + portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is + zero. */ + pxIdleTaskStackBuffer, + pxIdleTaskTCBBuffer); /*lint !e961 MISRA exception, justified as it + is not a redundant explicit cast to all + supported compilers. */ + + if (xIdleTaskHandle != NULL) { + xReturn = pdPASS; + } else { + xReturn = pdFAIL; + } + } +#else + { + /* The Idle task is being created using dynamically allocated RAM. */ + xReturn = xTaskCreate( + prvIdleTask, + configIDLE_TASK_NAME, + configMINIMAL_STACK_SIZE, + (void *)NULL, + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | + portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is + zero. */ + &xIdleTaskHandle); /*lint !e961 MISRA exception, justified as it is + not a redundant explicit cast to all supported + compilers. */ + } +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +#if (configUSE_TIMERS == 1) + { + if (xReturn == pdPASS) { + xReturn = xTimerCreateTimerTask(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } +#endif /* configUSE_TIMERS */ + + if (xReturn == pdPASS) { +/* freertos_tasks_c_additions_init() should only be called if the user +definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is +the only macro called by the function. */ +#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT + { + freertos_tasks_c_additions_init(); + } +#endif + + /* Interrupts are turned off here, to ensure a tick does not occur + before or during the call to xPortStartScheduler(). The stacks of + the created tasks contain a status word with interrupts switched on + so interrupts will automatically get re-enabled when the first task + starts to run. */ + portDISABLE_INTERRUPTS(); + +#if (configUSE_NEWLIB_REENTRANT == 1) + { + /* Switch Newlib's _impure_ptr variable to point to the _reent + structure specific to the task that will run first. + See the third party link + http://www.nadler.com/embedded/newlibAndFreeRTOS.html + for additional information. */ + _impure_ptr = &(pxCurrentTCB->xNewLib_reent); + } +#endif /* configUSE_NEWLIB_REENTRANT */ + + xNextTaskUnblockTime = portMAX_DELAY; + xSchedulerRunning = pdTRUE; + xTickCount = (TickType_t)configINITIAL_TICK_COUNT; + + /* If configGENERATE_RUN_TIME_STATS is defined then the following + macro must be defined to configure the timer/counter used to generate + the run time counter time base. NOTE: If + configGENERATE_RUN_TIME_STATS is set to 0 and the following line fails + to build then ensure you do not have + portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your + FreeRTOSConfig.h file. */ + portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); + + traceTASK_SWITCHED_IN(); + + /* Setting up the timer tick is hardware specific and thus in the + portable interface. */ + if (xPortStartScheduler() != pdFALSE) { + /* Should not reach here as if the scheduler is running the + function will not return. */ + } else { + /* Should only reach here if a task calls xTaskEndScheduler(). */ + } + } else { + /* This line will only be reached if the kernel could not be started, + because there was not enough FreeRTOS heap to create the idle task + or the timer task. */ + configASSERT(xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY); + } + + /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0, + meaning xIdleTaskHandle is not used anywhere else. */ + (void)xIdleTaskHandle; +} +/*-----------------------------------------------------------*/ + +void vTaskEndScheduler(void) +{ + /* Stop the scheduler interrupts and call the portable scheduler end + routine so the original ISRs can be restored if necessary. The port + layer must ensure interrupts enable bit is left in the correct state. */ + portDISABLE_INTERRUPTS(); + xSchedulerRunning = pdFALSE; + vPortEndScheduler(); +} +/*----------------------------------------------------------*/ + +void vTaskSuspendAll(void) +{ + /* A critical section is not required as the variable is of type + BaseType_t. Please read Richard Barry's reply in the following link to a + post in the FreeRTOS support forum before reporting this as a bug! - + http://goo.gl/wu4acr */ + + /* portSOFRWARE_BARRIER() is only implemented for emulated/simulated ports + that do not otherwise exhibit real time behaviour. */ + portSOFTWARE_BARRIER(); + + /* The scheduler is suspended if uxSchedulerSuspended is non-zero. An + increment is used to allow calls to vTaskSuspendAll() to nest. */ + ++uxSchedulerSuspended; + + /* Enforces ordering for ports and optimised compilers that may otherwise + place the above increment elsewhere. */ + portMEMORY_BARRIER(); +} +/*----------------------------------------------------------*/ + +#if (configUSE_TICKLESS_IDLE != 0) + +static TickType_t prvGetExpectedIdleTime(void) +{ + TickType_t xReturn; + UBaseType_t uxHigherPriorityReadyTasks = pdFALSE; + +/* uxHigherPriorityReadyTasks takes care of the case where +configUSE_PREEMPTION is 0, so there may be tasks above the idle priority +task that are in the Ready state, even though the idle task is +running. */ +# if (configUSE_PORT_OPTIMISED_TASK_SELECTION == 0) + { + if (uxTopReadyPriority > tskIDLE_PRIORITY) { + uxHigherPriorityReadyTasks = pdTRUE; + } + } +# else + { + const UBaseType_t uxLeastSignificantBit = (UBaseType_t)0x01; + + /* When port optimised task selection is used the uxTopReadyPriority + variable is used as a bit map. If bits other than the least + significant bit are set then there are tasks that have a priority + above the idle priority that are in the Ready state. This takes + care of the case where the co-operative scheduler is in use. */ + if (uxTopReadyPriority > uxLeastSignificantBit) { + uxHigherPriorityReadyTasks = pdTRUE; + } + } +# endif + + if (pxCurrentTCB->uxPriority > tskIDLE_PRIORITY) { + xReturn = 0; + } else if ( + listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[tskIDLE_PRIORITY])) > 1) { + /* There are other idle priority tasks in the ready state. If + time slicing is used then the very next tick interrupt must be + processed. */ + xReturn = 0; + } else if (uxHigherPriorityReadyTasks != pdFALSE) { + /* There are tasks in the Ready state that have a priority above the + idle priority. This path can only be reached if + configUSE_PREEMPTION is 0. */ + xReturn = 0; + } else { + xReturn = xNextTaskUnblockTime - xTickCount; + } + + return xReturn; +} + +#endif /* configUSE_TICKLESS_IDLE */ +/*----------------------------------------------------------*/ + +BaseType_t xTaskResumeAll(void) +{ + TCB_t *pxTCB = NULL; + BaseType_t xAlreadyYielded = pdFALSE; + + /* If uxSchedulerSuspended is zero then this function does not match a + previous call to vTaskSuspendAll(). */ + configASSERT(uxSchedulerSuspended); + + /* It is possible that an ISR caused a task to be removed from an event + list while the scheduler was suspended. If this was the case then the + removed task will have been added to the xPendingReadyList. Once the + scheduler has been resumed it is safe to move all the pending ready + tasks from this list into their appropriate ready list. */ + taskENTER_CRITICAL(); + { + --uxSchedulerSuspended; + + if (uxSchedulerSuspended == (UBaseType_t)pdFALSE) { + if (uxCurrentNumberOfTasks > (UBaseType_t)0U) { + /* Move any readied tasks from the pending list into the + appropriate ready list. */ + while (listLIST_IS_EMPTY(&xPendingReadyList) == pdFALSE) { + pxTCB = listGET_OWNER_OF_HEAD_ENTRY( + (&xPendingReadyList)); /*lint !e9079 void * is used as + this macro is used with timers + and co-routines too. Alignment + is known to be fine as the + type of the pointer stored and + retrieved is the same. */ + (void)uxListRemove(&(pxTCB->xEventListItem)); + (void)uxListRemove(&(pxTCB->xStateListItem)); + prvAddTaskToReadyList(pxTCB); + + /* If the moved task has a priority higher than the current + task then a yield must be performed. */ + if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority) { + xYieldPending = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + + if (pxTCB != NULL) { + /* A task was unblocked while the scheduler was suspended, + which may have prevented the next unblock time from being + re-calculated, in which case re-calculate it now. Mainly + important for low power tickless implementations, where + this can prevent an unnecessary exit from low power + state. */ + prvResetNextTaskUnblockTime(); + } + + /* If any ticks occurred while the scheduler was suspended then + they should be processed now. This ensures the tick count does + not slip, and that any delayed tasks are resumed at the correct + time. */ + { + TickType_t xPendedCounts = + xPendedTicks; /* Non-volatile copy. */ + + if (xPendedCounts > (TickType_t)0U) { + do { + if (xTaskIncrementTick() != pdFALSE) { + xYieldPending = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + --xPendedCounts; + } while (xPendedCounts > (TickType_t)0U); + + xPendedTicks = 0; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + + if (xYieldPending != pdFALSE) { +#if (configUSE_PREEMPTION != 0) + { + xAlreadyYielded = pdTRUE; + } +#endif + taskYIELD_IF_USING_PREEMPTION(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + return xAlreadyYielded; +} +/*-----------------------------------------------------------*/ + +TickType_t xTaskGetTickCount(void) +{ + TickType_t xTicks; + + /* Critical section required if running on a 16 bit processor. */ + portTICK_TYPE_ENTER_CRITICAL(); + { + xTicks = xTickCount; + } + portTICK_TYPE_EXIT_CRITICAL(); + + return xTicks; +} +/*-----------------------------------------------------------*/ + +TickType_t xTaskGetTickCountFromISR(void) +{ + TickType_t xReturn; + UBaseType_t uxSavedInterruptStatus; + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: https://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR(); + { + xReturn = xTickCount; + } + portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxTaskGetNumberOfTasks(void) +{ + /* A critical section is not required because the variables are of type + BaseType_t. */ + return uxCurrentNumberOfTasks; +} +/*-----------------------------------------------------------*/ + +char *pcTaskGetName( + TaskHandle_t xTaskToQuery) /*lint !e971 Unqualified char types are allowed + for strings and single characters only. */ +{ + TCB_t *pxTCB; + + /* If null is passed in here then the name of the calling task is being + queried. */ + pxTCB = prvGetTCBFromHandle(xTaskToQuery); + configASSERT(pxTCB); + return &(pxTCB->pcTaskName[0]); +} +/*-----------------------------------------------------------*/ + +#if (INCLUDE_xTaskGetHandle == 1) + +static TCB_t *prvSearchForNameWithinSingleList( + List_t *pxList, + const char pcNameToQuery[]) +{ + TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL; + UBaseType_t x; + char cNextChar; + BaseType_t xBreakLoop; + + /* This function is called with the scheduler suspended. */ + + if (listCURRENT_LIST_LENGTH(pxList) > (UBaseType_t)0) { + listGET_OWNER_OF_NEXT_ENTRY( + pxFirstTCB, + pxList); /*lint !e9079 void * is used as this macro is used with + timers and co-routines too. Alignment is known to be + fine as the type of the pointer stored and retrieved is + the same. */ + + do { + listGET_OWNER_OF_NEXT_ENTRY( + pxNextTCB, + pxList); /*lint !e9079 void * is used as this macro is used with + timers and co-routines too. Alignment is known to + be fine as the type of the pointer stored and + retrieved is the same. */ + + /* Check each character in the name looking for a match or + mismatch. */ + xBreakLoop = pdFALSE; + for (x = (UBaseType_t)0; x < (UBaseType_t)configMAX_TASK_NAME_LEN; + x++) { + cNextChar = pxNextTCB->pcTaskName[x]; + + if (cNextChar != pcNameToQuery[x]) { + /* Characters didn't match. */ + xBreakLoop = pdTRUE; + } else if (cNextChar == (char)0x00) { + /* Both strings terminated, a match must have been + found. */ + pxReturn = pxNextTCB; + xBreakLoop = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + + if (xBreakLoop != pdFALSE) { + break; + } + } + + if (pxReturn != NULL) { + /* The handle has been found. */ + break; + } + + } while (pxNextTCB != pxFirstTCB); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + return pxReturn; +} + +#endif /* INCLUDE_xTaskGetHandle */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_xTaskGetHandle == 1) + +TaskHandle_t xTaskGetHandle( + const char *pcNameToQuery) /*lint !e971 Unqualified char types are allowed + for strings and single characters only. */ +{ + UBaseType_t uxQueue = configMAX_PRIORITIES; + TCB_t *pxTCB; + + /* Task names will be truncated to configMAX_TASK_NAME_LEN - 1 bytes. */ + configASSERT(strlen(pcNameToQuery) < configMAX_TASK_NAME_LEN); + + vTaskSuspendAll(); + { + /* Search the ready lists. */ + do { + uxQueue--; + pxTCB = prvSearchForNameWithinSingleList( + (List_t *)&(pxReadyTasksLists[uxQueue]), pcNameToQuery); + + if (pxTCB != NULL) { + /* Found the handle. */ + break; + } + + } while ( + uxQueue > + (UBaseType_t) + tskIDLE_PRIORITY); /*lint !e961 MISRA exception as the casts are + only redundant for some ports. */ + + /* Search the delayed lists. */ + if (pxTCB == NULL) { + pxTCB = prvSearchForNameWithinSingleList( + (List_t *)pxDelayedTaskList, pcNameToQuery); + } + + if (pxTCB == NULL) { + pxTCB = prvSearchForNameWithinSingleList( + (List_t *)pxOverflowDelayedTaskList, pcNameToQuery); + } + +# if (INCLUDE_vTaskSuspend == 1) + { + if (pxTCB == NULL) { + /* Search the suspended list. */ + pxTCB = prvSearchForNameWithinSingleList( + &xSuspendedTaskList, pcNameToQuery); + } + } +# endif + +# if (INCLUDE_vTaskDelete == 1) + { + if (pxTCB == NULL) { + /* Search the deleted list. */ + pxTCB = prvSearchForNameWithinSingleList( + &xTasksWaitingTermination, pcNameToQuery); + } + } +# endif + } + (void)xTaskResumeAll(); + + return pxTCB; +} + +#endif /* INCLUDE_xTaskGetHandle */ +/*-----------------------------------------------------------*/ + +#if (configUSE_TRACE_FACILITY == 1) + +UBaseType_t uxTaskGetSystemState( + TaskStatus_t *const pxTaskStatusArray, + const UBaseType_t uxArraySize, + uint32_t *const pulTotalRunTime) +{ + UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES; + + vTaskSuspendAll(); + { + /* Is there a space in the array for each task in the system? */ + if (uxArraySize >= uxCurrentNumberOfTasks) { + /* Fill in an TaskStatus_t structure with information on each + task in the Ready state. */ + do { + uxQueue--; + uxTask += prvListTasksWithinSingleList( + &(pxTaskStatusArray[uxTask]), + &(pxReadyTasksLists[uxQueue]), + eReady); + + } while ( + uxQueue > + (UBaseType_t) + tskIDLE_PRIORITY); /*lint !e961 MISRA exception as the casts + are only redundant for some ports. */ + + /* Fill in an TaskStatus_t structure with information on each + task in the Blocked state. */ + uxTask += prvListTasksWithinSingleList( + &(pxTaskStatusArray[uxTask]), + (List_t *)pxDelayedTaskList, + eBlocked); + uxTask += prvListTasksWithinSingleList( + &(pxTaskStatusArray[uxTask]), + (List_t *)pxOverflowDelayedTaskList, + eBlocked); + +# if (INCLUDE_vTaskDelete == 1) + { + /* Fill in an TaskStatus_t structure with information on + each task that has been deleted but not yet cleaned up. */ + uxTask += prvListTasksWithinSingleList( + &(pxTaskStatusArray[uxTask]), + &xTasksWaitingTermination, + eDeleted); + } +# endif + +# if (INCLUDE_vTaskSuspend == 1) + { + /* Fill in an TaskStatus_t structure with information on + each task in the Suspended state. */ + uxTask += prvListTasksWithinSingleList( + &(pxTaskStatusArray[uxTask]), + &xSuspendedTaskList, + eSuspended); + } +# endif + +# if (configGENERATE_RUN_TIME_STATS == 1) + { + if (pulTotalRunTime != NULL) { +# ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE((*pulTotalRunTime)); +# else + *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); +# endif + } + } +# else + { + if (pulTotalRunTime != NULL) { + *pulTotalRunTime = 0; + } + } +# endif + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + (void)xTaskResumeAll(); + + return uxTask; +} + +#endif /* configUSE_TRACE_FACILITY */ +/*----------------------------------------------------------*/ + +#if (INCLUDE_xTaskGetIdleTaskHandle == 1) + +TaskHandle_t xTaskGetIdleTaskHandle(void) +{ + /* If xTaskGetIdleTaskHandle() is called before the scheduler has been + started, then xIdleTaskHandle will be NULL. */ + configASSERT((xIdleTaskHandle != NULL)); + return xIdleTaskHandle; +} + +#endif /* INCLUDE_xTaskGetIdleTaskHandle */ +/*----------------------------------------------------------*/ + +/* This conditional compilation should use inequality to 0, not equality to 1. +This is to ensure vTaskStepTick() is available when user defined low power mode +implementations require configUSE_TICKLESS_IDLE to be set to a value other than +1. */ +#if (configUSE_TICKLESS_IDLE != 0) + +void vTaskStepTick(const TickType_t xTicksToJump) +{ + /* Correct the tick count value after a period during which the tick + was suppressed. Note this does *not* call the tick hook function for + each stepped tick. */ + configASSERT((xTickCount + xTicksToJump) <= xNextTaskUnblockTime); + xTickCount += xTicksToJump; + traceINCREASE_TICK_COUNT(xTicksToJump); +} + +#endif /* configUSE_TICKLESS_IDLE */ +/*----------------------------------------------------------*/ + +BaseType_t xTaskCatchUpTicks(TickType_t xTicksToCatchUp) +{ + BaseType_t xYieldRequired = pdFALSE; + + /* Must not be called with the scheduler suspended as the implementation + relies on xPendedTicks being wound down to 0 in xTaskResumeAll(). */ + configASSERT(uxSchedulerSuspended == 0); + + /* Use xPendedTicks to mimic xTicksToCatchUp number of ticks occurring when + the scheduler is suspended so the ticks are executed in xTaskResumeAll(). */ + vTaskSuspendAll(); + xPendedTicks += xTicksToCatchUp; + xYieldRequired = xTaskResumeAll(); + + return xYieldRequired; +} +/*----------------------------------------------------------*/ + +#if (INCLUDE_xTaskAbortDelay == 1) + +BaseType_t xTaskAbortDelay(TaskHandle_t xTask) +{ + TCB_t *pxTCB = xTask; + BaseType_t xReturn; + + configASSERT(pxTCB); + + vTaskSuspendAll(); + { + /* A task can only be prematurely removed from the Blocked state if + 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. */ + (void)uxListRemove(&(pxTCB->xStateListItem)); + + /* Is the task waiting on an event also? If so remove it from + the event list too. Interrupts can touch the event list item, + even though the scheduler is suspended, so a critical section + is used. */ + taskENTER_CRITICAL(); + { + if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != NULL) { + (void)uxListRemove(&(pxTCB->xEventListItem)); + + /* This lets the task know it was forcibly removed from the + blocked state so it should not re-evaluate its block time + and then block again. */ + pxTCB->ucDelayAborted = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + /* Place the unblocked task into the appropriate ready list. */ + prvAddTaskToReadyList(pxTCB); + +/* A task being unblocked cannot cause an immediate context +switch if preemption is turned off. */ +# if (configUSE_PREEMPTION == 1) + { + /* Preemption is on, but a context switch should only be + performed if the unblocked task has a priority that is + equal to or higher than the currently executing task. */ + if (pxTCB->uxPriority > pxCurrentTCB->uxPriority) { + /* Pend the yield to be performed when the scheduler + is unsuspended. */ + xYieldPending = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } +# endif /* configUSE_PREEMPTION */ + } else { + xReturn = pdFAIL; + } + } + (void)xTaskResumeAll(); + + return xReturn; +} + +#endif /* INCLUDE_xTaskAbortDelay */ +/*----------------------------------------------------------*/ + +BaseType_t xTaskIncrementTick(void) +{ + TCB_t *pxTCB; + TickType_t xItemValue; + BaseType_t xSwitchRequired = pdFALSE; + + /* Called by the portable layer each time a tick interrupt occurs. + Increments the tick then checks to see if the new tick value will cause any + tasks to be unblocked. */ + traceTASK_INCREMENT_TICK(xTickCount); + if (uxSchedulerSuspended == (UBaseType_t)pdFALSE) { + /* Minor optimisation. The tick count cannot change in this + block. */ + const TickType_t xConstTickCount = xTickCount + (TickType_t)1; + + /* Increment the RTOS tick, switching the delayed and overflowed + delayed lists if it wraps to 0. */ + xTickCount = xConstTickCount; + + if (xConstTickCount == + (TickType_t)0U) /*lint !e774 'if' does not always evaluate to false + as it is looking for an overflow. */ + { + taskSWITCH_DELAYED_LISTS(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* See if this tick has made a timeout expire. Tasks are stored in + the queue in the order of their wake time - meaning once one task + has been found whose block time has not expired there is no need to + look any further down the list. */ + if (xConstTickCount >= xNextTaskUnblockTime) { + for (;;) { + if (listLIST_IS_EMPTY(pxDelayedTaskList) != pdFALSE) { + /* The delayed list is empty. Set xNextTaskUnblockTime + to the maximum possible value so it is extremely + unlikely that the + if( xTickCount >= xNextTaskUnblockTime ) test will pass + next time through. */ + xNextTaskUnblockTime = + portMAX_DELAY; /*lint !e961 MISRA exception as the casts + are only redundant for some ports. */ + break; + } else { + /* The delayed list is not empty, get the value of the + item at the head of the delayed list. This is the time + at which the task at the head of the delayed list must + be removed from the Blocked state. */ + pxTCB = listGET_OWNER_OF_HEAD_ENTRY( + pxDelayedTaskList); /*lint !e9079 void * is used as this + macro is used with timers and + co-routines too. Alignment is + known to be fine as the type of + the pointer stored and retrieved + is the same. */ + xItemValue = + listGET_LIST_ITEM_VALUE(&(pxTCB->xStateListItem)); + + if (xConstTickCount < xItemValue) { + /* It is not time to unblock this item yet, but the + item value is the time at which the task at the head + of the blocked list must be removed from the Blocked + state - so record the item value in + xNextTaskUnblockTime. */ + xNextTaskUnblockTime = xItemValue; + break; /*lint !e9011 Code structure here is deedmed + easier to understand with multiple breaks. */ + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* It is time to remove the item from the Blocked state. */ + (void)uxListRemove(&(pxTCB->xStateListItem)); + + /* Is the task waiting on an event also? If so remove + it from the event list. */ + if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != + NULL) { + (void)uxListRemove(&(pxTCB->xEventListItem)); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* Place the unblocked task into the appropriate ready + list. */ + prvAddTaskToReadyList(pxTCB); + +/* A task being unblocked cannot cause an immediate +context switch if preemption is turned off. */ +#if (configUSE_PREEMPTION == 1) + { + /* Preemption is on, but a context switch should + only be performed if the unblocked task has a + priority that is equal to or higher than the + currently executing task. */ + if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority) { + xSwitchRequired = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } +#endif /* configUSE_PREEMPTION */ + } + } + } + +/* Tasks of equal priority to the currently running task will share +processing time (time slice) if preemption is on, and the application +writer has not explicitly turned time slicing off. */ +#if ((configUSE_PREEMPTION == 1) && (configUSE_TIME_SLICING == 1)) + { + if (listCURRENT_LIST_LENGTH( + &(pxReadyTasksLists[pxCurrentTCB->uxPriority])) > + (UBaseType_t)1) { + xSwitchRequired = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } +#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) \ + */ + +#if (configUSE_TICK_HOOK == 1) + { + /* Guard against the tick hook being called when the pended tick + count is being unwound (when the scheduler is being unlocked). */ + if (xPendedTicks == (TickType_t)0) { + vApplicationTickHook(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } +#endif /* configUSE_TICK_HOOK */ + +#if (configUSE_PREEMPTION == 1) + { + if (xYieldPending != pdFALSE) { + xSwitchRequired = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } +#endif /* configUSE_PREEMPTION */ + } else { + ++xPendedTicks; + +/* The tick hook gets called at regular intervals, even if the +scheduler is locked. */ +#if (configUSE_TICK_HOOK == 1) + { + vApplicationTickHook(); + } +#endif + } + + return xSwitchRequired; +} +/*-----------------------------------------------------------*/ + +#if (configUSE_APPLICATION_TASK_TAG == 1) + +void vTaskSetApplicationTaskTag( + TaskHandle_t xTask, + TaskHookFunction_t pxHookFunction) +{ + TCB_t *xTCB; + + /* If xTask is NULL then it is the task hook of the calling task that is + getting set. */ + if (xTask == NULL) { + xTCB = (TCB_t *)pxCurrentTCB; + } else { + xTCB = xTask; + } + + /* Save the hook function in the TCB. A critical section is required as + the value can be accessed from an interrupt. */ + taskENTER_CRITICAL(); + { + xTCB->pxTaskTag = pxHookFunction; + } + taskEXIT_CRITICAL(); +} + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +#if (configUSE_APPLICATION_TASK_TAG == 1) + +TaskHookFunction_t xTaskGetApplicationTaskTag(TaskHandle_t xTask) +{ + TCB_t *pxTCB; + TaskHookFunction_t xReturn; + + /* If xTask is NULL then set the calling task's hook. */ + pxTCB = prvGetTCBFromHandle(xTask); + + /* Save the hook function in the TCB. A critical section is required as + the value can be accessed from an interrupt. */ + taskENTER_CRITICAL(); + { + xReturn = pxTCB->pxTaskTag; + } + taskEXIT_CRITICAL(); + + return xReturn; +} + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +#if (configUSE_APPLICATION_TASK_TAG == 1) + +TaskHookFunction_t xTaskGetApplicationTaskTagFromISR(TaskHandle_t xTask) +{ + TCB_t *pxTCB; + TaskHookFunction_t xReturn; + UBaseType_t uxSavedInterruptStatus; + + /* If xTask is NULL then set the calling task's hook. */ + pxTCB = prvGetTCBFromHandle(xTask); + + /* Save the hook function in the TCB. A critical section is required as + the value can be accessed from an interrupt. */ + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + xReturn = pxTCB->pxTaskTag; + } + portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus); + + return xReturn; +} + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +#if (configUSE_APPLICATION_TASK_TAG == 1) + +BaseType_t xTaskCallApplicationTaskHook(TaskHandle_t xTask, void *pvParameter) +{ + TCB_t *xTCB; + BaseType_t xReturn; + + /* If xTask is NULL then we are calling our own task hook. */ + if (xTask == NULL) { + xTCB = pxCurrentTCB; + } else { + xTCB = xTask; + } + + if (xTCB->pxTaskTag != NULL) { + xReturn = xTCB->pxTaskTag(pvParameter); + } else { + xReturn = pdFAIL; + } + + return xReturn; +} + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +void vTaskSwitchContext(void) +{ + if (uxSchedulerSuspended != (UBaseType_t)pdFALSE) { + /* The scheduler is currently suspended - do not allow a context + switch. */ + xYieldPending = pdTRUE; + } else { + xYieldPending = pdFALSE; + traceTASK_SWITCHED_OUT(); + +#if (configGENERATE_RUN_TIME_STATS == 1) + { +# ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE(ulTotalRunTime); +# else + ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); +# endif + + /* Add the amount of time the task has been running to the + accumulated time so far. The time the task started running was + stored in ulTaskSwitchedInTime. Note that there is no overflow + protection here so count values are only valid until the timer + overflows. The guard against negative values is to protect + against suspect run time stat counter implementations - which + are provided by the application, not the kernel. */ + if (ulTotalRunTime > ulTaskSwitchedInTime) { + pxCurrentTCB->ulRunTimeCounter += + (ulTotalRunTime - ulTaskSwitchedInTime); + } else { + mtCOVERAGE_TEST_MARKER(); + } + ulTaskSwitchedInTime = ulTotalRunTime; + } +#endif /* configGENERATE_RUN_TIME_STATS */ + + /* Check for stack overflow, if configured. */ + taskCHECK_FOR_STACK_OVERFLOW(); + +/* Before the currently running task is switched out, save its errno. */ +#if (configUSE_POSIX_ERRNO == 1) + { + pxCurrentTCB->iTaskErrno = FreeRTOS_errno; + } +#endif + + /* Select a new task to run using either the generic C or port + optimised asm code. */ + taskSELECT_HIGHEST_PRIORITY_TASK(); /*lint !e9079 void * is used as this + macro is used with timers and + co-routines too. Alignment is + known to be fine as the type of + the pointer stored and retrieved + is the same. */ + traceTASK_SWITCHED_IN(); + +/* After the new task is switched in, update the global errno. */ +#if (configUSE_POSIX_ERRNO == 1) + { + FreeRTOS_errno = pxCurrentTCB->iTaskErrno; + } +#endif + +#if (configUSE_NEWLIB_REENTRANT == 1) + { + /* Switch Newlib's _impure_ptr variable to point to the _reent + structure specific to this task. + See the third party link + http://www.nadler.com/embedded/newlibAndFreeRTOS.html + for additional information. */ + _impure_ptr = &(pxCurrentTCB->xNewLib_reent); + } +#endif /* configUSE_NEWLIB_REENTRANT */ + } +} +/*-----------------------------------------------------------*/ + +void vTaskPlaceOnEventList( + List_t *const pxEventList, + const TickType_t xTicksToWait) +{ + configASSERT(pxEventList); + + /* 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. The queue that contains the event + list is locked, preventing simultaneous access from interrupts. */ + vListInsert(pxEventList, &(pxCurrentTCB->xEventListItem)); + + prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE); +} +/*-----------------------------------------------------------*/ + +void vTaskPlaceOnUnorderedEventList( + List_t *pxEventList, + const TickType_t xItemValue, + const TickType_t xTicksToWait) +{ + configASSERT(pxEventList); + + /* 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. 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. 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)); + + prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE); +} +/*-----------------------------------------------------------*/ + +#if (configUSE_TIMERS == 1) + +void vTaskPlaceOnEventListRestricted( + List_t *const pxEventList, + TickType_t xTicksToWait, + const BaseType_t xWaitIndefinitely) +{ + configASSERT(pxEventList); + + /* This function should not be called by application code hence the + 'Restricted' in its name. It is not part of the public API. It is + designed for use by kernel code, and has special calling requirements - + it should be called with the scheduler suspended. */ + + /* Place the event list item of the TCB in the appropriate event list. + In this case it is assume that this is the only task that is going to + be waiting on this event list, so the faster vListInsertEnd() function + can be used in place of vListInsert. */ + vListInsertEnd(pxEventList, &(pxCurrentTCB->xEventListItem)); + + /* If the task should block indefinitely then set the block time to a + value that will be recognised as an indefinite delay inside the + prvAddCurrentTaskToDelayedList() function. */ + if (xWaitIndefinitely != pdFALSE) { + xTicksToWait = portMAX_DELAY; + } + + traceTASK_DELAY_UNTIL((xTickCount + xTicksToWait)); + prvAddCurrentTaskToDelayedList(xTicksToWait, xWaitIndefinitely); +} + +#endif /* configUSE_TIMERS */ +/*-----------------------------------------------------------*/ + +BaseType_t xTaskRemoveFromEventList(const List_t *const pxEventList) +{ + TCB_t *pxUnblockedTCB; + BaseType_t xReturn; + + /* 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 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 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. */ + pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( + pxEventList); /*lint !e9079 void * is used as this macro is used with + timers and co-routines too. Alignment is known to be + fine as the type of the pointer stored and retrieved is + the same. */ + configASSERT(pxUnblockedTCB); + (void)uxListRemove(&(pxUnblockedTCB->xEventListItem)); + + if (uxSchedulerSuspended == (UBaseType_t)pdFALSE) { + (void)uxListRemove(&(pxUnblockedTCB->xStateListItem)); + prvAddTaskToReadyList(pxUnblockedTCB); + +#if (configUSE_TICKLESS_IDLE != 0) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + might be set to the blocked task's time out time. If the task is + unblocked for a reason other than a timeout xNextTaskUnblockTime is + normally left unchanged, because it is automatically reset to a new + value when the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter sleep + mode at the earliest possible time - so reset xNextTaskUnblockTime + here to ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } +#endif + } else { + /* The delayed and ready lists cannot be accessed, so hold this task + pending until the scheduler is resumed. */ + vListInsertEnd(&(xPendingReadyList), &(pxUnblockedTCB->xEventListItem)); + } + + 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. */ + xReturn = pdTRUE; + + /* Mark that a yield is pending in case the user is not using the + "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. + */ + xYieldPending = pdTRUE; + } else { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vTaskRemoveFromUnorderedEventList( + ListItem_t *pxEventListItem, + const TickType_t xItemValue) +{ + TCB_t *pxUnblockedTCB; + + /* 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 event list form the event flag. Interrupts do not access + event flags. */ + pxUnblockedTCB = listGET_LIST_ITEM_OWNER( + pxEventListItem); /*lint !e9079 void * is used as this macro is used + with timers and co-routines too. Alignment is + known to be fine as the type of the pointer stored + and retrieved is the same. */ + configASSERT(pxUnblockedTCB); + (void)uxListRemove(pxEventListItem); + +#if (configUSE_TICKLESS_IDLE != 0) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + might be set to the blocked task's time out time. If the task is + unblocked for a reason other than a timeout xNextTaskUnblockTime is + normally left unchanged, because it is automatically reset to a new + value when the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter sleep mode + at the earliest possible time - so reset xNextTaskUnblockTime here to + ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } +#endif + + /* 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->xStateListItem)); + prvAddTaskToReadyList(pxUnblockedTCB); + + if (pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority) { + /* The unblocked task has a priority above that of the calling task, so + a context switch is required. This function is called with the + scheduler suspended so xYieldPending is set so the context switch + occurs immediately that the scheduler is resumed (unsuspended). */ + xYieldPending = pdTRUE; + } +} +/*-----------------------------------------------------------*/ + +void vTaskSetTimeOutState(TimeOut_t *const pxTimeOut) +{ + configASSERT(pxTimeOut); + taskENTER_CRITICAL(); + { + pxTimeOut->xOverflowCount = xNumOfOverflows; + pxTimeOut->xTimeOnEntering = xTickCount; + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +void vTaskInternalSetTimeOutState(TimeOut_t *const pxTimeOut) +{ + /* For internal use only as it does not use a critical section. */ + pxTimeOut->xOverflowCount = xNumOfOverflows; + pxTimeOut->xTimeOnEntering = xTickCount; +} +/*-----------------------------------------------------------*/ + +BaseType_t xTaskCheckForTimeOut( + TimeOut_t *const pxTimeOut, + TickType_t *const pxTicksToWait) +{ + BaseType_t xReturn; + + configASSERT(pxTimeOut); + configASSERT(pxTicksToWait); + + taskENTER_CRITICAL(); + { + /* 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 != (uint8_t)pdFALSE) { + /* The delay was aborted, which is not the same as a time out, + but has the same result. */ + pxCurrentTCB->ucDelayAborted = pdFALSE; + xReturn = pdTRUE; + } else +#endif + +#if (INCLUDE_vTaskSuspend == 1) + if (*pxTicksToWait == portMAX_DELAY) { + /* If INCLUDE_vTaskSuspend is set to 1 and the block time + specified is the maximum block time then the task should block + indefinitely, and therefore never time out. */ + xReturn = pdFALSE; + } else +#endif + + if ((xNumOfOverflows != pxTimeOut->xOverflowCount) && + (xConstTickCount >= + pxTimeOut + ->xTimeOnEntering)) /*lint !e525 Indentation preferred as + is to make code within pre-processor + directives clearer. */ + { + /* The tick count is greater than the time at which + vTaskSetTimeout() was called, but has also overflowed since + vTaskSetTimeOut() was called. It must have wrapped all the way + around and gone past again. This passed since vTaskSetTimeout() + was called. */ + xReturn = pdTRUE; + } 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 -= xElapsedTime; + vTaskInternalSetTimeOutState(pxTimeOut); + xReturn = pdFALSE; + } else { + *pxTicksToWait = 0; + xReturn = pdTRUE; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vTaskMissedYield(void) +{ + xYieldPending = pdTRUE; +} +/*-----------------------------------------------------------*/ + +#if (configUSE_TRACE_FACILITY == 1) + +UBaseType_t uxTaskGetTaskNumber(TaskHandle_t xTask) +{ + UBaseType_t uxReturn; + TCB_t const *pxTCB; + + if (xTask != NULL) { + pxTCB = xTask; + uxReturn = pxTCB->uxTaskNumber; + } else { + uxReturn = 0U; + } + + return uxReturn; +} + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if (configUSE_TRACE_FACILITY == 1) + +void vTaskSetTaskNumber(TaskHandle_t xTask, const UBaseType_t uxHandle) +{ + TCB_t *pxTCB; + + if (xTask != NULL) { + pxTCB = xTask; + pxTCB->uxTaskNumber = uxHandle; + } +} + +#endif /* configUSE_TRACE_FACILITY */ + +/* + * ----------------------------------------------------------- + * The Idle task. + * ---------------------------------------------------------- + * + * The portTASK_FUNCTION() macro is used to allow port/compiler specific + * language extensions. The equivalent prototype for this function is: + * + * void prvIdleTask( void *pvParameters ); + * + */ +static portTASK_FUNCTION(prvIdleTask, pvParameters) +{ + /* Stop warnings. */ + (void)pvParameters; + + /** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE + SCHEDULER IS STARTED. **/ + + /* In case a task that has a secure context deletes itself, in which case + the idle task is responsible for deleting the task's secure context, if + any. */ + portALLOCATE_SECURE_CONTEXT(configMINIMAL_SECURE_STACK_SIZE); + + for (;;) { + /* See if any tasks have deleted themselves - if so then the idle task + is responsible for freeing the deleted task's TCB and stack. */ + prvCheckTasksWaitingTermination(); + +#if (configUSE_PREEMPTION == 0) + { + /* If we are not using preemption we keep forcing a task switch to + see if any other task has become available. If we are using + preemption we don't need to do this as any task becoming available + will automatically get the processor anyway. */ + taskYIELD(); + } +#endif /* configUSE_PREEMPTION */ + +#if ((configUSE_PREEMPTION == 1) && (configIDLE_SHOULD_YIELD == 1)) + { + /* When using preemption tasks of equal priority will be + timesliced. If a task that is sharing the idle priority is ready + to run then the idle task should yield before the end of the + timeslice. + + A critical region is not required here as we are just reading from + the list, and an occasional incorrect value will not matter. If + the ready list at the idle priority contains more than one task + then a task other than the idle task is ready to execute. */ + if (listCURRENT_LIST_LENGTH( + &(pxReadyTasksLists[tskIDLE_PRIORITY])) > (UBaseType_t)1) { + taskYIELD(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } +#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) \ + ) */ + +#if (configUSE_IDLE_HOOK == 1) + { + extern void vApplicationIdleHook(void); + + /* Call the user defined function from within the idle task. This + allows the application designer to add background functionality + without the overhead of a separate task. + NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, + CALL A FUNCTION THAT MIGHT BLOCK. */ + vApplicationIdleHook(); + } +#endif /* configUSE_IDLE_HOOK */ + +/* This conditional compilation should use inequality to 0, not equality +to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when +user defined low power mode implementations require +configUSE_TICKLESS_IDLE to be set to a value other than 1. */ +#if (configUSE_TICKLESS_IDLE != 0) + { + TickType_t xExpectedIdleTime; + + /* It is not desirable to suspend then resume the scheduler on + each iteration of the idle task. Therefore, a preliminary + test of the expected idle time is performed without the + scheduler suspended. The result here is not necessarily + valid. */ + xExpectedIdleTime = prvGetExpectedIdleTime(); + + if (xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP) { + vTaskSuspendAll(); + { + /* Now the scheduler is suspended, the expected idle + time can be sampled again, and this time its value can + be used. */ + configASSERT(xNextTaskUnblockTime >= xTickCount); + xExpectedIdleTime = prvGetExpectedIdleTime(); + + /* Define the following macro to set xExpectedIdleTime to 0 + if the application does not want + portSUPPRESS_TICKS_AND_SLEEP() to be called. */ + configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( + xExpectedIdleTime); + + if (xExpectedIdleTime >= + configEXPECTED_IDLE_TIME_BEFORE_SLEEP) { + traceLOW_POWER_IDLE_BEGIN(); + portSUPPRESS_TICKS_AND_SLEEP(xExpectedIdleTime); + traceLOW_POWER_IDLE_END(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + (void)xTaskResumeAll(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } +#endif /* configUSE_TICKLESS_IDLE */ + } +} +/*-----------------------------------------------------------*/ + +#if (configUSE_TICKLESS_IDLE != 0) + +eSleepModeStatus eTaskConfirmSleepModeStatus(void) +{ + /* The idle task exists in addition to the application tasks. */ + const UBaseType_t uxNonApplicationTasks = 1; + eSleepModeStatus eReturn = eStandardSleep; + + /* This function must be called from a critical section. */ + + if (listCURRENT_LIST_LENGTH(&xPendingReadyList) != 0) { + /* A task was made ready while the scheduler was suspended. */ + eReturn = eAbortSleep; + } else if (xYieldPending != pdFALSE) { + /* A yield was pended while the scheduler was suspended. */ + eReturn = eAbortSleep; + } else { + /* If all the tasks are in the suspended list (which might mean they + have an infinite block time rather than actually being suspended) + then it is safe to turn all clocks off and just wait for external + interrupts. */ + if (listCURRENT_LIST_LENGTH(&xSuspendedTaskList) == + (uxCurrentNumberOfTasks - uxNonApplicationTasks)) { + eReturn = eNoTasksWaitingTimeout; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + + return eReturn; +} + +#endif /* configUSE_TICKLESS_IDLE */ +/*-----------------------------------------------------------*/ + +#if (configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0) + +void vTaskSetThreadLocalStoragePointer( + TaskHandle_t xTaskToSet, + BaseType_t xIndex, + void *pvValue) +{ + TCB_t *pxTCB; + + if (xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS) { + pxTCB = prvGetTCBFromHandle(xTaskToSet); + configASSERT(pxTCB != NULL); + pxTCB->pvThreadLocalStoragePointers[xIndex] = pvValue; + } +} + +#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ +/*-----------------------------------------------------------*/ + +#if (configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0) + +void *pvTaskGetThreadLocalStoragePointer( + TaskHandle_t xTaskToQuery, + BaseType_t xIndex) +{ + void *pvReturn = NULL; + TCB_t *pxTCB; + + if (xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS) { + pxTCB = prvGetTCBFromHandle(xTaskToQuery); + pvReturn = pxTCB->pvThreadLocalStoragePointers[xIndex]; + } else { + pvReturn = NULL; + } + + return pvReturn; +} + +#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ +/*-----------------------------------------------------------*/ + +#if (portUSING_MPU_WRAPPERS == 1) + +void vTaskAllocateMPURegions( + TaskHandle_t xTaskToModify, + const MemoryRegion_t *const xRegions) +{ + TCB_t *pxTCB; + + /* If null is passed in here then we are modifying the MPU settings of + the calling task. */ + pxTCB = prvGetTCBFromHandle(xTaskToModify); + + vPortStoreTaskMPUSettings(&(pxTCB->xMPUSettings), xRegions, NULL, 0); +} + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseTaskLists(void) +{ + UBaseType_t uxPriority; + + for (uxPriority = (UBaseType_t)0U; + uxPriority < (UBaseType_t)configMAX_PRIORITIES; + uxPriority++) { + vListInitialise(&(pxReadyTasksLists[uxPriority])); + } + + vListInitialise(&xDelayedTaskList1); + vListInitialise(&xDelayedTaskList2); + vListInitialise(&xPendingReadyList); + +#if (INCLUDE_vTaskDelete == 1) + { + vListInitialise(&xTasksWaitingTermination); + } +#endif /* INCLUDE_vTaskDelete */ + +#if (INCLUDE_vTaskSuspend == 1) + { + vListInitialise(&xSuspendedTaskList); + } +#endif /* INCLUDE_vTaskSuspend */ + + /* Start with pxDelayedTaskList using list1 and the + pxOverflowDelayedTaskList using list2. */ + pxDelayedTaskList = &xDelayedTaskList1; + pxOverflowDelayedTaskList = &xDelayedTaskList2; +} +/*-----------------------------------------------------------*/ + +static void prvCheckTasksWaitingTermination(void) +{ + /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/ + +#if (INCLUDE_vTaskDelete == 1) + { + TCB_t *pxTCB; + + /* uxDeletedTasksWaitingCleanUp is used to prevent taskENTER_CRITICAL() + being called too often in the idle task. */ + while (uxDeletedTasksWaitingCleanUp > (UBaseType_t)0U) { + taskENTER_CRITICAL(); + { + pxTCB = listGET_OWNER_OF_HEAD_ENTRY( + (&xTasksWaitingTermination)); /*lint !e9079 void * is used + as this macro is used with + timers and co-routines too. + Alignment is known to be + fine as the type of the + pointer stored and + retrieved is the same. */ + (void)uxListRemove(&(pxTCB->xStateListItem)); + --uxCurrentNumberOfTasks; + --uxDeletedTasksWaitingCleanUp; + } + taskEXIT_CRITICAL(); + + prvDeleteTCB(pxTCB); + } + } +#endif /* INCLUDE_vTaskDelete */ +} +/*-----------------------------------------------------------*/ + +#if (configUSE_TRACE_FACILITY == 1) + +void vTaskGetInfo( + TaskHandle_t xTask, + TaskStatus_t *pxTaskStatus, + BaseType_t xGetFreeStackSpace, + eTaskState eState) +{ + TCB_t *pxTCB; + + /* xTask is NULL then get the state of the calling task. */ + pxTCB = prvGetTCBFromHandle(xTask); + + pxTaskStatus->xHandle = (TaskHandle_t)pxTCB; + pxTaskStatus->pcTaskName = (const char *)&(pxTCB->pcTaskName[0]); + pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority; + pxTaskStatus->pxStackBase = pxTCB->pxStack; + pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber; + +# if (configUSE_MUTEXES == 1) + { + pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority; + } +# else + { + pxTaskStatus->uxBasePriority = 0; + } +# endif + +# if (configGENERATE_RUN_TIME_STATS == 1) + { + pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter; + } +# else + { + pxTaskStatus->ulRunTimeCounter = 0; + } +# endif + + /* Obtaining the task state is a little fiddly, so is only done if the + value of eState passed into this function is eInvalid - otherwise the + state is just set to whatever is passed in. */ + if (eState != eInvalid) { + if (pxTCB == pxCurrentTCB) { + pxTaskStatus->eCurrentState = eRunning; + } else { + pxTaskStatus->eCurrentState = eState; + +# 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) { + vTaskSuspendAll(); + { + if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != + NULL) { + pxTaskStatus->eCurrentState = eBlocked; + } + } + (void)xTaskResumeAll(); + } + } +# endif /* INCLUDE_vTaskSuspend */ + } + } else { + pxTaskStatus->eCurrentState = eTaskGetState(pxTCB); + } + + /* Obtaining the stack space takes some time, so the xGetFreeStackSpace + parameter is provided to allow it to be skipped. */ + if (xGetFreeStackSpace != pdFALSE) { +# if (portSTACK_GROWTH > 0) + { + pxTaskStatus->usStackHighWaterMark = + prvTaskCheckFreeStackSpace((uint8_t *)pxTCB->pxEndOfStack); + } +# else + { + pxTaskStatus->usStackHighWaterMark = + prvTaskCheckFreeStackSpace((uint8_t *)pxTCB->pxStack); + } +# endif + } else { + pxTaskStatus->usStackHighWaterMark = 0; + } +} + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if (configUSE_TRACE_FACILITY == 1) + +static UBaseType_t prvListTasksWithinSingleList( + TaskStatus_t *pxTaskStatusArray, + List_t *pxList, + eTaskState eState) +{ + configLIST_VOLATILE TCB_t *pxNextTCB, *pxFirstTCB; + UBaseType_t uxTask = 0; + + if (listCURRENT_LIST_LENGTH(pxList) > (UBaseType_t)0) { + listGET_OWNER_OF_NEXT_ENTRY( + pxFirstTCB, + pxList); /*lint !e9079 void * is used as this macro is used with + timers and co-routines too. Alignment is known to be + fine as the type of the pointer stored and retrieved is + the same. */ + + /* Populate an TaskStatus_t structure within the + pxTaskStatusArray array for each task that is referenced from + pxList. See the definition of TaskStatus_t in task.h for the + meaning of each TaskStatus_t structure member. */ + do { + listGET_OWNER_OF_NEXT_ENTRY( + pxNextTCB, + pxList); /*lint !e9079 void * is used as this macro is used with + timers and co-routines too. Alignment is known to + be fine as the type of the pointer stored and + retrieved is the same. */ + vTaskGetInfo( + (TaskHandle_t)pxNextTCB, + &(pxTaskStatusArray[uxTask]), + pdTRUE, + eState); + uxTask++; + } while (pxNextTCB != pxFirstTCB); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + return uxTask; +} + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( \ + (configUSE_TRACE_FACILITY == 1) || \ + (INCLUDE_uxTaskGetStackHighWaterMark == 1) || \ + (INCLUDE_uxTaskGetStackHighWaterMark2 == 1)) + +static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( + const uint8_t *pucStackByte) +{ + uint32_t ulCount = 0U; + + while (*pucStackByte == (uint8_t)tskSTACK_FILL_BYTE) { + pucStackByte -= portSTACK_GROWTH; + ulCount++; + } + + ulCount /= + (uint32_t)sizeof(StackType_t); /*lint !e961 Casting is not redundant on + smaller architectures. */ + + return (configSTACK_DEPTH_TYPE)ulCount; +} + +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( \ + INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( \ + INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_uxTaskGetStackHighWaterMark2 == 1) + +/* uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are the +same except for their return type. Using configSTACK_DEPTH_TYPE allows the +user to determine the return type. It gets around the problem of the value +overflowing on 8-bit types without breaking backward compatibility for +applications that expect an 8-bit return type. */ +configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2(TaskHandle_t xTask) +{ + TCB_t *pxTCB; + uint8_t *pucEndOfStack; + configSTACK_DEPTH_TYPE uxReturn; + + /* uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are + the same except for their return type. Using configSTACK_DEPTH_TYPE + allows the user to determine the return type. It gets around the + problem of the value overflowing on 8-bit types without breaking + backward compatibility for applications that expect an 8-bit return + type. */ + + pxTCB = prvGetTCBFromHandle(xTask); + +# if portSTACK_GROWTH < 0 + { + pucEndOfStack = (uint8_t *)pxTCB->pxStack; + } +# else + { + pucEndOfStack = (uint8_t *)pxTCB->pxEndOfStack; + } +# endif + + uxReturn = prvTaskCheckFreeStackSpace(pucEndOfStack); + + return uxReturn; +} + +#endif /* INCLUDE_uxTaskGetStackHighWaterMark2 */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_uxTaskGetStackHighWaterMark == 1) + +UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask) +{ + TCB_t *pxTCB; + uint8_t *pucEndOfStack; + UBaseType_t uxReturn; + + pxTCB = prvGetTCBFromHandle(xTask); + +# if portSTACK_GROWTH < 0 + { + pucEndOfStack = (uint8_t *)pxTCB->pxStack; + } +# else + { + pucEndOfStack = (uint8_t *)pxTCB->pxEndOfStack; + } +# endif + + uxReturn = (UBaseType_t)prvTaskCheckFreeStackSpace(pucEndOfStack); + + return uxReturn; +} + +#endif /* INCLUDE_uxTaskGetStackHighWaterMark */ +/*-----------------------------------------------------------*/ + +#if (INCLUDE_vTaskDelete == 1) + +static void prvDeleteTCB(TCB_t *pxTCB) +{ + /* This call is required specifically for the TriCore port. It must be + above the vPortFree() calls. The call is also used by ports/demos that + want to allocate and clean RAM statically. */ + portCLEAN_UP_TCB(pxTCB); + +/* Free up the memory allocated by the scheduler for the task. It is up +to the task to free any memory allocated at the application level. +See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html +for additional information. */ +# if (configUSE_NEWLIB_REENTRANT == 1) + { + _reclaim_reent(&(pxTCB->xNewLib_reent)); + } +# endif /* configUSE_NEWLIB_REENTRANT */ + +# if ( \ + (configSUPPORT_DYNAMIC_ALLOCATION == 1) && \ + (configSUPPORT_STATIC_ALLOCATION == 0) && \ + (portUSING_MPU_WRAPPERS == 0)) + { + /* The task can only have been allocated dynamically - free both + the stack and TCB. */ + vPortFree(pxTCB->pxStack); + vPortFree(pxTCB); + } +# elif ( \ + tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != \ + 0) /*lint !e731 !e9029 Macro has been consolidated for readability \ + reasons. */ + { + /* The task could have been allocated statically or dynamically, so + check what was statically allocated before trying to free the + memory. */ + if (pxTCB->ucStaticallyAllocated == + tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB) { + /* Both the stack and TCB were allocated dynamically, so both + must be freed. */ + vPortFree(pxTCB->pxStack); + vPortFree(pxTCB); + } else if ( + pxTCB->ucStaticallyAllocated == + tskSTATICALLY_ALLOCATED_STACK_ONLY) { + /* Only the stack was statically allocated, so the TCB is the + only memory that must be freed. */ + vPortFree(pxTCB); + } else { + /* Neither the stack nor the TCB were allocated dynamically, so + nothing needs to be freed. */ + configASSERT( + pxTCB->ucStaticallyAllocated == + tskSTATICALLY_ALLOCATED_STACK_AND_TCB); + mtCOVERAGE_TEST_MARKER(); + } + } +# endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +} + +#endif /* INCLUDE_vTaskDelete */ +/*-----------------------------------------------------------*/ + +static void prvResetNextTaskUnblockTime(void) +{ + TCB_t *pxTCB; + + if (listLIST_IS_EMPTY(pxDelayedTaskList) != pdFALSE) { + /* The new current delayed list is empty. Set xNextTaskUnblockTime to + the maximum possible value so it is extremely unlikely that the + if( xTickCount >= xNextTaskUnblockTime ) test will pass until + there is an item in the delayed list. */ + xNextTaskUnblockTime = portMAX_DELAY; + } else { + /* The new current delayed list is not empty, get the value of + the item at the head of the delayed list. This is the time at + which the task at the head of the delayed list should be removed + from the Blocked state. */ + (pxTCB) = listGET_OWNER_OF_HEAD_ENTRY( + pxDelayedTaskList); /*lint !e9079 void * is used as this macro is + used with timers and co-routines too. + Alignment is known to be fine as the type of + the pointer stored and retrieved is the same. + */ + xNextTaskUnblockTime = + listGET_LIST_ITEM_VALUE(&((pxTCB)->xStateListItem)); + } +} +/*-----------------------------------------------------------*/ + +#if ((INCLUDE_xTaskGetCurrentTaskHandle == 1) || (configUSE_MUTEXES == 1)) + +TaskHandle_t xTaskGetCurrentTaskHandle(void) +{ + TaskHandle_t xReturn; + + /* A critical section is not required as this is not called from + an interrupt and the current TCB will always be the same for any + individual execution thread. */ + xReturn = pxCurrentTCB; + + return xReturn; +} + +#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES \ + == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ((INCLUDE_xTaskGetSchedulerState == 1) || (configUSE_TIMERS == 1)) + +BaseType_t xTaskGetSchedulerState(void) +{ + BaseType_t xReturn; + + if (xSchedulerRunning == pdFALSE) { + xReturn = taskSCHEDULER_NOT_STARTED; + } else { + if (uxSchedulerSuspended == (UBaseType_t)pdFALSE) { + xReturn = taskSCHEDULER_RUNNING; + } else { + xReturn = taskSCHEDULER_SUSPENDED; + } + } + + return xReturn; +} + +#endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 \ + ) ) */ +/*-----------------------------------------------------------*/ + +#if (configUSE_MUTEXES == 1) + +BaseType_t xTaskPriorityInherit(TaskHandle_t const pxMutexHolder) +{ + TCB_t *const pxMutexHolderTCB = 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 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 (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(&(pxMutexHolderTCB->xEventListItem)) & + taskEVENT_LIST_ITEM_VALUE_IN_USE) == 0UL) { + 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 { + mtCOVERAGE_TEST_MARKER(); + } + + /* 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[pxMutexHolderTCB->uxPriority]), + &(pxMutexHolderTCB->xStateListItem)) != pdFALSE) { + if (uxListRemove(&(pxMutexHolderTCB->xStateListItem)) == + (UBaseType_t)0) { + /* It is known that the task is in its ready list so + there is no need to check again and the port level + reset macro can be called directly. */ + portRESET_READY_PRIORITY( + pxMutexHolderTCB->uxPriority, uxTopReadyPriority); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* Inherit the priority before being moved into the new list. */ + pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority; + prvAddTaskToReadyList(pxMutexHolderTCB); + } else { + /* Just inherit the priority. */ + pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority; + } + + traceTASK_PRIORITY_INHERIT( + pxMutexHolderTCB, pxCurrentTCB->uxPriority); + + /* Inheritance occurred. */ + xReturn = pdTRUE; + } else { + if (pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority) { + /* The base priority of the mutex holder is lower than the + priority of the task attempting to take the mutex, but the + current priority of the mutex holder is not lower than the + priority of the task attempting to take the mutex. + Therefore the mutex holder must have already inherited a + priority, but inheritance would have occurred if that had + not been the case. */ + xReturn = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; +} + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if (configUSE_MUTEXES == 1) + +BaseType_t xTaskPriorityDisinherit(TaskHandle_t const pxMutexHolder) +{ + TCB_t *const pxTCB = pxMutexHolder; + BaseType_t xReturn = pdFALSE; + + if (pxMutexHolder != NULL) { + /* 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. */ + configASSERT(pxTCB == pxCurrentTCB); + configASSERT(pxTCB->uxMutexesHeld); + (pxTCB->uxMutexesHeld)--; + + /* Has the holder of the mutex inherited the priority of another + task? */ + if (pxTCB->uxPriority != pxTCB->uxBasePriority) { + /* Only disinherit if no other mutexes are held. */ + if (pxTCB->uxMutexesHeld == (UBaseType_t)0) { + /* 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/delayed list. */ + if (uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0) { + taskRESET_READY_PRIORITY(pxTCB->uxPriority); + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* Disinherit the priority before adding the task into the + new ready list. */ + traceTASK_PRIORITY_DISINHERIT(pxTCB, pxTCB->uxBasePriority); + pxTCB->uxPriority = pxTCB->uxBasePriority; + + /* Reset the event list item value. It cannot be in use for + any other purpose if this task is running, and it must be + running to give back the mutex. */ + listSET_LIST_ITEM_VALUE( + &(pxTCB->xEventListItem), + (TickType_t)configMAX_PRIORITIES - + (TickType_t) + pxTCB->uxPriority); /*lint !e961 MISRA exception as + the casts are only redundant + for some ports. */ + prvAddTaskToReadyList(pxTCB); + + /* Return true to indicate that a context switch is required. + This is only actually required in the corner case whereby + multiple mutexes were held and the mutexes were given back + in an order different to that in which they were taken. + If a context switch did not occur when the first mutex was + returned, even if a task was waiting on it, then a context + switch should occur when the last mutex is returned whether + a task is waiting on it or not. */ + xReturn = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; +} + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if (configUSE_MUTEXES == 1) + +void vTaskPriorityDisinheritAfterTimeout( + TaskHandle_t const pxMutexHolder, + UBaseType_t uxHighestPriorityWaitingTask) +{ + TCB_t *const pxTCB = 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) { + /* It is known that the task is in its ready list so + there is no need to check again and the port level + reset macro can be called directly. */ + portRESET_READY_PRIORITY( + pxTCB->uxPriority, uxTopReadyPriority); + } 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) +{ + portDISABLE_INTERRUPTS(); + + if (xSchedulerRunning != pdFALSE) { + (pxCurrentTCB->uxCriticalNesting)++; + + /* This is not the interrupt safe version of the enter critical + function so assert() if it is being called from an interrupt + context. Only API functions that end in "FromISR" can be used in an + interrupt. Only assert if the critical nesting count is 1 to + protect against recursive calls if the assert function also uses a + critical section. */ + if (pxCurrentTCB->uxCriticalNesting == 1) { + portASSERT_IF_IN_ISR(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } +} + +#endif /* portCRITICAL_NESTING_IN_TCB */ +/*-----------------------------------------------------------*/ + +#if (portCRITICAL_NESTING_IN_TCB == 1) + +void vTaskExitCritical(void) +{ + if (xSchedulerRunning != pdFALSE) { + if (pxCurrentTCB->uxCriticalNesting > 0U) { + (pxCurrentTCB->uxCriticalNesting)--; + + if (pxCurrentTCB->uxCriticalNesting == 0U) { + portENABLE_INTERRUPTS(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } +} + +#endif /* portCRITICAL_NESTING_IN_TCB */ +/*-----------------------------------------------------------*/ + +#if ( \ + (configUSE_TRACE_FACILITY == 1) && \ + (configUSE_STATS_FORMATTING_FUNCTIONS > 0)) + +static char *prvWriteNameToBuffer(char *pcBuffer, const char *pcTaskName) +{ + size_t x; + + /* Start by copying the entire string. */ + strcpy(pcBuffer, pcTaskName); + + /* Pad the end of the string with spaces to ensure columns line up when + printed out. */ + for (x = strlen(pcBuffer); x < (size_t)(configMAX_TASK_NAME_LEN - 1); x++) { + pcBuffer[x] = ' '; + } + + /* Terminate. */ + pcBuffer[x] = (char)0x00; + + /* Return the new end of string. */ + return &(pcBuffer[x]); +} + +#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( \ + configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */ +/*-----------------------------------------------------------*/ + +#if ( \ + (configUSE_TRACE_FACILITY == 1) && \ + (configUSE_STATS_FORMATTING_FUNCTIONS > 0) && \ + (configSUPPORT_DYNAMIC_ALLOCATION == 1)) + +void vTaskList(char *pcWriteBuffer) +{ + TaskStatus_t *pxTaskStatusArray; + UBaseType_t uxArraySize, x; + char cStatus; + + /* + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many + * of the demo applications. Do not consider it to be part of the + * scheduler. + * + * vTaskList() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that + * displays task names, states and stack usage. + * + * vTaskList() has a dependency on the sprintf() C library function that + * might bloat the code size, use a lot of stack, and provide different + * results on different platforms. An alternative, tiny, third party, + * and limited functionality implementation of sprintf() is provided in + * many of the FreeRTOS/Demo sub-directories in a file called + * printf-stdarg.c (note printf-stdarg.c does not provide a full + * snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly + * through a call to vTaskList(). + */ + + /* Make sure the write buffer does not contain a string. */ + *pcWriteBuffer = (char)0x00; + + /* Take a snapshot of the number of tasks in case it changes while this + function is executing. */ + uxArraySize = uxCurrentNumberOfTasks; + + /* Allocate an array index for each task. NOTE! if + configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will + equate to NULL. */ + pxTaskStatusArray = pvPortMalloc( + uxCurrentNumberOfTasks * + sizeof( + TaskStatus_t)); /*lint !e9079 All values returned by pvPortMalloc() + have at least the alignment required by the MCU's + stack and this allocation allocates a struct that + has the alignment requirements of a pointer. */ + + if (pxTaskStatusArray != NULL) { + /* Generate the (binary) data. */ + uxArraySize = + uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, NULL); + + /* Create a human readable table from the binary data. */ + for (x = 0; x < uxArraySize; x++) { + switch (pxTaskStatusArray[x].eCurrentState) { + case eRunning: + cStatus = tskRUNNING_CHAR; + break; + + case eReady: + cStatus = tskREADY_CHAR; + break; + + case eBlocked: + cStatus = tskBLOCKED_CHAR; + break; + + case eSuspended: + cStatus = tskSUSPENDED_CHAR; + break; + + case eDeleted: + cStatus = tskDELETED_CHAR; + break; + + case eInvalid: /* Fall through. */ + default: /* Should not get here, but it is included + to prevent static checking errors. */ + cStatus = (char)0x00; + break; + } + + /* Write the task name to the string, padding with spaces so it + can be printed in tabular form more easily. */ + pcWriteBuffer = prvWriteNameToBuffer( + pcWriteBuffer, pxTaskStatusArray[x].pcTaskName); + + /* Write the rest of the string. */ + sprintf( + pcWriteBuffer, + "\t%c\t%u\t%u\t%u\r\n", + cStatus, + (unsigned int)pxTaskStatusArray[x].uxCurrentPriority, + (unsigned int)pxTaskStatusArray[x].usStackHighWaterMark, + (unsigned int)pxTaskStatusArray[x] + .xTaskNumber); /*lint !e586 sprintf() allowed as this is + compiled with many compilers and this is a + utility function only - not part of the + core kernel implementation. */ + pcWriteBuffer += strlen( + pcWriteBuffer); /*lint !e9016 Pointer arithmetic ok on char + pointers especially as in this case where it + best denotes the intent of the code. */ + } + + /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION + is 0 then vPortFree() will be #defined to nothing. */ + vPortFree(pxTaskStatusArray); + } else { + mtCOVERAGE_TEST_MARKER(); + } +} + +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( \ + configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( \ + configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ +/*----------------------------------------------------------*/ + +#if ( \ + (configGENERATE_RUN_TIME_STATS == 1) && \ + (configUSE_STATS_FORMATTING_FUNCTIONS > 0) && \ + (configSUPPORT_DYNAMIC_ALLOCATION == 1)) + +void vTaskGetRunTimeStats(char *pcWriteBuffer) +{ + TaskStatus_t *pxTaskStatusArray; + UBaseType_t uxArraySize, x; + uint32_t ulTotalTime, ulStatsAsPercentage; + +# if (configUSE_TRACE_FACILITY != 1) + { +#error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats(). + } +# endif + + /* + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many + * of the demo applications. Do not consider it to be part of the + * scheduler. + * + * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part + * of the uxTaskGetSystemState() output into a human readable table that + * displays the amount of time each task has spent in the Running state + * in both absolute and percentage terms. + * + * vTaskGetRunTimeStats() has a dependency on the sprintf() C library + * function that might bloat the code size, use a lot of stack, and + * provide different results on different platforms. An alternative, + * tiny, third party, and limited functionality implementation of + * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in + * a file called printf-stdarg.c (note printf-stdarg.c does not provide + * a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly + * through a call to vTaskGetRunTimeStats(). + */ + + /* Make sure the write buffer does not contain a string. */ + *pcWriteBuffer = (char)0x00; + + /* Take a snapshot of the number of tasks in case it changes while this + function is executing. */ + uxArraySize = uxCurrentNumberOfTasks; + + /* Allocate an array index for each task. NOTE! If + configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will + equate to NULL. */ + pxTaskStatusArray = pvPortMalloc( + uxCurrentNumberOfTasks * + sizeof( + TaskStatus_t)); /*lint !e9079 All values returned by pvPortMalloc() + have at least the alignment required by the MCU's + stack and this allocation allocates a struct that + has the alignment requirements of a pointer. */ + + if (pxTaskStatusArray != NULL) { + /* Generate the (binary) data. */ + uxArraySize = + uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalTime); + + /* For percentage calculations. */ + ulTotalTime /= 100UL; + + /* Avoid divide by zero errors. */ + if (ulTotalTime > 0UL) { + /* Create a human readable table from the binary data. */ + for (x = 0; x < uxArraySize; x++) { + /* What percentage of the total run time has the task used? + This will always be rounded down to the nearest integer. + ulTotalRunTimeDiv100 has already been divided by 100. */ + ulStatsAsPercentage = + pxTaskStatusArray[x].ulRunTimeCounter / ulTotalTime; + + /* Write the task name to the string, padding with + spaces so it can be printed in tabular form more + easily. */ + pcWriteBuffer = prvWriteNameToBuffer( + pcWriteBuffer, pxTaskStatusArray[x].pcTaskName); + + if (ulStatsAsPercentage > 0UL) { +# ifdef portLU_PRINTF_SPECIFIER_REQUIRED + { + sprintf( + pcWriteBuffer, + "\t%lu\t\t%lu%%\r\n", + pxTaskStatusArray[x].ulRunTimeCounter, + ulStatsAsPercentage); + } +# else + { + /* sizeof( int ) == sizeof( long ) so a smaller + printf() library can be used. */ + sprintf( + pcWriteBuffer, + "\t%u\t\t%u%%\r\n", + (unsigned int)pxTaskStatusArray[x].ulRunTimeCounter, + (unsigned int) + ulStatsAsPercentage); /*lint !e586 sprintf() + allowed as this is + compiled with many + compilers and this is a + utility function only - + not part of the core + kernel implementation. + */ + } +# endif + } else { +/* If the percentage is zero here then the task has +consumed less than 1% of the total run time. */ +# ifdef portLU_PRINTF_SPECIFIER_REQUIRED + { + sprintf( + pcWriteBuffer, + "\t%lu\t\t<1%%\r\n", + pxTaskStatusArray[x].ulRunTimeCounter); + } +# else + { + /* sizeof( int ) == sizeof( long ) so a smaller + printf() library can be used. */ + sprintf( + pcWriteBuffer, + "\t%u\t\t<1%%\r\n", + (unsigned int)pxTaskStatusArray[x] + .ulRunTimeCounter); /*lint !e586 sprintf() + allowed as this is + compiled with many + compilers and this is a + utility function only - + not part of the core + kernel implementation. */ + } +# endif + } + + pcWriteBuffer += + strlen(pcWriteBuffer); /*lint !e9016 Pointer arithmetic ok + on char pointers especially as in + this case where it best denotes + the intent of the code. */ + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + + /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION + is 0 then vPortFree() will be #defined to nothing. */ + vPortFree(pxTaskStatusArray); + } else { + mtCOVERAGE_TEST_MARKER(); + } +} + +#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( \ + configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( \ + configSUPPORT_STATIC_ALLOCATION == 1 ) ) */ +/*-----------------------------------------------------------*/ + +TickType_t uxTaskResetEventItemValue(void) +{ + TickType_t uxReturn; + + uxReturn = listGET_LIST_ITEM_VALUE(&(pxCurrentTCB->xEventListItem)); + + /* Reset the event list item to its normal value - so it can be used with + queues and semaphores. */ + listSET_LIST_ITEM_VALUE( + &(pxCurrentTCB->xEventListItem), + ((TickType_t)configMAX_PRIORITIES - + (TickType_t)pxCurrentTCB + ->uxPriority)); /*lint !e961 MISRA exception as the casts are only + redundant for some ports. */ + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +#if (configUSE_MUTEXES == 1) + +TaskHandle_t pvTaskIncrementMutexHeldCount(void) +{ + /* If xSemaphoreCreateMutex() is called before any tasks have been created + then pxCurrentTCB will be NULL. */ + if (pxCurrentTCB != NULL) { + (pxCurrentTCB->uxMutexesHeld)++; + } + + return pxCurrentTCB; +} + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if (configUSE_TASK_NOTIFICATIONS == 1) + +uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait) +{ + uint32_t ulReturn; + + taskENTER_CRITICAL(); + { + /* Only block if the notification count is not already non-zero. */ + if (pxCurrentTCB->ulNotifiedValue == 0UL) { + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; + + if (xTicksToWait > (TickType_t)0) { + prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE); + traceTASK_NOTIFY_TAKE_BLOCK(); + + /* All ports are written to allow a yield in a critical + section (some will yield immediately, others wait until the + critical section exits) - but it is not something that + application code should ever do. */ + portYIELD_WITHIN_API(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + traceTASK_NOTIFY_TAKE(); + ulReturn = pxCurrentTCB->ulNotifiedValue; + + if (ulReturn != 0UL) { + if (xClearCountOnExit != pdFALSE) { + pxCurrentTCB->ulNotifiedValue = 0UL; + } else { + pxCurrentTCB->ulNotifiedValue = ulReturn - (uint32_t)1; + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + + pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + taskEXIT_CRITICAL(); + + return ulReturn; +} + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if (configUSE_TASK_NOTIFICATIONS == 1) + +BaseType_t xTaskNotifyWait( + uint32_t ulBitsToClearOnEntry, + uint32_t ulBitsToClearOnExit, + uint32_t *pulNotificationValue, + TickType_t xTicksToWait) +{ + BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + /* Only block if a notification is not already pending. */ + if (pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED) { + /* Clear bits in the task's notification value as bits may get + set by the notifying task or interrupt. This can be used to + clear the value to zero. */ + pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry; + + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; + + if (xTicksToWait > (TickType_t)0) { + prvAddCurrentTaskToDelayedList(xTicksToWait, pdTRUE); + traceTASK_NOTIFY_WAIT_BLOCK(); + + /* All ports are written to allow a yield in a critical + section (some will yield immediately, others wait until the + critical section exits) - but it is not something that + application code should ever do. */ + portYIELD_WITHIN_API(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + traceTASK_NOTIFY_WAIT(); + + if (pulNotificationValue != NULL) { + /* Output the current notification value, which may or may not + have changed. */ + *pulNotificationValue = pxCurrentTCB->ulNotifiedValue; + } + + /* If ucNotifyValue is set then either the task never entered the + blocked state (because a notification was already pending) or the + task unblocked because of a notification. Otherwise the task + unblocked because of a timeout. */ + if (pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED) { + /* A notification was not received. */ + xReturn = pdFALSE; + } else { + /* A notification was already pending or a notification was + received while the task was waiting. */ + pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit; + xReturn = pdTRUE; + } + + pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + taskEXIT_CRITICAL(); + + return xReturn; +} + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if (configUSE_TASK_NOTIFICATIONS == 1) + +BaseType_t xTaskGenericNotify( + TaskHandle_t xTaskToNotify, + uint32_t ulValue, + eNotifyAction eAction, + uint32_t *pulPreviousNotificationValue) +{ + TCB_t *pxTCB; + BaseType_t xReturn = pdPASS; + uint8_t ucOriginalNotifyState; + + configASSERT(xTaskToNotify); + pxTCB = xTaskToNotify; + + taskENTER_CRITICAL(); + { + if (pulPreviousNotificationValue != NULL) { + *pulPreviousNotificationValue = pxTCB->ulNotifiedValue; + } + + ucOriginalNotifyState = pxTCB->ucNotifyState; + + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + switch (eAction) { + case eSetBits: + pxTCB->ulNotifiedValue |= ulValue; + break; + + case eIncrement: + (pxTCB->ulNotifiedValue)++; + break; + + case eSetValueWithOverwrite: + pxTCB->ulNotifiedValue = ulValue; + break; + + case eSetValueWithoutOverwrite: + if (ucOriginalNotifyState != taskNOTIFICATION_RECEIVED) { + pxTCB->ulNotifiedValue = ulValue; + } else { + /* The value could not be written to the task. */ + xReturn = pdFAIL; + } + break; + + case eNoAction: + /* The task is being notified without its notify value being + updated. */ + break; + + default: + /* Should not get here if all enums are handled. + Artificially force an assert by testing a value the + compiler can't assume is const. */ + configASSERT(pxTCB->ulNotifiedValue == ~0UL); + + break; + } + + traceTASK_NOTIFY(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if (ucOriginalNotifyState == taskWAITING_NOTIFICATION) { + (void)uxListRemove(&(pxTCB->xStateListItem)); + prvAddTaskToReadyList(pxTCB); + + /* The task should not have been on an event list. */ + configASSERT( + listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) == NULL); + +# if (configUSE_TICKLESS_IDLE != 0) + { + /* If a task is blocked waiting for a notification then + xNextTaskUnblockTime might be set to the blocked task's time + out time. If the task is unblocked for a reason other than + a timeout xNextTaskUnblockTime is normally left unchanged, + because it will automatically get reset to a new value when + the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter + sleep mode at the earliest possible time - so reset + xNextTaskUnblockTime here to ensure it is updated at the + earliest possible time. */ + prvResetNextTaskUnblockTime(); + } +# endif + + if (pxTCB->uxPriority > pxCurrentTCB->uxPriority) { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + taskYIELD_IF_USING_PREEMPTION(); + } else { + mtCOVERAGE_TEST_MARKER(); + } + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if (configUSE_TASK_NOTIFICATIONS == 1) + +BaseType_t xTaskGenericNotifyFromISR( + TaskHandle_t xTaskToNotify, + uint32_t ulValue, + eNotifyAction eAction, + uint32_t *pulPreviousNotificationValue, + BaseType_t *pxHigherPriorityTaskWoken) +{ + TCB_t *pxTCB; + uint8_t ucOriginalNotifyState; + BaseType_t xReturn = pdPASS; + UBaseType_t uxSavedInterruptStatus; + + configASSERT(xTaskToNotify); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + pxTCB = xTaskToNotify; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + if (pulPreviousNotificationValue != NULL) { + *pulPreviousNotificationValue = pxTCB->ulNotifiedValue; + } + + ucOriginalNotifyState = pxTCB->ucNotifyState; + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + switch (eAction) { + case eSetBits: + pxTCB->ulNotifiedValue |= ulValue; + break; + + case eIncrement: + (pxTCB->ulNotifiedValue)++; + break; + + case eSetValueWithOverwrite: + pxTCB->ulNotifiedValue = ulValue; + break; + + case eSetValueWithoutOverwrite: + if (ucOriginalNotifyState != taskNOTIFICATION_RECEIVED) { + pxTCB->ulNotifiedValue = ulValue; + } else { + /* The value could not be written to the task. */ + xReturn = pdFAIL; + } + break; + + case eNoAction: + /* The task is being notified without its notify value being + updated. */ + break; + + default: + /* Should not get here if all enums are handled. + Artificially force an assert by testing a value the + compiler can't assume is const. */ + configASSERT(pxTCB->ulNotifiedValue == ~0UL); + break; + } + + traceTASK_NOTIFY_FROM_ISR(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if (ucOriginalNotifyState == taskWAITING_NOTIFICATION) { + /* The task should not have been on an event list. */ + configASSERT( + listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) == NULL); + + if (uxSchedulerSuspended == (UBaseType_t)pdFALSE) { + (void)uxListRemove(&(pxTCB->xStateListItem)); + prvAddTaskToReadyList(pxTCB); + } else { + /* The delayed and ready lists cannot be accessed, so hold + this task pending until the scheduler is resumed. */ + vListInsertEnd(&(xPendingReadyList), &(pxTCB->xEventListItem)); + } + + if (pxTCB->uxPriority > pxCurrentTCB->uxPriority) { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + if (pxHigherPriorityTaskWoken != NULL) { + *pxHigherPriorityTaskWoken = pdTRUE; + } + + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter to an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus); + + return xReturn; +} + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if (configUSE_TASK_NOTIFICATIONS == 1) + +void vTaskNotifyGiveFromISR( + TaskHandle_t xTaskToNotify, + BaseType_t *pxHigherPriorityTaskWoken) +{ + TCB_t *pxTCB; + uint8_t ucOriginalNotifyState; + UBaseType_t uxSavedInterruptStatus; + + configASSERT(xTaskToNotify); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + pxTCB = xTaskToNotify; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + ucOriginalNotifyState = pxTCB->ucNotifyState; + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + /* 'Giving' is equivalent to incrementing a count in a counting + semaphore. */ + (pxTCB->ulNotifiedValue)++; + + traceTASK_NOTIFY_GIVE_FROM_ISR(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if (ucOriginalNotifyState == taskWAITING_NOTIFICATION) { + /* The task should not have been on an event list. */ + configASSERT( + listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) == NULL); + + if (uxSchedulerSuspended == (UBaseType_t)pdFALSE) { + (void)uxListRemove(&(pxTCB->xStateListItem)); + prvAddTaskToReadyList(pxTCB); + } else { + /* The delayed and ready lists cannot be accessed, so hold + this task pending until the scheduler is resumed. */ + vListInsertEnd(&(xPendingReadyList), &(pxTCB->xEventListItem)); + } + + if (pxTCB->uxPriority > pxCurrentTCB->uxPriority) { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + if (pxHigherPriorityTaskWoken != NULL) { + *pxHigherPriorityTaskWoken = pdTRUE; + } + + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter in an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus); +} + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if (configUSE_TASK_NOTIFICATIONS == 1) + +BaseType_t xTaskNotifyStateClear(TaskHandle_t xTask) +{ + TCB_t *pxTCB; + BaseType_t xReturn; + + /* If null is passed in here then it is the calling task that is having + its notification state cleared. */ + pxTCB = prvGetTCBFromHandle(xTask); + + taskENTER_CRITICAL(); + { + if (pxTCB->ucNotifyState == taskNOTIFICATION_RECEIVED) { + pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + xReturn = pdPASS; + } else { + xReturn = pdFAIL; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if (configUSE_TASK_NOTIFICATIONS == 1) + +uint32_t ulTaskNotifyValueClear(TaskHandle_t xTask, uint32_t ulBitsToClear) +{ + TCB_t *pxTCB; + uint32_t ulReturn; + + /* If null is passed in here then it is the calling task that is having + its notification state cleared. */ + pxTCB = prvGetTCBFromHandle(xTask); + + taskENTER_CRITICAL(); + { + /* Return the notification as it was before the bits were cleared, + then clear the bit mask. */ + ulReturn = pxCurrentTCB->ulNotifiedValue; + pxTCB->ulNotifiedValue &= ~ulBitsToClear; + } + taskEXIT_CRITICAL(); + + return ulReturn; +} + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if ( \ + (configGENERATE_RUN_TIME_STATS == 1) && \ + (INCLUDE_xTaskGetIdleTaskHandle == 1)) + +uint32_t ulTaskGetIdleRunTimeCounter(void) +{ + return xIdleTaskHandle->ulRunTimeCounter; +} + +#endif +/*-----------------------------------------------------------*/ + +static void prvAddCurrentTaskToDelayedList( + TickType_t xTicksToWait, + const BaseType_t xCanBlockIndefinitely) +{ + TickType_t xTimeToWake; + const TickType_t xConstTickCount = xTickCount; + +#if (INCLUDE_xTaskAbortDelay == 1) + { + /* About to enter a delayed list, so ensure the ucDelayAborted flag is + reset to pdFALSE so it can be detected as having been set to pdTRUE + when the task leaves the Blocked state. */ + pxCurrentTCB->ucDelayAborted = pdFALSE; + } +#endif + + /* 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->xStateListItem)) == (UBaseType_t)0) { + /* The current task must be in a ready list, so there is no need to + check, and the port reset macro can be called directly. */ + portRESET_READY_PRIORITY( + pxCurrentTCB->uxPriority, + uxTopReadyPriority); /*lint !e931 pxCurrentTCB cannot change as it + is the calling task. + pxCurrentTCB->uxPriority and + uxTopReadyPriority cannot change as called + with scheduler suspended or in a critical + section. */ + } else { + mtCOVERAGE_TEST_MARKER(); + } + +#if (INCLUDE_vTaskSuspend == 1) + { + if ((xTicksToWait == portMAX_DELAY) && + (xCanBlockIndefinitely != pdFALSE)) { + /* Add the task to the suspended task list instead of a delayed task + list to ensure it is not woken by a timing event. It will block + indefinitely. */ + vListInsertEnd( + &xSuspendedTaskList, &(pxCurrentTCB->xStateListItem)); + } 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, the + kernel will manage it correctly. */ + xTimeToWake = xConstTickCount + xTicksToWait; + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( + &(pxCurrentTCB->xStateListItem), xTimeToWake); + + if (xTimeToWake < xConstTickCount) { + /* Wake time has overflowed. Place this item in the overflow + list. */ + vListInsert( + pxOverflowDelayedTaskList, &(pxCurrentTCB->xStateListItem)); + } else { + /* The wake time has not overflowed, so the current block list + is used. */ + vListInsert(pxDelayedTaskList, &(pxCurrentTCB->xStateListItem)); + + /* If the task entering the blocked state was placed at the + head of the list of blocked tasks then xNextTaskUnblockTime + needs to be updated too. */ + if (xTimeToWake < xNextTaskUnblockTime) { + xNextTaskUnblockTime = xTimeToWake; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + } + } +#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, the kernel + will manage it correctly. */ + xTimeToWake = xConstTickCount + xTicksToWait; + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xStateListItem), xTimeToWake); + + if (xTimeToWake < xConstTickCount) { + /* Wake time has overflowed. Place this item in the overflow list. + */ + vListInsert( + pxOverflowDelayedTaskList, &(pxCurrentTCB->xStateListItem)); + } else { + /* The wake time has not overflowed, so the current block list is + * used. */ + vListInsert(pxDelayedTaskList, &(pxCurrentTCB->xStateListItem)); + + /* If the task entering the blocked state was placed at the head of + the list of blocked tasks then xNextTaskUnblockTime needs to be + updated too. */ + if (xTimeToWake < xNextTaskUnblockTime) { + xNextTaskUnblockTime = xTimeToWake; + } else { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Avoid compiler warning when INCLUDE_vTaskSuspend is not 1. */ + (void)xCanBlockIndefinitely; + } +#endif /* INCLUDE_vTaskSuspend */ +} + +/* Code below here allows additional code to be inserted into this source file, +especially where access to file scope functions and data is needed (for example +when performing module tests). */ + +#ifdef FREERTOS_MODULE_TEST +# include "tasks_test_access_functions.h" +#endif + +#if (configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1) + +# include "freertos_tasks_c_additions.h" + +# ifdef FREERTOS_TASKS_C_ADDITIONS_INIT +static void freertos_tasks_c_additions_init(void) +{ + FREERTOS_TASKS_C_ADDITIONS_INIT(); +} +# endif + +#endif |