· 8 years ago · Jan 19, 2018, 09:10 AM
1/*
2 FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
3 All rights reserved
4
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
6
7 This file is part of the FreeRTOS distribution.
8
9 FreeRTOS is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License (version 2) as published by the
11 Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
12
13 ***************************************************************************
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
15 >>! distribute a combined work that includes FreeRTOS without being !<<
16 >>! obliged to provide the source code for proprietary components !<<
17 >>! outside of the FreeRTOS kernel. !<<
18 ***************************************************************************
19
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
23 link: http://www.freertos.org/a00114.html
24
25 ***************************************************************************
26 * *
27 * FreeRTOS provides completely free yet professionally developed, *
28 * robust, strictly quality controlled, supported, and cross *
29 * platform software that is more than just the market leader, it *
30 * is the industry's de facto standard. *
31 * *
32 * Help yourself get started quickly while simultaneously helping *
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
34 * tutorial book, reference manual, or both: *
35 * http://www.FreeRTOS.org/Documentation *
36 * *
37 ***************************************************************************
38
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
40 the FAQ page "My application does not run, what could be wrong?". Have you
41 defined configASSERT()?
42
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
44 embedded software for free we request you assist our global community by
45 participating in the support forum.
46
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
48 be as productive as possible as early as possible. Now you can receive
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
50 Ltd, and the world's leading authority on the world's leading RTOS.
51
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
55
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
58
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
61 licenses offer ticketed support, indemnification and commercial middleware.
62
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
64 engineered and independently SIL3 certified version for use in safety and
65 mission critical applications that require provable dependability.
66
67 1 tab == 4 spaces!
68*/
69
70/* Standard includes. */
71#include <stdlib.h>
72#include <string.h>
73
74/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
75all the API functions to use the MPU wrappers. That should only be done when
76task.h is included from an application file. */
77#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
78
79/* FreeRTOS includes. */
80#include "Arduino_FreeRTOS.h"
81#include "task.h"
82#include "timers.h"
83#include "StackMacros.h"
84
85/* Lint e961 and e750 are suppressed as a MISRA exception justified because the
86MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
87header files above, but not in this file, in order to generate the correct
88privileged Vs unprivileged linkage and placement. */
89#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
90
91/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting
92functions but without including stdio.h here. */
93#if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 )
94 /* At the bottom of this file are two optional functions that can be used
95 to generate human readable text from the raw data generated by the
96 uxTaskGetSystemState() function. Note the formatting functions are provided
97 for convenience only, and are NOT considered part of the kernel. */
98 #include <stdio.h>
99#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
100
101/*
102 * Defines the size, in words, of the stack allocated to the idle task.
103 */
104#define tskIDLE_STACK_SIZE configIDLE_STACK_SIZE
105
106#if( configUSE_PREEMPTION == 0 )
107 /* If the cooperative scheduler is being used then a yield should not be
108 performed just because a higher priority task has been woken. */
109 #define taskYIELD_IF_USING_PREEMPTION()
110#else
111 #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
112#endif
113
114/* Values that can be assigned to the ucNotifyState member of the TCB. */
115#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 )
116#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 )
117#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 )
118
119/*
120 * The value used to fill the stack of a task when the task is created. This
121 * is used purely for checking the high water mark for tasks.
122 */
123#define tskSTACK_FILL_BYTE ( 0xa5U )
124
125/* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using
126dynamically allocated RAM, in which case when any task is deleted it is known
127that both the task's stack and TCB need to be freed. Sometimes the
128FreeRTOSConfig.h settings only allow a task to be created using statically
129allocated RAM, in which case when any task is deleted it is known that neither
130the task's stack or TCB should be freed. Sometimes the FreeRTOSConfig.h
131settings allow a task to be created using either statically or dynamically
132allocated RAM, in which case a member of the TCB is used to record whether the
133stack and/or TCB were allocated statically or dynamically, so when a task is
134deleted the RAM that was allocated dynamically is freed again and no attempt is
135made to free the RAM that was allocated statically.
136tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a
137task to be created using either statically or dynamically allocated RAM. Note
138that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with
139a statically allocated stack and a dynamically allocated TCB. */
140#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) )
141#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 )
142#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 )
143#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 )
144
145/*
146 * Macros used by vListTask to indicate which state a task is in.
147 */
148#define tskBLOCKED_CHAR ( 'B' )
149#define tskREADY_CHAR ( 'R' )
150#define tskDELETED_CHAR ( 'D' )
151#define tskSUSPENDED_CHAR ( 'S' )
152
153/*
154 * Some kernel aware debuggers require the data the debugger needs access to be
155 * global, rather than file scope.
156 */
157#ifdef portREMOVE_STATIC_QUALIFIER
158 #define static
159#endif
160
161#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
162
163 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
164 performed in a generic way that is not optimised to any particular
165 microcontroller architecture. */
166
167 /* uxTopReadyPriority holds the priority of the highest priority ready
168 state task. */
169 #define taskRECORD_READY_PRIORITY( uxPriority ) \
170 { \
171 if( ( uxPriority ) > uxTopReadyPriority ) \
172 { \
173 uxTopReadyPriority = ( uxPriority ); \
174 } \
175 } /* taskRECORD_READY_PRIORITY */
176
177 /*-----------------------------------------------------------*/
178#if 0
179 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
180 { \
181 UBaseType_t uxTopPriority = uxTopReadyPriority; \
182 \
183 /* Find the highest priority queue that contains ready tasks. */ \
184 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \
185 { \
186 configASSERT( uxTopPriority ); \
187 --uxTopPriority; \
188 } \
189 \
190 /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
191 the same priority get an equal share of the processor time. */ \
192 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
193 uxTopReadyPriority = uxTopPriority; \
194 } /* taskSELECT_HIGHEST_PRIORITY_TASK */
195
196 /*-----------------------------------------------------------*/
197#endif
198 /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as
199 they are only required when a port optimised method of task selection is
200 being used. */
201 #define taskRESET_READY_PRIORITY( uxPriority )
202 #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
203
204#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
205
206 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is
207 performed in a way that is tailored to the particular microcontroller
208 architecture being used. */
209
210 /* A port optimised version is provided. Call the port defined macros. */
211 #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
212
213 /*-----------------------------------------------------------*/
214
215 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
216 { \
217 UBaseType_t uxTopPriority; \
218 \
219 /* Find the highest priority list that contains ready tasks. */ \
220 portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
221 configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
222 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
223 } /* taskSELECT_HIGHEST_PRIORITY_TASK() */
224
225 /*-----------------------------------------------------------*/
226
227 /* A port optimised version is provided, call it only if the TCB being reset
228 is being referenced from a ready list. If it is referenced from a delayed
229 or suspended list then it won't be in a ready list. */
230 #define taskRESET_READY_PRIORITY( uxPriority ) \
231 { \
232 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) \
233 { \
234 portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \
235 } \
236 }
237
238#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
239
240/*-----------------------------------------------------------*/
241
242/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
243count overflows. */
244#define taskSWITCH_DELAYED_LISTS() \
245{ \
246 List_t *pxTemp; \
247 \
248 /* The delayed tasks list should be empty when the lists are switched. */ \
249 configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \
250 \
251 pxTemp = pxDelayedTaskList; \
252 pxDelayedTaskList = pxOverflowDelayedTaskList; \
253 pxOverflowDelayedTaskList = pxTemp; \
254 xNumOfOverflows++; \
255 prvResetNextTaskUnblockTime(); \
256}
257
258/*-----------------------------------------------------------*/
259
260/*
261 * Place the task represented by pxTCB into the appropriate ready list for
262 * the task. It is inserted at the end of the list.
263 */
264#define prvAddTaskToReadyList( pxTCB ) \
265 traceMOVED_TASK_TO_READY_STATE( pxTCB ); \
266 taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
267 vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
268 tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
269/*-----------------------------------------------------------*/
270
271/*
272 * Several functions take an TaskHandle_t parameter that can optionally be NULL,
273 * where NULL is used to indicate that the handle of the currently executing
274 * task should be used in place of the parameter. This macro simply checks to
275 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
276 */
277#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) )
278
279/* The item value of the event list item is normally used to hold the priority
280of the task to which it belongs (coded to allow it to be held in reverse
281priority order). However, it is occasionally borrowed for other purposes. It
282is important its value is not updated due to a task priority change while it is
283being used for another purpose. The following bit definition is used to inform
284the scheduler that the value should not be changed - in which case it is the
285responsibility of whichever module is using the value to ensure it gets set back
286to its original value when it is released. */
287#if( configUSE_16_BIT_TICKS == 1 )
288 #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U
289#else
290 #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL
291#endif
292
293/*
294 * Task control block. A task control block (TCB) is allocated for each task,
295 * and stores task state information, including a pointer to the task's context
296 * (the task's run time environment, including register values)
297 */
298typedef struct tskTaskControlBlock
299{
300 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. */
301
302 #if ( portUSING_MPU_WRAPPERS == 1 )
303 xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
304 #endif
305
306 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 ). */
307 ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
308 UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
309 StackType_t *pxStack; /*< Points to the start of the stack. */
310 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. */
311
312#if ( configUSE_RM_PERIODIC == 1 )
313 TickType_t tick_period;
314 TickType_t time_period;
315 TickType_t tick_length;
316
317 TickType_t task_runTime;
318
319 volatile StackType_t *pxTopOfStackRM;
320
321 unsigned char active;
322
323 void (*task_function)(void*);
324 void* task_param;
325#endif
326
327 #if ( portSTACK_GROWTH > 0 )
328 StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */
329 #endif
330
331 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
332 UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
333 #endif
334
335 #if ( configUSE_TRACE_FACILITY == 1 )
336 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. */
337 UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
338 #endif
339
340 #if ( configUSE_MUTEXES == 1 )
341 UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
342 UBaseType_t uxMutexesHeld;
343 #endif
344
345 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
346 TaskHookFunction_t pxTaskTag;
347 #endif
348
349 #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
350 void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
351 #endif
352
353 #if( configGENERATE_RUN_TIME_STATS == 1 )
354 uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
355 #endif
356
357 #if ( configUSE_NEWLIB_REENTRANT == 1 )
358 /* Allocate a Newlib reent structure that is specific to this task.
359 Note Newlib support has been included by popular demand, but is not
360 used by the FreeRTOS maintainers themselves. FreeRTOS is not
361 responsible for resulting newlib operation. User must be familiar with
362 newlib and must provide system-wide implementations of the necessary
363 stubs. Be warned that (at the time of writing) the current newlib design
364 implements a system-wide malloc() that must be provided with locks. */
365 struct _reent xNewLib_reent;
366 #endif
367
368 #if( configUSE_TASK_NOTIFICATIONS == 1 )
369 volatile uint32_t ulNotifiedValue;
370 volatile uint8_t ucNotifyState;
371 #endif
372
373 /* See the comments above the definition of
374 tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
375 #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
376 uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
377 #endif
378
379 #if( INCLUDE_xTaskAbortDelay == 1 )
380 uint8_t ucDelayAborted;
381 #endif
382
383} tskTCB;
384
385/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
386below to enable the use of older kernel aware debuggers. */
387typedef tskTCB TCB_t;
388
389/*lint -e956 A manual analysis and inspection has been used to determine which
390static variables must be declared volatile. */
391
392PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
393/* Lists for ready and blocked tasks. --------------------*/
394PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */
395PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */
396PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
397PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */
398PRIVILEGED_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. */
399PRIVILEGED_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. */
400
401#if( INCLUDE_vTaskDelete == 1 )
402
403 PRIVILEGED_DATA static List_t xTasksWaitingTermination; /*< Tasks that have been deleted - but their memory not yet freed. */
404 PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U;
405
406#endif
407
408#if ( INCLUDE_vTaskSuspend == 1 )
409
410 PRIVILEGED_DATA static List_t xSuspendedTaskList; /*< Tasks that are currently suspended. */
411
412#endif
413
414/* Other file private variables. --------------------------------*/
415PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
416PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U;
417PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
418PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
419PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U;
420PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE;
421PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0;
422PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;
423PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */
424PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /* < Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */
425
426/* Context switches are held pending while the scheduler is suspended. Also,
427interrupts must not manipulate the xStateListItem of a TCB, or any of the
428lists the xStateListItem can be referenced from, if the scheduler is suspended.
429If an interrupt needs to unblock a task while the scheduler is suspended then it
430moves the task's event list item into the xPendingReadyList, ready for the
431kernel to move the task from the pending ready list into the real ready list
432when the scheduler is unsuspended. The pending ready list itself can only be
433accessed from a critical section. */
434PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE;
435
436#if ( configGENERATE_RUN_TIME_STATS == 1 )
437
438 PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
439 PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */
440
441#endif
442
443/*lint +e956 */
444
445/*-----------------------------------------------------------*/
446
447/* Callback function prototypes. --------------------------*/
448#if( configCHECK_FOR_STACK_OVERFLOW > 0 )
449 extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );
450#endif
451
452#if( configUSE_TICK_HOOK > 0 )
453 extern void vApplicationTickHook( void );
454#endif
455
456#if( configSUPPORT_STATIC_ALLOCATION == 1 )
457 extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );
458#endif
459
460/* File private functions. --------------------------------*/
461
462/**
463 * Utility task that simply returns pdTRUE if the task referenced by xTask is
464 * currently in the Suspended state, or pdFALSE if the task referenced by xTask
465 * is in any other state.
466 */
467#if ( INCLUDE_vTaskSuspend == 1 )
468 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
469#endif /* INCLUDE_vTaskSuspend */
470
471/*
472 * Utility to ready all the lists used by the scheduler. This is called
473 * automatically upon the creation of the first task.
474 */
475static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
476
477/*
478 * The idle task, which as all tasks is implemented as a never ending loop.
479 * The idle task is automatically created and added to the ready lists upon
480 * creation of the first user task.
481 *
482 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
483 * language extensions. The equivalent prototype for this function is:
484 *
485 * void prvIdleTask( void *pvParameters );
486 *
487 */
488static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
489
490/*
491 * Utility to free all memory allocated by the scheduler to hold a TCB,
492 * including the stack pointed to by the TCB.
493 *
494 * This does not free memory allocated by the task itself (i.e. memory
495 * allocated by calls to pvPortMalloc from within the tasks application code).
496 */
497#if ( INCLUDE_vTaskDelete == 1 )
498
499 static void prvDeleteTCB( TCB_t *pxTCB ) PRIVILEGED_FUNCTION;
500
501#endif
502
503/*
504 * Used only by the idle task. This checks to see if anything has been placed
505 * in the list of tasks waiting to be deleted. If so the task is cleaned up
506 * and its TCB deleted.
507 */
508static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
509
510/*
511 * The currently executing task is entering the Blocked state. Add the task to
512 * either the current or the overflow delayed task list.
513 */
514static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION;
515
516/*
517 * Fills an TaskStatus_t structure with information on each task that is
518 * referenced from the pxList list (which may be a ready list, a delayed list,
519 * a suspended list, etc.).
520 *
521 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
522 * NORMAL APPLICATION CODE.
523 */
524#if ( configUSE_TRACE_FACILITY == 1 )
525
526 static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION;
527
528#endif
529
530/*
531 * Searches pxList for a task with name pcNameToQuery - returning a handle to
532 * the task if it is found, or NULL if the task is not found.
533 */
534#if ( INCLUDE_xTaskGetHandle == 1 )
535
536 static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] ) PRIVILEGED_FUNCTION;
537
538#endif
539
540/*
541 * When a task is created, the stack of the task is filled with a known value.
542 * This function determines the 'high water mark' of the task stack by
543 * determining how much of the stack remains at the original preset value.
544 */
545#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
546
547 static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION;
548
549#endif
550
551/*
552 * Return the amount of time, in ticks, that will pass before the kernel will
553 * next move a task from the Blocked state to the Running state.
554 *
555 * This conditional compilation should use inequality to 0, not equality to 1.
556 * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user
557 * defined low power mode implementations require configUSE_TICKLESS_IDLE to be
558 * set to a value other than 1.
559 */
560#if ( configUSE_TICKLESS_IDLE != 0 )
561
562 static TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION;
563
564#endif
565
566/*
567 * Set xNextTaskUnblockTime to the time at which the next Blocked state task
568 * will exit the Blocked state.
569 */
570static void prvResetNextTaskUnblockTime( void );
571
572#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
573
574 /*
575 * Helper function used to pad task names with spaces when printing out
576 * human readable tables of task information.
577 */
578 static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) PRIVILEGED_FUNCTION;
579
580#endif
581
582/*
583 * Called after a Task_t structure has been allocated either statically or
584 * dynamically to fill in the structure's members.
585 */
586static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
587 const char * const pcName,
588 const uint32_t ulStackDepth,
589 void * const pvParameters,
590 UBaseType_t uxPriority,
591 TaskHandle_t * const pxCreatedTask,
592 TCB_t *pxNewTCB,
593 const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
594
595/*
596 * Called after a new task has been created and initialised to place the task
597 * under the control of the scheduler.
598 */
599static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
600
601#if ( configUSE_RM_PERIODIC == 1)
602 inline void taskSELECT_HIGHEST_PRIORITY_TASK()
603 {
604 UBaseType_t uxTopPriority = uxTopReadyPriority;
605
606 do
607 {
608 if(listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ))
609 {
610 configASSERT( uxTopPriority );
611 --uxTopPriority;
612 }
613 else
614 {
615 pxCurrentTCB = listGET_OWNER_OF_HEAD_ENTRY( &( pxReadyTasksLists[ uxTopPriority ] ) );
616
617 if(xTickCount % pxCurrentTCB->tick_period == 0)
618 {
619 pxCurrentTCB->task_runTime = 0;
620// pxCurrentTCB->pxTopOfStack = pxPortInitialiseStack( pxCurrentTCB->pxTopOfStackRM, pxCurrentTCB->task_function, pxCurrentTCB->task_param );
621 return;
622 }
623 else if(pxCurrentTCB->task_runTime > pxCurrentTCB->tick_length)
624 {
625 --uxTopPriority;
626 }
627 else
628 {
629 return;
630 }
631 }
632 }while(uxTopPriority);
633
634 pxCurrentTCB = listGET_OWNER_OF_HEAD_ENTRY( &( pxReadyTasksLists[ uxTopPriority ] ) );
635 }
636#endif
637
638/*-----------------------------------------------------------*/
639
640#if( configSUPPORT_STATIC_ALLOCATION == 1 )
641
642 TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
643 const char * const pcName,
644 const uint32_t ulStackDepth,
645 void * const pvParameters,
646 UBaseType_t uxPriority,
647 StackType_t * const puxStackBuffer,
648 StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
649 {
650 TCB_t *pxNewTCB;
651 TaskHandle_t xReturn;
652
653 configASSERT( puxStackBuffer != NULL );
654 configASSERT( pxTaskBuffer != NULL );
655
656 if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
657 {
658 /* The memory used for the task's TCB and stack are passed into this
659 function - use them. */
660 pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */
661 pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
662
663 #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
664 {
665 /* Tasks can be created statically or dynamically, so note this
666 task was created statically in case the task is later deleted. */
667 pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
668 }
669 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
670
671 prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL );
672 prvAddNewTaskToReadyList( pxNewTCB );
673 }
674 else
675 {
676 xReturn = NULL;
677 }
678
679 return xReturn;
680 }
681
682#endif /* SUPPORT_STATIC_ALLOCATION */
683/*-----------------------------------------------------------*/
684
685#if( portUSING_MPU_WRAPPERS == 1 )
686
687 BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
688 {
689 TCB_t *pxNewTCB;
690 BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
691
692 configASSERT( pxTaskDefinition->puxStackBuffer );
693
694 if( pxTaskDefinition->puxStackBuffer != NULL )
695 {
696 /* Allocate space for the TCB. Where the memory comes from depends
697 on the implementation of the port malloc function and whether or
698 not static allocation is being used. */
699 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
700
701 if( pxNewTCB != NULL )
702 {
703 /* Store the stack location in the TCB. */
704 pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer;
705
706 /* Tasks can be created statically or dynamically, so note
707 this task had a statically allocated stack in case it is
708 later deleted. The TCB was allocated dynamically. */
709 pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY;
710
711 prvInitialiseNewTask( pxTaskDefinition->pvTaskCode,
712 pxTaskDefinition->pcName,
713 ( uint32_t ) pxTaskDefinition->usStackDepth,
714 pxTaskDefinition->pvParameters,
715 pxTaskDefinition->uxPriority,
716 pxCreatedTask, pxNewTCB,
717 pxTaskDefinition->xRegions );
718
719 prvAddNewTaskToReadyList( pxNewTCB );
720 xReturn = pdPASS;
721 }
722 }
723
724 return xReturn;
725 }
726
727#endif /* portUSING_MPU_WRAPPERS */
728/*-----------------------------------------------------------*/
729
730#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
731
732 BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
733 const char * const pcName,
734 const uint16_t usStackDepth,
735 void * const pvParameters,
736 UBaseType_t uxPriority,
737 TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
738 {
739 TCB_t *pxNewTCB;
740 BaseType_t xReturn;
741
742 /* If the stack grows down then allocate the stack then the TCB so the stack
743 does not grow into the TCB. Likewise if the stack grows up then allocate
744 the TCB then the stack. */
745 #if( portSTACK_GROWTH > 0 )
746 {
747 /* Allocate space for the TCB. Where the memory comes from depends on
748 the implementation of the port malloc function and whether or not static
749 allocation is being used. */
750 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
751
752 if( pxNewTCB != NULL )
753 {
754 /* Allocate space for the stack used by the task being created.
755 The base of the stack memory stored in the TCB so the task can
756 be deleted later if required. */
757 pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
758
759 if( pxNewTCB->pxStack == NULL )
760 {
761 /* Could not allocate the stack. Delete the allocated TCB. */
762 vPortFree( pxNewTCB );
763 pxNewTCB = NULL;
764 }
765 }
766 }
767 #else /* portSTACK_GROWTH */
768 {
769 StackType_t *pxStack;
770
771 /* Allocate space for the stack used by the task being created. */
772 pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
773
774 if( pxStack != NULL )
775 {
776 /* Allocate space for the TCB. */
777 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */
778
779 if( pxNewTCB != NULL )
780 {
781 /* Store the stack location in the TCB. */
782 pxNewTCB->pxStack = pxStack;
783 }
784 else
785 {
786 /* The stack cannot be used as the TCB was not created. Free
787 it again. */
788 vPortFree( pxStack );
789 }
790 }
791 else
792 {
793 pxNewTCB = NULL;
794 }
795 }
796 #endif /* portSTACK_GROWTH */
797
798 if( pxNewTCB != NULL )
799 {
800 #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
801 {
802 /* Tasks can be created statically or dynamically, so note this
803 task was created dynamically in case it is later deleted. */
804 pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
805 }
806 #endif /* configSUPPORT_STATIC_ALLOCATION */
807
808 prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
809 prvAddNewTaskToReadyList( pxNewTCB );
810 xReturn = pdPASS;
811 }
812 else
813 {
814 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
815 }
816
817 return xReturn;
818 }
819
820#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
821/*-----------------------------------------------------------*/
822
823#if ( configUSE_RM_PERIODIC == 1)
824 periodic_task_info list_of_task_info[8];
825 static unsigned char task_info_counter = 0;
826
827 void xPeriodicTaskCreate(periodic_task_info* new_task_info)
828 {
829 memcpy(&list_of_task_info[task_info_counter++], new_task_info, sizeof(periodic_task_info));
830 }
831#endif
832
833static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
834 const char * const pcName,
835 const uint32_t ulStackDepth,
836 void * const pvParameters,
837 UBaseType_t uxPriority,
838 TaskHandle_t * const pxCreatedTask,
839 TCB_t *pxNewTCB,
840 const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
841{
842StackType_t *pxTopOfStack;
843UBaseType_t x;
844
845#if ( configUSE_RM_PERIODIC == 1 )
846{
847 pxNewTCB->tick_period = portMAX_DELAY;
848 pxNewTCB->time_period = portMAX_DELAY;
849 pxNewTCB->tick_length = portMAX_DELAY;
850 pxNewTCB->task_runTime = 0;
851 pxNewTCB->task_param = 0;
852}
853#endif
854 #if( portUSING_MPU_WRAPPERS == 1 )
855 /* Should the task be created in privileged mode? */
856 BaseType_t xRunPrivileged;
857 if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
858 {
859 xRunPrivileged = pdTRUE;
860 }
861 else
862 {
863 xRunPrivileged = pdFALSE;
864 }
865 uxPriority &= ~portPRIVILEGE_BIT;
866 #endif /* portUSING_MPU_WRAPPERS == 1 */
867
868 /* Avoid dependency on memset() if it is not required. */
869 #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
870 {
871 /* Fill the stack with a known value to assist debugging. */
872 ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
873 }
874 #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */
875
876 /* Calculate the top of stack address. This depends on whether the stack
877 grows from high memory to low (as per the 80x86) or vice versa.
878 portSTACK_GROWTH is used to make the result positive or negative as required
879 by the port. */
880 #if( portSTACK_GROWTH < 0 )
881 {
882 pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
883 pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */
884
885 /* Check the alignment of the calculated top of stack is correct. */
886 configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
887 }
888 #else /* portSTACK_GROWTH */
889 {
890 pxTopOfStack = pxNewTCB->pxStack;
891
892 /* Check the alignment of the stack buffer is correct. */
893 configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
894
895 /* The other extreme of the stack space is required if stack checking is
896 performed. */
897 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
898 }
899 #endif /* portSTACK_GROWTH */
900
901 /* Store the task name in the TCB. */
902 for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
903 {
904 pxNewTCB->pcTaskName[ x ] = pcName[ x ];
905
906 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
907 configMAX_TASK_NAME_LEN characters just in case the memory after the
908 string is not accessible (extremely unlikely). */
909 if( pcName[ x ] == 0x00 )
910 {
911 break;
912 }
913 else
914 {
915 mtCOVERAGE_TEST_MARKER();
916 }
917 }
918
919 /* Ensure the name string is terminated in the case that the string length
920 was greater or equal to configMAX_TASK_NAME_LEN. */
921 pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
922
923 /* This is used as an array index so must ensure it's not too large. First
924 remove the privilege bit if one is present. */
925 if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
926 {
927 uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
928 }
929 else
930 {
931 mtCOVERAGE_TEST_MARKER();
932 }
933
934 pxNewTCB->uxPriority = uxPriority;
935 #if ( configUSE_MUTEXES == 1 )
936 {
937 pxNewTCB->uxBasePriority = uxPriority;
938 pxNewTCB->uxMutexesHeld = 0;
939 }
940 #endif /* configUSE_MUTEXES */
941
942 vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
943 vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
944
945 /* Set the pxNewTCB as a link back from the ListItem_t. This is so we can get
946 back to the containing TCB from a generic item in a list. */
947 listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
948
949 /* Event lists are always in priority order. */
950 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. */
951 listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
952
953 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
954 {
955 pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U;
956 }
957 #endif /* portCRITICAL_NESTING_IN_TCB */
958
959 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
960 {
961 pxNewTCB->pxTaskTag = NULL;
962 }
963 #endif /* configUSE_APPLICATION_TASK_TAG */
964
965 #if ( configGENERATE_RUN_TIME_STATS == 1 )
966 {
967 pxNewTCB->ulRunTimeCounter = 0UL;
968 }
969 #endif /* configGENERATE_RUN_TIME_STATS */
970
971 #if ( portUSING_MPU_WRAPPERS == 1 )
972 {
973 vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, ulStackDepth );
974 }
975 #else
976 {
977 /* Avoid compiler warning about unreferenced parameter. */
978 ( void ) xRegions;
979 }
980 #endif
981
982 #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
983 {
984 for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
985 {
986 pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL;
987 }
988 }
989 #endif
990
991 #if ( configUSE_TASK_NOTIFICATIONS == 1 )
992 {
993 pxNewTCB->ulNotifiedValue = 0;
994 pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
995 }
996 #endif
997
998 #if ( configUSE_NEWLIB_REENTRANT == 1 )
999 {
1000 /* Initialise this task's Newlib reent structure. */
1001 _REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) );
1002 }
1003 #endif
1004
1005 #if( INCLUDE_xTaskAbortDelay == 1 )
1006 {
1007 pxNewTCB->ucDelayAborted = pdFALSE;
1008 }
1009 #endif
1010
1011 /* Initialize the TCB stack to look as if the task was already running,
1012 but had been interrupted by the scheduler. The return address is set
1013 to the start of the task function. Once the stack has been initialised
1014 the top of stack variable is updated. */
1015 #if( portUSING_MPU_WRAPPERS == 1 )
1016 {
1017 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
1018 }
1019 #else /* portUSING_MPU_WRAPPERS */
1020 {
1021 pxNewTCB->pxTopOfStackRM = pxNewTCB->pxTopOfStack;
1022 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
1023 }
1024 #endif /* portUSING_MPU_WRAPPERS */
1025
1026 if( ( void * ) pxCreatedTask != NULL )
1027 {
1028 /* Pass the handle out in an anonymous way. The handle can be used to
1029 change the created task's priority, delete the created task, etc.*/
1030 *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
1031 }
1032 else
1033 {
1034 mtCOVERAGE_TEST_MARKER();
1035 }
1036}
1037/*-----------------------------------------------------------*/
1038
1039static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
1040{
1041 /* Ensure interrupts don't access the task lists while the lists are being
1042 updated. */
1043 taskENTER_CRITICAL();
1044 {
1045 uxCurrentNumberOfTasks++;
1046 if( pxCurrentTCB == NULL )
1047 {
1048 /* There are no other tasks, or all the other tasks are in
1049 the suspended state - make this the current task. */
1050 pxCurrentTCB = pxNewTCB;
1051
1052 if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
1053 {
1054 /* This is the first task to be created so do the preliminary
1055 initialisation required. We will not recover if this call
1056 fails, but we will report the failure. */
1057 prvInitialiseTaskLists();
1058 }
1059 else
1060 {
1061 mtCOVERAGE_TEST_MARKER();
1062 }
1063 }
1064 else
1065 {
1066 /* If the scheduler is not already running, make this task the
1067 current task if it is the highest priority task to be created
1068 so far. */
1069 if( xSchedulerRunning == pdFALSE )
1070 {
1071 if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
1072 {
1073 pxCurrentTCB = pxNewTCB;
1074 }
1075 else
1076 {
1077 mtCOVERAGE_TEST_MARKER();
1078 }
1079 }
1080 else
1081 {
1082 mtCOVERAGE_TEST_MARKER();
1083 }
1084 }
1085
1086 uxTaskNumber++;
1087
1088 #if ( configUSE_TRACE_FACILITY == 1 )
1089 {
1090 /* Add a counter into the TCB for tracing only. */
1091 pxNewTCB->uxTCBNumber = uxTaskNumber;
1092 }
1093 #endif /* configUSE_TRACE_FACILITY */
1094 traceTASK_CREATE( pxNewTCB );
1095
1096 prvAddTaskToReadyList( pxNewTCB );
1097
1098 portSETUP_TCB( pxNewTCB );
1099 }
1100 taskEXIT_CRITICAL();
1101
1102 if( xSchedulerRunning != pdFALSE )
1103 {
1104 /* If the created task is of a higher priority than the current task
1105 then it should run now. */
1106 if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
1107 {
1108 taskYIELD_IF_USING_PREEMPTION();
1109 }
1110 else
1111 {
1112 mtCOVERAGE_TEST_MARKER();
1113 }
1114 }
1115 else
1116 {
1117 mtCOVERAGE_TEST_MARKER();
1118 }
1119}
1120/*-----------------------------------------------------------*/
1121
1122#if ( INCLUDE_vTaskDelete == 1 )
1123
1124 void vTaskDelete( TaskHandle_t xTaskToDelete )
1125 {
1126 TCB_t *pxTCB;
1127
1128 taskENTER_CRITICAL();
1129 {
1130 /* If null is passed in here then it is the calling task that is
1131 being deleted. */
1132 pxTCB = prvGetTCBFromHandle( xTaskToDelete );
1133
1134 /* Remove task from the ready list. */
1135 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
1136 {
1137 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
1138 }
1139 else
1140 {
1141 mtCOVERAGE_TEST_MARKER();
1142 }
1143
1144 /* Is the task waiting on an event also? */
1145 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
1146 {
1147 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
1148 }
1149 else
1150 {
1151 mtCOVERAGE_TEST_MARKER();
1152 }
1153
1154 /* Increment the uxTaskNumber also so kernel aware debuggers can
1155 detect that the task lists need re-generating. This is done before
1156 portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will
1157 not return. */
1158 uxTaskNumber++;
1159
1160 if( pxTCB == pxCurrentTCB )
1161 {
1162 /* A task is deleting itself. This cannot complete within the
1163 task itself, as a context switch to another task is required.
1164 Place the task in the termination list. The idle task will
1165 check the termination list and free up any memory allocated by
1166 the scheduler for the TCB and stack of the deleted task. */
1167 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
1168
1169 /* Increment the ucTasksDeleted variable so the idle task knows
1170 there is a task that has been deleted and that it should therefore
1171 check the xTasksWaitingTermination list. */
1172 ++uxDeletedTasksWaitingCleanUp;
1173
1174 /* The pre-delete hook is primarily for the Windows simulator,
1175 in which Windows specific clean up operations are performed,
1176 after which it is not possible to yield away from this task -
1177 hence xYieldPending is used to latch that a context switch is
1178 required. */
1179 portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
1180 }
1181 else
1182 {
1183 --uxCurrentNumberOfTasks;
1184 prvDeleteTCB( pxTCB );
1185
1186 /* Reset the next expected unblock time in case it referred to
1187 the task that has just been deleted. */
1188 prvResetNextTaskUnblockTime();
1189 }
1190
1191 traceTASK_DELETE( pxTCB );
1192 }
1193 taskEXIT_CRITICAL();
1194
1195 /* Force a reschedule if it is the currently running task that has just
1196 been deleted. */
1197 if( xSchedulerRunning != pdFALSE )
1198 {
1199 if( pxTCB == pxCurrentTCB )
1200 {
1201 configASSERT( uxSchedulerSuspended == 0 );
1202 portYIELD_WITHIN_API();
1203 }
1204 else
1205 {
1206 mtCOVERAGE_TEST_MARKER();
1207 }
1208 }
1209 }
1210
1211#endif /* INCLUDE_vTaskDelete */
1212/*-----------------------------------------------------------*/
1213
1214#if ( INCLUDE_vTaskDelayUntil == 1 )
1215
1216 void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
1217 {
1218 TickType_t xTimeToWake;
1219 BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;
1220
1221 configASSERT( pxPreviousWakeTime );
1222 configASSERT( ( xTimeIncrement > 0U ) );
1223 configASSERT( uxSchedulerSuspended == 0 );
1224
1225 vTaskSuspendAll();
1226 {
1227 /* Minor optimisation. The tick count cannot change in this
1228 block. */
1229 const TickType_t xConstTickCount = xTickCount;
1230
1231 /* Generate the tick time at which the task wants to wake. */
1232 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
1233
1234 if( xConstTickCount < *pxPreviousWakeTime )
1235 {
1236 /* The tick count has overflowed since this function was
1237 lasted called. In this case the only time we should ever
1238 actually delay is if the wake time has also overflowed,
1239 and the wake time is greater than the tick time. When this
1240 is the case it is as if neither time had overflowed. */
1241 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
1242 {
1243 xShouldDelay = pdTRUE;
1244 }
1245 else
1246 {
1247 mtCOVERAGE_TEST_MARKER();
1248 }
1249 }
1250 else
1251 {
1252 /* The tick time has not overflowed. In this case we will
1253 delay if either the wake time has overflowed, and/or the
1254 tick time is less than the wake time. */
1255 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
1256 {
1257 xShouldDelay = pdTRUE;
1258 }
1259 else
1260 {
1261 mtCOVERAGE_TEST_MARKER();
1262 }
1263 }
1264
1265 /* Update the wake time ready for the next call. */
1266 *pxPreviousWakeTime = xTimeToWake;
1267
1268 if( xShouldDelay != pdFALSE )
1269 {
1270 traceTASK_DELAY_UNTIL( xTimeToWake );
1271
1272 /* prvAddCurrentTaskToDelayedList() needs the block time, not
1273 the time to wake, so subtract the current tick count. */
1274 prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );
1275 }
1276 else
1277 {
1278 mtCOVERAGE_TEST_MARKER();
1279 }
1280 }
1281 xAlreadyYielded = xTaskResumeAll();
1282
1283 /* Force a reschedule if xTaskResumeAll has not already done so, we may
1284 have put ourselves to sleep. */
1285 if( xAlreadyYielded == pdFALSE )
1286 {
1287 portYIELD_WITHIN_API();
1288 }
1289 else
1290 {
1291 mtCOVERAGE_TEST_MARKER();
1292 }
1293 }
1294
1295#endif /* INCLUDE_vTaskDelayUntil */
1296/*-----------------------------------------------------------*/
1297
1298#if ( INCLUDE_vTaskDelay == 1 )
1299
1300 void vTaskDelay( const TickType_t xTicksToDelay )
1301 {
1302 BaseType_t xAlreadyYielded = pdFALSE;
1303
1304 /* A delay time of zero just forces a reschedule. */
1305 if( xTicksToDelay > ( TickType_t ) 0U )
1306 {
1307 configASSERT( uxSchedulerSuspended == 0 );
1308 vTaskSuspendAll();
1309 {
1310 traceTASK_DELAY();
1311
1312 /* A task that is removed from the event list while the
1313 scheduler is suspended will not get placed in the ready
1314 list or removed from the blocked list until the scheduler
1315 is resumed.
1316
1317 This task cannot be in an event list as it is the currently
1318 executing task. */
1319 prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
1320 }
1321 xAlreadyYielded = xTaskResumeAll();
1322 }
1323 else
1324 {
1325 mtCOVERAGE_TEST_MARKER();
1326 }
1327
1328 /* Force a reschedule if xTaskResumeAll has not already done so, we may
1329 have put ourselves to sleep. */
1330 if( xAlreadyYielded == pdFALSE )
1331 {
1332 portYIELD_WITHIN_API();
1333 }
1334 else
1335 {
1336 mtCOVERAGE_TEST_MARKER();
1337 }
1338 }
1339
1340#endif /* INCLUDE_vTaskDelay */
1341/*-----------------------------------------------------------*/
1342
1343#if( ( INCLUDE_eTaskGetState == 1 ) || ( configUSE_TRACE_FACILITY == 1 ) )
1344
1345 eTaskState eTaskGetState( TaskHandle_t xTask )
1346 {
1347 eTaskState eReturn;
1348 List_t *pxStateList;
1349 const TCB_t * const pxTCB = ( TCB_t * ) xTask;
1350
1351 configASSERT( pxTCB );
1352
1353 if( pxTCB == pxCurrentTCB )
1354 {
1355 /* The task calling this function is querying its own state. */
1356 eReturn = eRunning;
1357 }
1358 else
1359 {
1360 taskENTER_CRITICAL();
1361 {
1362 pxStateList = ( List_t * ) listLIST_ITEM_CONTAINER( &( pxTCB->xStateListItem ) );
1363 }
1364 taskEXIT_CRITICAL();
1365
1366 if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) )
1367 {
1368 /* The task being queried is referenced from one of the Blocked
1369 lists. */
1370 eReturn = eBlocked;
1371 }
1372
1373 #if ( INCLUDE_vTaskSuspend == 1 )
1374 else if( pxStateList == &xSuspendedTaskList )
1375 {
1376 /* The task being queried is referenced from the suspended
1377 list. Is it genuinely suspended or is it block
1378 indefinitely? */
1379 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL )
1380 {
1381 eReturn = eSuspended;
1382 }
1383 else
1384 {
1385 eReturn = eBlocked;
1386 }
1387 }
1388 #endif
1389
1390 #if ( INCLUDE_vTaskDelete == 1 )
1391 else if( ( pxStateList == &xTasksWaitingTermination ) || ( pxStateList == NULL ) )
1392 {
1393 /* The task being queried is referenced from the deleted
1394 tasks list, or it is not referenced from any lists at
1395 all. */
1396 eReturn = eDeleted;
1397 }
1398 #endif
1399
1400 else /*lint !e525 Negative indentation is intended to make use of pre-processor clearer. */
1401 {
1402 /* If the task is not in any other state, it must be in the
1403 Ready (including pending ready) state. */
1404 eReturn = eReady;
1405 }
1406 }
1407
1408 return eReturn;
1409 } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */
1410
1411#endif /* INCLUDE_eTaskGetState */
1412/*-----------------------------------------------------------*/
1413
1414#if ( INCLUDE_uxTaskPriorityGet == 1 )
1415
1416 UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask )
1417 {
1418 TCB_t *pxTCB;
1419 UBaseType_t uxReturn;
1420
1421 taskENTER_CRITICAL();
1422 {
1423 /* If null is passed in here then it is the priority of the that
1424 called uxTaskPriorityGet() that is being queried. */
1425 pxTCB = prvGetTCBFromHandle( xTask );
1426 uxReturn = pxTCB->uxPriority;
1427 }
1428 taskEXIT_CRITICAL();
1429
1430 return uxReturn;
1431 }
1432
1433#endif /* INCLUDE_uxTaskPriorityGet */
1434/*-----------------------------------------------------------*/
1435
1436#if ( INCLUDE_uxTaskPriorityGet == 1 )
1437
1438 UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask )
1439 {
1440 TCB_t *pxTCB;
1441 UBaseType_t uxReturn, uxSavedInterruptState;
1442
1443 /* RTOS ports that support interrupt nesting have the concept of a
1444 maximum system call (or maximum API call) interrupt priority.
1445 Interrupts that are above the maximum system call priority are keep
1446 permanently enabled, even when the RTOS kernel is in a critical section,
1447 but cannot make any calls to FreeRTOS API functions. If configASSERT()
1448 is defined in FreeRTOSConfig.h then
1449 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
1450 failure if a FreeRTOS API function is called from an interrupt that has
1451 been assigned a priority above the configured maximum system call
1452 priority. Only FreeRTOS functions that end in FromISR can be called
1453 from interrupts that have been assigned a priority at or (logically)
1454 below the maximum system call interrupt priority. FreeRTOS maintains a
1455 separate interrupt safe API to ensure interrupt entry is as fast and as
1456 simple as possible. More information (albeit Cortex-M specific) is
1457 provided on the following link:
1458 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
1459 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
1460
1461 uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR();
1462 {
1463 /* If null is passed in here then it is the priority of the calling
1464 task that is being queried. */
1465 pxTCB = prvGetTCBFromHandle( xTask );
1466 uxReturn = pxTCB->uxPriority;
1467 }
1468 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptState );
1469
1470 return uxReturn;
1471 }
1472
1473#endif /* INCLUDE_uxTaskPriorityGet */
1474/*-----------------------------------------------------------*/
1475
1476#if ( INCLUDE_vTaskPrioritySet == 1 )
1477
1478 void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
1479 {
1480 TCB_t *pxTCB;
1481 UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;
1482 BaseType_t xYieldRequired = pdFALSE;
1483
1484 configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
1485
1486 /* Ensure the new priority is valid. */
1487 if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
1488 {
1489 uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
1490 }
1491 else
1492 {
1493 mtCOVERAGE_TEST_MARKER();
1494 }
1495
1496 taskENTER_CRITICAL();
1497 {
1498 /* If null is passed in here then it is the priority of the calling
1499 task that is being changed. */
1500 pxTCB = prvGetTCBFromHandle( xTask );
1501
1502 traceTASK_PRIORITY_SET( pxTCB, uxNewPriority );
1503
1504 #if ( configUSE_MUTEXES == 1 )
1505 {
1506 uxCurrentBasePriority = pxTCB->uxBasePriority;
1507 }
1508 #else
1509 {
1510 uxCurrentBasePriority = pxTCB->uxPriority;
1511 }
1512 #endif
1513
1514 if( uxCurrentBasePriority != uxNewPriority )
1515 {
1516 /* The priority change may have readied a task of higher
1517 priority than the calling task. */
1518 if( uxNewPriority > uxCurrentBasePriority )
1519 {
1520 if( pxTCB != pxCurrentTCB )
1521 {
1522 /* The priority of a task other than the currently
1523 running task is being raised. Is the priority being
1524 raised above that of the running task? */
1525 if( uxNewPriority >= pxCurrentTCB->uxPriority )
1526 {
1527 xYieldRequired = pdTRUE;
1528 }
1529 else
1530 {
1531 mtCOVERAGE_TEST_MARKER();
1532 }
1533 }
1534 else
1535 {
1536 /* The priority of the running task is being raised,
1537 but the running task must already be the highest
1538 priority task able to run so no yield is required. */
1539 }
1540 }
1541 else if( pxTCB == pxCurrentTCB )
1542 {
1543 /* Setting the priority of the running task down means
1544 there may now be another task of higher priority that
1545 is ready to execute. */
1546 xYieldRequired = pdTRUE;
1547 }
1548 else
1549 {
1550 /* Setting the priority of any other task down does not
1551 require a yield as the running task must be above the
1552 new priority of the task being modified. */
1553 }
1554
1555 /* Remember the ready list the task might be referenced from
1556 before its uxPriority member is changed so the
1557 taskRESET_READY_PRIORITY() macro can function correctly. */
1558 uxPriorityUsedOnEntry = pxTCB->uxPriority;
1559
1560 #if ( configUSE_MUTEXES == 1 )
1561 {
1562 /* Only change the priority being used if the task is not
1563 currently using an inherited priority. */
1564 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
1565 {
1566 pxTCB->uxPriority = uxNewPriority;
1567 }
1568 else
1569 {
1570 mtCOVERAGE_TEST_MARKER();
1571 }
1572
1573 /* The base priority gets set whatever. */
1574 pxTCB->uxBasePriority = uxNewPriority;
1575 }
1576 #else
1577 {
1578 pxTCB->uxPriority = uxNewPriority;
1579 }
1580 #endif
1581
1582 /* Only reset the event list item value if the value is not
1583 being used for anything else. */
1584 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
1585 {
1586 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. */
1587 }
1588 else
1589 {
1590 mtCOVERAGE_TEST_MARKER();
1591 }
1592
1593 /* If the task is in the blocked or suspended list we need do
1594 nothing more than change it's priority variable. However, if
1595 the task is in a ready list it needs to be removed and placed
1596 in the list appropriate to its new priority. */
1597 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
1598 {
1599 /* The task is currently in its ready list - remove before adding
1600 it to it's new ready list. As we are in a critical section we
1601 can do this even if the scheduler is suspended. */
1602 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
1603 {
1604 /* It is known that the task is in its ready list so
1605 there is no need to check again and the port level
1606 reset macro can be called directly. */
1607 portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );
1608 }
1609 else
1610 {
1611 mtCOVERAGE_TEST_MARKER();
1612 }
1613 prvAddTaskToReadyList( pxTCB );
1614 }
1615 else
1616 {
1617 mtCOVERAGE_TEST_MARKER();
1618 }
1619
1620 if( xYieldRequired != pdFALSE )
1621 {
1622 taskYIELD_IF_USING_PREEMPTION();
1623 }
1624 else
1625 {
1626 mtCOVERAGE_TEST_MARKER();
1627 }
1628
1629 /* Remove compiler warning about unused variables when the port
1630 optimised task selection is not being used. */
1631 ( void ) uxPriorityUsedOnEntry;
1632 }
1633 }
1634 taskEXIT_CRITICAL();
1635 }
1636
1637#endif /* INCLUDE_vTaskPrioritySet */
1638/*-----------------------------------------------------------*/
1639
1640#if ( INCLUDE_vTaskSuspend == 1 )
1641
1642 void vTaskSuspend( TaskHandle_t xTaskToSuspend )
1643 {
1644 TCB_t *pxTCB;
1645
1646 taskENTER_CRITICAL();
1647 {
1648 /* If null is passed in here then it is the running task that is
1649 being suspended. */
1650 pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
1651
1652 traceTASK_SUSPEND( pxTCB );
1653
1654 /* Remove task from the ready/delayed list and place in the
1655 suspended list. */
1656 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
1657 {
1658 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
1659 }
1660 else
1661 {
1662 mtCOVERAGE_TEST_MARKER();
1663 }
1664
1665 /* Is the task waiting on an event also? */
1666 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
1667 {
1668 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
1669 }
1670 else
1671 {
1672 mtCOVERAGE_TEST_MARKER();
1673 }
1674
1675 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
1676 }
1677 taskEXIT_CRITICAL();
1678
1679 if( xSchedulerRunning != pdFALSE )
1680 {
1681 /* Reset the next expected unblock time in case it referred to the
1682 task that is now in the Suspended state. */
1683 taskENTER_CRITICAL();
1684 {
1685 prvResetNextTaskUnblockTime();
1686 }
1687 taskEXIT_CRITICAL();
1688 }
1689 else
1690 {
1691 mtCOVERAGE_TEST_MARKER();
1692 }
1693
1694 if( pxTCB == pxCurrentTCB )
1695 {
1696 if( xSchedulerRunning != pdFALSE )
1697 {
1698 /* The current task has just been suspended. */
1699 configASSERT( uxSchedulerSuspended == 0 );
1700 portYIELD_WITHIN_API();
1701 }
1702 else
1703 {
1704 /* The scheduler is not running, but the task that was pointed
1705 to by pxCurrentTCB has just been suspended and pxCurrentTCB
1706 must be adjusted to point to a different task. */
1707 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
1708 {
1709 /* No other tasks are ready, so set pxCurrentTCB back to
1710 NULL so when the next task is created pxCurrentTCB will
1711 be set to point to it no matter what its relative priority
1712 is. */
1713 pxCurrentTCB = NULL;
1714 }
1715 else
1716 {
1717 vTaskSwitchContext();
1718 }
1719 }
1720 }
1721 else
1722 {
1723 mtCOVERAGE_TEST_MARKER();
1724 }
1725 }
1726
1727#endif /* INCLUDE_vTaskSuspend */
1728/*-----------------------------------------------------------*/
1729
1730#if ( INCLUDE_vTaskSuspend == 1 )
1731
1732 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask )
1733 {
1734 BaseType_t xReturn = pdFALSE;
1735 const TCB_t * const pxTCB = ( TCB_t * ) xTask;
1736
1737 /* Accesses xPendingReadyList so must be called from a critical
1738 section. */
1739
1740 /* It does not make sense to check if the calling task is suspended. */
1741 configASSERT( xTask );
1742
1743 /* Is the task being resumed actually in the suspended list? */
1744 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ) != pdFALSE )
1745 {
1746 /* Has the task already been resumed from within an ISR? */
1747 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE )
1748 {
1749 /* Is it in the suspended list because it is in the Suspended
1750 state, or because is is blocked with no timeout? */
1751 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE )
1752 {
1753 xReturn = pdTRUE;
1754 }
1755 else
1756 {
1757 mtCOVERAGE_TEST_MARKER();
1758 }
1759 }
1760 else
1761 {
1762 mtCOVERAGE_TEST_MARKER();
1763 }
1764 }
1765 else
1766 {
1767 mtCOVERAGE_TEST_MARKER();
1768 }
1769
1770 return xReturn;
1771 } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */
1772
1773#endif /* INCLUDE_vTaskSuspend */
1774/*-----------------------------------------------------------*/
1775
1776#if ( INCLUDE_vTaskSuspend == 1 )
1777
1778 void vTaskResume( TaskHandle_t xTaskToResume )
1779 {
1780 TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
1781
1782 /* It does not make sense to resume the calling task. */
1783 configASSERT( xTaskToResume );
1784
1785 /* The parameter cannot be NULL as it is impossible to resume the
1786 currently executing task. */
1787 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
1788 {
1789 taskENTER_CRITICAL();
1790 {
1791 if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
1792 {
1793 traceTASK_RESUME( pxTCB );
1794
1795 /* As we are in a critical section we can access the ready
1796 lists even if the scheduler is suspended. */
1797 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
1798 prvAddTaskToReadyList( pxTCB );
1799
1800 /* We may have just resumed a higher priority task. */
1801 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1802 {
1803 /* This yield may not cause the task just resumed to run,
1804 but will leave the lists in the correct state for the
1805 next yield. */
1806 taskYIELD_IF_USING_PREEMPTION();
1807 }
1808 else
1809 {
1810 mtCOVERAGE_TEST_MARKER();
1811 }
1812 }
1813 else
1814 {
1815 mtCOVERAGE_TEST_MARKER();
1816 }
1817 }
1818 taskEXIT_CRITICAL();
1819 }
1820 else
1821 {
1822 mtCOVERAGE_TEST_MARKER();
1823 }
1824 }
1825
1826#endif /* INCLUDE_vTaskSuspend */
1827
1828/*-----------------------------------------------------------*/
1829
1830#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
1831
1832 BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )
1833 {
1834 BaseType_t xYieldRequired = pdFALSE;
1835 TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
1836 UBaseType_t uxSavedInterruptStatus;
1837
1838 configASSERT( xTaskToResume );
1839
1840 /* RTOS ports that support interrupt nesting have the concept of a
1841 maximum system call (or maximum API call) interrupt priority.
1842 Interrupts that are above the maximum system call priority are keep
1843 permanently enabled, even when the RTOS kernel is in a critical section,
1844 but cannot make any calls to FreeRTOS API functions. If configASSERT()
1845 is defined in FreeRTOSConfig.h then
1846 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
1847 failure if a FreeRTOS API function is called from an interrupt that has
1848 been assigned a priority above the configured maximum system call
1849 priority. Only FreeRTOS functions that end in FromISR can be called
1850 from interrupts that have been assigned a priority at or (logically)
1851 below the maximum system call interrupt priority. FreeRTOS maintains a
1852 separate interrupt safe API to ensure interrupt entry is as fast and as
1853 simple as possible. More information (albeit Cortex-M specific) is
1854 provided on the following link:
1855 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
1856 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
1857
1858 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
1859 {
1860 if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
1861 {
1862 traceTASK_RESUME_FROM_ISR( pxTCB );
1863
1864 /* Check the ready lists can be accessed. */
1865 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
1866 {
1867 /* Ready lists can be accessed so move the task from the
1868 suspended list to the ready list directly. */
1869 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
1870 {
1871 xYieldRequired = pdTRUE;
1872 }
1873 else
1874 {
1875 mtCOVERAGE_TEST_MARKER();
1876 }
1877
1878 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
1879 prvAddTaskToReadyList( pxTCB );
1880 }
1881 else
1882 {
1883 /* The delayed or ready lists cannot be accessed so the task
1884 is held in the pending ready list until the scheduler is
1885 unsuspended. */
1886 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
1887 }
1888 }
1889 else
1890 {
1891 mtCOVERAGE_TEST_MARKER();
1892 }
1893 }
1894 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
1895
1896 return xYieldRequired;
1897 }
1898
1899#endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */
1900/*-----------------------------------------------------------*/
1901
1902#if ( configUSE_RM_PERIODIC == 1)
1903 int priorityCompare(const periodic_task_info* a, const periodic_task_info* b)
1904 {
1905 if(a->tick_period > b->tick_period)
1906 return -1;
1907 else if(a->tick_period == b->tick_period)
1908 return 0;
1909 else
1910 return 1;
1911 }
1912
1913 void setExtraParamTCB(TCB_t* task, periodic_task_info* new_task_info)
1914 {
1915 task->tick_period = new_task_info->tick_period;
1916// task->time_period = 0;
1917 task->tick_length = new_task_info->tick_length;
1918 task->task_runTime = 0;
1919 task->task_function = new_task_info->task_function;
1920 task->task_param = new_task_info->task_param;
1921 }
1922
1923 unsigned char checkCollectionOfTasks()
1924 {
1925 for(unsigned char i = 0; i < task_info_counter; i++)
1926 {
1927 periodic_task_info* task = &list_of_task_info[i];
1928
1929 if(task->tick_length > task->tick_period)
1930 return 0;
1931 }
1932 return 1;
1933 }
1934#endif
1935
1936void vTaskStartScheduler( void )
1937{
1938BaseType_t xReturn;
1939
1940 /* Add the idle task at the lowest priority. */
1941 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
1942 {
1943 StaticTask_t *pxIdleTaskTCBBuffer = NULL;
1944 StackType_t *pxIdleTaskStackBuffer = NULL;
1945 uint32_t ulIdleTaskStackSize;
1946
1947 /* The Idle task is created using user provided RAM - obtain the
1948 address of the RAM then create the idle task. */
1949 vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
1950 xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
1951 "IDLE",
1952 ulIdleTaskStackSize,
1953 ( void * ) NULL,
1954 ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
1955 pxIdleTaskStackBuffer,
1956 pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
1957
1958 if( xIdleTaskHandle != NULL )
1959 {
1960 xReturn = pdPASS;
1961 }
1962 else
1963 {
1964 xReturn = pdFAIL;
1965 }
1966 }
1967 #else
1968 {
1969 /* The Idle task is being created using dynamically allocated RAM. */
1970 xReturn = xTaskCreate( prvIdleTask,
1971 "IDLE", tskIDLE_STACK_SIZE,
1972 ( void * ) NULL,
1973 ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
1974 &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
1975 #if( configUSE_RM_PERIODIC == 1 )
1976 {
1977 if(checkCollectionOfTasks())
1978 {
1979 qsort(list_of_task_info, task_info_counter, sizeof(periodic_task_info), priorityCompare);
1980
1981 for(unsigned char i = 0; i < task_info_counter; i++)
1982 {
1983 TaskHandle_t pxCreatedPeriodicTask;
1984
1985 xReturn = xTaskCreate(list_of_task_info[i].task_function,"ATask", list_of_task_info[i].stack_depth, list_of_task_info[i].task_param, i + 1, &pxCreatedPeriodicTask);
1986
1987 TCB_t * pxNewTCB = prvGetTCBFromHandle(pxCreatedPeriodicTask);
1988
1989 setExtraParamTCB(pxNewTCB, &list_of_task_info[i]);
1990
1991 pxCurrentTCB = pxNewTCB;
1992 }
1993 }
1994 }
1995 #endif
1996 }
1997 #endif /* configSUPPORT_STATIC_ALLOCATION */
1998
1999
2000 #if ( configUSE_TIMERS == 1 )
2001 {
2002 if( xReturn == pdPASS )
2003 {
2004 xReturn = xTimerCreateTimerTask();
2005 }
2006 else
2007 {
2008 mtCOVERAGE_TEST_MARKER();
2009 }
2010 }
2011 #endif /* configUSE_TIMERS */
2012
2013 if( xReturn == pdPASS )
2014 {
2015 /* Interrupts are turned off here, to ensure a tick does not occur
2016 before or during the call to xPortStartScheduler(). The stacks of
2017 the created tasks contain a status word with interrupts switched on
2018 so interrupts will automatically get re-enabled when the first task
2019 starts to run. */
2020 portDISABLE_INTERRUPTS();
2021
2022 #if ( configUSE_NEWLIB_REENTRANT == 1 )
2023 {
2024 /* Switch Newlib's _impure_ptr variable to point to the _reent
2025 structure specific to the task that will run first. */
2026 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
2027 }
2028 #endif /* configUSE_NEWLIB_REENTRANT */
2029
2030 xNextTaskUnblockTime = portMAX_DELAY;
2031 xSchedulerRunning = pdTRUE;
2032 xTickCount = ( TickType_t ) 0U;
2033
2034 /* If configGENERATE_RUN_TIME_STATS is defined then the following
2035 macro must be defined to configure the timer/counter used to generate
2036 the run time counter time base. */
2037 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
2038
2039 /* Setting up the timer tick is hardware specific and thus in the
2040 portable interface. */
2041 if( xPortStartScheduler() != pdFALSE )
2042 {
2043 /* Should not reach here as if the scheduler is running the
2044 function will not return. */
2045 }
2046 else
2047 {
2048 /* Should only reach here if a task calls xTaskEndScheduler(). */
2049 }
2050 }
2051 else
2052 {
2053 /* This line will only be reached if the kernel could not be started,
2054 because there was not enough FreeRTOS heap to create the idle task
2055 or the timer task. */
2056 configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
2057 }
2058
2059 /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,
2060 meaning xIdleTaskHandle is not used anywhere else. */
2061 ( void ) xIdleTaskHandle;
2062}
2063/*-----------------------------------------------------------*/
2064
2065void vTaskEndScheduler( void )
2066{
2067 /* Stop the scheduler interrupts and call the portable scheduler end
2068 routine so the original ISRs can be restored if necessary. The port
2069 layer must ensure interrupts enable bit is left in the correct state. */
2070 portDISABLE_INTERRUPTS();
2071 xSchedulerRunning = pdFALSE;
2072 vPortEndScheduler();
2073 portENABLE_INTERRUPTS(); /* As per comment, enable interrupts. */
2074}
2075/*----------------------------------------------------------*/
2076
2077void vTaskSuspendAll( void )
2078{
2079 /* A critical section is not required as the variable is of type
2080 BaseType_t. Please read Richard Barry's reply in the following link to a
2081 post in the FreeRTOS support forum before reporting this as a bug! -
2082 http://goo.gl/wu4acr */
2083 ++uxSchedulerSuspended;
2084}
2085/*----------------------------------------------------------*/
2086
2087#if ( configUSE_TICKLESS_IDLE != 0 )
2088
2089 static TickType_t prvGetExpectedIdleTime( void )
2090 {
2091 TickType_t xReturn;
2092 UBaseType_t uxHigherPriorityReadyTasks = pdFALSE;
2093
2094 /* uxHigherPriorityReadyTasks takes care of the case where
2095 configUSE_PREEMPTION is 0, so there may be tasks above the idle priority
2096 task that are in the Ready state, even though the idle task is
2097 running. */
2098 #if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
2099 {
2100 if( uxTopReadyPriority > tskIDLE_PRIORITY )
2101 {
2102 uxHigherPriorityReadyTasks = pdTRUE;
2103 }
2104 }
2105 #else
2106 {
2107 const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01;
2108
2109 /* When port optimised task selection is used the uxTopReadyPriority
2110 variable is used as a bit map. If bits other than the least
2111 significant bit are set then there are tasks that have a priority
2112 above the idle priority that are in the Ready state. This takes
2113 care of the case where the co-operative scheduler is in use. */
2114 if( uxTopReadyPriority > uxLeastSignificantBit )
2115 {
2116 uxHigherPriorityReadyTasks = pdTRUE;
2117 }
2118 }
2119 #endif
2120
2121 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )
2122 {
2123 xReturn = 0;
2124 }
2125 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )
2126 {
2127 /* There are other idle priority tasks in the ready state. If
2128 time slicing is used then the very next tick interrupt must be
2129 processed. */
2130 xReturn = 0;
2131 }
2132 else if( uxHigherPriorityReadyTasks != pdFALSE )
2133 {
2134 /* There are tasks in the Ready state that have a priority above the
2135 idle priority. This path can only be reached if
2136 configUSE_PREEMPTION is 0. */
2137 xReturn = 0;
2138 }
2139 else
2140 {
2141 xReturn = xNextTaskUnblockTime - xTickCount;
2142 }
2143
2144 return xReturn;
2145 }
2146
2147#endif /* configUSE_TICKLESS_IDLE */
2148/*----------------------------------------------------------*/
2149
2150BaseType_t xTaskResumeAll( void )
2151{
2152TCB_t *pxTCB = NULL;
2153BaseType_t xAlreadyYielded = pdFALSE;
2154
2155 /* If uxSchedulerSuspended is zero then this function does not match a
2156 previous call to vTaskSuspendAll(). */
2157 configASSERT( uxSchedulerSuspended );
2158
2159 /* It is possible that an ISR caused a task to be removed from an event
2160 list while the scheduler was suspended. If this was the case then the
2161 removed task will have been added to the xPendingReadyList. Once the
2162 scheduler has been resumed it is safe to move all the pending ready
2163 tasks from this list into their appropriate ready list. */
2164 taskENTER_CRITICAL();
2165 {
2166 --uxSchedulerSuspended;
2167
2168 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
2169 {
2170 if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
2171 {
2172 /* Move any readied tasks from the pending list into the
2173 appropriate ready list. */
2174 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
2175 {
2176 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
2177 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
2178 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
2179 prvAddTaskToReadyList( pxTCB );
2180
2181 /* If the moved task has a priority higher than the current
2182 task then a yield must be performed. */
2183 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
2184 {
2185 xYieldPending = pdTRUE;
2186 }
2187 else
2188 {
2189 mtCOVERAGE_TEST_MARKER();
2190 }
2191 }
2192
2193 if( pxTCB != NULL )
2194 {
2195 /* A task was unblocked while the scheduler was suspended,
2196 which may have prevented the next unblock time from being
2197 re-calculated, in which case re-calculate it now. Mainly
2198 important for low power tickless implementations, where
2199 this can prevent an unnecessary exit from low power
2200 state. */
2201 prvResetNextTaskUnblockTime();
2202 }
2203
2204 /* If any ticks occurred while the scheduler was suspended then
2205 they should be processed now. This ensures the tick count does
2206 not slip, and that any delayed tasks are resumed at the correct
2207 time. */
2208 {
2209 UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */
2210
2211 if( uxPendedCounts > ( UBaseType_t ) 0U )
2212 {
2213 do
2214 {
2215 if( xTaskIncrementTick() != pdFALSE )
2216 {
2217 xYieldPending = pdTRUE;
2218 }
2219 else
2220 {
2221 mtCOVERAGE_TEST_MARKER();
2222 }
2223 --uxPendedCounts;
2224 } while( uxPendedCounts > ( UBaseType_t ) 0U );
2225
2226 uxPendedTicks = 0;
2227 }
2228 else
2229 {
2230 mtCOVERAGE_TEST_MARKER();
2231 }
2232 }
2233
2234 if( xYieldPending != pdFALSE )
2235 {
2236 #if( configUSE_PREEMPTION != 0 )
2237 {
2238 xAlreadyYielded = pdTRUE;
2239 }
2240 #endif
2241 taskYIELD_IF_USING_PREEMPTION();
2242 }
2243 else
2244 {
2245 mtCOVERAGE_TEST_MARKER();
2246 }
2247 }
2248 }
2249 else
2250 {
2251 mtCOVERAGE_TEST_MARKER();
2252 }
2253 }
2254 taskEXIT_CRITICAL();
2255
2256 return xAlreadyYielded;
2257}
2258/*-----------------------------------------------------------*/
2259
2260TickType_t xTaskGetTickCount( void )
2261{
2262TickType_t xTicks;
2263
2264 /* Critical section required if running on a 16 bit processor. */
2265 portTICK_TYPE_ENTER_CRITICAL();
2266 {
2267 xTicks = xTickCount;
2268 }
2269 portTICK_TYPE_EXIT_CRITICAL();
2270
2271 return xTicks;
2272}
2273/*-----------------------------------------------------------*/
2274
2275TickType_t xTaskGetTickCountFromISR( void )
2276{
2277TickType_t xReturn;
2278UBaseType_t uxSavedInterruptStatus;
2279
2280 /* RTOS ports that support interrupt nesting have the concept of a maximum
2281 system call (or maximum API call) interrupt priority. Interrupts that are
2282 above the maximum system call priority are kept permanently enabled, even
2283 when the RTOS kernel is in a critical section, but cannot make any calls to
2284 FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h
2285 then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
2286 failure if a FreeRTOS API function is called from an interrupt that has been
2287 assigned a priority above the configured maximum system call priority.
2288 Only FreeRTOS functions that end in FromISR can be called from interrupts
2289 that have been assigned a priority at or (logically) below the maximum
2290 system call interrupt priority. FreeRTOS maintains a separate interrupt
2291 safe API to ensure interrupt entry is as fast and as simple as possible.
2292 More information (albeit Cortex-M specific) is provided on the following
2293 link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */
2294 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
2295
2296 uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR();
2297 {
2298 xReturn = xTickCount;
2299 }
2300 portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
2301
2302 return xReturn;
2303}
2304/*-----------------------------------------------------------*/
2305
2306UBaseType_t uxTaskGetNumberOfTasks( void )
2307{
2308 /* A critical section is not required because the variables are of type
2309 BaseType_t. */
2310 return uxCurrentNumberOfTasks;
2311}
2312/*-----------------------------------------------------------*/
2313
2314char *pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
2315{
2316TCB_t *pxTCB;
2317
2318 /* If null is passed in here then the name of the calling task is being
2319 queried. */
2320 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
2321 configASSERT( pxTCB );
2322 return &( pxTCB->pcTaskName[ 0 ] );
2323}
2324/*-----------------------------------------------------------*/
2325
2326#if ( INCLUDE_xTaskGetHandle == 1 )
2327
2328 static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] )
2329 {
2330 TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL;
2331 UBaseType_t x;
2332 char cNextChar;
2333
2334 /* This function is called with the scheduler suspended. */
2335
2336 if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
2337 {
2338 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
2339
2340 do
2341 {
2342 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
2343
2344 /* Check each character in the name looking for a match or
2345 mismatch. */
2346 for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
2347 {
2348 cNextChar = pxNextTCB->pcTaskName[ x ];
2349
2350 if( cNextChar != pcNameToQuery[ x ] )
2351 {
2352 /* Characters didn't match. */
2353 break;
2354 }
2355 else if( cNextChar == 0x00 )
2356 {
2357 /* Both strings terminated, a match must have been
2358 found. */
2359 pxReturn = pxNextTCB;
2360 break;
2361 }
2362 else
2363 {
2364 mtCOVERAGE_TEST_MARKER();
2365 }
2366 }
2367
2368 if( pxReturn != NULL )
2369 {
2370 /* The handle has been found. */
2371 break;
2372 }
2373
2374 } while( pxNextTCB != pxFirstTCB );
2375 }
2376 else
2377 {
2378 mtCOVERAGE_TEST_MARKER();
2379 }
2380
2381 return pxReturn;
2382 }
2383
2384#endif /* INCLUDE_xTaskGetHandle */
2385/*-----------------------------------------------------------*/
2386
2387#if ( INCLUDE_xTaskGetHandle == 1 )
2388
2389 TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
2390 {
2391 UBaseType_t uxQueue = configMAX_PRIORITIES;
2392 TCB_t* pxTCB;
2393
2394 /* Task names will be truncated to configMAX_TASK_NAME_LEN - 1 bytes. */
2395 configASSERT( strlen( pcNameToQuery ) < configMAX_TASK_NAME_LEN );
2396
2397 vTaskSuspendAll();
2398 {
2399 /* Search the ready lists. */
2400 do
2401 {
2402 uxQueue--;
2403 pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) &( pxReadyTasksLists[ uxQueue ] ), pcNameToQuery );
2404
2405 if( pxTCB != NULL )
2406 {
2407 /* Found the handle. */
2408 break;
2409 }
2410
2411 } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
2412
2413 /* Search the delayed lists. */
2414 if( pxTCB == NULL )
2415 {
2416 pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxDelayedTaskList, pcNameToQuery );
2417 }
2418
2419 if( pxTCB == NULL )
2420 {
2421 pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxOverflowDelayedTaskList, pcNameToQuery );
2422 }
2423
2424 #if ( INCLUDE_vTaskSuspend == 1 )
2425 {
2426 if( pxTCB == NULL )
2427 {
2428 /* Search the suspended list. */
2429 pxTCB = prvSearchForNameWithinSingleList( &xSuspendedTaskList, pcNameToQuery );
2430 }
2431 }
2432 #endif
2433
2434 #if( INCLUDE_vTaskDelete == 1 )
2435 {
2436 if( pxTCB == NULL )
2437 {
2438 /* Search the deleted list. */
2439 pxTCB = prvSearchForNameWithinSingleList( &xTasksWaitingTermination, pcNameToQuery );
2440 }
2441 }
2442 #endif
2443 }
2444 ( void ) xTaskResumeAll();
2445
2446 return ( TaskHandle_t ) pxTCB;
2447 }
2448
2449#endif /* INCLUDE_xTaskGetHandle */
2450/*-----------------------------------------------------------*/
2451
2452#if ( configUSE_TRACE_FACILITY == 1 )
2453
2454 UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime )
2455 {
2456 UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;
2457
2458 vTaskSuspendAll();
2459 {
2460 /* Is there a space in the array for each task in the system? */
2461 if( uxArraySize >= uxCurrentNumberOfTasks )
2462 {
2463 /* Fill in an TaskStatus_t structure with information on each
2464 task in the Ready state. */
2465 do
2466 {
2467 uxQueue--;
2468 uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady );
2469
2470 } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
2471
2472 /* Fill in an TaskStatus_t structure with information on each
2473 task in the Blocked state. */
2474 uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked );
2475 uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked );
2476
2477 #if( INCLUDE_vTaskDelete == 1 )
2478 {
2479 /* Fill in an TaskStatus_t structure with information on
2480 each task that has been deleted but not yet cleaned up. */
2481 uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted );
2482 }
2483 #endif
2484
2485 #if ( INCLUDE_vTaskSuspend == 1 )
2486 {
2487 /* Fill in an TaskStatus_t structure with information on
2488 each task in the Suspended state. */
2489 uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended );
2490 }
2491 #endif
2492
2493 #if ( configGENERATE_RUN_TIME_STATS == 1)
2494 {
2495 if( pulTotalRunTime != NULL )
2496 {
2497 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
2498 portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) );
2499 #else
2500 *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
2501 #endif
2502 }
2503 }
2504 #else
2505 {
2506 if( pulTotalRunTime != NULL )
2507 {
2508 *pulTotalRunTime = 0;
2509 }
2510 }
2511 #endif
2512 }
2513 else
2514 {
2515 mtCOVERAGE_TEST_MARKER();
2516 }
2517 }
2518 ( void ) xTaskResumeAll();
2519
2520 return uxTask;
2521 }
2522
2523#endif /* configUSE_TRACE_FACILITY */
2524/*----------------------------------------------------------*/
2525
2526#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
2527
2528 TaskHandle_t xTaskGetIdleTaskHandle( void )
2529 {
2530 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been
2531 started, then xIdleTaskHandle will be NULL. */
2532 configASSERT( ( xIdleTaskHandle != NULL ) );
2533 return xIdleTaskHandle;
2534 }
2535
2536#endif /* INCLUDE_xTaskGetIdleTaskHandle */
2537/*----------------------------------------------------------*/
2538
2539/* This conditional compilation should use inequality to 0, not equality to 1.
2540This is to ensure vTaskStepTick() is available when user defined low power mode
2541implementations require configUSE_TICKLESS_IDLE to be set to a value other than
25421. */
2543#if ( configUSE_TICKLESS_IDLE != 0 )
2544
2545 void vTaskStepTick( const TickType_t xTicksToJump )
2546 {
2547 /* Correct the tick count value after a period during which the tick
2548 was suppressed. Note this does *not* call the tick hook function for
2549 each stepped tick. */
2550 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );
2551 xTickCount += xTicksToJump;
2552 traceINCREASE_TICK_COUNT( xTicksToJump );
2553 }
2554
2555#endif /* configUSE_TICKLESS_IDLE */
2556/*----------------------------------------------------------*/
2557
2558#if ( INCLUDE_xTaskAbortDelay == 1 )
2559
2560 BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
2561 {
2562 TCB_t *pxTCB = ( TCB_t * ) xTask;
2563 BaseType_t xReturn = pdFALSE;
2564
2565 configASSERT( pxTCB );
2566
2567 vTaskSuspendAll();
2568 {
2569 /* A task can only be prematurely removed from the Blocked state if
2570 it is actually in the Blocked state. */
2571 if( eTaskGetState( xTask ) == eBlocked )
2572 {
2573 /* Remove the reference to the task from the blocked list. An
2574 interrupt won't touch the xStateListItem because the
2575 scheduler is suspended. */
2576 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
2577
2578 /* Is the task waiting on an event also? If so remove it from
2579 the event list too. Interrupts can touch the event list item,
2580 even though the scheduler is suspended, so a critical section
2581 is used. */
2582 taskENTER_CRITICAL();
2583 {
2584 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
2585 {
2586 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
2587 pxTCB->ucDelayAborted = pdTRUE;
2588 }
2589 else
2590 {
2591 mtCOVERAGE_TEST_MARKER();
2592 }
2593 }
2594 taskEXIT_CRITICAL();
2595
2596 /* Place the unblocked task into the appropriate ready list. */
2597 prvAddTaskToReadyList( pxTCB );
2598
2599 /* A task being unblocked cannot cause an immediate context
2600 switch if preemption is turned off. */
2601 #if ( configUSE_PREEMPTION == 1 )
2602 {
2603 /* Preemption is on, but a context switch should only be
2604 performed if the unblocked task has a priority that is
2605 equal to or higher than the currently executing task. */
2606 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
2607 {
2608 /* Pend the yield to be performed when the scheduler
2609 is unsuspended. */
2610 xYieldPending = pdTRUE;
2611 }
2612 else
2613 {
2614 mtCOVERAGE_TEST_MARKER();
2615 }
2616 }
2617 #endif /* configUSE_PREEMPTION */
2618 }
2619 else
2620 {
2621 mtCOVERAGE_TEST_MARKER();
2622 }
2623 }
2624 xTaskResumeAll();
2625
2626 return xReturn;
2627 }
2628
2629#endif /* INCLUDE_xTaskAbortDelay */
2630/*----------------------------------------------------------*/
2631
2632BaseType_t xTaskIncrementTick( void )
2633{
2634TCB_t * pxTCB;
2635TickType_t xItemValue;
2636BaseType_t xSwitchRequired = pdFALSE;
2637
2638 /* Called by the portable layer each time a tick interrupt occurs.
2639 Increments the tick then checks to see if the new tick value will cause any
2640 tasks to be unblocked. */
2641 traceTASK_INCREMENT_TICK( xTickCount );
2642
2643#if ( configUSE_RM_PERIODIC == 1)
2644 pxCurrentTCB->task_runTime++;
2645
2646 xSwitchRequired = pdTRUE;
2647#endif
2648 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
2649 {
2650 /* Minor optimisation. The tick count cannot change in this
2651 block. */
2652 const TickType_t xConstTickCount = xTickCount + 1;
2653
2654 /* Increment the RTOS tick, switching the delayed and overflowed
2655 delayed lists if it wraps to 0. */
2656 xTickCount = xConstTickCount;
2657
2658 if( xConstTickCount == ( TickType_t ) 0U )
2659 {
2660 taskSWITCH_DELAYED_LISTS();
2661 }
2662 else
2663 {
2664 mtCOVERAGE_TEST_MARKER();
2665 }
2666
2667 /* See if this tick has made a timeout expire. Tasks are stored in
2668 the queue in the order of their wake time - meaning once one task
2669 has been found whose block time has not expired there is no need to
2670 look any further down the list. */
2671 if( xConstTickCount >= xNextTaskUnblockTime )
2672 {
2673 for( ;; )
2674 {
2675 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
2676 {
2677 /* The delayed list is empty. Set xNextTaskUnblockTime
2678 to the maximum possible value so it is extremely
2679 unlikely that the
2680 if( xTickCount >= xNextTaskUnblockTime ) test will pass
2681 next time through. */
2682 xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
2683 break;
2684 }
2685 else
2686 {
2687 /* The delayed list is not empty, get the value of the
2688 item at the head of the delayed list. This is the time
2689 at which the task at the head of the delayed list must
2690 be removed from the Blocked state. */
2691 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
2692 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
2693
2694 if( xConstTickCount < xItemValue )
2695 {
2696 /* It is not time to unblock this item yet, but the
2697 item value is the time at which the task at the head
2698 of the blocked list must be removed from the Blocked
2699 state - so record the item value in
2700 xNextTaskUnblockTime. */
2701 xNextTaskUnblockTime = xItemValue;
2702 break;
2703 }
2704 else
2705 {
2706 mtCOVERAGE_TEST_MARKER();
2707 }
2708
2709 /* It is time to remove the item from the Blocked state. */
2710 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
2711
2712 /* Is the task waiting on an event also? If so remove
2713 it from the event list. */
2714 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
2715 {
2716 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
2717 }
2718 else
2719 {
2720 mtCOVERAGE_TEST_MARKER();
2721 }
2722
2723 /* Place the unblocked task into the appropriate ready
2724 list. */
2725 prvAddTaskToReadyList( pxTCB );
2726
2727 /* A task being unblocked cannot cause an immediate
2728 context switch if preemption is turned off. */
2729 #if ( configUSE_PREEMPTION == 1 )
2730 {
2731 /* Preemption is on, but a context switch should
2732 only be performed if the unblocked task has a
2733 priority that is equal to or higher than the
2734 currently executing task. */
2735 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
2736 {
2737 xSwitchRequired = pdTRUE;
2738 }
2739 else
2740 {
2741 mtCOVERAGE_TEST_MARKER();
2742 }
2743 }
2744 #endif /* configUSE_PREEMPTION */
2745 }
2746 }
2747 }
2748
2749 /* Tasks of equal priority to the currently running task will share
2750 processing time (time slice) if preemption is on, and the application
2751 writer has not explicitly turned time slicing off. */
2752 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
2753 {
2754 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
2755 {
2756 xSwitchRequired = pdTRUE;
2757 }
2758 else
2759 {
2760 mtCOVERAGE_TEST_MARKER();
2761 }
2762 }
2763 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
2764
2765 #if ( configUSE_TICK_HOOK == 1 )
2766 {
2767 /* Guard against the tick hook being called when the pended tick
2768 count is being unwound (when the scheduler is being unlocked). */
2769 if( uxPendedTicks == ( UBaseType_t ) 0U )
2770 {
2771 vApplicationTickHook();
2772 }
2773 else
2774 {
2775 mtCOVERAGE_TEST_MARKER();
2776 }
2777 }
2778 #endif /* configUSE_TICK_HOOK */
2779 }
2780 else
2781 {
2782 ++uxPendedTicks;
2783
2784 /* The tick hook gets called at regular intervals, even if the
2785 scheduler is locked. */
2786 #if ( configUSE_TICK_HOOK == 1 )
2787 {
2788 vApplicationTickHook();
2789 }
2790 #endif
2791 }
2792
2793 #if ( configUSE_PREEMPTION == 1 )
2794 {
2795 if( xYieldPending != pdFALSE )
2796 {
2797 xSwitchRequired = pdTRUE;
2798 }
2799 else
2800 {
2801 mtCOVERAGE_TEST_MARKER();
2802 }
2803 }
2804 #endif /* configUSE_PREEMPTION */
2805
2806 return xSwitchRequired;
2807}
2808/*-----------------------------------------------------------*/
2809
2810#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2811
2812 void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction )
2813 {
2814 TCB_t *xTCB;
2815
2816 /* If xTask is NULL then it is the task hook of the calling task that is
2817 getting set. */
2818 if( xTask == NULL )
2819 {
2820 xTCB = ( TCB_t * ) pxCurrentTCB;
2821 }
2822 else
2823 {
2824 xTCB = ( TCB_t * ) xTask;
2825 }
2826
2827 /* Save the hook function in the TCB. A critical section is required as
2828 the value can be accessed from an interrupt. */
2829 taskENTER_CRITICAL();
2830 xTCB->pxTaskTag = pxHookFunction;
2831 taskEXIT_CRITICAL();
2832 }
2833
2834#endif /* configUSE_APPLICATION_TASK_TAG */
2835/*-----------------------------------------------------------*/
2836
2837#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2838
2839 TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask )
2840 {
2841 TCB_t *xTCB;
2842 TaskHookFunction_t xReturn;
2843
2844 /* If xTask is NULL then we are setting our own task hook. */
2845 if( xTask == NULL )
2846 {
2847 xTCB = ( TCB_t * ) pxCurrentTCB;
2848 }
2849 else
2850 {
2851 xTCB = ( TCB_t * ) xTask;
2852 }
2853
2854 /* Save the hook function in the TCB. A critical section is required as
2855 the value can be accessed from an interrupt. */
2856 taskENTER_CRITICAL();
2857 {
2858 xReturn = xTCB->pxTaskTag;
2859 }
2860 taskEXIT_CRITICAL();
2861
2862 return xReturn;
2863 }
2864
2865#endif /* configUSE_APPLICATION_TASK_TAG */
2866/*-----------------------------------------------------------*/
2867
2868#if ( configUSE_APPLICATION_TASK_TAG == 1 )
2869
2870 BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter )
2871 {
2872 TCB_t *xTCB;
2873 BaseType_t xReturn;
2874
2875 /* If xTask is NULL then we are calling our own task hook. */
2876 if( xTask == NULL )
2877 {
2878 xTCB = ( TCB_t * ) pxCurrentTCB;
2879 }
2880 else
2881 {
2882 xTCB = ( TCB_t * ) xTask;
2883 }
2884
2885 if( xTCB->pxTaskTag != NULL )
2886 {
2887 xReturn = xTCB->pxTaskTag( pvParameter );
2888 }
2889 else
2890 {
2891 xReturn = pdFAIL;
2892 }
2893
2894 return xReturn;
2895 }
2896
2897#endif /* configUSE_APPLICATION_TASK_TAG */
2898/*-----------------------------------------------------------*/
2899
2900void vTaskSwitchContext( void )
2901{
2902 if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
2903 {
2904 /* The scheduler is currently suspended - do not allow a context
2905 switch. */
2906 xYieldPending = pdTRUE;
2907 }
2908 else
2909 {
2910 xYieldPending = pdFALSE;
2911 traceTASK_SWITCHED_OUT();
2912
2913 #if ( configGENERATE_RUN_TIME_STATS == 1 )
2914 {
2915 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
2916 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
2917 #else
2918 ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
2919 #endif
2920
2921 /* Add the amount of time the task has been running to the
2922 accumulated time so far. The time the task started running was
2923 stored in ulTaskSwitchedInTime. Note that there is no overflow
2924 protection here so count values are only valid until the timer
2925 overflows. The guard against negative values is to protect
2926 against suspect run time stat counter implementations - which
2927 are provided by the application, not the kernel. */
2928 if( ulTotalRunTime > ulTaskSwitchedInTime )
2929 {
2930 pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
2931 }
2932 else
2933 {
2934 mtCOVERAGE_TEST_MARKER();
2935 }
2936 ulTaskSwitchedInTime = ulTotalRunTime;
2937 }
2938 #endif /* configGENERATE_RUN_TIME_STATS */
2939
2940 /* Check for stack overflow, if configured. */
2941 taskCHECK_FOR_STACK_OVERFLOW();
2942
2943 /* Select a new task to run using either the generic C or port
2944 optimised asm code. */
2945 taskSELECT_HIGHEST_PRIORITY_TASK();
2946 traceTASK_SWITCHED_IN();
2947
2948 #if ( configUSE_NEWLIB_REENTRANT == 1 )
2949 {
2950 /* Switch Newlib's _impure_ptr variable to point to the _reent
2951 structure specific to this task. */
2952 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
2953 }
2954 #endif /* configUSE_NEWLIB_REENTRANT */
2955 }
2956}
2957/*-----------------------------------------------------------*/
2958
2959void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait )
2960{
2961 configASSERT( pxEventList );
2962
2963 /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE
2964 SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */
2965
2966 /* Place the event list item of the TCB in the appropriate event list.
2967 This is placed in the list in priority order so the highest priority task
2968 is the first to be woken by the event. The queue that contains the event
2969 list is locked, preventing simultaneous access from interrupts. */
2970 vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );
2971
2972 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
2973}
2974/*-----------------------------------------------------------*/
2975
2976void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait )
2977{
2978 configASSERT( pxEventList );
2979
2980 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
2981 the event groups implementation. */
2982 configASSERT( uxSchedulerSuspended != 0 );
2983
2984 /* Store the item value in the event list item. It is safe to access the
2985 event list item here as interrupts won't access the event list item of a
2986 task that is not in the Blocked state. */
2987 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
2988
2989 /* Place the event list item of the TCB at the end of the appropriate event
2990 list. It is safe to access the event list here because it is part of an
2991 event group implementation - and interrupts don't access event groups
2992 directly (instead they access them indirectly by pending function calls to
2993 the task level). */
2994 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
2995
2996 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
2997}
2998/*-----------------------------------------------------------*/
2999
3000#if( configUSE_TIMERS == 1 )
3001
3002 void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely )
3003 {
3004 configASSERT( pxEventList );
3005
3006 /* This function should not be called by application code hence the
3007 'Restricted' in its name. It is not part of the public API. It is
3008 designed for use by kernel code, and has special calling requirements -
3009 it should be called with the scheduler suspended. */
3010
3011
3012 /* Place the event list item of the TCB in the appropriate event list.
3013 In this case it is assume that this is the only task that is going to
3014 be waiting on this event list, so the faster vListInsertEnd() function
3015 can be used in place of vListInsert. */
3016 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
3017
3018 /* If the task should block indefinitely then set the block time to a
3019 value that will be recognised as an indefinite delay inside the
3020 prvAddCurrentTaskToDelayedList() function. */
3021 if( xWaitIndefinitely != pdFALSE )
3022 {
3023 xTicksToWait = portMAX_DELAY;
3024 }
3025
3026 traceTASK_DELAY_UNTIL( ( xTickCount + xTicksToWait ) );
3027 prvAddCurrentTaskToDelayedList( xTicksToWait, xWaitIndefinitely );
3028 }
3029
3030#endif /* configUSE_TIMERS */
3031/*-----------------------------------------------------------*/
3032
3033BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
3034{
3035TCB_t *pxUnblockedTCB;
3036BaseType_t xReturn;
3037
3038 /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be
3039 called from a critical section within an ISR. */
3040
3041 /* The event list is sorted in priority order, so the first in the list can
3042 be removed as it is known to be the highest priority. Remove the TCB from
3043 the delayed list, and add it to the ready list.
3044
3045 If an event is for a queue that is locked then this function will never
3046 get called - the lock count on the queue will get modified instead. This
3047 means exclusive access to the event list is guaranteed here.
3048
3049 This function assumes that a check has already been made to ensure that
3050 pxEventList is not empty. */
3051 pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
3052 configASSERT( pxUnblockedTCB );
3053 ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) );
3054
3055 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
3056 {
3057 ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) );
3058 prvAddTaskToReadyList( pxUnblockedTCB );
3059 }
3060 else
3061 {
3062 /* The delayed and ready lists cannot be accessed, so hold this task
3063 pending until the scheduler is resumed. */
3064 vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
3065 }
3066
3067 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
3068 {
3069 /* Return true if the task removed from the event list has a higher
3070 priority than the calling task. This allows the calling task to know if
3071 it should force a context switch now. */
3072 xReturn = pdTRUE;
3073
3074 /* Mark that a yield is pending in case the user is not using the
3075 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
3076 xYieldPending = pdTRUE;
3077 }
3078 else
3079 {
3080 xReturn = pdFALSE;
3081 }
3082
3083 #if( configUSE_TICKLESS_IDLE != 0 )
3084 {
3085 /* If a task is blocked on a kernel object then xNextTaskUnblockTime
3086 might be set to the blocked task's time out time. If the task is
3087 unblocked for a reason other than a timeout xNextTaskUnblockTime is
3088 normally left unchanged, because it is automatically reset to a new
3089 value when the tick count equals xNextTaskUnblockTime. However if
3090 tickless idling is used it might be more important to enter sleep mode
3091 at the earliest possible time - so reset xNextTaskUnblockTime here to
3092 ensure it is updated at the earliest possible time. */
3093 prvResetNextTaskUnblockTime();
3094 }
3095 #endif
3096
3097 return xReturn;
3098}
3099/*-----------------------------------------------------------*/
3100
3101BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
3102{
3103TCB_t *pxUnblockedTCB;
3104BaseType_t xReturn;
3105
3106 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
3107 the event flags implementation. */
3108 configASSERT( uxSchedulerSuspended != pdFALSE );
3109
3110 /* Store the new item value in the event list. */
3111 listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE );
3112
3113 /* Remove the event list form the event flag. Interrupts do not access
3114 event flags. */
3115 pxUnblockedTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxEventListItem );
3116 configASSERT( pxUnblockedTCB );
3117 ( void ) uxListRemove( pxEventListItem );
3118
3119 /* Remove the task from the delayed list and add it to the ready list. The
3120 scheduler is suspended so interrupts will not be accessing the ready
3121 lists. */
3122 ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) );
3123 prvAddTaskToReadyList( pxUnblockedTCB );
3124
3125 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
3126 {
3127 /* Return true if the task removed from the event list has
3128 a higher priority than the calling task. This allows
3129 the calling task to know if it should force a context
3130 switch now. */
3131 xReturn = pdTRUE;
3132
3133 /* Mark that a yield is pending in case the user is not using the
3134 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
3135 xYieldPending = pdTRUE;
3136 }
3137 else
3138 {
3139 xReturn = pdFALSE;
3140 }
3141
3142 return xReturn;
3143}
3144/*-----------------------------------------------------------*/
3145
3146void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )
3147{
3148 configASSERT( pxTimeOut );
3149 pxTimeOut->xOverflowCount = xNumOfOverflows;
3150 pxTimeOut->xTimeOnEntering = xTickCount;
3151}
3152/*-----------------------------------------------------------*/
3153
3154BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait )
3155{
3156BaseType_t xReturn;
3157
3158 configASSERT( pxTimeOut );
3159 configASSERT( pxTicksToWait );
3160
3161 taskENTER_CRITICAL();
3162 {
3163 /* Minor optimisation. The tick count cannot change in this block. */
3164 const TickType_t xConstTickCount = xTickCount;
3165
3166 #if( INCLUDE_xTaskAbortDelay == 1 )
3167 if( pxCurrentTCB->ucDelayAborted != pdFALSE )
3168 {
3169 /* The delay was aborted, which is not the same as a time out,
3170 but has the same result. */
3171 pxCurrentTCB->ucDelayAborted = pdFALSE;
3172 xReturn = pdTRUE;
3173 }
3174 else
3175 #endif
3176
3177 #if ( INCLUDE_vTaskSuspend == 1 )
3178 if( *pxTicksToWait == portMAX_DELAY )
3179 {
3180 /* If INCLUDE_vTaskSuspend is set to 1 and the block time
3181 specified is the maximum block time then the task should block
3182 indefinitely, and therefore never time out. */
3183 xReturn = pdFALSE;
3184 }
3185 else
3186 #endif
3187
3188 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */
3189 {
3190 /* The tick count is greater than the time at which
3191 vTaskSetTimeout() was called, but has also overflowed since
3192 vTaskSetTimeOut() was called. It must have wrapped all the way
3193 around and gone past again. This passed since vTaskSetTimeout()
3194 was called. */
3195 xReturn = pdTRUE;
3196 }
3197 else if( ( ( TickType_t ) ( xConstTickCount - pxTimeOut->xTimeOnEntering ) ) < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */
3198 {
3199 /* Not a genuine timeout. Adjust parameters for time remaining. */
3200 *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering );
3201 vTaskSetTimeOutState( pxTimeOut );
3202 xReturn = pdFALSE;
3203 }
3204 else
3205 {
3206 xReturn = pdTRUE;
3207 }
3208 }
3209 taskEXIT_CRITICAL();
3210
3211 return xReturn;
3212}
3213/*-----------------------------------------------------------*/
3214
3215void vTaskMissedYield( void )
3216{
3217 xYieldPending = pdTRUE;
3218}
3219/*-----------------------------------------------------------*/
3220
3221#if ( configUSE_TRACE_FACILITY == 1 )
3222
3223 UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask )
3224 {
3225 UBaseType_t uxReturn;
3226 TCB_t *pxTCB;
3227
3228 if( xTask != NULL )
3229 {
3230 pxTCB = ( TCB_t * ) xTask;
3231 uxReturn = pxTCB->uxTaskNumber;
3232 }
3233 else
3234 {
3235 uxReturn = 0U;
3236 }
3237
3238 return uxReturn;
3239 }
3240
3241#endif /* configUSE_TRACE_FACILITY */
3242/*-----------------------------------------------------------*/
3243
3244#if ( configUSE_TRACE_FACILITY == 1 )
3245
3246 void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle )
3247 {
3248 TCB_t *pxTCB;
3249
3250 if( xTask != NULL )
3251 {
3252 pxTCB = ( TCB_t * ) xTask;
3253 pxTCB->uxTaskNumber = uxHandle;
3254 }
3255 }
3256
3257#endif /* configUSE_TRACE_FACILITY */
3258
3259/*
3260 * -----------------------------------------------------------
3261 * The Idle task.
3262 * ----------------------------------------------------------
3263 *
3264 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
3265 * language extensions. The equivalent prototype for this function is:
3266 *
3267 * void prvIdleTask( void *pvParameters );
3268 *
3269 */
3270static portTASK_FUNCTION( prvIdleTask, pvParameters )
3271{
3272 /* Stop warnings. */
3273 ( void ) pvParameters;
3274
3275 /** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
3276 SCHEDULER IS STARTED. **/
3277
3278 for( ;; )
3279 {
3280 /* See if any tasks have deleted themselves - if so then the idle task
3281 is responsible for freeing the deleted task's TCB and stack. */
3282 prvCheckTasksWaitingTermination();
3283
3284 #if ( configUSE_PREEMPTION == 0 )
3285 {
3286 /* If we are not using preemption we keep forcing a task switch to
3287 see if any other task has become available. If we are using
3288 preemption we don't need to do this as any task becoming available
3289 will automatically get the processor anyway. */
3290 taskYIELD();
3291 }
3292 #endif /* configUSE_PREEMPTION */
3293
3294 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
3295 {
3296 /* When using preemption tasks of equal priority will be
3297 timesliced. If a task that is sharing the idle priority is ready
3298 to run then the idle task should yield before the end of the
3299 timeslice.
3300
3301 A critical region is not required here as we are just reading from
3302 the list, and an occasional incorrect value will not matter. If
3303 the ready list at the idle priority contains more than one task
3304 then a task other than the idle task is ready to execute. */
3305 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
3306 {
3307 taskYIELD();
3308 }
3309 else
3310 {
3311 mtCOVERAGE_TEST_MARKER();
3312 }
3313 }
3314 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
3315
3316 #if ( configUSE_IDLE_HOOK == 1 )
3317 {
3318 extern void vApplicationIdleHook( void );
3319
3320 /* Call the user defined function from within the idle task. This
3321 allows the application designer to add background functionality
3322 without the overhead of a separate task.
3323 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
3324 CALL A FUNCTION THAT MIGHT BLOCK. */
3325 vApplicationIdleHook();
3326 }
3327 #endif /* configUSE_IDLE_HOOK */
3328
3329 /* This conditional compilation should use inequality to 0, not equality
3330 to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
3331 user defined low power mode implementations require
3332 configUSE_TICKLESS_IDLE to be set to a value other than 1. */
3333 #if ( configUSE_TICKLESS_IDLE != 0 )
3334 {
3335 TickType_t xExpectedIdleTime;
3336
3337 /* It is not desirable to suspend then resume the scheduler on
3338 each iteration of the idle task. Therefore, a preliminary
3339 test of the expected idle time is performed without the
3340 scheduler suspended. The result here is not necessarily
3341 valid. */
3342 xExpectedIdleTime = prvGetExpectedIdleTime();
3343
3344 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
3345 {
3346 vTaskSuspendAll();
3347 {
3348 /* Now the scheduler is suspended, the expected idle
3349 time can be sampled again, and this time its value can
3350 be used. */
3351 configASSERT( xNextTaskUnblockTime >= xTickCount );
3352 xExpectedIdleTime = prvGetExpectedIdleTime();
3353
3354 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
3355 {
3356 traceLOW_POWER_IDLE_BEGIN();
3357 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
3358 traceLOW_POWER_IDLE_END();
3359 }
3360 else
3361 {
3362 mtCOVERAGE_TEST_MARKER();
3363 }
3364 }
3365 ( void ) xTaskResumeAll();
3366 }
3367 else
3368 {
3369 mtCOVERAGE_TEST_MARKER();
3370 }
3371 }
3372 #endif /* configUSE_TICKLESS_IDLE */
3373 }
3374}
3375/*-----------------------------------------------------------*/
3376
3377#if( configUSE_TICKLESS_IDLE != 0 )
3378
3379 eSleepModeStatus eTaskConfirmSleepModeStatus( void )
3380 {
3381 /* The idle task exists in addition to the application tasks. */
3382 const UBaseType_t uxNonApplicationTasks = 1;
3383 eSleepModeStatus eReturn = eStandardSleep;
3384
3385 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )
3386 {
3387 /* A task was made ready while the scheduler was suspended. */
3388 eReturn = eAbortSleep;
3389 }
3390 else if( xYieldPending != pdFALSE )
3391 {
3392 /* A yield was pended while the scheduler was suspended. */
3393 eReturn = eAbortSleep;
3394 }
3395 else
3396 {
3397 /* If all the tasks are in the suspended list (which might mean they
3398 have an infinite block time rather than actually being suspended)
3399 then it is safe to turn all clocks off and just wait for external
3400 interrupts. */
3401 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
3402 {
3403 eReturn = eNoTasksWaitingTimeout;
3404 }
3405 else
3406 {
3407 mtCOVERAGE_TEST_MARKER();
3408 }
3409 }
3410
3411 return eReturn;
3412 }
3413
3414#endif /* configUSE_TICKLESS_IDLE */
3415/*-----------------------------------------------------------*/
3416
3417#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
3418
3419 void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue )
3420 {
3421 TCB_t *pxTCB;
3422
3423 if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
3424 {
3425 pxTCB = prvGetTCBFromHandle( xTaskToSet );
3426 pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue;
3427 }
3428 }
3429
3430#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */
3431/*-----------------------------------------------------------*/
3432
3433#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
3434
3435 void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex )
3436 {
3437 void *pvReturn = NULL;
3438 TCB_t *pxTCB;
3439
3440 if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS )
3441 {
3442 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
3443 pvReturn = pxTCB->pvThreadLocalStoragePointers[ xIndex ];
3444 }
3445 else
3446 {
3447 pvReturn = NULL;
3448 }
3449
3450 return pvReturn;
3451 }
3452
3453#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */
3454/*-----------------------------------------------------------*/
3455
3456#if ( portUSING_MPU_WRAPPERS == 1 )
3457
3458 void vTaskAllocateMPURegions( TaskHandle_t xTaskToModify, const MemoryRegion_t * const xRegions )
3459 {
3460 TCB_t *pxTCB;
3461
3462 /* If null is passed in here then we are modifying the MPU settings of
3463 the calling task. */
3464 pxTCB = prvGetTCBFromHandle( xTaskToModify );
3465
3466 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
3467 }
3468
3469#endif /* portUSING_MPU_WRAPPERS */
3470/*-----------------------------------------------------------*/
3471
3472static void prvInitialiseTaskLists( void )
3473{
3474UBaseType_t uxPriority;
3475
3476 for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
3477 {
3478 vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
3479 }
3480
3481 vListInitialise( &xDelayedTaskList1 );
3482 vListInitialise( &xDelayedTaskList2 );
3483 vListInitialise( &xPendingReadyList );
3484
3485 #if ( INCLUDE_vTaskDelete == 1 )
3486 {
3487 vListInitialise( &xTasksWaitingTermination );
3488 }
3489 #endif /* INCLUDE_vTaskDelete */
3490
3491 #if ( INCLUDE_vTaskSuspend == 1 )
3492 {
3493 vListInitialise( &xSuspendedTaskList );
3494 }
3495 #endif /* INCLUDE_vTaskSuspend */
3496
3497 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
3498 using list2. */
3499 pxDelayedTaskList = &xDelayedTaskList1;
3500 pxOverflowDelayedTaskList = &xDelayedTaskList2;
3501}
3502/*-----------------------------------------------------------*/
3503
3504static void prvCheckTasksWaitingTermination( void )
3505{
3506
3507 /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/
3508
3509 #if ( INCLUDE_vTaskDelete == 1 )
3510 {
3511 BaseType_t xListIsEmpty;
3512
3513 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
3514 too often in the idle task. */
3515 while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
3516 {
3517 vTaskSuspendAll();
3518 {
3519 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
3520 }
3521 ( void ) xTaskResumeAll();
3522
3523 if( xListIsEmpty == pdFALSE )
3524 {
3525 TCB_t *pxTCB;
3526
3527 taskENTER_CRITICAL();
3528 {
3529 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
3530 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
3531 --uxCurrentNumberOfTasks;
3532 --uxDeletedTasksWaitingCleanUp;
3533 }
3534 taskEXIT_CRITICAL();
3535
3536 prvDeleteTCB( pxTCB );
3537 }
3538 else
3539 {
3540 mtCOVERAGE_TEST_MARKER();
3541 }
3542 }
3543 }
3544 #endif /* INCLUDE_vTaskDelete */
3545}
3546/*-----------------------------------------------------------*/
3547
3548#if( configUSE_TRACE_FACILITY == 1 )
3549
3550 void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState )
3551 {
3552 TCB_t *pxTCB;
3553
3554 /* xTask is NULL then get the state of the calling task. */
3555 pxTCB = prvGetTCBFromHandle( xTask );
3556
3557 pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB;
3558 pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName [ 0 ] );
3559 pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority;
3560 pxTaskStatus->pxStackBase = pxTCB->pxStack;
3561 pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;
3562
3563 #if ( INCLUDE_vTaskSuspend == 1 )
3564 {
3565 /* If the task is in the suspended list then there is a chance it is
3566 actually just blocked indefinitely - so really it should be reported as
3567 being in the Blocked state. */
3568 if( pxTaskStatus->eCurrentState == eSuspended )
3569 {
3570 vTaskSuspendAll();
3571 {
3572 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
3573 {
3574 pxTaskStatus->eCurrentState = eBlocked;
3575 }
3576 }
3577 xTaskResumeAll();
3578 }
3579 }
3580 #endif /* INCLUDE_vTaskSuspend */
3581
3582 #if ( configUSE_MUTEXES == 1 )
3583 {
3584 pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
3585 }
3586 #else
3587 {
3588 pxTaskStatus->uxBasePriority = 0;
3589 }
3590 #endif
3591
3592 #if ( configGENERATE_RUN_TIME_STATS == 1 )
3593 {
3594 pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter;
3595 }
3596 #else
3597 {
3598 pxTaskStatus->ulRunTimeCounter = 0;
3599 }
3600 #endif
3601
3602 /* Obtaining the task state is a little fiddly, so is only done if the value
3603 of eState passed into this function is eInvalid - otherwise the state is
3604 just set to whatever is passed in. */
3605 if( eState != eInvalid )
3606 {
3607 pxTaskStatus->eCurrentState = eState;
3608 }
3609 else
3610 {
3611 pxTaskStatus->eCurrentState = eTaskGetState( xTask );
3612 }
3613
3614 /* Obtaining the stack space takes some time, so the xGetFreeStackSpace
3615 parameter is provided to allow it to be skipped. */
3616 if( xGetFreeStackSpace != pdFALSE )
3617 {
3618 #if ( portSTACK_GROWTH > 0 )
3619 {
3620 pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack );
3621 }
3622 #else
3623 {
3624 pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack );
3625 }
3626 #endif
3627 }
3628 else
3629 {
3630 pxTaskStatus->usStackHighWaterMark = 0;
3631 }
3632 }
3633
3634#endif /* configUSE_TRACE_FACILITY */
3635/*-----------------------------------------------------------*/
3636
3637#if ( configUSE_TRACE_FACILITY == 1 )
3638
3639 static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
3640 {
3641 volatile TCB_t *pxNextTCB, *pxFirstTCB;
3642 UBaseType_t uxTask = 0;
3643
3644 if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
3645 {
3646 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
3647
3648 /* Populate an TaskStatus_t structure within the
3649 pxTaskStatusArray array for each task that is referenced from
3650 pxList. See the definition of TaskStatus_t in task.h for the
3651 meaning of each TaskStatus_t structure member. */
3652 do
3653 {
3654 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
3655 vTaskGetInfo( ( TaskHandle_t ) pxNextTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState );
3656 uxTask++;
3657 } while( pxNextTCB != pxFirstTCB );
3658 }
3659 else
3660 {
3661 mtCOVERAGE_TEST_MARKER();
3662 }
3663
3664 return uxTask;
3665 }
3666
3667#endif /* configUSE_TRACE_FACILITY */
3668/*-----------------------------------------------------------*/
3669
3670#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
3671
3672 static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte )
3673 {
3674 uint32_t ulCount = 0U;
3675
3676 while( *pucStackByte == ( uint8_t ) tskSTACK_FILL_BYTE )
3677 {
3678 pucStackByte -= portSTACK_GROWTH;
3679 ulCount++;
3680 }
3681
3682 ulCount /= ( uint32_t ) sizeof( StackType_t ); /*lint !e961 Casting is not redundant on smaller architectures. */
3683
3684 return ( uint16_t ) ulCount;
3685 }
3686
3687#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */
3688/*-----------------------------------------------------------*/
3689
3690#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
3691
3692 UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
3693 {
3694 TCB_t *pxTCB;
3695 uint8_t *pucEndOfStack;
3696 UBaseType_t uxReturn;
3697
3698 pxTCB = prvGetTCBFromHandle( xTask );
3699
3700 #if portSTACK_GROWTH < 0
3701 {
3702 pucEndOfStack = ( uint8_t * ) pxTCB->pxStack;
3703 }
3704 #else
3705 {
3706 pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack;
3707 }
3708 #endif
3709
3710 uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack );
3711
3712 return uxReturn;
3713 }
3714
3715#endif /* INCLUDE_uxTaskGetStackHighWaterMark */
3716/*-----------------------------------------------------------*/
3717
3718#if ( INCLUDE_vTaskDelete == 1 )
3719
3720 static void prvDeleteTCB( TCB_t *pxTCB )
3721 {
3722 /* This call is required specifically for the TriCore port. It must be
3723 above the vPortFree() calls. The call is also used by ports/demos that
3724 want to allocate and clean RAM statically. */
3725 portCLEAN_UP_TCB( pxTCB );
3726
3727 /* Free up the memory allocated by the scheduler for the task. It is up
3728 to the task to free any memory allocated at the application level. */
3729 #if ( configUSE_NEWLIB_REENTRANT == 1 )
3730 {
3731 _reclaim_reent( &( pxTCB->xNewLib_reent ) );
3732 }
3733 #endif /* configUSE_NEWLIB_REENTRANT */
3734
3735 #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) )
3736 {
3737 /* The task can only have been allocated dynamically - free both
3738 the stack and TCB. */
3739 vPortFree( pxTCB->pxStack );
3740 vPortFree( pxTCB );
3741 }
3742 #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 )
3743 {
3744 /* The task could have been allocated statically or dynamically, so
3745 check what was statically allocated before trying to free the
3746 memory. */
3747 if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB )
3748 {
3749 /* Both the stack and TCB were allocated dynamically, so both
3750 must be freed. */
3751 vPortFree( pxTCB->pxStack );
3752 vPortFree( pxTCB );
3753 }
3754 else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY )
3755 {
3756 /* Only the stack was statically allocated, so the TCB is the
3757 only memory that must be freed. */
3758 vPortFree( pxTCB );
3759 }
3760 else
3761 {
3762 /* Neither the stack nor the TCB were allocated dynamically, so
3763 nothing needs to be freed. */
3764 configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB )
3765 mtCOVERAGE_TEST_MARKER();
3766 }
3767 }
3768 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
3769 }
3770
3771#endif /* INCLUDE_vTaskDelete */
3772/*-----------------------------------------------------------*/
3773
3774static void prvResetNextTaskUnblockTime( void )
3775{
3776TCB_t *pxTCB;
3777
3778 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
3779 {
3780 /* The new current delayed list is empty. Set xNextTaskUnblockTime to
3781 the maximum possible value so it is extremely unlikely that the
3782 if( xTickCount >= xNextTaskUnblockTime ) test will pass until
3783 there is an item in the delayed list. */
3784 xNextTaskUnblockTime = portMAX_DELAY;
3785 }
3786 else
3787 {
3788 /* The new current delayed list is not empty, get the value of
3789 the item at the head of the delayed list. This is the time at
3790 which the task at the head of the delayed list should be removed
3791 from the Blocked state. */
3792 ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
3793 xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) );
3794 }
3795}
3796/*-----------------------------------------------------------*/
3797
3798#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
3799
3800 TaskHandle_t xTaskGetCurrentTaskHandle( void )
3801 {
3802 TaskHandle_t xReturn;
3803
3804 /* A critical section is not required as this is not called from
3805 an interrupt and the current TCB will always be the same for any
3806 individual execution thread. */
3807 xReturn = pxCurrentTCB;
3808
3809 return xReturn;
3810 }
3811
3812#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
3813/*-----------------------------------------------------------*/
3814
3815#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
3816
3817 BaseType_t xTaskGetSchedulerState( void )
3818 {
3819 BaseType_t xReturn;
3820
3821 if( xSchedulerRunning == pdFALSE )
3822 {
3823 xReturn = taskSCHEDULER_NOT_STARTED;
3824 }
3825 else
3826 {
3827 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
3828 {
3829 xReturn = taskSCHEDULER_RUNNING;
3830 }
3831 else
3832 {
3833 xReturn = taskSCHEDULER_SUSPENDED;
3834 }
3835 }
3836
3837 return xReturn;
3838 }
3839
3840#endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */
3841/*-----------------------------------------------------------*/
3842
3843#if ( configUSE_MUTEXES == 1 )
3844
3845 void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
3846 {
3847 TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
3848
3849 /* If the mutex was given back by an interrupt while the queue was
3850 locked then the mutex holder might now be NULL. */
3851 if( pxMutexHolder != NULL )
3852 {
3853 /* If the holder of the mutex has a priority below the priority of
3854 the task attempting to obtain the mutex then it will temporarily
3855 inherit the priority of the task attempting to obtain the mutex. */
3856 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
3857 {
3858 /* Adjust the mutex holder state to account for its new
3859 priority. Only reset the event list item value if the value is
3860 not being used for anything else. */
3861 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
3862 {
3863 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
3864 }
3865 else
3866 {
3867 mtCOVERAGE_TEST_MARKER();
3868 }
3869
3870 /* If the task being modified is in the ready state it will need
3871 to be moved into a new list. */
3872 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
3873 {
3874 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
3875 {
3876 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
3877 }
3878 else
3879 {
3880 mtCOVERAGE_TEST_MARKER();
3881 }
3882
3883 /* Inherit the priority before being moved into the new list. */
3884 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
3885 prvAddTaskToReadyList( pxTCB );
3886 }
3887 else
3888 {
3889 /* Just inherit the priority. */
3890 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
3891 }
3892
3893 traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );
3894 }
3895 else
3896 {
3897 mtCOVERAGE_TEST_MARKER();
3898 }
3899 }
3900 else
3901 {
3902 mtCOVERAGE_TEST_MARKER();
3903 }
3904 }
3905
3906#endif /* configUSE_MUTEXES */
3907/*-----------------------------------------------------------*/
3908
3909#if ( configUSE_MUTEXES == 1 )
3910
3911 BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder )
3912 {
3913 TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
3914 BaseType_t xReturn = pdFALSE;
3915
3916 if( pxMutexHolder != NULL )
3917 {
3918 /* A task can only have an inherited priority if it holds the mutex.
3919 If the mutex is held by a task then it cannot be given from an
3920 interrupt, and if a mutex is given by the holding task then it must
3921 be the running state task. */
3922 configASSERT( pxTCB == pxCurrentTCB );
3923
3924 configASSERT( pxTCB->uxMutexesHeld );
3925 ( pxTCB->uxMutexesHeld )--;
3926
3927 /* Has the holder of the mutex inherited the priority of another
3928 task? */
3929 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
3930 {
3931 /* Only disinherit if no other mutexes are held. */
3932 if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 )
3933 {
3934 /* A task can only have an inherited priority if it holds
3935 the mutex. If the mutex is held by a task then it cannot be
3936 given from an interrupt, and if a mutex is given by the
3937 holding task then it must be the running state task. Remove
3938 the holding task from the ready list. */
3939 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
3940 {
3941 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
3942 }
3943 else
3944 {
3945 mtCOVERAGE_TEST_MARKER();
3946 }
3947
3948 /* Disinherit the priority before adding the task into the
3949 new ready list. */
3950 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
3951 pxTCB->uxPriority = pxTCB->uxBasePriority;
3952
3953 /* Reset the event list item value. It cannot be in use for
3954 any other purpose if this task is running, and it must be
3955 running to give back the mutex. */
3956 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. */
3957 prvAddTaskToReadyList( pxTCB );
3958
3959 /* Return true to indicate that a context switch is required.
3960 This is only actually required in the corner case whereby
3961 multiple mutexes were held and the mutexes were given back
3962 in an order different to that in which they were taken.
3963 If a context switch did not occur when the first mutex was
3964 returned, even if a task was waiting on it, then a context
3965 switch should occur when the last mutex is returned whether
3966 a task is waiting on it or not. */
3967 xReturn = pdTRUE;
3968 }
3969 else
3970 {
3971 mtCOVERAGE_TEST_MARKER();
3972 }
3973 }
3974 else
3975 {
3976 mtCOVERAGE_TEST_MARKER();
3977 }
3978 }
3979 else
3980 {
3981 mtCOVERAGE_TEST_MARKER();
3982 }
3983
3984 return xReturn;
3985 }
3986
3987#endif /* configUSE_MUTEXES */
3988/*-----------------------------------------------------------*/
3989
3990#if ( portCRITICAL_NESTING_IN_TCB == 1 )
3991
3992 void vTaskEnterCritical( void )
3993 {
3994 portDISABLE_INTERRUPTS();
3995
3996 if( xSchedulerRunning != pdFALSE )
3997 {
3998 ( pxCurrentTCB->uxCriticalNesting )++;
3999
4000 /* This is not the interrupt safe version of the enter critical
4001 function so assert() if it is being called from an interrupt
4002 context. Only API functions that end in "FromISR" can be used in an
4003 interrupt. Only assert if the critical nesting count is 1 to
4004 protect against recursive calls if the assert function also uses a
4005 critical section. */
4006 if( pxCurrentTCB->uxCriticalNesting == 1 )
4007 {
4008 portASSERT_IF_IN_ISR();
4009 }
4010 }
4011 else
4012 {
4013 mtCOVERAGE_TEST_MARKER();
4014 }
4015 }
4016
4017#endif /* portCRITICAL_NESTING_IN_TCB */
4018/*-----------------------------------------------------------*/
4019
4020#if ( portCRITICAL_NESTING_IN_TCB == 1 )
4021
4022 void vTaskExitCritical( void )
4023 {
4024 if( xSchedulerRunning != pdFALSE )
4025 {
4026 if( pxCurrentTCB->uxCriticalNesting > 0U )
4027 {
4028 ( pxCurrentTCB->uxCriticalNesting )--;
4029
4030 if( pxCurrentTCB->uxCriticalNesting == 0U )
4031 {
4032 portENABLE_INTERRUPTS();
4033 }
4034 else
4035 {
4036 mtCOVERAGE_TEST_MARKER();
4037 }
4038 }
4039 else
4040 {
4041 mtCOVERAGE_TEST_MARKER();
4042 }
4043 }
4044 else
4045 {
4046 mtCOVERAGE_TEST_MARKER();
4047 }
4048 }
4049
4050#endif /* portCRITICAL_NESTING_IN_TCB */
4051/*-----------------------------------------------------------*/
4052
4053#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
4054
4055 static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName )
4056 {
4057 size_t x;
4058
4059 /* Start by copying the entire string. */
4060 strcpy( pcBuffer, pcTaskName );
4061
4062 /* Pad the end of the string with spaces to ensure columns line up when
4063 printed out. */
4064 for( x = strlen( pcBuffer ); x < ( size_t ) ( configMAX_TASK_NAME_LEN - 1 ); x++ )
4065 {
4066 pcBuffer[ x ] = ' ';
4067 }
4068
4069 /* Terminate. */
4070 pcBuffer[ x ] = 0x00;
4071
4072 /* Return the new end of string. */
4073 return &( pcBuffer[ x ] );
4074 }
4075
4076#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */
4077/*-----------------------------------------------------------*/
4078
4079#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
4080
4081 void vTaskList( char * pcWriteBuffer )
4082 {
4083 TaskStatus_t *pxTaskStatusArray;
4084 volatile UBaseType_t uxArraySize, x;
4085 char cStatus;
4086
4087 /*
4088 * PLEASE NOTE:
4089 *
4090 * This function is provided for convenience only, and is used by many
4091 * of the demo applications. Do not consider it to be part of the
4092 * scheduler.
4093 *
4094 * vTaskList() calls uxTaskGetSystemState(), then formats part of the
4095 * uxTaskGetSystemState() output into a human readable table that
4096 * displays task names, states and stack usage.
4097 *
4098 * vTaskList() has a dependency on the sprintf() C library function that
4099 * might bloat the code size, use a lot of stack, and provide different
4100 * results on different platforms. An alternative, tiny, third party,
4101 * and limited functionality implementation of sprintf() is provided in
4102 * many of the FreeRTOS/Demo sub-directories in a file called
4103 * printf-stdarg.c (note printf-stdarg.c does not provide a full
4104 * snprintf() implementation!).
4105 *
4106 * It is recommended that production systems call uxTaskGetSystemState()
4107 * directly to get access to raw stats data, rather than indirectly
4108 * through a call to vTaskList().
4109 */
4110
4111
4112 /* Make sure the write buffer does not contain a string. */
4113 *pcWriteBuffer = 0x00;
4114
4115 /* Take a snapshot of the number of tasks in case it changes while this
4116 function is executing. */
4117 uxArraySize = uxCurrentNumberOfTasks;
4118
4119 /* Allocate an array index for each task. NOTE! if
4120 configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will
4121 equate to NULL. */
4122 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) );
4123
4124 if( pxTaskStatusArray != NULL )
4125 {
4126 /* Generate the (binary) data. */
4127 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL );
4128
4129 /* Create a human readable table from the binary data. */
4130 for( x = 0; x < uxArraySize; x++ )
4131 {
4132 switch( pxTaskStatusArray[ x ].eCurrentState )
4133 {
4134 case eReady: cStatus = tskREADY_CHAR;
4135 break;
4136
4137 case eBlocked: cStatus = tskBLOCKED_CHAR;
4138 break;
4139
4140 case eSuspended: cStatus = tskSUSPENDED_CHAR;
4141 break;
4142
4143 case eDeleted: cStatus = tskDELETED_CHAR;
4144 break;
4145
4146 default: /* Should not get here, but it is included
4147 to prevent static checking errors. */
4148 cStatus = 0x00;
4149 break;
4150 }
4151
4152 /* Write the task name to the string, padding with spaces so it
4153 can be printed in tabular form more easily. */
4154 pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
4155
4156 /* Write the rest of the string. */
4157 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 );
4158 pcWriteBuffer += strlen( pcWriteBuffer );
4159 }
4160
4161 /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION
4162 is 0 then vPortFree() will be #defined to nothing. */
4163 vPortFree( pxTaskStatusArray );
4164 }
4165 else
4166 {
4167 mtCOVERAGE_TEST_MARKER();
4168 }
4169 }
4170
4171#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
4172/*----------------------------------------------------------*/
4173
4174#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
4175
4176 void vTaskGetRunTimeStats( char *pcWriteBuffer )
4177 {
4178 TaskStatus_t *pxTaskStatusArray;
4179 volatile UBaseType_t uxArraySize, x;
4180 uint32_t ulTotalTime, ulStatsAsPercentage;
4181
4182 #if( configUSE_TRACE_FACILITY != 1 )
4183 {
4184 #error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
4185 }
4186 #endif
4187
4188 /*
4189 * PLEASE NOTE:
4190 *
4191 * This function is provided for convenience only, and is used by many
4192 * of the demo applications. Do not consider it to be part of the
4193 * scheduler.
4194 *
4195 * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part
4196 * of the uxTaskGetSystemState() output into a human readable table that
4197 * displays the amount of time each task has spent in the Running state
4198 * in both absolute and percentage terms.
4199 *
4200 * vTaskGetRunTimeStats() has a dependency on the sprintf() C library
4201 * function that might bloat the code size, use a lot of stack, and
4202 * provide different results on different platforms. An alternative,
4203 * tiny, third party, and limited functionality implementation of
4204 * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in
4205 * a file called printf-stdarg.c (note printf-stdarg.c does not provide
4206 * a full snprintf() implementation!).
4207 *
4208 * It is recommended that production systems call uxTaskGetSystemState()
4209 * directly to get access to raw stats data, rather than indirectly
4210 * through a call to vTaskGetRunTimeStats().
4211 */
4212
4213 /* Make sure the write buffer does not contain a string. */
4214 *pcWriteBuffer = 0x00;
4215
4216 /* Take a snapshot of the number of tasks in case it changes while this
4217 function is executing. */
4218 uxArraySize = uxCurrentNumberOfTasks;
4219
4220 /* Allocate an array index for each task. NOTE! If
4221 configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will
4222 equate to NULL. */
4223 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) );
4224
4225 if( pxTaskStatusArray != NULL )
4226 {
4227 /* Generate the (binary) data. */
4228 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime );
4229
4230 /* For percentage calculations. */
4231 ulTotalTime /= 100UL;
4232
4233 /* Avoid divide by zero errors. */
4234 if( ulTotalTime > 0 )
4235 {
4236 /* Create a human readable table from the binary data. */
4237 for( x = 0; x < uxArraySize; x++ )
4238 {
4239 /* What percentage of the total run time has the task used?
4240 This will always be rounded down to the nearest integer.
4241 ulTotalRunTimeDiv100 has already been divided by 100. */
4242 ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime;
4243
4244 /* Write the task name to the string, padding with
4245 spaces so it can be printed in tabular form more
4246 easily. */
4247 pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName );
4248
4249 if( ulStatsAsPercentage > 0UL )
4250 {
4251 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
4252 {
4253 sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
4254 }
4255 #else
4256 {
4257 /* sizeof( int ) == sizeof( long ) so a smaller
4258 printf() library can be used. */
4259 sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
4260 }
4261 #endif
4262 }
4263 else
4264 {
4265 /* If the percentage is zero here then the task has
4266 consumed less than 1% of the total run time. */
4267 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
4268 {
4269 sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter );
4270 }
4271 #else
4272 {
4273 /* sizeof( int ) == sizeof( long ) so a smaller
4274 printf() library can be used. */
4275 sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter );
4276 }
4277 #endif
4278 }
4279
4280 pcWriteBuffer += strlen( pcWriteBuffer );
4281 }
4282 }
4283 else
4284 {
4285 mtCOVERAGE_TEST_MARKER();
4286 }
4287
4288 /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION
4289 is 0 then vPortFree() will be #defined to nothing. */
4290 vPortFree( pxTaskStatusArray );
4291 }
4292 else
4293 {
4294 mtCOVERAGE_TEST_MARKER();
4295 }
4296 }
4297
4298#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
4299/*-----------------------------------------------------------*/
4300
4301TickType_t uxTaskResetEventItemValue( void )
4302{
4303TickType_t uxReturn;
4304
4305 uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ) );
4306
4307 /* Reset the event list item to its normal value - so it can be used with
4308 queues and semaphores. */
4309 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. */
4310
4311 return uxReturn;
4312}
4313/*-----------------------------------------------------------*/
4314
4315#if ( configUSE_MUTEXES == 1 )
4316
4317 void *pvTaskIncrementMutexHeldCount( void )
4318 {
4319 /* If xSemaphoreCreateMutex() is called before any tasks have been created
4320 then pxCurrentTCB will be NULL. */
4321 if( pxCurrentTCB != NULL )
4322 {
4323 ( pxCurrentTCB->uxMutexesHeld )++;
4324 }
4325
4326 return pxCurrentTCB;
4327 }
4328
4329#endif /* configUSE_MUTEXES */
4330/*-----------------------------------------------------------*/
4331
4332#if( configUSE_TASK_NOTIFICATIONS == 1 )
4333
4334 uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
4335 {
4336 uint32_t ulReturn;
4337
4338 taskENTER_CRITICAL();
4339 {
4340 /* Only block if the notification count is not already non-zero. */
4341 if( pxCurrentTCB->ulNotifiedValue == 0UL )
4342 {
4343 /* Mark this task as waiting for a notification. */
4344 pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;
4345
4346 if( xTicksToWait > ( TickType_t ) 0 )
4347 {
4348 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
4349 traceTASK_NOTIFY_TAKE_BLOCK();
4350
4351 /* All ports are written to allow a yield in a critical
4352 section (some will yield immediately, others wait until the
4353 critical section exits) - but it is not something that
4354 application code should ever do. */
4355 portYIELD_WITHIN_API();
4356 }
4357 else
4358 {
4359 mtCOVERAGE_TEST_MARKER();
4360 }
4361 }
4362 else
4363 {
4364 mtCOVERAGE_TEST_MARKER();
4365 }
4366 }
4367 taskEXIT_CRITICAL();
4368
4369 taskENTER_CRITICAL();
4370 {
4371 traceTASK_NOTIFY_TAKE();
4372 ulReturn = pxCurrentTCB->ulNotifiedValue;
4373
4374 if( ulReturn != 0UL )
4375 {
4376 if( xClearCountOnExit != pdFALSE )
4377 {
4378 pxCurrentTCB->ulNotifiedValue = 0UL;
4379 }
4380 else
4381 {
4382 pxCurrentTCB->ulNotifiedValue = ulReturn - 1;
4383 }
4384 }
4385 else
4386 {
4387 mtCOVERAGE_TEST_MARKER();
4388 }
4389
4390 pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
4391 }
4392 taskEXIT_CRITICAL();
4393
4394 return ulReturn;
4395 }
4396
4397#endif /* configUSE_TASK_NOTIFICATIONS */
4398/*-----------------------------------------------------------*/
4399
4400#if( configUSE_TASK_NOTIFICATIONS == 1 )
4401
4402 BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
4403 {
4404 BaseType_t xReturn;
4405
4406 taskENTER_CRITICAL();
4407 {
4408 /* Only block if a notification is not already pending. */
4409 if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
4410 {
4411 /* Clear bits in the task's notification value as bits may get
4412 set by the notifying task or interrupt. This can be used to
4413 clear the value to zero. */
4414 pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;
4415
4416 /* Mark this task as waiting for a notification. */
4417 pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;
4418
4419 if( xTicksToWait > ( TickType_t ) 0 )
4420 {
4421 prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
4422 traceTASK_NOTIFY_WAIT_BLOCK();
4423
4424 /* All ports are written to allow a yield in a critical
4425 section (some will yield immediately, others wait until the
4426 critical section exits) - but it is not something that
4427 application code should ever do. */
4428 portYIELD_WITHIN_API();
4429 }
4430 else
4431 {
4432 mtCOVERAGE_TEST_MARKER();
4433 }
4434 }
4435 else
4436 {
4437 mtCOVERAGE_TEST_MARKER();
4438 }
4439 }
4440 taskEXIT_CRITICAL();
4441
4442 taskENTER_CRITICAL();
4443 {
4444 traceTASK_NOTIFY_WAIT();
4445
4446 if( pulNotificationValue != NULL )
4447 {
4448 /* Output the current notification value, which may or may not
4449 have changed. */
4450 *pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
4451 }
4452
4453 /* If ucNotifyValue is set then either the task never entered the
4454 blocked state (because a notification was already pending) or the
4455 task unblocked because of a notification. Otherwise the task
4456 unblocked because of a timeout. */
4457 if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION )
4458 {
4459 /* A notification was not received. */
4460 xReturn = pdFALSE;
4461 }
4462 else
4463 {
4464 /* A notification was already pending or a notification was
4465 received while the task was waiting. */
4466 pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
4467 xReturn = pdTRUE;
4468 }
4469
4470 pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
4471 }
4472 taskEXIT_CRITICAL();
4473
4474 return xReturn;
4475 }
4476
4477#endif /* configUSE_TASK_NOTIFICATIONS */
4478/*-----------------------------------------------------------*/
4479
4480#if( configUSE_TASK_NOTIFICATIONS == 1 )
4481
4482 BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
4483 {
4484 TCB_t * pxTCB;
4485 BaseType_t xReturn = pdPASS;
4486 uint8_t ucOriginalNotifyState;
4487
4488 configASSERT( xTaskToNotify );
4489 pxTCB = ( TCB_t * ) xTaskToNotify;
4490
4491 taskENTER_CRITICAL();
4492 {
4493 if( pulPreviousNotificationValue != NULL )
4494 {
4495 *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
4496 }
4497
4498 ucOriginalNotifyState = pxTCB->ucNotifyState;
4499
4500 pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
4501
4502 switch( eAction )
4503 {
4504 case eSetBits :
4505 pxTCB->ulNotifiedValue |= ulValue;
4506 break;
4507
4508 case eIncrement :
4509 ( pxTCB->ulNotifiedValue )++;
4510 break;
4511
4512 case eSetValueWithOverwrite :
4513 pxTCB->ulNotifiedValue = ulValue;
4514 break;
4515
4516 case eSetValueWithoutOverwrite :
4517 if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
4518 {
4519 pxTCB->ulNotifiedValue = ulValue;
4520 }
4521 else
4522 {
4523 /* The value could not be written to the task. */
4524 xReturn = pdFAIL;
4525 }
4526 break;
4527
4528 case eNoAction:
4529 /* The task is being notified without its notify value being
4530 updated. */
4531 break;
4532 }
4533
4534 traceTASK_NOTIFY();
4535
4536 /* If the task is in the blocked state specifically to wait for a
4537 notification then unblock it now. */
4538 if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
4539 {
4540 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
4541 prvAddTaskToReadyList( pxTCB );
4542
4543 /* The task should not have been on an event list. */
4544 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4545
4546 #if( configUSE_TICKLESS_IDLE != 0 )
4547 {
4548 /* If a task is blocked waiting for a notification then
4549 xNextTaskUnblockTime might be set to the blocked task's time
4550 out time. If the task is unblocked for a reason other than
4551 a timeout xNextTaskUnblockTime is normally left unchanged,
4552 because it will automatically get reset to a new value when
4553 the tick count equals xNextTaskUnblockTime. However if
4554 tickless idling is used it might be more important to enter
4555 sleep mode at the earliest possible time - so reset
4556 xNextTaskUnblockTime here to ensure it is updated at the
4557 earliest possible time. */
4558 prvResetNextTaskUnblockTime();
4559 }
4560 #endif
4561
4562 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
4563 {
4564 /* The notified task has a priority above the currently
4565 executing task so a yield is required. */
4566 taskYIELD_IF_USING_PREEMPTION();
4567 }
4568 else
4569 {
4570 mtCOVERAGE_TEST_MARKER();
4571 }
4572 }
4573 else
4574 {
4575 mtCOVERAGE_TEST_MARKER();
4576 }
4577 }
4578 taskEXIT_CRITICAL();
4579
4580 return xReturn;
4581 }
4582
4583#endif /* configUSE_TASK_NOTIFICATIONS */
4584/*-----------------------------------------------------------*/
4585
4586#if( configUSE_TASK_NOTIFICATIONS == 1 )
4587
4588 BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )
4589 {
4590 TCB_t * pxTCB;
4591 uint8_t ucOriginalNotifyState;
4592 BaseType_t xReturn = pdPASS;
4593 UBaseType_t uxSavedInterruptStatus;
4594
4595 configASSERT( xTaskToNotify );
4596
4597 /* RTOS ports that support interrupt nesting have the concept of a
4598 maximum system call (or maximum API call) interrupt priority.
4599 Interrupts that are above the maximum system call priority are keep
4600 permanently enabled, even when the RTOS kernel is in a critical section,
4601 but cannot make any calls to FreeRTOS API functions. If configASSERT()
4602 is defined in FreeRTOSConfig.h then
4603 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
4604 failure if a FreeRTOS API function is called from an interrupt that has
4605 been assigned a priority above the configured maximum system call
4606 priority. Only FreeRTOS functions that end in FromISR can be called
4607 from interrupts that have been assigned a priority at or (logically)
4608 below the maximum system call interrupt priority. FreeRTOS maintains a
4609 separate interrupt safe API to ensure interrupt entry is as fast and as
4610 simple as possible. More information (albeit Cortex-M specific) is
4611 provided on the following link:
4612 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
4613 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
4614
4615 pxTCB = ( TCB_t * ) xTaskToNotify;
4616
4617 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
4618 {
4619 if( pulPreviousNotificationValue != NULL )
4620 {
4621 *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
4622 }
4623
4624 ucOriginalNotifyState = pxTCB->ucNotifyState;
4625 pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
4626
4627 switch( eAction )
4628 {
4629 case eSetBits :
4630 pxTCB->ulNotifiedValue |= ulValue;
4631 break;
4632
4633 case eIncrement :
4634 ( pxTCB->ulNotifiedValue )++;
4635 break;
4636
4637 case eSetValueWithOverwrite :
4638 pxTCB->ulNotifiedValue = ulValue;
4639 break;
4640
4641 case eSetValueWithoutOverwrite :
4642 if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
4643 {
4644 pxTCB->ulNotifiedValue = ulValue;
4645 }
4646 else
4647 {
4648 /* The value could not be written to the task. */
4649 xReturn = pdFAIL;
4650 }
4651 break;
4652
4653 case eNoAction :
4654 /* The task is being notified without its notify value being
4655 updated. */
4656 break;
4657 }
4658
4659 traceTASK_NOTIFY_FROM_ISR();
4660
4661 /* If the task is in the blocked state specifically to wait for a
4662 notification then unblock it now. */
4663 if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
4664 {
4665 /* The task should not have been on an event list. */
4666 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4667
4668 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
4669 {
4670 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
4671 prvAddTaskToReadyList( pxTCB );
4672 }
4673 else
4674 {
4675 /* The delayed and ready lists cannot be accessed, so hold
4676 this task pending until the scheduler is resumed. */
4677 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
4678 }
4679
4680 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
4681 {
4682 /* The notified task has a priority above the currently
4683 executing task so a yield is required. */
4684 if( pxHigherPriorityTaskWoken != NULL )
4685 {
4686 *pxHigherPriorityTaskWoken = pdTRUE;
4687 }
4688 else
4689 {
4690 /* Mark that a yield is pending in case the user is not
4691 using the "xHigherPriorityTaskWoken" parameter to an ISR
4692 safe FreeRTOS function. */
4693 xYieldPending = pdTRUE;
4694 }
4695 }
4696 else
4697 {
4698 mtCOVERAGE_TEST_MARKER();
4699 }
4700 }
4701 }
4702 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
4703
4704 return xReturn;
4705 }
4706
4707#endif /* configUSE_TASK_NOTIFICATIONS */
4708/*-----------------------------------------------------------*/
4709
4710#if( configUSE_TASK_NOTIFICATIONS == 1 )
4711
4712 void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken )
4713 {
4714 TCB_t * pxTCB;
4715 uint8_t ucOriginalNotifyState;
4716 UBaseType_t uxSavedInterruptStatus;
4717
4718 configASSERT( xTaskToNotify );
4719
4720 /* RTOS ports that support interrupt nesting have the concept of a
4721 maximum system call (or maximum API call) interrupt priority.
4722 Interrupts that are above the maximum system call priority are keep
4723 permanently enabled, even when the RTOS kernel is in a critical section,
4724 but cannot make any calls to FreeRTOS API functions. If configASSERT()
4725 is defined in FreeRTOSConfig.h then
4726 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
4727 failure if a FreeRTOS API function is called from an interrupt that has
4728 been assigned a priority above the configured maximum system call
4729 priority. Only FreeRTOS functions that end in FromISR can be called
4730 from interrupts that have been assigned a priority at or (logically)
4731 below the maximum system call interrupt priority. FreeRTOS maintains a
4732 separate interrupt safe API to ensure interrupt entry is as fast and as
4733 simple as possible. More information (albeit Cortex-M specific) is
4734 provided on the following link:
4735 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
4736 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
4737
4738 pxTCB = ( TCB_t * ) xTaskToNotify;
4739
4740 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
4741 {
4742 ucOriginalNotifyState = pxTCB->ucNotifyState;
4743 pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
4744
4745 /* 'Giving' is equivalent to incrementing a count in a counting
4746 semaphore. */
4747 ( pxTCB->ulNotifiedValue )++;
4748
4749 traceTASK_NOTIFY_GIVE_FROM_ISR();
4750
4751 /* If the task is in the blocked state specifically to wait for a
4752 notification then unblock it now. */
4753 if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
4754 {
4755 /* The task should not have been on an event list. */
4756 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
4757
4758 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
4759 {
4760 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
4761 prvAddTaskToReadyList( pxTCB );
4762 }
4763 else
4764 {
4765 /* The delayed and ready lists cannot be accessed, so hold
4766 this task pending until the scheduler is resumed. */
4767 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
4768 }
4769
4770 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
4771 {
4772 /* The notified task has a priority above the currently
4773 executing task so a yield is required. */
4774 if( pxHigherPriorityTaskWoken != NULL )
4775 {
4776 *pxHigherPriorityTaskWoken = pdTRUE;
4777 }
4778 else
4779 {
4780 /* Mark that a yield is pending in case the user is not
4781 using the "xHigherPriorityTaskWoken" parameter in an ISR
4782 safe FreeRTOS function. */
4783 xYieldPending = pdTRUE;
4784 }
4785 }
4786 else
4787 {
4788 mtCOVERAGE_TEST_MARKER();
4789 }
4790 }
4791 }
4792 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
4793 }
4794
4795#endif /* configUSE_TASK_NOTIFICATIONS */
4796
4797/*-----------------------------------------------------------*/
4798
4799#if( configUSE_TASK_NOTIFICATIONS == 1 )
4800
4801 BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask )
4802 {
4803 TCB_t *pxTCB;
4804 BaseType_t xReturn;
4805
4806 /* If null is passed in here then it is the calling task that is having
4807 its notification state cleared. */
4808 pxTCB = prvGetTCBFromHandle( xTask );
4809
4810 taskENTER_CRITICAL();
4811 {
4812 if( pxTCB->ucNotifyState == taskNOTIFICATION_RECEIVED )
4813 {
4814 pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
4815 xReturn = pdPASS;
4816 }
4817 else
4818 {
4819 xReturn = pdFAIL;
4820 }
4821 }
4822 taskEXIT_CRITICAL();
4823
4824 return xReturn;
4825 }
4826
4827#endif /* configUSE_TASK_NOTIFICATIONS */
4828/*-----------------------------------------------------------*/
4829
4830
4831static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely )
4832{
4833TickType_t xTimeToWake;
4834const TickType_t xConstTickCount = xTickCount;
4835
4836 #if( INCLUDE_xTaskAbortDelay == 1 )
4837 {
4838 /* About to enter a delayed list, so ensure the ucDelayAborted flag is
4839 reset to pdFALSE so it can be detected as having been set to pdTRUE
4840 when the task leaves the Blocked state. */
4841 pxCurrentTCB->ucDelayAborted = pdFALSE;
4842 }
4843 #endif
4844
4845 /* Remove the task from the ready list before adding it to the blocked list
4846 as the same list item is used for both lists. */
4847 if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
4848 {
4849 /* The current task must be in a ready list, so there is no need to
4850 check, and the port reset macro can be called directly. */
4851 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
4852 }
4853 else
4854 {
4855 mtCOVERAGE_TEST_MARKER();
4856 }
4857
4858 #if ( INCLUDE_vTaskSuspend == 1 )
4859 {
4860 if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
4861 {
4862 /* Add the task to the suspended task list instead of a delayed task
4863 list to ensure it is not woken by a timing event. It will block
4864 indefinitely. */
4865 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
4866 }
4867 else
4868 {
4869 /* Calculate the time at which the task should be woken if the event
4870 does not occur. This may overflow but this doesn't matter, the
4871 kernel will manage it correctly. */
4872 xTimeToWake = xConstTickCount + xTicksToWait;
4873
4874 /* The list item will be inserted in wake time order. */
4875 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
4876
4877 if( xTimeToWake < xConstTickCount )
4878 {
4879 /* Wake time has overflowed. Place this item in the overflow
4880 list. */
4881 vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
4882 }
4883 else
4884 {
4885 /* The wake time has not overflowed, so the current block list
4886 is used. */
4887 vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
4888
4889 /* If the task entering the blocked state was placed at the
4890 head of the list of blocked tasks then xNextTaskUnblockTime
4891 needs to be updated too. */
4892 if( xTimeToWake < xNextTaskUnblockTime )
4893 {
4894 xNextTaskUnblockTime = xTimeToWake;
4895 }
4896 else
4897 {
4898 mtCOVERAGE_TEST_MARKER();
4899 }
4900 }
4901 }
4902 }
4903 #else /* INCLUDE_vTaskSuspend */
4904 {
4905 /* Calculate the time at which the task should be woken if the event
4906 does not occur. This may overflow but this doesn't matter, the kernel
4907 will manage it correctly. */
4908 xTimeToWake = xConstTickCount + xTicksToWait;
4909
4910 /* The list item will be inserted in wake time order. */
4911 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
4912
4913 if( xTimeToWake < xConstTickCount )
4914 {
4915 /* Wake time has overflowed. Place this item in the overflow list. */
4916 vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
4917 }
4918 else
4919 {
4920 /* The wake time has not overflowed, so the current block list is used. */
4921 vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
4922
4923 /* If the task entering the blocked state was placed at the head of the
4924 list of blocked tasks then xNextTaskUnblockTime needs to be updated
4925 too. */
4926 if( xTimeToWake < xNextTaskUnblockTime )
4927 {
4928 xNextTaskUnblockTime = xTimeToWake;
4929 }
4930 else
4931 {
4932 mtCOVERAGE_TEST_MARKER();
4933 }
4934 }
4935
4936 /* Avoid compiler warning when INCLUDE_vTaskSuspend is not 1. */
4937 ( void ) xCanBlockIndefinitely;
4938 }
4939 #endif /* INCLUDE_vTaskSuspend */
4940}
4941
4942
4943#ifdef FREERTOS_MODULE_TEST
4944 #include "tasks_test_access_functions.h"
4945#endif