]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/tasks.c
Added portASSERT_IF_INTERRUPT_PRIORITY_INVALID() implementation to Cortex-M3 and...
[freertos] / FreeRTOS / Source / tasks.c
1 /*\r
2     FreeRTOS V7.4.2 - Copyright (C) 2013 Real Time Engineers Ltd.\r
3 \r
4     FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME.  PLEASE VISIT\r
5     http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     ***************************************************************************\r
8      *                                                                       *\r
9      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
10      *    Complete, revised, and edited pdf reference manuals are also       *\r
11      *    available.                                                         *\r
12      *                                                                       *\r
13      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
14      *    ensuring you get running as quickly as possible and with an        *\r
15      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
16      *    the FreeRTOS project to continue with its mission of providing     *\r
17      *    professional grade, cross platform, de facto standard solutions    *\r
18      *    for microcontrollers - completely free of charge!                  *\r
19      *                                                                       *\r
20      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
21      *                                                                       *\r
22      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
23      *                                                                       *\r
24     ***************************************************************************\r
25 \r
26 \r
27     This file is part of the FreeRTOS distribution.\r
28 \r
29     FreeRTOS is free software; you can redistribute it and/or modify it under\r
30     the terms of the GNU General Public License (version 2) as published by the\r
31     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
32 \r
33     >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to\r
34     distribute a combined work that includes FreeRTOS without being obliged to\r
35     provide the source code for proprietary components outside of the FreeRTOS\r
36     kernel.\r
37 \r
38     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
39     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
40     FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\r
41     details. You should have received a copy of the GNU General Public License\r
42     and the FreeRTOS license exception along with FreeRTOS; if not it can be\r
43     viewed here: http://www.freertos.org/a00114.html and also obtained by\r
44     writing to Real Time Engineers Ltd., contact details for whom are available\r
45     on the FreeRTOS WEB site.\r
46 \r
47     1 tab == 4 spaces!\r
48 \r
49     ***************************************************************************\r
50      *                                                                       *\r
51      *    Having a problem?  Start by reading the FAQ "My application does   *\r
52      *    not run, what could be wrong?"                                     *\r
53      *                                                                       *\r
54      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
55      *                                                                       *\r
56     ***************************************************************************\r
57 \r
58 \r
59     http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
60     license and Real Time Engineers Ltd. contact details.\r
61 \r
62     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
63     including FreeRTOS+Trace - an indispensable productivity tool, and our new\r
64     fully thread aware and reentrant UDP/IP stack.\r
65 \r
66     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
67     Integrity Systems, who sell the code with commercial support,\r
68     indemnification and middleware, under the OpenRTOS brand.\r
69 \r
70     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
71     engineered and independently SIL3 certified version for use in safety and\r
72     mission critical applications that require provable dependability.\r
73 */\r
74 \r
75 /* Standard includes. */\r
76 #include <stdio.h>\r
77 #include <stdlib.h>\r
78 #include <string.h>\r
79 \r
80 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
81 all the API functions to use the MPU wrappers.  That should only be done when\r
82 task.h is included from an application file. */\r
83 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
84 \r
85 /* FreeRTOS includes. */\r
86 #include "FreeRTOS.h"\r
87 #include "task.h"\r
88 #include "timers.h"\r
89 #include "StackMacros.h"\r
90 \r
91 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
92 \r
93 /* Sanity check the configuration. */\r
94 #if configUSE_TICKLESS_IDLE != 0\r
95         #if INCLUDE_vTaskSuspend != 1\r
96                 #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0\r
97         #endif /* INCLUDE_vTaskSuspend */\r
98 #endif /* configUSE_TICKLESS_IDLE */\r
99 \r
100 /*\r
101  * Defines the size, in words, of the stack allocated to the idle task.\r
102  */\r
103 #define tskIDLE_STACK_SIZE      configMINIMAL_STACK_SIZE\r
104 \r
105 /*\r
106  * Task control block.  A task control block (TCB) is allocated for each task,\r
107  * and stores task state information, including a pointer to the task's context\r
108  * (the task's run time environment, including register values)\r
109  */\r
110 typedef struct tskTaskControlBlock\r
111 {\r
112         volatile portSTACK_TYPE *pxTopOfStack;          /*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */\r
113 \r
114         #if ( portUSING_MPU_WRAPPERS == 1 )\r
115                 xMPU_SETTINGS xMPUSettings;                             /*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */\r
116         #endif\r
117 \r
118         xListItem                               xGenericListItem;       /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */\r
119         xListItem                               xEventListItem;         /*< Used to reference a task from an event list. */\r
120         unsigned portBASE_TYPE  uxPriority;                     /*< The priority of the task.  0 is the lowest priority. */\r
121         portSTACK_TYPE                  *pxStack;                       /*< Points to the start of the stack. */\r
122         signed char                             pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */\r
123 \r
124         #if ( portSTACK_GROWTH > 0 )\r
125                 portSTACK_TYPE *pxEndOfStack;                   /*< Points to the end of the stack on architectures where the stack grows up from low memory. */\r
126         #endif\r
127 \r
128         #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
129                 unsigned portBASE_TYPE uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */\r
130         #endif\r
131 \r
132         #if ( configUSE_TRACE_FACILITY == 1 )\r
133                 unsigned portBASE_TYPE  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. */\r
134                 unsigned portBASE_TYPE  uxTaskNumber;   /*< Stores a number specifically for use by third party trace code. */\r
135         #endif\r
136 \r
137         #if ( configUSE_MUTEXES == 1 )\r
138                 unsigned portBASE_TYPE uxBasePriority;  /*< The priority last assigned to the task - used by the priority inheritance mechanism. */\r
139         #endif\r
140 \r
141         #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
142                 pdTASK_HOOK_CODE pxTaskTag;\r
143         #endif\r
144 \r
145         #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
146                 unsigned long ulRunTimeCounter;                 /*< Stores the amount of time the task has spent in the Running state. */\r
147         #endif\r
148 \r
149         #if ( configUSE_NEWLIB_REENTRANT == 1 )\r
150                 /* Allocate a Newlib reent structure that is specific to this task.\r
151                 Note Newlib support has been included by popular demand, but is not\r
152                 used by the FreeRTOS maintainers themselves.  FreeRTOS is not\r
153                 responsible for resulting newlib operation.  User must be familiar with\r
154                 newlib and must provide system-wide implementations of the necessary\r
155                 stubs. Be warned that (at the time of writing) the current newlib design\r
156                 implements a system-wide malloc() that must be provided with locks. */\r
157                 struct _reent xNewLib_reent;\r
158         #endif\r
159 \r
160 } tskTCB;\r
161 \r
162 \r
163 /*\r
164  * Some kernel aware debuggers require the data the debugger needs access to to\r
165  * be global, rather than file scope.\r
166  */\r
167 #ifdef portREMOVE_STATIC_QUALIFIER\r
168         #define static\r
169 #endif\r
170 \r
171 /*lint -e956 */\r
172 PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;\r
173 \r
174 /* Lists for ready and blocked tasks. --------------------*/\r
175 PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */\r
176 PRIVILEGED_DATA static xList xDelayedTaskList1;                                                 /*< Delayed tasks. */\r
177 PRIVILEGED_DATA static xList xDelayedTaskList2;                                                 /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */\r
178 PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ;                             /*< Points to the delayed task list currently being used. */\r
179 PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList;              /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */\r
180 PRIVILEGED_DATA static xList xPendingReadyList;                                                 /*< Tasks that have been readied while the scheduler was suspended.  They will be moved to the ready list when the scheduler is resumed. */\r
181 \r
182 #if ( INCLUDE_vTaskDelete == 1 )\r
183 \r
184         PRIVILEGED_DATA static xList xTasksWaitingTermination;                          /*< Tasks that have been deleted - but the their memory not yet freed. */\r
185         PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0U;\r
186 \r
187 #endif\r
188 \r
189 #if ( INCLUDE_vTaskSuspend == 1 )\r
190 \r
191         PRIVILEGED_DATA static xList xSuspendedTaskList;                                        /*< Tasks that are currently suspended. */\r
192 \r
193 #endif\r
194 \r
195 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )\r
196 \r
197         PRIVILEGED_DATA static xTaskHandle xIdleTaskHandle = NULL;                      /*< Holds the handle of the idle task.  The idle task is created automatically when the scheduler is started. */\r
198 \r
199 #endif\r
200 \r
201 /* File private variables. --------------------------------*/\r
202 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks   = ( unsigned portBASE_TYPE ) 0U;\r
203 PRIVILEGED_DATA static volatile portTickType xTickCount                                                 = ( portTickType ) 0U;\r
204 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority                                 = tskIDLE_PRIORITY;\r
205 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority               = tskIDLE_PRIORITY;\r
206 PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning                  = pdFALSE;\r
207 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended             = ( unsigned portBASE_TYPE ) pdFALSE;\r
208 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxPendedTicks                    = ( unsigned portBASE_TYPE ) 0U;\r
209 PRIVILEGED_DATA static volatile portBASE_TYPE xYieldPending                                             = ( portBASE_TYPE ) pdFALSE;\r
210 PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows                                   = ( portBASE_TYPE ) 0;\r
211 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber                                              = ( unsigned portBASE_TYPE ) 0U;\r
212 PRIVILEGED_DATA static volatile portTickType xNextTaskUnblockTime                               = ( portTickType ) portMAX_DELAY;\r
213 \r
214 #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
215 \r
216         PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL;        /*< Holds the value of a timer/counter the last time a task was switched in. */\r
217         PRIVILEGED_DATA static unsigned long ulTotalRunTime = 0UL;                              /*< Holds the total amount of execution time as defined by the run time counter clock. */\r
218 \r
219 #endif\r
220 \r
221 /* Debugging and trace facilities private variables and macros. ------------*/\r
222 \r
223 /*\r
224  * The value used to fill the stack of a task when the task is created.  This\r
225  * is used purely for checking the high water mark for tasks.\r
226  */\r
227 #define tskSTACK_FILL_BYTE      ( 0xa5U )\r
228 \r
229 /*\r
230  * Macros used by vListTask to indicate which state a task is in.\r
231  */\r
232 #define tskBLOCKED_CHAR         ( ( signed char ) 'B' )\r
233 #define tskREADY_CHAR           ( ( signed char ) 'R' )\r
234 #define tskDELETED_CHAR         ( ( signed char ) 'D' )\r
235 #define tskSUSPENDED_CHAR       ( ( signed char ) 'S' )\r
236 \r
237 /*-----------------------------------------------------------*/\r
238 \r
239 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )\r
240 \r
241         /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is\r
242         performed in a generic way that is not optimised to any particular\r
243         microcontroller architecture. */\r
244 \r
245         /* uxTopReadyPriority holds the priority of the highest priority ready\r
246         state task. */\r
247         #define taskRECORD_READY_PRIORITY( uxPriority )                                                                                                                                         \\r
248         {                                                                                                                                                                                                                                       \\r
249                 if( ( uxPriority ) > uxTopReadyPriority )                                                                                                                                               \\r
250                 {                                                                                                                                                                                                                               \\r
251                         uxTopReadyPriority = ( uxPriority );                                                                                                                                            \\r
252                 }                                                                                                                                                                                                                               \\r
253         } /* taskRECORD_READY_PRIORITY */\r
254 \r
255         /*-----------------------------------------------------------*/\r
256 \r
257         #define taskSELECT_HIGHEST_PRIORITY_TASK()                                                                                                                                                      \\r
258         {                                                                                                                                                                                                                                       \\r
259                 /* Find the highest priority queue that contains ready tasks. */                                                                                                \\r
260                 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )                                                                              \\r
261                 {                                                                                                                                                                                                                               \\r
262                         configASSERT( uxTopReadyPriority );                                                                                                                                                     \\r
263                         --uxTopReadyPriority;                                                                                                                                                                           \\r
264                 }                                                                                                                                                                                                                               \\r
265                                                                                                                                                                                                                                                 \\r
266                 /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of                                                                                \\r
267                 the     same priority get an equal share of the processor time. */                                                                                                      \\r
268                 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );                                              \\r
269         } /* taskSELECT_HIGHEST_PRIORITY_TASK */\r
270 \r
271         /*-----------------------------------------------------------*/\r
272 \r
273         /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as\r
274         they are only required when a port optimised method of task selection is\r
275         being used. */\r
276         #define taskRESET_READY_PRIORITY( uxPriority )\r
277         #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )\r
278 \r
279 #else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */\r
280 \r
281         /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is\r
282         performed in a way that is tailored to the particular microcontroller\r
283         architecture being used. */\r
284 \r
285         /* A port optimised version is provided.  Call the port defined macros. */\r
286         #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )\r
287 \r
288         /*-----------------------------------------------------------*/\r
289 \r
290         #define taskSELECT_HIGHEST_PRIORITY_TASK()                                                                                                              \\r
291         {                                                                                                                                                                                               \\r
292         unsigned portBASE_TYPE uxTopPriority;                                                                                                                   \\r
293                                                                                                                                                                                                         \\r
294                 /* Find the highest priority queue that contains ready tasks. */                                                        \\r
295                 portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );                                                          \\r
296                 configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 );         \\r
297                 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );           \\r
298         } /* taskSELECT_HIGHEST_PRIORITY_TASK() */\r
299 \r
300         /*-----------------------------------------------------------*/\r
301 \r
302         /* A port optimised version is provided, call it only if the TCB being reset\r
303         is being referenced from a ready list.  If it is referenced from a delayed\r
304         or suspended list then it won't be in a ready list. */\r
305         #define taskRESET_READY_PRIORITY( uxPriority )                                                                                                  \\r
306         {                                                                                                                                                                                               \\r
307                 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == 0 )                          \\r
308                 {                                                                                                                                                                                       \\r
309                         portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );                                             \\r
310                 }                                                                                                                                                                                       \\r
311         }\r
312 \r
313 #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */\r
314 \r
315 /*-----------------------------------------------------------*/\r
316 \r
317 /* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick\r
318 count overflows. */\r
319 #define taskSWITCH_DELAYED_LISTS()                                                                                                                                      \\r
320 {                                                                                                                                                                                                       \\r
321         xList *pxTemp;                                                                                                                                                                  \\r
322                                                                                                                                                                                                         \\r
323         /* The delayed tasks list should be empty when the lists are switched. */                                               \\r
324         configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );                                                                             \\r
325                                                                                                                                                                                                         \\r
326         pxTemp = pxDelayedTaskList;                                                                                                                                             \\r
327         pxDelayedTaskList = pxOverflowDelayedTaskList;                                                                                                  \\r
328         pxOverflowDelayedTaskList = pxTemp;                                                                                                                             \\r
329         xNumOfOverflows++;                                                                                                                                                              \\r
330                                                                                                                                                                                                         \\r
331         if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )                                                                                 \\r
332         {                                                                                                                                                                                               \\r
333                 /* The new current delayed list is empty.  Set                                                                                          \\r
334                 xNextTaskUnblockTime to the maximum possible value so it is                                                                     \\r
335                 extremely unlikely that the                                                                                                                                     \\r
336                 if( xTickCount >= xNextTaskUnblockTime ) test will pass until                                                           \\r
337                 there is an item in the delayed list. */                                                                                                        \\r
338                 xNextTaskUnblockTime = portMAX_DELAY;                                                                                                           \\r
339         }                                                                                                                                                                                               \\r
340         else                                                                                                                                                                                    \\r
341         {                                                                                                                                                                                               \\r
342                 /* The new current delayed list is not empty, get the value of                                                          \\r
343                 the item at the head of the delayed list.  This is the time at                                                          \\r
344                 which the task at the head of the delayed list should be removed                                                        \\r
345                 from the Blocked state. */                                                                                                                                      \\r
346                 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );                                          \\r
347                 xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );                         \\r
348         }                                                                                                                                                                                               \\r
349 }\r
350 \r
351 /*-----------------------------------------------------------*/\r
352 \r
353 /*\r
354  * Place the task represented by pxTCB into the appropriate ready list for\r
355  * the task.  It is inserted at the end of the list.\r
356  */\r
357 #define prvAddTaskToReadyList( pxTCB )                                                                                                                                                          \\r
358         traceMOVED_TASK_TO_READY_STATE( pxTCB )                                                                                                                                                 \\r
359         taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );                                                                                                                             \\r
360         vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )\r
361 /*-----------------------------------------------------------*/\r
362 \r
363 /*\r
364  * Several functions take an xTaskHandle parameter that can optionally be NULL,\r
365  * where NULL is used to indicate that the handle of the currently executing\r
366  * task should be used in place of the parameter.  This macro simply checks to\r
367  * see if the parameter is NULL and returns a pointer to the appropriate TCB.\r
368  */\r
369 #define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) )\r
370 \r
371 /* Callback function prototypes. --------------------------*/\r
372 extern void vApplicationStackOverflowHook( xTaskHandle xTask, signed char *pcTaskName );\r
373 extern void vApplicationTickHook( void );\r
374 \r
375 /* File private functions. --------------------------------*/\r
376 \r
377 /*\r
378  * Utility to ready a TCB for a given task.  Mainly just copies the parameters\r
379  * into the TCB structure.\r
380  */\r
381 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;\r
382 \r
383 /*\r
384  * Utility to ready all the lists used by the scheduler.  This is called\r
385  * automatically upon the creation of the first task.\r
386  */\r
387 static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;\r
388 \r
389 /*\r
390  * The idle task, which as all tasks is implemented as a never ending loop.\r
391  * The idle task is automatically created and added to the ready lists upon\r
392  * creation of the first user task.\r
393  *\r
394  * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific\r
395  * language extensions.  The equivalent prototype for this function is:\r
396  *\r
397  * void prvIdleTask( void *pvParameters );\r
398  *\r
399  */\r
400 static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );\r
401 \r
402 /*\r
403  * Utility to free all memory allocated by the scheduler to hold a TCB,\r
404  * including the stack pointed to by the TCB.\r
405  *\r
406  * This does not free memory allocated by the task itself (i.e. memory\r
407  * allocated by calls to pvPortMalloc from within the tasks application code).\r
408  */\r
409 #if ( INCLUDE_vTaskDelete == 1 )\r
410 \r
411         static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;\r
412 \r
413 #endif\r
414 \r
415 /*\r
416  * Used only by the idle task.  This checks to see if anything has been placed\r
417  * in the list of tasks waiting to be deleted.  If so the task is cleaned up\r
418  * and its TCB deleted.\r
419  */\r
420 static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;\r
421 \r
422 /*\r
423  * The currently executing task is entering the Blocked state.  Add the task to\r
424  * either the current or the overflow delayed task list.\r
425  */\r
426 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION;\r
427 \r
428 /*\r
429  * Allocates memory from the heap for a TCB and associated stack.  Checks the\r
430  * allocation was successful.\r
431  */\r
432 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;\r
433 \r
434 /*\r
435  * Fills an xTaskStatusType structure with information on each task that is\r
436  * referenced from the pxList list (which may be a ready list, a delayed list,\r
437  * a suspended list, etc.).\r
438  *\r
439  * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM\r
440  * NORMAL APPLICATION CODE.\r
441  */\r
442 #if ( configUSE_TRACE_FACILITY == 1 )\r
443 \r
444         static unsigned portBASE_TYPE prvListTaskWithinSingleList( xTaskStatusType *pxTaskStatusArray, xList *pxList, eTaskState eState ) PRIVILEGED_FUNCTION;\r
445 \r
446 #endif\r
447 \r
448 /*\r
449  * When a task is created, the stack of the task is filled with a known value.\r
450  * This function determines the 'high water mark' of the task stack by\r
451  * determining how much of the stack remains at the original preset value.\r
452  */\r
453 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )\r
454 \r
455         static unsigned short prvTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;\r
456 \r
457 #endif\r
458 \r
459 /*\r
460  * Return the amount of time, in ticks, that will pass before the kernel will\r
461  * next move a task from the Blocked state to the Running state.\r
462  *\r
463  * This conditional compilation should use inequality to 0, not equality to 1.\r
464  * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user\r
465  * defined low power mode implementations require configUSE_TICKLESS_IDLE to be\r
466  * set to a value other than 1.\r
467  */\r
468 #if ( configUSE_TICKLESS_IDLE != 0 )\r
469 \r
470         static portTickType prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION;\r
471 \r
472 #endif\r
473 \r
474 /*lint +e956 */\r
475 \r
476 signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )\r
477 {\r
478 signed portBASE_TYPE xReturn;\r
479 tskTCB * pxNewTCB;\r
480 \r
481         configASSERT( pxTaskCode );\r
482         configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );\r
483 \r
484         /* Allocate the memory required by the TCB and stack for the new task,\r
485         checking that the allocation was successful. */\r
486         pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );\r
487 \r
488         if( pxNewTCB != NULL )\r
489         {\r
490                 portSTACK_TYPE *pxTopOfStack;\r
491 \r
492                 #if( portUSING_MPU_WRAPPERS == 1 )\r
493                         /* Should the task be created in privileged mode? */\r
494                         portBASE_TYPE xRunPrivileged;\r
495                         if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )\r
496                         {\r
497                                 xRunPrivileged = pdTRUE;\r
498                         }\r
499                         else\r
500                         {\r
501                                 xRunPrivileged = pdFALSE;\r
502                         }\r
503                         uxPriority &= ~portPRIVILEGE_BIT;\r
504                 #endif /* portUSING_MPU_WRAPPERS == 1 */\r
505 \r
506                 /* Calculate the top of stack address.  This depends on whether the\r
507                 stack grows from high memory to low (as per the 80x86) or visa versa.\r
508                 portSTACK_GROWTH is used to make the result positive or negative as\r
509                 required by the port. */\r
510                 #if( portSTACK_GROWTH < 0 )\r
511                 {\r
512                         pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );\r
513                         pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK  ) );\r
514 \r
515                         /* Check the alignment of the calculated top of stack is correct. */\r
516                         configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );\r
517                 }\r
518                 #else /* portSTACK_GROWTH */\r
519                 {\r
520                         pxTopOfStack = pxNewTCB->pxStack;\r
521 \r
522                         /* Check the alignment of the stack buffer is correct. */\r
523                         configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );\r
524 \r
525                         /* If we want to use stack checking on architectures that use\r
526                         a positive stack growth direction then we also need to store the\r
527                         other extreme of the stack space. */\r
528                         pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );\r
529                 }\r
530                 #endif /* portSTACK_GROWTH */\r
531 \r
532                 /* Setup the newly allocated TCB with the initial state of the task. */\r
533                 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );\r
534 \r
535                 /* Initialize the TCB stack to look as if the task was already running,\r
536                 but had been interrupted by the scheduler.  The return address is set\r
537                 to the start of the task function. Once the stack has been initialised\r
538                 the     top of stack variable is updated. */\r
539                 #if( portUSING_MPU_WRAPPERS == 1 )\r
540                 {\r
541                         pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );\r
542                 }\r
543                 #else /* portUSING_MPU_WRAPPERS */\r
544                 {\r
545                         pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );\r
546                 }\r
547                 #endif /* portUSING_MPU_WRAPPERS */\r
548 \r
549                 if( ( void * ) pxCreatedTask != NULL )\r
550                 {\r
551                         /* Pass the TCB out - in an anonymous way.  The calling function/\r
552                         task can use this as a handle to delete the task later if\r
553                         required.*/\r
554                         *pxCreatedTask = ( xTaskHandle ) pxNewTCB;\r
555                 }\r
556 \r
557                 /* Ensure interrupts don't access the task lists while they are being\r
558                 updated. */\r
559                 taskENTER_CRITICAL();\r
560                 {\r
561                         uxCurrentNumberOfTasks++;\r
562                         if( pxCurrentTCB == NULL )\r
563                         {\r
564                                 /* There are no other tasks, or all the other tasks are in\r
565                                 the suspended state - make this the current task. */\r
566                                 pxCurrentTCB =  pxNewTCB;\r
567 \r
568                                 if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )\r
569                                 {\r
570                                         /* This is the first task to be created so do the preliminary\r
571                                         initialisation required.  We will not recover if this call\r
572                                         fails, but we will report the failure. */\r
573                                         prvInitialiseTaskLists();\r
574                                 }\r
575                         }\r
576                         else\r
577                         {\r
578                                 /* If the scheduler is not already running, make this task the\r
579                                 current task if it is the highest priority task to be created\r
580                                 so far. */\r
581                                 if( xSchedulerRunning == pdFALSE )\r
582                                 {\r
583                                         if( pxCurrentTCB->uxPriority <= uxPriority )\r
584                                         {\r
585                                                 pxCurrentTCB = pxNewTCB;\r
586                                         }\r
587                                 }\r
588                         }\r
589 \r
590                         /* Remember the top priority to make context switching faster.  Use\r
591                         the priority in pxNewTCB as this has been capped to a valid value. */\r
592                         if( pxNewTCB->uxPriority > uxTopUsedPriority )\r
593                         {\r
594                                 uxTopUsedPriority = pxNewTCB->uxPriority;\r
595                         }\r
596 \r
597                         uxTaskNumber++;\r
598 \r
599                         #if ( configUSE_TRACE_FACILITY == 1 )\r
600                         {\r
601                                 /* Add a counter into the TCB for tracing only. */\r
602                                 pxNewTCB->uxTCBNumber = uxTaskNumber;\r
603                         }\r
604                         #endif /* configUSE_TRACE_FACILITY */\r
605                         traceTASK_CREATE( pxNewTCB );\r
606 \r
607                         prvAddTaskToReadyList( pxNewTCB );\r
608 \r
609                         xReturn = pdPASS;\r
610                         portSETUP_TCB( pxNewTCB );\r
611                 }\r
612                 taskEXIT_CRITICAL();\r
613         }\r
614         else\r
615         {\r
616                 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;\r
617                 traceTASK_CREATE_FAILED();\r
618         }\r
619 \r
620         if( xReturn == pdPASS )\r
621         {\r
622                 if( xSchedulerRunning != pdFALSE )\r
623                 {\r
624                         /* If the created task is of a higher priority than the current task\r
625                         then it should run now. */\r
626                         if( pxCurrentTCB->uxPriority < uxPriority )\r
627                         {\r
628                                 portYIELD_WITHIN_API();\r
629                         }\r
630                 }\r
631         }\r
632 \r
633         return xReturn;\r
634 }\r
635 /*-----------------------------------------------------------*/\r
636 \r
637 #if ( INCLUDE_vTaskDelete == 1 )\r
638 \r
639         void vTaskDelete( xTaskHandle xTaskToDelete )\r
640         {\r
641         tskTCB *pxTCB;\r
642 \r
643                 taskENTER_CRITICAL();\r
644                 {\r
645                         /* Ensure a yield is performed if the current task is being\r
646                         deleted. */\r
647                         if( xTaskToDelete == pxCurrentTCB )\r
648                         {\r
649                                 xTaskToDelete = NULL;\r
650                         }\r
651 \r
652                         /* If null is passed in here then we are deleting ourselves. */\r
653                         pxTCB = prvGetTCBFromHandle( xTaskToDelete );\r
654 \r
655                         /* Remove task from the ready list and place in the     termination list.\r
656                         This will stop the task from be scheduled.  The idle task will check\r
657                         the termination list and free up any memory allocated by the\r
658                         scheduler for the TCB and stack. */\r
659                         if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )\r
660                         {\r
661                                 taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
662                         }\r
663 \r
664                         /* Is the task waiting on an event also? */\r
665                         if( pxTCB->xEventListItem.pvContainer != NULL )\r
666                         {\r
667                                 uxListRemove( &( pxTCB->xEventListItem ) );\r
668                         }\r
669 \r
670                         vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );\r
671 \r
672                         /* Increment the ucTasksDeleted variable so the idle task knows\r
673                         there is a task that has been deleted and that it should therefore\r
674                         check the xTasksWaitingTermination list. */\r
675                         ++uxTasksDeleted;\r
676 \r
677                         /* Increment the uxTaskNumberVariable also so kernel aware debuggers\r
678                         can detect that the task lists need re-generating. */\r
679                         uxTaskNumber++;\r
680 \r
681                         traceTASK_DELETE( pxTCB );\r
682                 }\r
683                 taskEXIT_CRITICAL();\r
684 \r
685                 /* Force a reschedule if we have just deleted the current task. */\r
686                 if( xSchedulerRunning != pdFALSE )\r
687                 {\r
688                         if( ( void * ) xTaskToDelete == NULL )\r
689                         {\r
690                                 portYIELD_WITHIN_API();\r
691                         }\r
692                 }\r
693         }\r
694 \r
695 #endif /* INCLUDE_vTaskDelete */\r
696 /*-----------------------------------------------------------*/\r
697 \r
698 #if ( INCLUDE_vTaskDelayUntil == 1 )\r
699 \r
700         void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )\r
701         {\r
702         portTickType xTimeToWake;\r
703         portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;\r
704 \r
705                 configASSERT( pxPreviousWakeTime );\r
706                 configASSERT( ( xTimeIncrement > 0U ) );\r
707 \r
708                 vTaskSuspendAll();\r
709                 {\r
710                         /* Generate the tick time at which the task wants to wake. */\r
711                         xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;\r
712 \r
713                         if( xTickCount < *pxPreviousWakeTime )\r
714                         {\r
715                                 /* The tick count has overflowed since this function was\r
716                                 lasted called.  In this case the only time we should ever\r
717                                 actually delay is if the wake time has also     overflowed,\r
718                                 and the wake time is greater than the tick time.  When this\r
719                                 is the case it is as if neither time had overflowed. */\r
720                                 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )\r
721                                 {\r
722                                         xShouldDelay = pdTRUE;\r
723                                 }\r
724                         }\r
725                         else\r
726                         {\r
727                                 /* The tick time has not overflowed.  In this case we will\r
728                                 delay if either the wake time has overflowed, and/or the\r
729                                 tick time is less than the wake time. */\r
730                                 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )\r
731                                 {\r
732                                         xShouldDelay = pdTRUE;\r
733                                 }\r
734                         }\r
735 \r
736                         /* Update the wake time ready for the next call. */\r
737                         *pxPreviousWakeTime = xTimeToWake;\r
738 \r
739                         if( xShouldDelay != pdFALSE )\r
740                         {\r
741                                 traceTASK_DELAY_UNTIL();\r
742 \r
743                                 /* We must remove ourselves from the ready list before adding\r
744                                 ourselves to the blocked list as the same list item is used for\r
745                                 both lists. */\r
746                                 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )\r
747                                 {\r
748                                         /* The current task must be in a ready list, so there is\r
749                                         no need to check, and the port reset macro can be called\r
750                                         directly. */\r
751                                         portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );\r
752                                 }\r
753 \r
754                                 prvAddCurrentTaskToDelayedList( xTimeToWake );\r
755                         }\r
756                 }\r
757                 xAlreadyYielded = xTaskResumeAll();\r
758 \r
759                 /* Force a reschedule if xTaskResumeAll has not already done so, we may\r
760                 have put ourselves to sleep. */\r
761                 if( xAlreadyYielded == pdFALSE )\r
762                 {\r
763                         portYIELD_WITHIN_API();\r
764                 }\r
765         }\r
766 \r
767 #endif /* INCLUDE_vTaskDelayUntil */\r
768 /*-----------------------------------------------------------*/\r
769 \r
770 #if ( INCLUDE_vTaskDelay == 1 )\r
771 \r
772         void vTaskDelay( portTickType xTicksToDelay )\r
773         {\r
774         portTickType xTimeToWake;\r
775         signed portBASE_TYPE xAlreadyYielded = pdFALSE;\r
776 \r
777                 /* A delay time of zero just forces a reschedule. */\r
778                 if( xTicksToDelay > ( portTickType ) 0U )\r
779                 {\r
780                         vTaskSuspendAll();\r
781                         {\r
782                                 traceTASK_DELAY();\r
783 \r
784                                 /* A task that is removed from the event list while the\r
785                                 scheduler is suspended will not get placed in the ready\r
786                                 list or removed from the blocked list until the scheduler\r
787                                 is resumed.\r
788 \r
789                                 This task cannot be in an event list as it is the currently\r
790                                 executing task. */\r
791 \r
792                                 /* Calculate the time to wake - this may overflow but this is\r
793                                 not a problem. */\r
794                                 xTimeToWake = xTickCount + xTicksToDelay;\r
795 \r
796                                 /* We must remove ourselves from the ready list before adding\r
797                                 ourselves to the blocked list as the same list item is used for\r
798                                 both lists. */\r
799                                 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )\r
800                                 {\r
801                                         /* The current task must be in a ready list, so there is\r
802                                         no need to check, and the port reset macro can be called\r
803                                         directly. */\r
804                                         portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );\r
805                                 }\r
806                                 prvAddCurrentTaskToDelayedList( xTimeToWake );\r
807                         }\r
808                         xAlreadyYielded = xTaskResumeAll();\r
809                 }\r
810 \r
811                 /* Force a reschedule if xTaskResumeAll has not already done so, we may\r
812                 have put ourselves to sleep. */\r
813                 if( xAlreadyYielded == pdFALSE )\r
814                 {\r
815                         portYIELD_WITHIN_API();\r
816                 }\r
817         }\r
818 \r
819 #endif /* INCLUDE_vTaskDelay */\r
820 /*-----------------------------------------------------------*/\r
821 \r
822 #if ( INCLUDE_eTaskGetState == 1 )\r
823 \r
824         eTaskState eTaskGetState( xTaskHandle xTask )\r
825         {\r
826         eTaskState eReturn;\r
827         xList *pxStateList;\r
828         tskTCB *pxTCB;\r
829 \r
830                 pxTCB = ( tskTCB * ) xTask;\r
831 \r
832                 if( pxTCB == pxCurrentTCB )\r
833                 {\r
834                         /* The task calling this function is querying its own state. */\r
835                         eReturn = eRunning;\r
836                 }\r
837                 else\r
838                 {\r
839                         taskENTER_CRITICAL();\r
840                         {\r
841                                 pxStateList = ( xList * ) listLIST_ITEM_CONTAINER( &( pxTCB->xGenericListItem ) );\r
842                         }\r
843                         taskEXIT_CRITICAL();\r
844 \r
845                         if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) )\r
846                         {\r
847                                 /* The task being queried is referenced from one of the Blocked\r
848                                 lists. */\r
849                                 eReturn = eBlocked;\r
850                         }\r
851 \r
852                         #if ( INCLUDE_vTaskSuspend == 1 )\r
853                                 else if( pxStateList == &xSuspendedTaskList )\r
854                                 {\r
855                                         /* The task being queried is referenced from the suspended\r
856                                         list. */\r
857                                         eReturn = eSuspended;\r
858                                 }\r
859                         #endif\r
860 \r
861                         #if ( INCLUDE_vTaskDelete == 1 )\r
862                                 else if( pxStateList == &xTasksWaitingTermination )\r
863                                 {\r
864                                         /* The task being queried is referenced from the deleted\r
865                                         tasks list. */\r
866                                         eReturn = eDeleted;\r
867                                 }\r
868                         #endif\r
869 \r
870                         else\r
871                         {\r
872                                 /* If the task is not in any other state, it must be in the\r
873                                 Ready (including pending ready) state. */\r
874                                 eReturn = eReady;\r
875                         }\r
876                 }\r
877 \r
878                 return eReturn;\r
879         }\r
880 \r
881 #endif /* INCLUDE_eTaskGetState */\r
882 /*-----------------------------------------------------------*/\r
883 \r
884 #if ( INCLUDE_uxTaskPriorityGet == 1 )\r
885 \r
886         unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle xTask )\r
887         {\r
888         tskTCB *pxTCB;\r
889         unsigned portBASE_TYPE uxReturn;\r
890 \r
891                 taskENTER_CRITICAL();\r
892                 {\r
893                         /* If null is passed in here then we are changing the\r
894                         priority of the calling function. */\r
895                         pxTCB = prvGetTCBFromHandle( xTask );\r
896                         uxReturn = pxTCB->uxPriority;\r
897                 }\r
898                 taskEXIT_CRITICAL();\r
899 \r
900                 return uxReturn;\r
901         }\r
902 \r
903 #endif /* INCLUDE_uxTaskPriorityGet */\r
904 /*-----------------------------------------------------------*/\r
905 \r
906 #if ( INCLUDE_vTaskPrioritySet == 1 )\r
907 \r
908         void vTaskPrioritySet( xTaskHandle xTask, unsigned portBASE_TYPE uxNewPriority )\r
909         {\r
910         tskTCB *pxTCB;\r
911         unsigned portBASE_TYPE uxCurrentPriority, uxPriorityUsedOnEntry;\r
912         portBASE_TYPE xYieldRequired = pdFALSE;\r
913 \r
914                 configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );\r
915 \r
916                 /* Ensure the new priority is valid. */\r
917                 if( uxNewPriority >= configMAX_PRIORITIES )\r
918                 {\r
919                         uxNewPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;\r
920                 }\r
921 \r
922                 taskENTER_CRITICAL();\r
923                 {\r
924                         if( xTask == ( xTaskHandle ) pxCurrentTCB )\r
925                         {\r
926                                 xTask = NULL;\r
927                         }\r
928 \r
929                         /* If null is passed in here then we are changing the\r
930                         priority of the calling function. */\r
931                         pxTCB = prvGetTCBFromHandle( xTask );\r
932 \r
933                         traceTASK_PRIORITY_SET( pxTCB, uxNewPriority );\r
934 \r
935                         #if ( configUSE_MUTEXES == 1 )\r
936                         {\r
937                                 uxCurrentPriority = pxTCB->uxBasePriority;\r
938                         }\r
939                         #else\r
940                         {\r
941                                 uxCurrentPriority = pxTCB->uxPriority;\r
942                         }\r
943                         #endif\r
944 \r
945                         if( uxCurrentPriority != uxNewPriority )\r
946                         {\r
947                                 /* The priority change may have readied a task of higher\r
948                                 priority than the calling task. */\r
949                                 if( uxNewPriority > uxCurrentPriority )\r
950                                 {\r
951                                         if( xTask != NULL )\r
952                                         {\r
953                                                 /* The priority of another task is being raised.  If we\r
954                                                 were raising the priority of the currently running task\r
955                                                 there would be no need to switch as it must have already\r
956                                                 been the highest priority task. */\r
957                                                 xYieldRequired = pdTRUE;\r
958                                         }\r
959                                 }\r
960                                 else if( xTask == NULL )\r
961                                 {\r
962                                         /* Setting our own priority down means there may now be another\r
963                                         task of higher priority that is ready to execute. */\r
964                                         xYieldRequired = pdTRUE;\r
965                                 }\r
966 \r
967                                 /* Remember the ready list the task might be referenced from\r
968                                 before its uxPriority member is changed so the\r
969                                 taskRESET_READY_PRIORITY() macro can function correctly. */\r
970                                 uxPriorityUsedOnEntry = pxTCB->uxPriority;\r
971 \r
972                                 #if ( configUSE_MUTEXES == 1 )\r
973                                 {\r
974                                         /* Only change the priority being used if the task is not\r
975                                         currently using an inherited priority. */\r
976                                         if( pxTCB->uxBasePriority == pxTCB->uxPriority )\r
977                                         {\r
978                                                 pxTCB->uxPriority = uxNewPriority;\r
979                                         }\r
980 \r
981                                         /* The base priority gets set whatever. */\r
982                                         pxTCB->uxBasePriority = uxNewPriority;\r
983                                 }\r
984                                 #else\r
985                                 {\r
986                                         pxTCB->uxPriority = uxNewPriority;\r
987                                 }\r
988                                 #endif\r
989 \r
990                                 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );\r
991 \r
992                                 /* If the task is in the blocked or suspended list we need do\r
993                                 nothing more than change it's priority variable. However, if\r
994                                 the task is in a ready list it needs to be removed and placed\r
995                                 in the queue appropriate to its new priority. */\r
996                                 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )\r
997                                 {\r
998                                         /* The task is currently in its ready list - remove before adding\r
999                                         it to it's new ready list.  As we are in a critical section we\r
1000                                         can do this even if the scheduler is suspended. */\r
1001                                         if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )\r
1002                                         {\r
1003                                                 taskRESET_READY_PRIORITY( uxPriorityUsedOnEntry );\r
1004                                         }\r
1005                                         prvAddTaskToReadyList( pxTCB );\r
1006                                 }\r
1007 \r
1008                                 if( xYieldRequired == pdTRUE )\r
1009                                 {\r
1010                                         portYIELD_WITHIN_API();\r
1011                                 }\r
1012 \r
1013                                 /* Remove compiler warning about unused variables when the port\r
1014                                 optimised task selection is not being used. */\r
1015                                 ( void ) uxPriorityUsedOnEntry;\r
1016                         }\r
1017                 }\r
1018                 taskEXIT_CRITICAL();\r
1019         }\r
1020 \r
1021 #endif /* INCLUDE_vTaskPrioritySet */\r
1022 /*-----------------------------------------------------------*/\r
1023 \r
1024 #if ( INCLUDE_vTaskSuspend == 1 )\r
1025 \r
1026         void vTaskSuspend( xTaskHandle xTaskToSuspend )\r
1027         {\r
1028         tskTCB *pxTCB;\r
1029 \r
1030                 taskENTER_CRITICAL();\r
1031                 {\r
1032                         /* Ensure a yield is performed if the current task is being\r
1033                         suspended. */\r
1034                         if( xTaskToSuspend == ( xTaskHandle ) pxCurrentTCB )\r
1035                         {\r
1036                                 xTaskToSuspend = NULL;\r
1037                         }\r
1038 \r
1039                         /* If null is passed in here then we are suspending ourselves. */\r
1040                         pxTCB = prvGetTCBFromHandle( xTaskToSuspend );\r
1041 \r
1042                         traceTASK_SUSPEND( pxTCB );\r
1043 \r
1044                         /* Remove task from the ready/delayed list and place in the     suspended list. */\r
1045                         if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )\r
1046                         {\r
1047                                 taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
1048                         }\r
1049 \r
1050                         /* Is the task waiting on an event also? */\r
1051                         if( pxTCB->xEventListItem.pvContainer != NULL )\r
1052                         {\r
1053                                 uxListRemove( &( pxTCB->xEventListItem ) );\r
1054                         }\r
1055 \r
1056                         vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );\r
1057                 }\r
1058                 taskEXIT_CRITICAL();\r
1059 \r
1060                 if( ( void * ) xTaskToSuspend == NULL )\r
1061                 {\r
1062                         if( xSchedulerRunning != pdFALSE )\r
1063                         {\r
1064                                 /* We have just suspended the current task. */\r
1065                                 portYIELD_WITHIN_API();\r
1066                         }\r
1067                         else\r
1068                         {\r
1069                                 /* The scheduler is not running, but the task that was pointed\r
1070                                 to by pxCurrentTCB has just been suspended and pxCurrentTCB\r
1071                                 must be adjusted to point to a different task. */\r
1072                                 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )\r
1073                                 {\r
1074                                         /* No other tasks are ready, so set pxCurrentTCB back to\r
1075                                         NULL so when the next task is created pxCurrentTCB will\r
1076                                         be set to point to it no matter what its relative priority\r
1077                                         is. */\r
1078                                         pxCurrentTCB = NULL;\r
1079                                 }\r
1080                                 else\r
1081                                 {\r
1082                                         vTaskSwitchContext();\r
1083                                 }\r
1084                         }\r
1085                 }\r
1086         }\r
1087 \r
1088 #endif /* INCLUDE_vTaskSuspend */\r
1089 /*-----------------------------------------------------------*/\r
1090 \r
1091 #if ( INCLUDE_vTaskSuspend == 1 )\r
1092 \r
1093         signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )\r
1094         {\r
1095         portBASE_TYPE xReturn = pdFALSE;\r
1096         const tskTCB * const pxTCB = ( tskTCB * ) xTask;\r
1097 \r
1098                 /* It does not make sense to check if the calling task is suspended. */\r
1099                 configASSERT( xTask );\r
1100 \r
1101                 /* Is the task we are attempting to resume actually in the\r
1102                 suspended list? */\r
1103                 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )\r
1104                 {\r
1105                         /* Has the task already been resumed from within an ISR? */\r
1106                         if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )\r
1107                         {\r
1108                                 /* Is it in the suspended list because it is in the\r
1109                                 Suspended state?  It is possible to be in the suspended\r
1110                                 list because it is blocked on a task with no timeout\r
1111                                 specified. */\r
1112                                 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )\r
1113                                 {\r
1114                                         xReturn = pdTRUE;\r
1115                                 }\r
1116                         }\r
1117                 }\r
1118 \r
1119                 return xReturn;\r
1120         }\r
1121 \r
1122 #endif /* INCLUDE_vTaskSuspend */\r
1123 /*-----------------------------------------------------------*/\r
1124 \r
1125 #if ( INCLUDE_vTaskSuspend == 1 )\r
1126 \r
1127         void vTaskResume( xTaskHandle xTaskToResume )\r
1128         {\r
1129         tskTCB *pxTCB;\r
1130 \r
1131                 /* It does not make sense to resume the calling task. */\r
1132                 configASSERT( xTaskToResume );\r
1133 \r
1134                 /* Remove the task from whichever list it is currently in, and place\r
1135                 it in the ready list. */\r
1136                 pxTCB = ( tskTCB * ) xTaskToResume;\r
1137 \r
1138                 /* The parameter cannot be NULL as it is impossible to resume the\r
1139                 currently executing task. */\r
1140                 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )\r
1141                 {\r
1142                         taskENTER_CRITICAL();\r
1143                         {\r
1144                                 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )\r
1145                                 {\r
1146                                         traceTASK_RESUME( pxTCB );\r
1147 \r
1148                                         /* As we are in a critical section we can access the ready\r
1149                                         lists even if the scheduler is suspended. */\r
1150                                         uxListRemove(  &( pxTCB->xGenericListItem ) );\r
1151                                         prvAddTaskToReadyList( pxTCB );\r
1152 \r
1153                                         /* We may have just resumed a higher priority task. */\r
1154                                         if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
1155                                         {\r
1156                                                 /* This yield may not cause the task just resumed to run, but\r
1157                                                 will leave the lists in the correct state for the next yield. */\r
1158                                                 portYIELD_WITHIN_API();\r
1159                                         }\r
1160                                 }\r
1161                         }\r
1162                         taskEXIT_CRITICAL();\r
1163                 }\r
1164         }\r
1165 \r
1166 #endif /* INCLUDE_vTaskSuspend */\r
1167 \r
1168 /*-----------------------------------------------------------*/\r
1169 \r
1170 #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )\r
1171 \r
1172         portBASE_TYPE xTaskResumeFromISR( xTaskHandle xTaskToResume )\r
1173         {\r
1174         portBASE_TYPE xYieldRequired = pdFALSE;\r
1175         tskTCB *pxTCB;\r
1176         unsigned portBASE_TYPE uxSavedInterruptStatus;\r
1177 \r
1178                 configASSERT( xTaskToResume );\r
1179                 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();\r
1180 \r
1181                 pxTCB = ( tskTCB * ) xTaskToResume;\r
1182 \r
1183                 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
1184                 {\r
1185                         if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )\r
1186                         {\r
1187                                 traceTASK_RESUME_FROM_ISR( pxTCB );\r
1188 \r
1189                                 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1190                                 {\r
1191                                         xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );\r
1192                                         uxListRemove(  &( pxTCB->xGenericListItem ) );\r
1193                                         prvAddTaskToReadyList( pxTCB );\r
1194                                 }\r
1195                                 else\r
1196                                 {\r
1197                                         /* We cannot access the delayed or ready lists, so will hold this\r
1198                                         task pending until the scheduler is resumed, at which point a\r
1199                                         yield will be performed if necessary. */\r
1200                                         vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );\r
1201                                 }\r
1202                         }\r
1203                 }\r
1204                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1205 \r
1206                 return xYieldRequired;\r
1207         }\r
1208 \r
1209 #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */\r
1210 /*-----------------------------------------------------------*/\r
1211 \r
1212 void vTaskStartScheduler( void )\r
1213 {\r
1214 portBASE_TYPE xReturn;\r
1215 \r
1216         /* Add the idle task at the lowest priority. */\r
1217         #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )\r
1218         {\r
1219                 /* Create the idle task, storing its handle in xIdleTaskHandle so it can\r
1220                 be returned by the xTaskGetIdleTaskHandle() function. */\r
1221                 xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle );\r
1222         }\r
1223         #else\r
1224         {\r
1225                 /* Create the idle task without storing its handle. */\r
1226                 xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL );\r
1227         }\r
1228         #endif /* INCLUDE_xTaskGetIdleTaskHandle */\r
1229 \r
1230         #if ( configUSE_TIMERS == 1 )\r
1231         {\r
1232                 if( xReturn == pdPASS )\r
1233                 {\r
1234                         xReturn = xTimerCreateTimerTask();\r
1235                 }\r
1236         }\r
1237         #endif /* configUSE_TIMERS */\r
1238 \r
1239         if( xReturn == pdPASS )\r
1240         {\r
1241                 /* Interrupts are turned off here, to ensure a tick does not occur\r
1242                 before or during the call to xPortStartScheduler().  The stacks of\r
1243                 the created tasks contain a status word with interrupts switched on\r
1244                 so interrupts will automatically get re-enabled when the first task\r
1245                 starts to run.\r
1246 \r
1247                 STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE\r
1248                 DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */\r
1249                 portDISABLE_INTERRUPTS();\r
1250 \r
1251                 xSchedulerRunning = pdTRUE;\r
1252                 xTickCount = ( portTickType ) 0U;\r
1253 \r
1254                 /* If configGENERATE_RUN_TIME_STATS is defined then the following\r
1255                 macro must be defined to configure the timer/counter used to generate\r
1256                 the run time counter time base. */\r
1257                 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();\r
1258 \r
1259                 /* Setting up the timer tick is hardware specific and thus in the\r
1260                 portable interface. */\r
1261                 if( xPortStartScheduler() != pdFALSE )\r
1262                 {\r
1263                         /* Should not reach here as if the scheduler is running the\r
1264                         function will not return. */\r
1265                 }\r
1266                 else\r
1267                 {\r
1268                         /* Should only reach here if a task calls xTaskEndScheduler(). */\r
1269                 }\r
1270         }\r
1271         else\r
1272         {\r
1273                 /* This line will only be reached if the kernel could not be started,\r
1274                 because there was not enough FreeRTOS heap to create the idle task\r
1275                 or the timer task. */\r
1276                 configASSERT( xReturn );\r
1277         }\r
1278 }\r
1279 /*-----------------------------------------------------------*/\r
1280 \r
1281 void vTaskEndScheduler( void )\r
1282 {\r
1283         /* Stop the scheduler interrupts and call the portable scheduler end\r
1284         routine so the original ISRs can be restored if necessary.  The port\r
1285         layer must ensure interrupts enable     bit is left in the correct state. */\r
1286         portDISABLE_INTERRUPTS();\r
1287         xSchedulerRunning = pdFALSE;\r
1288         vPortEndScheduler();\r
1289 }\r
1290 /*----------------------------------------------------------*/\r
1291 \r
1292 void vTaskSuspendAll( void )\r
1293 {\r
1294         /* A critical section is not required as the variable is of type\r
1295         portBASE_TYPE. */\r
1296         ++uxSchedulerSuspended;\r
1297 }\r
1298 /*----------------------------------------------------------*/\r
1299 \r
1300 #if ( configUSE_TICKLESS_IDLE != 0 )\r
1301 \r
1302         static portTickType prvGetExpectedIdleTime( void )\r
1303         {\r
1304         portTickType xReturn;\r
1305 \r
1306                 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )\r
1307                 {\r
1308                         xReturn = 0;\r
1309                 }\r
1310                 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )\r
1311                 {\r
1312                         /* There are other idle priority tasks in the ready state.  If\r
1313                         time slicing is used then the very next tick interrupt must be\r
1314                         processed. */\r
1315                         xReturn = 0;\r
1316                 }\r
1317                 else\r
1318                 {\r
1319                         xReturn = xNextTaskUnblockTime - xTickCount;\r
1320                 }\r
1321 \r
1322                 return xReturn;\r
1323         }\r
1324 \r
1325 #endif /* configUSE_TICKLESS_IDLE */\r
1326 /*----------------------------------------------------------*/\r
1327 \r
1328 signed portBASE_TYPE xTaskResumeAll( void )\r
1329 {\r
1330 register tskTCB *pxTCB;\r
1331 signed portBASE_TYPE xAlreadyYielded = pdFALSE;\r
1332 portBASE_TYPE xYieldRequired = pdFALSE;\r
1333 \r
1334         /* If uxSchedulerSuspended is zero then this function does not match a\r
1335         previous call to vTaskSuspendAll(). */\r
1336         configASSERT( uxSchedulerSuspended );\r
1337 \r
1338         /* It is possible that an ISR caused a task to be removed from an event\r
1339         list while the scheduler was suspended.  If this was the case then the\r
1340         removed task will have been added to the xPendingReadyList.  Once the\r
1341         scheduler has been resumed it is safe to move all the pending ready\r
1342         tasks from this list into their appropriate ready list. */\r
1343         taskENTER_CRITICAL();\r
1344         {\r
1345                 --uxSchedulerSuspended;\r
1346 \r
1347                 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1348                 {\r
1349                         if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0U )\r
1350                         {\r
1351                                 /* Move any readied tasks from the pending list into the\r
1352                                 appropriate ready list. */\r
1353                                 while( listLIST_IS_EMPTY( ( xList * ) &xPendingReadyList ) == pdFALSE )\r
1354                                 {\r
1355                                         pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY(  ( ( xList * ) &xPendingReadyList ) );\r
1356                                         uxListRemove( &( pxTCB->xEventListItem ) );\r
1357                                         uxListRemove( &( pxTCB->xGenericListItem ) );\r
1358                                         prvAddTaskToReadyList( pxTCB );\r
1359 \r
1360                                         /* If we have moved a task that has a priority higher than\r
1361                                         the current task then we should yield. */\r
1362                                         if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
1363                                         {\r
1364                                                 xYieldRequired = pdTRUE;\r
1365                                         }\r
1366                                 }\r
1367 \r
1368                                 /* If any ticks occurred while the scheduler was suspended then\r
1369                                 they should be processed now.  This ensures the tick count does not\r
1370                                 slip, and that any delayed tasks are resumed at the correct time. */\r
1371                                 if( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U )\r
1372                                 {\r
1373                                         while( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U )\r
1374                                         {\r
1375                                                 if( xTaskIncrementTick() != pdFALSE )\r
1376                                                 {\r
1377                                                         xYieldRequired = pdTRUE;\r
1378                                                 }\r
1379                                                 --uxPendedTicks;\r
1380                                         }\r
1381                                 }\r
1382 \r
1383                                 if( ( xYieldRequired == pdTRUE ) || ( xYieldPending == pdTRUE ) )\r
1384                                 {\r
1385                                         xAlreadyYielded = pdTRUE;\r
1386                                         xYieldPending = pdFALSE;\r
1387                                         portYIELD_WITHIN_API();\r
1388                                 }\r
1389                         }\r
1390                 }\r
1391         }\r
1392         taskEXIT_CRITICAL();\r
1393 \r
1394         return xAlreadyYielded;\r
1395 }\r
1396 /*-----------------------------------------------------------*/\r
1397 \r
1398 portTickType xTaskGetTickCount( void )\r
1399 {\r
1400 portTickType xTicks;\r
1401 \r
1402         /* Critical section required if running on a 16 bit processor. */\r
1403         taskENTER_CRITICAL();\r
1404         {\r
1405                 xTicks = xTickCount;\r
1406         }\r
1407         taskEXIT_CRITICAL();\r
1408 \r
1409         return xTicks;\r
1410 }\r
1411 /*-----------------------------------------------------------*/\r
1412 \r
1413 portTickType xTaskGetTickCountFromISR( void )\r
1414 {\r
1415 portTickType xReturn;\r
1416 unsigned portBASE_TYPE uxSavedInterruptStatus;\r
1417 \r
1418         portASSERT_IF_INTERRUPT_PRIORITY_INVALID();\r
1419         \r
1420         uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
1421         xReturn = xTickCount;\r
1422         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1423 \r
1424         return xReturn;\r
1425 }\r
1426 /*-----------------------------------------------------------*/\r
1427 \r
1428 unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )\r
1429 {\r
1430         /* A critical section is not required because the variables are of type\r
1431         portBASE_TYPE. */\r
1432         return uxCurrentNumberOfTasks;\r
1433 }\r
1434 /*-----------------------------------------------------------*/\r
1435 \r
1436 #if ( INCLUDE_pcTaskGetTaskName == 1 )\r
1437 \r
1438         signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery )\r
1439         {\r
1440         tskTCB *pxTCB;\r
1441 \r
1442                 /* If null is passed in here then the name of the calling task is being queried. */\r
1443                 pxTCB = prvGetTCBFromHandle( xTaskToQuery );\r
1444                 configASSERT( pxTCB );\r
1445                 return &( pxTCB->pcTaskName[ 0 ] );\r
1446         }\r
1447 \r
1448 #endif /* INCLUDE_pcTaskGetTaskName */\r
1449 /*-----------------------------------------------------------*/\r
1450 \r
1451 #if ( configUSE_TRACE_FACILITY == 1 )\r
1452 \r
1453         unsigned portBASE_TYPE xTaskGetSystemState( xTaskStatusType *pxTaskStatusArray, unsigned portBASE_TYPE uxArraySize, unsigned long *pulTotalRunTime )\r
1454         {\r
1455         unsigned portBASE_TYPE uxTask = 0, uxQueue = configMAX_PRIORITIES;\r
1456 \r
1457                 vTaskSuspendAll();\r
1458                 {\r
1459                         /* Is there a space in the array for each task in the system? */\r
1460                         if( uxArraySize >= uxCurrentNumberOfTasks )\r
1461                         {\r
1462                                 /* Fill in an xTaskStatusType structure with information on each\r
1463                                 task in the Ready state. */\r
1464                                 do\r
1465                                 {\r
1466                                         uxQueue--;\r
1467                                         uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), eReady );\r
1468 \r
1469                                 }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );\r
1470 \r
1471                                 /* Fill in an xTaskStatusType structure with information on each\r
1472                                 task in the Blocked state. */\r
1473                                 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) pxDelayedTaskList, eBlocked );\r
1474                                 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) pxOverflowDelayedTaskList, eBlocked );\r
1475 \r
1476                                 #if( INCLUDE_vTaskDelete == 1 )\r
1477                                 {\r
1478                                         /* Fill in an xTaskStatusType structure with information on \r
1479                                         each task that has been deleted but not yet cleaned up. */\r
1480                                         uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted );\r
1481                                 }\r
1482                                 #endif\r
1483 \r
1484                                 #if ( INCLUDE_vTaskSuspend == 1 )\r
1485                                 {\r
1486                                         /* Fill in an xTaskStatusType structure with information on \r
1487                                         each task in the Suspended state. */\r
1488                                         uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended );\r
1489                                 }\r
1490                                 #endif\r
1491 \r
1492                                 #if ( configGENERATE_RUN_TIME_STATS == 1)\r
1493                                 {\r
1494                                         *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();\r
1495                                 }\r
1496                                 #else\r
1497                                 {\r
1498                                         *pulTotalRunTime = 0;\r
1499                                 }\r
1500                                 #endif\r
1501                         }\r
1502                 }\r
1503                 xTaskResumeAll();\r
1504 \r
1505                 return uxTask;\r
1506         }\r
1507 \r
1508 #endif /* configUSE_TRACE_FACILITY */\r
1509 /*----------------------------------------------------------*/\r
1510 \r
1511 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )\r
1512 \r
1513         xTaskHandle xTaskGetIdleTaskHandle( void )\r
1514         {\r
1515                 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been\r
1516                 started, then xIdleTaskHandle will be NULL. */\r
1517                 configASSERT( ( xIdleTaskHandle != NULL ) );\r
1518                 return xIdleTaskHandle;\r
1519         }\r
1520 \r
1521 #endif /* INCLUDE_xTaskGetIdleTaskHandle */\r
1522 /*----------------------------------------------------------*/\r
1523 \r
1524 /* This conditional compilation should use inequality to 0, not equality to 1.\r
1525 This is to ensure vTaskStepTick() is available when user defined low power mode\r
1526 implementations require configUSE_TICKLESS_IDLE to be set to a value other than\r
1527 1. */\r
1528 #if ( configUSE_TICKLESS_IDLE != 0 )\r
1529 \r
1530         void vTaskStepTick( portTickType xTicksToJump )\r
1531         {\r
1532                 /* Correct the tick count value after a period during which the tick\r
1533                 was suppressed.  Note this does *not* call the tick hook function for\r
1534                 each stepped tick. */\r
1535                 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );\r
1536                 xTickCount += xTicksToJump;\r
1537         }\r
1538 \r
1539 #endif /* configUSE_TICKLESS_IDLE */\r
1540 /*----------------------------------------------------------*/\r
1541 \r
1542 portBASE_TYPE xTaskIncrementTick( void )\r
1543 {\r
1544 tskTCB * pxTCB;\r
1545 portTickType xItemValue;\r
1546 portBASE_TYPE xSwitchRequired = pdFALSE;\r
1547 \r
1548         /* Called by the portable layer each time a tick interrupt occurs.\r
1549         Increments the tick then checks to see if the new tick value will cause any\r
1550         tasks to be unblocked. */\r
1551         traceTASK_INCREMENT_TICK( xTickCount );\r
1552         if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1553         {\r
1554                 /* Increment the RTOS tick, switching the delayed and overflowed\r
1555                 delayed lists if it wraps to 0. */\r
1556                 ++xTickCount;\r
1557                 if( xTickCount == ( portTickType ) 0U )\r
1558                 {\r
1559                         taskSWITCH_DELAYED_LISTS();\r
1560                 }\r
1561 \r
1562                 /* See if this tick has made a timeout expire.  Tasks are stored in the\r
1563                 queue in the order of their wake time - meaning once one tasks has been\r
1564                 found whose block time has not expired there is no need not look any\r
1565                 further down the list. */\r
1566                 if( xTickCount >= xNextTaskUnblockTime )\r
1567                 {\r
1568                         for( ;; )\r
1569                         {\r
1570                                 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )\r
1571                                 {\r
1572                                         /* The delayed list is empty.  Set xNextTaskUnblockTime to\r
1573                                         the     maximum possible value so it is extremely unlikely that\r
1574                                         the if( xTickCount >= xNextTaskUnblockTime ) test will pass\r
1575                                         next time through. */\r
1576                                         xNextTaskUnblockTime = portMAX_DELAY;\r
1577                                         break;\r
1578                                 }\r
1579                                 else\r
1580                                 {\r
1581                                         /* The delayed list is not empty, get the value of the item\r
1582                                         at the head of the delayed list.  This is the time at which\r
1583                                         the task at the head of the delayed list must be removed\r
1584                                         from the Blocked state. */\r
1585                                         pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );\r
1586                                         xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );\r
1587 \r
1588                                         if( xTickCount < xItemValue )\r
1589                                         {\r
1590                                                 /* It is not time to unblock this item yet, but the item\r
1591                                                 value is the time at which the task at the head of the\r
1592                                                 blocked list must be removed from the Blocked state -\r
1593                                                 so record the item value in xNextTaskUnblockTime. */\r
1594                                                 xNextTaskUnblockTime = xItemValue;\r
1595                                                 break;\r
1596                                         }\r
1597 \r
1598                                         /* It is time to remove the item from the Blocked state. */\r
1599                                         uxListRemove( &( pxTCB->xGenericListItem ) );\r
1600 \r
1601                                         /* Is the task waiting on an event also?  If so remove it\r
1602                                         from the event list. */\r
1603                                         if( pxTCB->xEventListItem.pvContainer != NULL )\r
1604                                         {\r
1605                                                 uxListRemove( &( pxTCB->xEventListItem ) );\r
1606                                         }\r
1607 \r
1608                                         /* Place the unblocked task into the appropriate ready\r
1609                                         list. */\r
1610                                         prvAddTaskToReadyList( pxTCB );\r
1611 \r
1612                                         /* A task being unblocked cannot cause an immediate context\r
1613                                         switch if preemption is turned off. */\r
1614                                         #if (  configUSE_PREEMPTION == 1 )\r
1615                                         {\r
1616                                                 /* Preemption is on, but a context switch should only\r
1617                                                 be performed if the unblocked task has a priority that\r
1618                                                 is equal to or higher than the currently executing\r
1619                                                 task. */\r
1620                                                 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
1621                                                 {\r
1622                                                         xSwitchRequired = pdTRUE;\r
1623                                                 }\r
1624                                         }\r
1625                                         #endif /* configUSE_PREEMPTION */\r
1626                                 }\r
1627                         }\r
1628                 }\r
1629 \r
1630                 /* Tasks of equal priority to the currently running task will share\r
1631                 processing time (time slice) if preemption is on, and the application\r
1632                 writer has not explicitly turned time slicing off. */\r
1633                 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )\r
1634                 {\r
1635                         if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > 1 )\r
1636                         {\r
1637                                 xSwitchRequired = pdTRUE;\r
1638                         }\r
1639                 }\r
1640                 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */\r
1641         }\r
1642         else\r
1643         {\r
1644                 ++uxPendedTicks;\r
1645 \r
1646                 /* The tick hook gets called at regular intervals, even if the\r
1647                 scheduler is locked. */\r
1648                 #if ( configUSE_TICK_HOOK == 1 )\r
1649                 {\r
1650                         vApplicationTickHook();\r
1651                 }\r
1652                 #endif\r
1653         }\r
1654 \r
1655         #if ( configUSE_TICK_HOOK == 1 )\r
1656         {\r
1657                 /* Guard against the tick hook being called when the missed tick\r
1658                 count is being unwound (when the scheduler is being unlocked). */\r
1659                 if( uxPendedTicks == ( unsigned portBASE_TYPE ) 0U )\r
1660                 {\r
1661                         vApplicationTickHook();\r
1662                 }\r
1663         }\r
1664         #endif /* configUSE_TICK_HOOK */\r
1665 \r
1666         return xSwitchRequired;\r
1667 }\r
1668 /*-----------------------------------------------------------*/\r
1669 \r
1670 #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
1671 \r
1672         void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction )\r
1673         {\r
1674         tskTCB *xTCB;\r
1675 \r
1676                 /* If xTask is NULL then we are setting our own task hook. */\r
1677                 if( xTask == NULL )\r
1678                 {\r
1679                         xTCB = ( tskTCB * ) pxCurrentTCB;\r
1680                 }\r
1681                 else\r
1682                 {\r
1683                         xTCB = ( tskTCB * ) xTask;\r
1684                 }\r
1685 \r
1686                 /* Save the hook function in the TCB.  A critical section is required as\r
1687                 the value can be accessed from an interrupt. */\r
1688                 taskENTER_CRITICAL();\r
1689                         xTCB->pxTaskTag = pxHookFunction;\r
1690                 taskEXIT_CRITICAL();\r
1691         }\r
1692 \r
1693 #endif /* configUSE_APPLICATION_TASK_TAG */\r
1694 /*-----------------------------------------------------------*/\r
1695 \r
1696 #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
1697 \r
1698         pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )\r
1699         {\r
1700         tskTCB *xTCB;\r
1701         pdTASK_HOOK_CODE xReturn;\r
1702 \r
1703                 /* If xTask is NULL then we are setting our own task hook. */\r
1704                 if( xTask == NULL )\r
1705                 {\r
1706                         xTCB = ( tskTCB * ) pxCurrentTCB;\r
1707                 }\r
1708                 else\r
1709                 {\r
1710                         xTCB = ( tskTCB * ) xTask;\r
1711                 }\r
1712 \r
1713                 /* Save the hook function in the TCB.  A critical section is required as\r
1714                 the value can be accessed from an interrupt. */\r
1715                 taskENTER_CRITICAL();\r
1716                         xReturn = xTCB->pxTaskTag;\r
1717                 taskEXIT_CRITICAL();\r
1718 \r
1719                 return xReturn;\r
1720         }\r
1721 \r
1722 #endif /* configUSE_APPLICATION_TASK_TAG */\r
1723 /*-----------------------------------------------------------*/\r
1724 \r
1725 #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
1726 \r
1727         portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )\r
1728         {\r
1729         tskTCB *xTCB;\r
1730         portBASE_TYPE xReturn;\r
1731 \r
1732                 /* If xTask is NULL then we are calling our own task hook. */\r
1733                 if( xTask == NULL )\r
1734                 {\r
1735                         xTCB = ( tskTCB * ) pxCurrentTCB;\r
1736                 }\r
1737                 else\r
1738                 {\r
1739                         xTCB = ( tskTCB * ) xTask;\r
1740                 }\r
1741 \r
1742                 if( xTCB->pxTaskTag != NULL )\r
1743                 {\r
1744                         xReturn = xTCB->pxTaskTag( pvParameter );\r
1745                 }\r
1746                 else\r
1747                 {\r
1748                         xReturn = pdFAIL;\r
1749                 }\r
1750 \r
1751                 return xReturn;\r
1752         }\r
1753 \r
1754 #endif /* configUSE_APPLICATION_TASK_TAG */\r
1755 /*-----------------------------------------------------------*/\r
1756 \r
1757 void vTaskSwitchContext( void )\r
1758 {\r
1759         if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )\r
1760         {\r
1761                 /* The scheduler is currently suspended - do not allow a context\r
1762                 switch. */\r
1763                 xYieldPending = pdTRUE;\r
1764         }\r
1765         else\r
1766         {\r
1767                 traceTASK_SWITCHED_OUT();\r
1768 \r
1769                 #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
1770                 {\r
1771                                 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE\r
1772                                         portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );\r
1773                                 #else\r
1774                                         ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();\r
1775                                 #endif\r
1776 \r
1777                                 /* Add the amount of time the task has been running to the\r
1778                                 accumulated     time so far.  The time the task started running was\r
1779                                 stored in ulTaskSwitchedInTime.  Note that there is no overflow\r
1780                                 protection here so count values are only valid until the timer\r
1781                                 overflows.  The guard against negative values is to protect\r
1782                                 against suspect run time stat counter implementations - which\r
1783                                 are provided by the application, not the kernel. */\r
1784                                 if( ulTotalRunTime > ulTaskSwitchedInTime )\r
1785                                 {\r
1786                                         pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );\r
1787                                 }\r
1788                                 ulTaskSwitchedInTime = ulTotalRunTime;\r
1789                 }\r
1790                 #endif /* configGENERATE_RUN_TIME_STATS */\r
1791 \r
1792                 taskFIRST_CHECK_FOR_STACK_OVERFLOW();\r
1793                 taskSECOND_CHECK_FOR_STACK_OVERFLOW();\r
1794 \r
1795                 taskSELECT_HIGHEST_PRIORITY_TASK();\r
1796 \r
1797                 traceTASK_SWITCHED_IN();\r
1798 \r
1799                 #if ( configUSE_NEWLIB_REENTRANT == 1 )\r
1800                 {\r
1801                         /* Switch Newlib's _impure_ptr variable to point to the _reent\r
1802                         structure specific to this task. */\r
1803                         _impure_ptr = &( pxCurrentTCB->xNewLib_reent );\r
1804                 }\r
1805                 #endif /* configUSE_NEWLIB_REENTRANT */\r
1806         }\r
1807 }\r
1808 /*-----------------------------------------------------------*/\r
1809 \r
1810 void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )\r
1811 {\r
1812 portTickType xTimeToWake;\r
1813 \r
1814         configASSERT( pxEventList );\r
1815 \r
1816         /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE\r
1817         SCHEDULER SUSPENDED. */\r
1818 \r
1819         /* Place the event list item of the TCB in the appropriate event list.\r
1820         This is placed in the list in priority order so the highest priority task\r
1821         is the first to be woken by the event. */\r
1822         vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );\r
1823 \r
1824         /* We must remove ourselves from the ready list before adding ourselves\r
1825         to the blocked list as the same list item is used for both lists.  We have\r
1826         exclusive access to the ready lists as the scheduler is locked. */\r
1827         if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )\r
1828         {\r
1829                 /* The current task must be in a ready list, so there is no need to\r
1830                 check, and the port reset macro can be called directly. */\r
1831                 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );\r
1832         }\r
1833 \r
1834         #if ( INCLUDE_vTaskSuspend == 1 )\r
1835         {\r
1836                 if( xTicksToWait == portMAX_DELAY )\r
1837                 {\r
1838                         /* Add ourselves to the suspended task list instead of a delayed task\r
1839                         list to ensure we are not woken by a timing event.  We will block\r
1840                         indefinitely. */\r
1841                         vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
1842                 }\r
1843                 else\r
1844                 {\r
1845                         /* Calculate the time at which the task should be woken if the event does\r
1846                         not occur.  This may overflow but this doesn't matter. */\r
1847                         xTimeToWake = xTickCount + xTicksToWait;\r
1848                         prvAddCurrentTaskToDelayedList( xTimeToWake );\r
1849                 }\r
1850         }\r
1851         #else /* INCLUDE_vTaskSuspend */\r
1852         {\r
1853                         /* Calculate the time at which the task should be woken if the event does\r
1854                         not occur.  This may overflow but this doesn't matter. */\r
1855                         xTimeToWake = xTickCount + xTicksToWait;\r
1856                         prvAddCurrentTaskToDelayedList( xTimeToWake );\r
1857         }\r
1858         #endif /* INCLUDE_vTaskSuspend */\r
1859 }\r
1860 /*-----------------------------------------------------------*/\r
1861 \r
1862 #if configUSE_TIMERS == 1\r
1863 \r
1864         void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait )\r
1865         {\r
1866         portTickType xTimeToWake;\r
1867 \r
1868                 configASSERT( pxEventList );\r
1869 \r
1870                 /* This function should not be called by application code hence the\r
1871                 'Restricted' in its name.  It is not part of the public API.  It is\r
1872                 designed for use by kernel code, and has special calling requirements -\r
1873                 it should be called from a critical section. */\r
1874 \r
1875 \r
1876                 /* Place the event list item of the TCB in the appropriate event list.\r
1877                 In this case it is assume that this is the only task that is going to\r
1878                 be waiting on this event list, so the faster vListInsertEnd() function\r
1879                 can be used in place of vListInsert. */\r
1880                 vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );\r
1881 \r
1882                 /* We must remove this task from the ready list before adding it to the\r
1883                 blocked list as the same list item is used for both lists.  This\r
1884                 function is called form a critical section. */\r
1885                 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )\r
1886                 {\r
1887                         /* The current task must be in a ready list, so there is no need to\r
1888                         check, and the port reset macro can be called directly. */\r
1889                         portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );\r
1890                 }\r
1891 \r
1892                 /* Calculate the time at which the task should be woken if the event does\r
1893                 not occur.  This may overflow but this doesn't matter. */\r
1894                 xTimeToWake = xTickCount + xTicksToWait;\r
1895 \r
1896                 traceTASK_DELAY_UNTIL();\r
1897                 prvAddCurrentTaskToDelayedList( xTimeToWake );\r
1898         }\r
1899 \r
1900 #endif /* configUSE_TIMERS */\r
1901 /*-----------------------------------------------------------*/\r
1902 \r
1903 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )\r
1904 {\r
1905 tskTCB *pxUnblockedTCB;\r
1906 portBASE_TYPE xReturn;\r
1907 \r
1908         /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE\r
1909         SCHEDULER SUSPENDED.  It can also be called from within an ISR. */\r
1910 \r
1911         /* The event list is sorted in priority order, so we can remove the\r
1912         first in the list, remove the TCB from the delayed list, and add\r
1913         it to the ready list.\r
1914 \r
1915         If an event is for a queue that is locked then this function will never\r
1916         get called - the lock count on the queue will get modified instead.  This\r
1917         means we can always expect exclusive access to the event list here.\r
1918 \r
1919         This function assumes that a check has already been made to ensure that\r
1920         pxEventList is not empty. */\r
1921         pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );\r
1922         configASSERT( pxUnblockedTCB );\r
1923         uxListRemove( &( pxUnblockedTCB->xEventListItem ) );\r
1924 \r
1925         if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1926         {\r
1927                 uxListRemove( &( pxUnblockedTCB->xGenericListItem ) );\r
1928                 prvAddTaskToReadyList( pxUnblockedTCB );\r
1929         }\r
1930         else\r
1931         {\r
1932                 /* We cannot access the delayed or ready lists, so will hold this\r
1933                 task pending until the scheduler is resumed. */\r
1934                 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );\r
1935         }\r
1936 \r
1937         if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
1938         {\r
1939                 /* Return true if the task removed from the event list has\r
1940                 a higher priority than the calling task.  This allows\r
1941                 the calling task to know if it should force a context\r
1942                 switch now. */\r
1943                 xReturn = pdTRUE;\r
1944         }\r
1945         else\r
1946         {\r
1947                 xReturn = pdFALSE;\r
1948         }\r
1949 \r
1950         return xReturn;\r
1951 }\r
1952 /*-----------------------------------------------------------*/\r
1953 \r
1954 void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )\r
1955 {\r
1956         configASSERT( pxTimeOut );\r
1957         pxTimeOut->xOverflowCount = xNumOfOverflows;\r
1958         pxTimeOut->xTimeOnEntering = xTickCount;\r
1959 }\r
1960 /*-----------------------------------------------------------*/\r
1961 \r
1962 portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )\r
1963 {\r
1964 portBASE_TYPE xReturn;\r
1965 \r
1966         configASSERT( pxTimeOut );\r
1967         configASSERT( pxTicksToWait );\r
1968 \r
1969         taskENTER_CRITICAL();\r
1970         {\r
1971                 #if ( INCLUDE_vTaskSuspend == 1 )\r
1972                         /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is\r
1973                         the maximum block time then the task should block indefinitely, and\r
1974                         therefore never time out. */\r
1975                         if( *pxTicksToWait == portMAX_DELAY )\r
1976                         {\r
1977                                 xReturn = pdFALSE;\r
1978                         }\r
1979                         else /* We are not blocking indefinitely, perform the checks below. */\r
1980                 #endif\r
1981 \r
1982                 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )\r
1983                 {\r
1984                         /* The tick count is greater than the time at which vTaskSetTimeout()\r
1985                         was called, but has also overflowed since vTaskSetTimeOut() was called.\r
1986                         It must have wrapped all the way around and gone past us again. This\r
1987                         passed since vTaskSetTimeout() was called. */\r
1988                         xReturn = pdTRUE;\r
1989                 }\r
1990                 else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )\r
1991                 {\r
1992                         /* Not a genuine timeout. Adjust parameters for time remaining. */\r
1993                         *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );\r
1994                         vTaskSetTimeOutState( pxTimeOut );\r
1995                         xReturn = pdFALSE;\r
1996                 }\r
1997                 else\r
1998                 {\r
1999                         xReturn = pdTRUE;\r
2000                 }\r
2001         }\r
2002         taskEXIT_CRITICAL();\r
2003 \r
2004         return xReturn;\r
2005 }\r
2006 /*-----------------------------------------------------------*/\r
2007 \r
2008 void vTaskMissedYield( void )\r
2009 {\r
2010         xYieldPending = pdTRUE;\r
2011 }\r
2012 /*-----------------------------------------------------------*/\r
2013 \r
2014 #if ( configUSE_TRACE_FACILITY == 1 )\r
2015 \r
2016         unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask )\r
2017         {\r
2018         unsigned portBASE_TYPE uxReturn;\r
2019         tskTCB *pxTCB;\r
2020 \r
2021                 if( xTask != NULL )\r
2022                 {\r
2023                         pxTCB = ( tskTCB * ) xTask;\r
2024                         uxReturn = pxTCB->uxTaskNumber;\r
2025                 }\r
2026                 else\r
2027                 {\r
2028                         uxReturn = 0U;\r
2029                 }\r
2030 \r
2031                 return uxReturn;\r
2032         }\r
2033 \r
2034 #endif /* configUSE_TRACE_FACILITY */\r
2035 /*-----------------------------------------------------------*/\r
2036 \r
2037 #if ( configUSE_TRACE_FACILITY == 1 )\r
2038 \r
2039         void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle )\r
2040         {\r
2041         tskTCB *pxTCB;\r
2042 \r
2043                 if( xTask != NULL )\r
2044                 {\r
2045                         pxTCB = ( tskTCB * ) xTask;\r
2046                         pxTCB->uxTaskNumber = uxHandle;\r
2047                 }\r
2048         }\r
2049 \r
2050 #endif /* configUSE_TRACE_FACILITY */\r
2051 \r
2052 /*\r
2053  * -----------------------------------------------------------\r
2054  * The Idle task.\r
2055  * ----------------------------------------------------------\r
2056  *\r
2057  * The portTASK_FUNCTION() macro is used to allow port/compiler specific\r
2058  * language extensions.  The equivalent prototype for this function is:\r
2059  *\r
2060  * void prvIdleTask( void *pvParameters );\r
2061  *\r
2062  */\r
2063 static portTASK_FUNCTION( prvIdleTask, pvParameters )\r
2064 {\r
2065         /* Stop warnings. */\r
2066         ( void ) pvParameters;\r
2067 \r
2068         for( ;; )\r
2069         {\r
2070                 /* See if any tasks have been deleted. */\r
2071                 prvCheckTasksWaitingTermination();\r
2072 \r
2073                 #if ( configUSE_PREEMPTION == 0 )\r
2074                 {\r
2075                         /* If we are not using preemption we keep forcing a task switch to\r
2076                         see if any other task has become available.  If we are using\r
2077                         preemption we don't need to do this as any task becoming available\r
2078                         will automatically get the processor anyway. */\r
2079                         taskYIELD();\r
2080                 }\r
2081                 #endif /* configUSE_PREEMPTION */\r
2082 \r
2083                 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )\r
2084                 {\r
2085                         /* When using preemption tasks of equal priority will be\r
2086                         timesliced.  If a task that is sharing the idle priority is ready\r
2087                         to run then the idle task should yield before the end of the\r
2088                         timeslice.\r
2089 \r
2090                         A critical region is not required here as we are just reading from\r
2091                         the list, and an occasional incorrect value will not matter.  If\r
2092                         the ready list at the idle priority contains more than one task\r
2093                         then a task other than the idle task is ready to execute. */\r
2094                         if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )\r
2095                         {\r
2096                                 taskYIELD();\r
2097                         }\r
2098                 }\r
2099                 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */\r
2100 \r
2101                 #if ( configUSE_IDLE_HOOK == 1 )\r
2102                 {\r
2103                         extern void vApplicationIdleHook( void );\r
2104 \r
2105                         /* Call the user defined function from within the idle task.  This\r
2106                         allows the application designer to add background functionality\r
2107                         without the overhead of a separate task.\r
2108                         NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,\r
2109                         CALL A FUNCTION THAT MIGHT BLOCK. */\r
2110                         vApplicationIdleHook();\r
2111                 }\r
2112                 #endif /* configUSE_IDLE_HOOK */\r
2113 \r
2114                 /* This conditional compilation should use inequality to 0, not equality\r
2115                 to 1.  This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when\r
2116                 user defined low power mode     implementations require\r
2117                 configUSE_TICKLESS_IDLE to be set to a value other than 1. */\r
2118                 #if ( configUSE_TICKLESS_IDLE != 0 )\r
2119                 {\r
2120                 portTickType xExpectedIdleTime;\r
2121 \r
2122                         /* It is not desirable to suspend then resume the scheduler on\r
2123                         each iteration of the idle task.  Therefore, a preliminary\r
2124                         test of the expected idle time is performed without the\r
2125                         scheduler suspended.  The result here is not necessarily\r
2126                         valid. */\r
2127                         xExpectedIdleTime = prvGetExpectedIdleTime();\r
2128 \r
2129                         if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )\r
2130                         {\r
2131                                 vTaskSuspendAll();\r
2132                                 {\r
2133                                         /* Now the scheduler is suspended, the expected idle\r
2134                                         time can be sampled again, and this time its value can\r
2135                                         be used. */\r
2136                                         configASSERT( xNextTaskUnblockTime >= xTickCount );\r
2137                                         xExpectedIdleTime = prvGetExpectedIdleTime();\r
2138 \r
2139                                         if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )\r
2140                                         {\r
2141                                                 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );\r
2142                                         }\r
2143                                 }\r
2144                                 xTaskResumeAll();\r
2145                         }\r
2146                 }\r
2147                 #endif /* configUSE_TICKLESS_IDLE */\r
2148         }\r
2149 } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */\r
2150 /*-----------------------------------------------------------*/\r
2151 \r
2152 #if configUSE_TICKLESS_IDLE != 0\r
2153 \r
2154         eSleepModeStatus eTaskConfirmSleepModeStatus( void )\r
2155         {\r
2156         eSleepModeStatus eReturn = eStandardSleep;\r
2157 \r
2158                 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )\r
2159                 {\r
2160                         /* A task was made ready while the scheduler was suspended. */\r
2161                         eReturn = eAbortSleep;\r
2162                 }\r
2163                 else if( xYieldPending != pdFALSE )\r
2164                 {\r
2165                         /* A yield was pended while the scheduler was suspended. */\r
2166                         eReturn = eAbortSleep;\r
2167                 }\r
2168                 else\r
2169                 {\r
2170                         #if configUSE_TIMERS == 0\r
2171                         {\r
2172                                 /* The idle task exists in addition to the application tasks. */\r
2173                                 const unsigned portBASE_TYPE uxNonApplicationTasks = 1;\r
2174 \r
2175                                 /* If timers are not being used and all the tasks are in the\r
2176                                 suspended list (which might mean they have an infinite block\r
2177                                 time rather than actually being suspended) then it is safe to\r
2178                                 turn all clocks off and just wait for external interrupts. */\r
2179                                 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )\r
2180                                 {\r
2181                                         eReturn = eNoTasksWaitingTimeout;\r
2182                                 }\r
2183                         }\r
2184                         #endif /* configUSE_TIMERS */\r
2185                 }\r
2186 \r
2187                 return eReturn;\r
2188         }\r
2189 #endif /* configUSE_TICKLESS_IDLE */\r
2190 /*-----------------------------------------------------------*/\r
2191 \r
2192 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )\r
2193 {\r
2194 portBASE_TYPE x;\r
2195 \r
2196         /* Store the task name in the TCB. */\r
2197         for( x = 0; x < configMAX_TASK_NAME_LEN; x++ )\r
2198         {\r
2199                 pxTCB->pcTaskName[ x ] = pcName[ x ];\r
2200 \r
2201                 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than\r
2202                 configMAX_TASK_NAME_LEN characters just in case the memory after the\r
2203                 string is not accessible (extremely unlikely). */\r
2204                 if( pcName[ x ] == 0x00 )\r
2205                 {\r
2206                         break;\r
2207                 }\r
2208         }\r
2209 \r
2210         /* Ensure the name string is terminated in the case that the string length\r
2211         was greater or equal to configMAX_TASK_NAME_LEN. */\r
2212         pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = ( signed char ) '\0';\r
2213 \r
2214         /* This is used as an array index so must ensure it's not too large.  First\r
2215         remove the privilege bit if one is present. */\r
2216         if( uxPriority >= configMAX_PRIORITIES )\r
2217         {\r
2218                 uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;\r
2219         }\r
2220 \r
2221         pxTCB->uxPriority = uxPriority;\r
2222         #if ( configUSE_MUTEXES == 1 )\r
2223         {\r
2224                 pxTCB->uxBasePriority = uxPriority;\r
2225         }\r
2226         #endif /* configUSE_MUTEXES */\r
2227 \r
2228         vListInitialiseItem( &( pxTCB->xGenericListItem ) );\r
2229         vListInitialiseItem( &( pxTCB->xEventListItem ) );\r
2230 \r
2231         /* Set the pxTCB as a link back from the xListItem.  This is so we can get\r
2232         back to the containing TCB from a generic item in a list. */\r
2233         listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );\r
2234 \r
2235         /* Event lists are always in priority order. */\r
2236         listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );\r
2237         listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );\r
2238 \r
2239         #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
2240         {\r
2241                 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0U;\r
2242         }\r
2243         #endif /* portCRITICAL_NESTING_IN_TCB */\r
2244 \r
2245         #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
2246         {\r
2247                 pxTCB->pxTaskTag = NULL;\r
2248         }\r
2249         #endif /* configUSE_APPLICATION_TASK_TAG */\r
2250 \r
2251         #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
2252         {\r
2253                 pxTCB->ulRunTimeCounter = 0UL;\r
2254         }\r
2255         #endif /* configGENERATE_RUN_TIME_STATS */\r
2256 \r
2257         #if ( portUSING_MPU_WRAPPERS == 1 )\r
2258         {\r
2259                 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );\r
2260         }\r
2261         #else /* portUSING_MPU_WRAPPERS */\r
2262         {\r
2263                 ( void ) xRegions;\r
2264                 ( void ) usStackDepth;\r
2265         }\r
2266         #endif /* portUSING_MPU_WRAPPERS */\r
2267 \r
2268         #if ( configUSE_NEWLIB_REENTRANT == 1 )\r
2269         {\r
2270                 /* Initialise this task's Newlib reent structure. */\r
2271                 _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) );\r
2272         }\r
2273         #endif /* configUSE_NEWLIB_REENTRANT */\r
2274 }\r
2275 /*-----------------------------------------------------------*/\r
2276 \r
2277 #if ( portUSING_MPU_WRAPPERS == 1 )\r
2278 \r
2279         void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )\r
2280         {\r
2281         tskTCB *pxTCB;\r
2282 \r
2283                 if( xTaskToModify == pxCurrentTCB )\r
2284                 {\r
2285                         xTaskToModify = NULL;\r
2286                 }\r
2287 \r
2288                 /* If null is passed in here then we are deleting ourselves. */\r
2289                 pxTCB = prvGetTCBFromHandle( xTaskToModify );\r
2290 \r
2291         vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );\r
2292         }\r
2293 \r
2294 #endif /* portUSING_MPU_WRAPPERS */\r
2295 /*-----------------------------------------------------------*/\r
2296 \r
2297 static void prvInitialiseTaskLists( void )\r
2298 {\r
2299 unsigned portBASE_TYPE uxPriority;\r
2300 \r
2301         for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < configMAX_PRIORITIES; uxPriority++ )\r
2302         {\r
2303                 vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );\r
2304         }\r
2305 \r
2306         vListInitialise( ( xList * ) &xDelayedTaskList1 );\r
2307         vListInitialise( ( xList * ) &xDelayedTaskList2 );\r
2308         vListInitialise( ( xList * ) &xPendingReadyList );\r
2309 \r
2310         #if ( INCLUDE_vTaskDelete == 1 )\r
2311         {\r
2312                 vListInitialise( ( xList * ) &xTasksWaitingTermination );\r
2313         }\r
2314         #endif /* INCLUDE_vTaskDelete */\r
2315 \r
2316         #if ( INCLUDE_vTaskSuspend == 1 )\r
2317         {\r
2318                 vListInitialise( ( xList * ) &xSuspendedTaskList );\r
2319         }\r
2320         #endif /* INCLUDE_vTaskSuspend */\r
2321 \r
2322         /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList\r
2323         using list2. */\r
2324         pxDelayedTaskList = &xDelayedTaskList1;\r
2325         pxOverflowDelayedTaskList = &xDelayedTaskList2;\r
2326 }\r
2327 /*-----------------------------------------------------------*/\r
2328 \r
2329 static void prvCheckTasksWaitingTermination( void )\r
2330 {\r
2331         #if ( INCLUDE_vTaskDelete == 1 )\r
2332         {\r
2333                 portBASE_TYPE xListIsEmpty;\r
2334 \r
2335                 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called\r
2336                 too often in the idle task. */\r
2337                 while( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0U )\r
2338                 {\r
2339                         vTaskSuspendAll();\r
2340                                 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );\r
2341                         xTaskResumeAll();\r
2342 \r
2343                         if( xListIsEmpty == pdFALSE )\r
2344                         {\r
2345                                 tskTCB *pxTCB;\r
2346 \r
2347                                 taskENTER_CRITICAL();\r
2348                                 {\r
2349                                         pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );\r
2350                                         uxListRemove( &( pxTCB->xGenericListItem ) );\r
2351                                         --uxCurrentNumberOfTasks;\r
2352                                         --uxTasksDeleted;\r
2353                                 }\r
2354                                 taskEXIT_CRITICAL();\r
2355 \r
2356                                 prvDeleteTCB( pxTCB );\r
2357                         }\r
2358                 }\r
2359         }\r
2360         #endif /* vTaskDelete */\r
2361 }\r
2362 /*-----------------------------------------------------------*/\r
2363 \r
2364 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake )\r
2365 {\r
2366         /* The list item will be inserted in wake time order. */\r
2367         listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );\r
2368 \r
2369         if( xTimeToWake < xTickCount )\r
2370         {\r
2371                 /* Wake time has overflowed.  Place this item in the overflow list. */\r
2372                 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
2373         }\r
2374         else\r
2375         {\r
2376                 /* The wake time has not overflowed, so we can use the current block list. */\r
2377                 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
2378 \r
2379                 /* If the task entering the blocked state was placed at the head of the\r
2380                 list of blocked tasks then xNextTaskUnblockTime needs to be updated\r
2381                 too. */\r
2382                 if( xTimeToWake < xNextTaskUnblockTime )\r
2383                 {\r
2384                         xNextTaskUnblockTime = xTimeToWake;\r
2385                 }\r
2386         }\r
2387 }\r
2388 /*-----------------------------------------------------------*/\r
2389 \r
2390 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )\r
2391 {\r
2392 tskTCB *pxNewTCB;\r
2393 \r
2394         /* Allocate space for the TCB.  Where the memory comes from depends on\r
2395         the implementation of the port malloc function. */\r
2396         pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );\r
2397 \r
2398         if( pxNewTCB != NULL )\r
2399         {\r
2400                 /* Allocate space for the stack used by the task being created.\r
2401                 The base of the stack memory stored in the TCB so the task can\r
2402                 be deleted later if required. */\r
2403                 pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );\r
2404 \r
2405                 if( pxNewTCB->pxStack == NULL )\r
2406                 {\r
2407                         /* Could not allocate the stack.  Delete the allocated TCB. */\r
2408                         vPortFree( pxNewTCB );\r
2409                         pxNewTCB = NULL;\r
2410                 }\r
2411                 else\r
2412                 {\r
2413                         /* Just to help debugging. */\r
2414                         memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( portSTACK_TYPE ) );\r
2415                 }\r
2416         }\r
2417 \r
2418         return pxNewTCB;\r
2419 }\r
2420 /*-----------------------------------------------------------*/\r
2421 \r
2422 #if ( configUSE_TRACE_FACILITY == 1 )\r
2423 \r
2424         static unsigned portBASE_TYPE prvListTaskWithinSingleList( xTaskStatusType *pxTaskStatusArray, xList *pxList, eTaskState eState )\r
2425         {\r
2426         volatile tskTCB *pxNextTCB, *pxFirstTCB;\r
2427         unsigned portBASE_TYPE uxTask = 0;\r
2428 \r
2429                 if( listCURRENT_LIST_LENGTH( pxList ) > 0 )\r
2430                 {                       \r
2431                         listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );\r
2432                         \r
2433                         /* Populate an xTaskStatusType structure within the \r
2434                         pxTaskStatusArray array for each task that is referenced from\r
2435                         pxList.  See the definition of xTaskStatusType in task.h for the\r
2436                         meaning of each xTaskStatusType structure member. */\r
2437                         do\r
2438                         {\r
2439                                 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );\r
2440 \r
2441                                 pxTaskStatusArray[ uxTask ].xHandle = ( xTaskHandle ) pxNextTCB;\r
2442                                 pxTaskStatusArray[ uxTask ].pcTaskName = ( const signed char * ) &( pxNextTCB->pcTaskName [ 0 ] );\r
2443                                 pxTaskStatusArray[ uxTask ].xTaskNumber = pxNextTCB->uxTCBNumber;\r
2444                                 pxTaskStatusArray[ uxTask ].eCurrentState = eState;\r
2445                                 pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority;\r
2446 \r
2447                                 #if ( configUSE_MUTEXES == 1 )\r
2448                                 {\r
2449                                         pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority;\r
2450                                 }\r
2451                                 #else\r
2452                                 {\r
2453                                         pxTaskStatusArray[ uxTask ].uxBasePriority = 0;\r
2454                                 }\r
2455                                 #endif\r
2456 \r
2457                                 #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
2458                                 {\r
2459                                         pxTaskStatusArray[ uxTask ].ulRunTimeCounter = pxNextTCB->ulRunTimeCounter;\r
2460                                 }\r
2461                                 #else\r
2462                                 {\r
2463                                         pxTaskStatusArray[ uxTask ].ulRunTimeCounter = 0;\r
2464                                 }\r
2465                                 #endif\r
2466 \r
2467                                 #if ( portSTACK_GROWTH > 0 )\r
2468                                 {\r
2469                                         ppxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );\r
2470                                 }\r
2471                                 #else\r
2472                                 {\r
2473                                         pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );\r
2474                                 }\r
2475                                 #endif\r
2476 \r
2477                                 uxTask++;\r
2478 \r
2479                         } while( pxNextTCB != pxFirstTCB );\r
2480                 }\r
2481 \r
2482                 return uxTask;\r
2483         }\r
2484 \r
2485 #endif /* configUSE_TRACE_FACILITY */\r
2486 /*-----------------------------------------------------------*/\r
2487 \r
2488 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )\r
2489 \r
2490         static unsigned short prvTaskCheckFreeStackSpace( const unsigned char * pucStackByte )\r
2491         {\r
2492         register unsigned short usCount = 0U;\r
2493 \r
2494                 while( *pucStackByte == tskSTACK_FILL_BYTE )\r
2495                 {\r
2496                         pucStackByte -= portSTACK_GROWTH;\r
2497                         usCount++;\r
2498                 }\r
2499 \r
2500                 usCount /= sizeof( portSTACK_TYPE );\r
2501 \r
2502                 return usCount;\r
2503         }\r
2504 \r
2505 #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */\r
2506 /*-----------------------------------------------------------*/\r
2507 \r
2508 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )\r
2509 \r
2510         unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )\r
2511         {\r
2512         tskTCB *pxTCB;\r
2513         unsigned char *pcEndOfStack;\r
2514         unsigned portBASE_TYPE uxReturn;\r
2515 \r
2516                 pxTCB = prvGetTCBFromHandle( xTask );\r
2517 \r
2518                 #if portSTACK_GROWTH < 0\r
2519                 {\r
2520                         pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;\r
2521                 }\r
2522                 #else\r
2523                 {\r
2524                         pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;\r
2525                 }\r
2526                 #endif\r
2527 \r
2528                 uxReturn = ( unsigned portBASE_TYPE ) prvTaskCheckFreeStackSpace( pcEndOfStack );\r
2529 \r
2530                 return uxReturn;\r
2531         }\r
2532 \r
2533 #endif /* INCLUDE_uxTaskGetStackHighWaterMark */\r
2534 /*-----------------------------------------------------------*/\r
2535 \r
2536 #if ( INCLUDE_vTaskDelete == 1 )\r
2537 \r
2538         static void prvDeleteTCB( tskTCB *pxTCB )\r
2539         {\r
2540                 /* This call is required specifically for the TriCore port.  It must be\r
2541                 above the vPortFree() calls.  The call is also used by ports/demos that\r
2542                 want to allocate and clean RAM statically. */\r
2543                 portCLEAN_UP_TCB( pxTCB );\r
2544 \r
2545                 /* Free up the memory allocated by the scheduler for the task.  It is up to\r
2546                 the task to free any memory allocated at the application level. */\r
2547                 vPortFreeAligned( pxTCB->pxStack );\r
2548                 vPortFree( pxTCB );\r
2549         }\r
2550 \r
2551 #endif /* INCLUDE_vTaskDelete */\r
2552 /*-----------------------------------------------------------*/\r
2553 \r
2554 #if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )\r
2555 \r
2556         xTaskHandle xTaskGetCurrentTaskHandle( void )\r
2557         {\r
2558         xTaskHandle xReturn;\r
2559 \r
2560                 /* A critical section is not required as this is not called from\r
2561                 an interrupt and the current TCB will always be the same for any\r
2562                 individual execution thread. */\r
2563                 xReturn = pxCurrentTCB;\r
2564 \r
2565                 return xReturn;\r
2566         }\r
2567 \r
2568 #endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */\r
2569 /*-----------------------------------------------------------*/\r
2570 \r
2571 #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )\r
2572 \r
2573         portBASE_TYPE xTaskGetSchedulerState( void )\r
2574         {\r
2575         portBASE_TYPE xReturn;\r
2576 \r
2577                 if( xSchedulerRunning == pdFALSE )\r
2578                 {\r
2579                         xReturn = taskSCHEDULER_NOT_STARTED;\r
2580                 }\r
2581                 else\r
2582                 {\r
2583                         if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
2584                         {\r
2585                                 xReturn = taskSCHEDULER_RUNNING;\r
2586                         }\r
2587                         else\r
2588                         {\r
2589                                 xReturn = taskSCHEDULER_SUSPENDED;\r
2590                         }\r
2591                 }\r
2592 \r
2593                 return xReturn;\r
2594         }\r
2595 \r
2596 #endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */\r
2597 /*-----------------------------------------------------------*/\r
2598 \r
2599 #if ( configUSE_MUTEXES == 1 )\r
2600 \r
2601         void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )\r
2602         {\r
2603         tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;\r
2604 \r
2605                 /* If the mutex was given back by an interrupt while the queue was\r
2606                 locked then the mutex holder might now be NULL. */\r
2607                 if( pxMutexHolder != NULL )\r
2608                 {\r
2609                         if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )\r
2610                         {\r
2611                                 /* Adjust the mutex holder state to account for its new priority. */\r
2612                                 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );\r
2613 \r
2614                                 /* If the task being modified is in the ready state it will need to\r
2615                                 be moved into a new list. */\r
2616                                 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE )\r
2617                                 {\r
2618                                         if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )\r
2619                                         {\r
2620                                                 taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
2621                                         }\r
2622 \r
2623                                         /* Inherit the priority before being moved into the new list. */\r
2624                                         pxTCB->uxPriority = pxCurrentTCB->uxPriority;\r
2625                                         prvAddTaskToReadyList( pxTCB );\r
2626                                 }\r
2627                                 else\r
2628                                 {\r
2629                                         /* Just inherit the priority. */\r
2630                                         pxTCB->uxPriority = pxCurrentTCB->uxPriority;\r
2631                                 }\r
2632 \r
2633                                 traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );\r
2634                         }\r
2635                 }\r
2636         }\r
2637 \r
2638 #endif /* configUSE_MUTEXES */\r
2639 /*-----------------------------------------------------------*/\r
2640 \r
2641 #if ( configUSE_MUTEXES == 1 )\r
2642 \r
2643         void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )\r
2644         {\r
2645         tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;\r
2646 \r
2647                 if( pxMutexHolder != NULL )\r
2648                 {\r
2649                         if( pxTCB->uxPriority != pxTCB->uxBasePriority )\r
2650                         {\r
2651                                 /* We must be the running task to be able to give the mutex back.\r
2652                                 Remove ourselves from the ready list we currently appear in. */\r
2653                                 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )\r
2654                                 {\r
2655                                         taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
2656                                 }\r
2657 \r
2658                                 /* Disinherit the priority before adding the task into the new\r
2659                                 ready list. */\r
2660                                 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );\r
2661                                 pxTCB->uxPriority = pxTCB->uxBasePriority;\r
2662                                 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );\r
2663                                 prvAddTaskToReadyList( pxTCB );\r
2664                         }\r
2665                 }\r
2666         }\r
2667 \r
2668 #endif /* configUSE_MUTEXES */\r
2669 /*-----------------------------------------------------------*/\r
2670 \r
2671 #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
2672 \r
2673         void vTaskEnterCritical( void )\r
2674         {\r
2675                 portDISABLE_INTERRUPTS();\r
2676 \r
2677                 if( xSchedulerRunning != pdFALSE )\r
2678                 {\r
2679                         ( pxCurrentTCB->uxCriticalNesting )++;\r
2680                 }\r
2681         }\r
2682 \r
2683 #endif /* portCRITICAL_NESTING_IN_TCB */\r
2684 /*-----------------------------------------------------------*/\r
2685 \r
2686 #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
2687 \r
2688         void vTaskExitCritical( void )\r
2689         {\r
2690                 if( xSchedulerRunning != pdFALSE )\r
2691                 {\r
2692                         if( pxCurrentTCB->uxCriticalNesting > 0U )\r
2693                         {\r
2694                                 ( pxCurrentTCB->uxCriticalNesting )--;\r
2695 \r
2696                                 if( pxCurrentTCB->uxCriticalNesting == 0U )\r
2697                                 {\r
2698                                         portENABLE_INTERRUPTS();\r
2699                                 }\r
2700                         }\r
2701                 }\r
2702         }\r
2703 \r
2704 #endif /* portCRITICAL_NESTING_IN_TCB */\r
2705 /*-----------------------------------------------------------*/\r
2706 \r
2707 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configINCLUDE_STATS_FORMATTING_FUNCTIONS == 1 ) )\r
2708 \r
2709         void vTaskList( signed char *pcWriteBuffer )\r
2710         {\r
2711         xTaskStatusType *pxTaskStatusArray;\r
2712         volatile unsigned portBASE_TYPE uxArraySize, x;\r
2713         unsigned long ulTotalRunTime;\r
2714         char cStatus;\r
2715 \r
2716                 /*\r
2717                  * PLEASE NOTE:\r
2718                  *\r
2719                  * This function is provided for convenience only, and is used by many\r
2720                  * of the demo applications.  Do not consider it to be part of the\r
2721                  * scheduler.\r
2722                  *\r
2723                  * vTaskList() calls xTaskGetSystemState(), then formats part of the\r
2724                  * xTaskGetSystemState() output into a human readable table that\r
2725                  * displays task names, states and stack usage.\r
2726                  *\r
2727                  * vTaskList() has a dependency on the sprintf() C library function that\r
2728                  * might bloat the code size, use a lot of stack, and provide different\r
2729                  * results on different platforms.  An alternative, tiny, third party,\r
2730                  * and limited functionality implementation of sprintf() is provided in\r
2731                  * many of the FreeRTOS/Demo sub-directories in a file called\r
2732                  * printf-stdarg.c (note printf-stdarg.c does not provide a full\r
2733                  * snprintf() implementation!).\r
2734                  *\r
2735                  * It is recommended that production systems call xTaskGetSystemState()\r
2736                  * directly to get access to raw stats data, rather than indirectly\r
2737                  * through a call to vTaskList().\r
2738                  */\r
2739 \r
2740 \r
2741                 /* Make sure the write buffer does not contain a string. */\r
2742                 *pcWriteBuffer = 0x00;\r
2743 \r
2744                 /* Take a snapshot of the number of tasks in case it changes while this\r
2745                 function is executing. */\r
2746                 uxArraySize = uxCurrentNumberOfTasks;\r
2747 \r
2748                 /* Allocate an array index for each task. */\r
2749                 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) );\r
2750 \r
2751                 if( pxTaskStatusArray != NULL )\r
2752                 {\r
2753                         /* Generate the (binary) data. */\r
2754                         uxArraySize = xTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalRunTime );\r
2755 \r
2756                         /* Create a human readable table from the binary data. */\r
2757                         for( x = 0; x < uxArraySize; x++ )\r
2758                         {\r
2759                                 switch( pxTaskStatusArray[ x ].eCurrentState )\r
2760                                 {\r
2761                                 case eReady:            cStatus = tskREADY_CHAR;\r
2762                                                                         break;\r
2763 \r
2764                                 case eBlocked:          cStatus = tskBLOCKED_CHAR;\r
2765                                                                         break;\r
2766 \r
2767                                 case eSuspended:        cStatus = tskSUSPENDED_CHAR;\r
2768                                                                         break;\r
2769 \r
2770                                 case eDeleted:          cStatus = tskDELETED_CHAR;\r
2771                                                                         break;\r
2772 \r
2773                                 default:                        /* Should not get here, but it is included\r
2774                                                                         to prevent static checking errors. */\r
2775                                                                         cStatus = 0x00;\r
2776                                                                         break;\r
2777                                 }\r
2778 \r
2779                                 sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxTaskStatusArray[ x ].pcTaskName, cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber );\r
2780                                 pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );\r
2781                         }\r
2782 \r
2783                         /* Free the array again. */\r
2784                         vPortFree( pxTaskStatusArray );\r
2785                 }\r
2786         }\r
2787 \r
2788 #endif /* configUSE_TRACE_FACILITY */\r
2789 /*----------------------------------------------------------*/\r
2790 \r
2791 #if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configINCLUDE_STATS_FORMATTING_FUNCTIONS == 1 ) )\r
2792 \r
2793         void vTaskGetRunTimeStats( signed char *pcWriteBuffer )\r
2794         {\r
2795         xTaskStatusType *pxTaskStatusArray;\r
2796         volatile unsigned portBASE_TYPE uxArraySize, x;\r
2797         unsigned long ulTotalRunTime, ulStatsAsPercentage;\r
2798 \r
2799                 /*\r
2800                  * PLEASE NOTE:\r
2801                  *\r
2802                  * This function is provided for convenience only, and is used by many\r
2803                  * of the demo applications.  Do not consider it to be part of the\r
2804                  * scheduler.\r
2805                  *\r
2806                  * vTaskGetRunTimeStats() calls xTaskGetSystemState(), then formats part\r
2807                  * of the xTaskGetSystemState() output into a human readable table that\r
2808                  * displays the amount of time each task has spent in the Running state\r
2809                  * in both absolute and percentage terms.\r
2810                  *\r
2811                  * vTaskGetRunTimeStats() has a dependency on the sprintf() C library\r
2812                  * function that might bloat the code size, use a lot of stack, and\r
2813                  * provide different results on different platforms.  An alternative,\r
2814                  * tiny, third party, and limited functionality implementation of\r
2815                  * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in\r
2816                  * a file called printf-stdarg.c (note printf-stdarg.c does not provide\r
2817                  * a full snprintf() implementation!).\r
2818                  *\r
2819                  * It is recommended that production systems call xTaskGetSystemState()\r
2820                  * directly to get access to raw stats data, rather than indirectly\r
2821                  * through a call to vTaskGetRunTimeStats().\r
2822                  */\r
2823 \r
2824                 /* Make sure the write buffer does not contain a string. */\r
2825                 *pcWriteBuffer = 0x00;\r
2826 \r
2827                 /* Take a snapshot of the number of tasks in case it changes while this\r
2828                 function is executing. */\r
2829                 uxArraySize = uxCurrentNumberOfTasks;\r
2830 \r
2831                 /* Allocate an array index for each task. */\r
2832                 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) );\r
2833 \r
2834                 if( pxTaskStatusArray != NULL )\r
2835                 {\r
2836                         /* Generate the (binary) data. */\r
2837                         uxArraySize = xTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalRunTime );\r
2838 \r
2839                         /* For percentage calculations. */\r
2840                         ulTotalRunTime /= 100UL;\r
2841 \r
2842                         /* Avoid divide by zero errors. */\r
2843                         if( ulTotalRunTime > 0 )\r
2844                         {\r
2845                                 /* Create a human readable table from the binary data. */\r
2846                                 for( x = 0; x < uxArraySize; x++ )\r
2847                                 {\r
2848                                         /* What percentage of the total run time has the task used?\r
2849                                         This will always be rounded down to the nearest integer.\r
2850                                         ulTotalRunTimeDiv100 has already been divided by 100. */\r
2851                                         ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalRunTime;\r
2852 \r
2853                                         if( ulStatsAsPercentage > 0UL )\r
2854                                         {\r
2855                                                 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED\r
2856                                                 {\r
2857                                                         sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );\r
2858                                                 }\r
2859                                                 #else\r
2860                                                 {\r
2861                                                         /* sizeof( int ) == sizeof( long ) so a smaller\r
2862                                                         printf() library can be used. */\r
2863                                                         sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );\r
2864                                                 }\r
2865                                                 #endif\r
2866                                         }\r
2867                                         else\r
2868                                         {\r
2869                                                 /* If the percentage is zero here then the task has\r
2870                                                 consumed less than 1% of the total run time. */\r
2871                                                 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED\r
2872                                                 {\r
2873                                                         sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter );\r
2874                                                 }\r
2875                                                 #else\r
2876                                                 {\r
2877                                                         /* sizeof( int ) == sizeof( long ) so a smaller\r
2878                                                         printf() library can be used. */\r
2879                                                         sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter );\r
2880                                                 }\r
2881                                                 #endif\r
2882                                         }\r
2883 \r
2884                                         pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );\r
2885                                 }\r
2886                         }\r
2887 \r
2888                         /* Free the array again. */\r
2889                         vPortFree( pxTaskStatusArray );\r
2890                 }\r
2891         }\r
2892 \r
2893 #endif /* configGENERATE_RUN_TIME_STATS */\r
2894 \r
2895 \r
2896 \r