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