aboutsummaryrefslogtreecommitdiff
path: root/product/rcar/src/CMSIS-FreeRTOS/Source/tasks.c
diff options
context:
space:
mode:
authorNicolas Royer <nroyer@baylibre.com>2020-09-27 17:06:50 +0200
committernicola-mazzucato-arm <42373140+nicola-mazzucato-arm@users.noreply.github.com>2020-10-15 17:45:38 +0100
commit084f9d4edade54160d16265b0108942709b2e7aa (patch)
tree2867fb045d52e03f2ddd36fc4820005a5872afd1 /product/rcar/src/CMSIS-FreeRTOS/Source/tasks.c
parentdb2d011984a280afbfdcde930ba1965db0d2b8d5 (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.c5356
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