]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/tasks.c
Add comments to the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() calls in the core...
[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 \r
1180                 /* RTOS ports that support interrupt nesting have the concept of a \r
1181                 maximum system call (or maximum API call) interrupt priority.  \r
1182                 Interrupts that are     above the maximum system call priority are keep \r
1183                 permanently enabled, even when the RTOS kernel is in a critical section, \r
1184                 but cannot make any calls to FreeRTOS API functions.  If configASSERT() \r
1185                 is defined in FreeRTOSConfig.h then \r
1186                 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion\r
1187                 failure if a FreeRTOS API function is called from an interrupt that has \r
1188                 been assigned a priority above the configured maximum system call \r
1189                 priority.  Only FreeRTOS functions that end in FromISR can be called \r
1190                 from interrupts that have been assigned a priority at or (logically) \r
1191                 below the maximum system call interrupt priority.  FreeRTOS maintains a \r
1192                 separate interrupt safe API to ensure interrupt entry is as fast and as \r
1193                 simple as possible.  More information (albeit Cortex-M specific) is \r
1194                 provided on the following link: \r
1195                 http://www.freertos.org/RTOS-Cortex-M3-M4.html */\r
1196                 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();\r
1197 \r
1198                 pxTCB = ( tskTCB * ) xTaskToResume;\r
1199 \r
1200                 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
1201                 {\r
1202                         if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )\r
1203                         {\r
1204                                 traceTASK_RESUME_FROM_ISR( pxTCB );\r
1205 \r
1206                                 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1207                                 {\r
1208                                         xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );\r
1209                                         uxListRemove(  &( pxTCB->xGenericListItem ) );\r
1210                                         prvAddTaskToReadyList( pxTCB );\r
1211                                 }\r
1212                                 else\r
1213                                 {\r
1214                                         /* We cannot access the delayed or ready lists, so will hold this\r
1215                                         task pending until the scheduler is resumed, at which point a\r
1216                                         yield will be performed if necessary. */\r
1217                                         vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );\r
1218                                 }\r
1219                         }\r
1220                 }\r
1221                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1222 \r
1223                 return xYieldRequired;\r
1224         }\r
1225 \r
1226 #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */\r
1227 /*-----------------------------------------------------------*/\r
1228 \r
1229 void vTaskStartScheduler( void )\r
1230 {\r
1231 portBASE_TYPE xReturn;\r
1232 \r
1233         /* Add the idle task at the lowest priority. */\r
1234         #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )\r
1235         {\r
1236                 /* Create the idle task, storing its handle in xIdleTaskHandle so it can\r
1237                 be returned by the xTaskGetIdleTaskHandle() function. */\r
1238                 xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle );\r
1239         }\r
1240         #else\r
1241         {\r
1242                 /* Create the idle task without storing its handle. */\r
1243                 xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL );\r
1244         }\r
1245         #endif /* INCLUDE_xTaskGetIdleTaskHandle */\r
1246 \r
1247         #if ( configUSE_TIMERS == 1 )\r
1248         {\r
1249                 if( xReturn == pdPASS )\r
1250                 {\r
1251                         xReturn = xTimerCreateTimerTask();\r
1252                 }\r
1253         }\r
1254         #endif /* configUSE_TIMERS */\r
1255 \r
1256         if( xReturn == pdPASS )\r
1257         {\r
1258                 /* Interrupts are turned off here, to ensure a tick does not occur\r
1259                 before or during the call to xPortStartScheduler().  The stacks of\r
1260                 the created tasks contain a status word with interrupts switched on\r
1261                 so interrupts will automatically get re-enabled when the first task\r
1262                 starts to run.\r
1263 \r
1264                 STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE\r
1265                 DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */\r
1266                 portDISABLE_INTERRUPTS();\r
1267 \r
1268                 xSchedulerRunning = pdTRUE;\r
1269                 xTickCount = ( portTickType ) 0U;\r
1270 \r
1271                 /* If configGENERATE_RUN_TIME_STATS is defined then the following\r
1272                 macro must be defined to configure the timer/counter used to generate\r
1273                 the run time counter time base. */\r
1274                 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();\r
1275 \r
1276                 /* Setting up the timer tick is hardware specific and thus in the\r
1277                 portable interface. */\r
1278                 if( xPortStartScheduler() != pdFALSE )\r
1279                 {\r
1280                         /* Should not reach here as if the scheduler is running the\r
1281                         function will not return. */\r
1282                 }\r
1283                 else\r
1284                 {\r
1285                         /* Should only reach here if a task calls xTaskEndScheduler(). */\r
1286                 }\r
1287         }\r
1288         else\r
1289         {\r
1290                 /* This line will only be reached if the kernel could not be started,\r
1291                 because there was not enough FreeRTOS heap to create the idle task\r
1292                 or the timer task. */\r
1293                 configASSERT( xReturn );\r
1294         }\r
1295 }\r
1296 /*-----------------------------------------------------------*/\r
1297 \r
1298 void vTaskEndScheduler( void )\r
1299 {\r
1300         /* Stop the scheduler interrupts and call the portable scheduler end\r
1301         routine so the original ISRs can be restored if necessary.  The port\r
1302         layer must ensure interrupts enable     bit is left in the correct state. */\r
1303         portDISABLE_INTERRUPTS();\r
1304         xSchedulerRunning = pdFALSE;\r
1305         vPortEndScheduler();\r
1306 }\r
1307 /*----------------------------------------------------------*/\r
1308 \r
1309 void vTaskSuspendAll( void )\r
1310 {\r
1311         /* A critical section is not required as the variable is of type\r
1312         portBASE_TYPE. */\r
1313         ++uxSchedulerSuspended;\r
1314 }\r
1315 /*----------------------------------------------------------*/\r
1316 \r
1317 #if ( configUSE_TICKLESS_IDLE != 0 )\r
1318 \r
1319         static portTickType prvGetExpectedIdleTime( void )\r
1320         {\r
1321         portTickType xReturn;\r
1322 \r
1323                 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )\r
1324                 {\r
1325                         xReturn = 0;\r
1326                 }\r
1327                 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )\r
1328                 {\r
1329                         /* There are other idle priority tasks in the ready state.  If\r
1330                         time slicing is used then the very next tick interrupt must be\r
1331                         processed. */\r
1332                         xReturn = 0;\r
1333                 }\r
1334                 else\r
1335                 {\r
1336                         xReturn = xNextTaskUnblockTime - xTickCount;\r
1337                 }\r
1338 \r
1339                 return xReturn;\r
1340         }\r
1341 \r
1342 #endif /* configUSE_TICKLESS_IDLE */\r
1343 /*----------------------------------------------------------*/\r
1344 \r
1345 signed portBASE_TYPE xTaskResumeAll( void )\r
1346 {\r
1347 register tskTCB *pxTCB;\r
1348 signed portBASE_TYPE xAlreadyYielded = pdFALSE;\r
1349 portBASE_TYPE xYieldRequired = pdFALSE;\r
1350 \r
1351         /* If uxSchedulerSuspended is zero then this function does not match a\r
1352         previous call to vTaskSuspendAll(). */\r
1353         configASSERT( uxSchedulerSuspended );\r
1354 \r
1355         /* It is possible that an ISR caused a task to be removed from an event\r
1356         list while the scheduler was suspended.  If this was the case then the\r
1357         removed task will have been added to the xPendingReadyList.  Once the\r
1358         scheduler has been resumed it is safe to move all the pending ready\r
1359         tasks from this list into their appropriate ready list. */\r
1360         taskENTER_CRITICAL();\r
1361         {\r
1362                 --uxSchedulerSuspended;\r
1363 \r
1364                 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1365                 {\r
1366                         if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0U )\r
1367                         {\r
1368                                 /* Move any readied tasks from the pending list into the\r
1369                                 appropriate ready list. */\r
1370                                 while( listLIST_IS_EMPTY( ( xList * ) &xPendingReadyList ) == pdFALSE )\r
1371                                 {\r
1372                                         pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY(  ( ( xList * ) &xPendingReadyList ) );\r
1373                                         uxListRemove( &( pxTCB->xEventListItem ) );\r
1374                                         uxListRemove( &( pxTCB->xGenericListItem ) );\r
1375                                         prvAddTaskToReadyList( pxTCB );\r
1376 \r
1377                                         /* If we have moved a task that has a priority higher than\r
1378                                         the current task then we should yield. */\r
1379                                         if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
1380                                         {\r
1381                                                 xYieldRequired = pdTRUE;\r
1382                                         }\r
1383                                 }\r
1384 \r
1385                                 /* If any ticks occurred while the scheduler was suspended then\r
1386                                 they should be processed now.  This ensures the tick count does not\r
1387                                 slip, and that any delayed tasks are resumed at the correct time. */\r
1388                                 if( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U )\r
1389                                 {\r
1390                                         while( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U )\r
1391                                         {\r
1392                                                 if( xTaskIncrementTick() != pdFALSE )\r
1393                                                 {\r
1394                                                         xYieldRequired = pdTRUE;\r
1395                                                 }\r
1396                                                 --uxPendedTicks;\r
1397                                         }\r
1398                                 }\r
1399 \r
1400                                 if( ( xYieldRequired == pdTRUE ) || ( xYieldPending == pdTRUE ) )\r
1401                                 {\r
1402                                         xAlreadyYielded = pdTRUE;\r
1403                                         xYieldPending = pdFALSE;\r
1404                                         portYIELD_WITHIN_API();\r
1405                                 }\r
1406                         }\r
1407                 }\r
1408         }\r
1409         taskEXIT_CRITICAL();\r
1410 \r
1411         return xAlreadyYielded;\r
1412 }\r
1413 /*-----------------------------------------------------------*/\r
1414 \r
1415 portTickType xTaskGetTickCount( void )\r
1416 {\r
1417 portTickType xTicks;\r
1418 \r
1419         /* Critical section required if running on a 16 bit processor. */\r
1420         taskENTER_CRITICAL();\r
1421         {\r
1422                 xTicks = xTickCount;\r
1423         }\r
1424         taskEXIT_CRITICAL();\r
1425 \r
1426         return xTicks;\r
1427 }\r
1428 /*-----------------------------------------------------------*/\r
1429 \r
1430 portTickType xTaskGetTickCountFromISR( void )\r
1431 {\r
1432 portTickType xReturn;\r
1433 unsigned portBASE_TYPE uxSavedInterruptStatus;\r
1434 \r
1435         /* RTOS ports that support interrupt nesting have the concept of a maximum\r
1436         system call (or maximum API call) interrupt priority.  Interrupts that are\r
1437         above the maximum system call priority are keep permanently enabled, even \r
1438         when the RTOS kernel is in a critical section, but cannot make any calls to\r
1439         FreeRTOS API functions.  If configASSERT() is defined in FreeRTOSConfig.h \r
1440         then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion\r
1441         failure if a FreeRTOS API function is called from an interrupt that has been\r
1442         assigned a priority above the configured maximum system call priority.\r
1443         Only FreeRTOS functions that end in FromISR can be called from interrupts\r
1444         that have been assigned a priority at or (logically) below the maximum \r
1445         system call     interrupt priority.  FreeRTOS maintains a separate interrupt \r
1446         safe API to ensure interrupt entry is as fast and as simple as possible.  \r
1447         More information (albeit Cortex-M specific) is provided on the following \r
1448         link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */\r
1449         portASSERT_IF_INTERRUPT_PRIORITY_INVALID();\r
1450         \r
1451         uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
1452         xReturn = xTickCount;\r
1453         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1454 \r
1455         return xReturn;\r
1456 }\r
1457 /*-----------------------------------------------------------*/\r
1458 \r
1459 unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )\r
1460 {\r
1461         /* A critical section is not required because the variables are of type\r
1462         portBASE_TYPE. */\r
1463         return uxCurrentNumberOfTasks;\r
1464 }\r
1465 /*-----------------------------------------------------------*/\r
1466 \r
1467 #if ( INCLUDE_pcTaskGetTaskName == 1 )\r
1468 \r
1469         signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery )\r
1470         {\r
1471         tskTCB *pxTCB;\r
1472 \r
1473                 /* If null is passed in here then the name of the calling task is being queried. */\r
1474                 pxTCB = prvGetTCBFromHandle( xTaskToQuery );\r
1475                 configASSERT( pxTCB );\r
1476                 return &( pxTCB->pcTaskName[ 0 ] );\r
1477         }\r
1478 \r
1479 #endif /* INCLUDE_pcTaskGetTaskName */\r
1480 /*-----------------------------------------------------------*/\r
1481 \r
1482 #if ( configUSE_TRACE_FACILITY == 1 )\r
1483 \r
1484         unsigned portBASE_TYPE xTaskGetSystemState( xTaskStatusType *pxTaskStatusArray, unsigned portBASE_TYPE uxArraySize, unsigned long *pulTotalRunTime )\r
1485         {\r
1486         unsigned portBASE_TYPE uxTask = 0, uxQueue = configMAX_PRIORITIES;\r
1487 \r
1488                 vTaskSuspendAll();\r
1489                 {\r
1490                         /* Is there a space in the array for each task in the system? */\r
1491                         if( uxArraySize >= uxCurrentNumberOfTasks )\r
1492                         {\r
1493                                 /* Fill in an xTaskStatusType structure with information on each\r
1494                                 task in the Ready state. */\r
1495                                 do\r
1496                                 {\r
1497                                         uxQueue--;\r
1498                                         uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), eReady );\r
1499 \r
1500                                 }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );\r
1501 \r
1502                                 /* Fill in an xTaskStatusType structure with information on each\r
1503                                 task in the Blocked state. */\r
1504                                 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) pxDelayedTaskList, eBlocked );\r
1505                                 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) pxOverflowDelayedTaskList, eBlocked );\r
1506 \r
1507                                 #if( INCLUDE_vTaskDelete == 1 )\r
1508                                 {\r
1509                                         /* Fill in an xTaskStatusType structure with information on \r
1510                                         each task that has been deleted but not yet cleaned up. */\r
1511                                         uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted );\r
1512                                 }\r
1513                                 #endif\r
1514 \r
1515                                 #if ( INCLUDE_vTaskSuspend == 1 )\r
1516                                 {\r
1517                                         /* Fill in an xTaskStatusType structure with information on \r
1518                                         each task in the Suspended state. */\r
1519                                         uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended );\r
1520                                 }\r
1521                                 #endif\r
1522 \r
1523                                 #if ( configGENERATE_RUN_TIME_STATS == 1)\r
1524                                 {\r
1525                                         *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();\r
1526                                 }\r
1527                                 #else\r
1528                                 {\r
1529                                         *pulTotalRunTime = 0;\r
1530                                 }\r
1531                                 #endif\r
1532                         }\r
1533                 }\r
1534                 xTaskResumeAll();\r
1535 \r
1536                 return uxTask;\r
1537         }\r
1538 \r
1539 #endif /* configUSE_TRACE_FACILITY */\r
1540 /*----------------------------------------------------------*/\r
1541 \r
1542 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )\r
1543 \r
1544         xTaskHandle xTaskGetIdleTaskHandle( void )\r
1545         {\r
1546                 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been\r
1547                 started, then xIdleTaskHandle will be NULL. */\r
1548                 configASSERT( ( xIdleTaskHandle != NULL ) );\r
1549                 return xIdleTaskHandle;\r
1550         }\r
1551 \r
1552 #endif /* INCLUDE_xTaskGetIdleTaskHandle */\r
1553 /*----------------------------------------------------------*/\r
1554 \r
1555 /* This conditional compilation should use inequality to 0, not equality to 1.\r
1556 This is to ensure vTaskStepTick() is available when user defined low power mode\r
1557 implementations require configUSE_TICKLESS_IDLE to be set to a value other than\r
1558 1. */\r
1559 #if ( configUSE_TICKLESS_IDLE != 0 )\r
1560 \r
1561         void vTaskStepTick( portTickType xTicksToJump )\r
1562         {\r
1563                 /* Correct the tick count value after a period during which the tick\r
1564                 was suppressed.  Note this does *not* call the tick hook function for\r
1565                 each stepped tick. */\r
1566                 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );\r
1567                 xTickCount += xTicksToJump;\r
1568         }\r
1569 \r
1570 #endif /* configUSE_TICKLESS_IDLE */\r
1571 /*----------------------------------------------------------*/\r
1572 \r
1573 portBASE_TYPE xTaskIncrementTick( void )\r
1574 {\r
1575 tskTCB * pxTCB;\r
1576 portTickType xItemValue;\r
1577 portBASE_TYPE xSwitchRequired = pdFALSE;\r
1578 \r
1579         /* Called by the portable layer each time a tick interrupt occurs.\r
1580         Increments the tick then checks to see if the new tick value will cause any\r
1581         tasks to be unblocked. */\r
1582         traceTASK_INCREMENT_TICK( xTickCount );\r
1583         if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1584         {\r
1585                 /* Increment the RTOS tick, switching the delayed and overflowed\r
1586                 delayed lists if it wraps to 0. */\r
1587                 ++xTickCount;\r
1588                 if( xTickCount == ( portTickType ) 0U )\r
1589                 {\r
1590                         taskSWITCH_DELAYED_LISTS();\r
1591                 }\r
1592 \r
1593                 /* See if this tick has made a timeout expire.  Tasks are stored in the\r
1594                 queue in the order of their wake time - meaning once one tasks has been\r
1595                 found whose block time has not expired there is no need not look any\r
1596                 further down the list. */\r
1597                 if( xTickCount >= xNextTaskUnblockTime )\r
1598                 {\r
1599                         for( ;; )\r
1600                         {\r
1601                                 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )\r
1602                                 {\r
1603                                         /* The delayed list is empty.  Set xNextTaskUnblockTime to\r
1604                                         the     maximum possible value so it is extremely unlikely that\r
1605                                         the if( xTickCount >= xNextTaskUnblockTime ) test will pass\r
1606                                         next time through. */\r
1607                                         xNextTaskUnblockTime = portMAX_DELAY;\r
1608                                         break;\r
1609                                 }\r
1610                                 else\r
1611                                 {\r
1612                                         /* The delayed list is not empty, get the value of the item\r
1613                                         at the head of the delayed list.  This is the time at which\r
1614                                         the task at the head of the delayed list must be removed\r
1615                                         from the Blocked state. */\r
1616                                         pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );\r
1617                                         xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );\r
1618 \r
1619                                         if( xTickCount < xItemValue )\r
1620                                         {\r
1621                                                 /* It is not time to unblock this item yet, but the item\r
1622                                                 value is the time at which the task at the head of the\r
1623                                                 blocked list must be removed from the Blocked state -\r
1624                                                 so record the item value in xNextTaskUnblockTime. */\r
1625                                                 xNextTaskUnblockTime = xItemValue;\r
1626                                                 break;\r
1627                                         }\r
1628 \r
1629                                         /* It is time to remove the item from the Blocked state. */\r
1630                                         uxListRemove( &( pxTCB->xGenericListItem ) );\r
1631 \r
1632                                         /* Is the task waiting on an event also?  If so remove it\r
1633                                         from the event list. */\r
1634                                         if( pxTCB->xEventListItem.pvContainer != NULL )\r
1635                                         {\r
1636                                                 uxListRemove( &( pxTCB->xEventListItem ) );\r
1637                                         }\r
1638 \r
1639                                         /* Place the unblocked task into the appropriate ready\r
1640                                         list. */\r
1641                                         prvAddTaskToReadyList( pxTCB );\r
1642 \r
1643                                         /* A task being unblocked cannot cause an immediate context\r
1644                                         switch if preemption is turned off. */\r
1645                                         #if (  configUSE_PREEMPTION == 1 )\r
1646                                         {\r
1647                                                 /* Preemption is on, but a context switch should only\r
1648                                                 be performed if the unblocked task has a priority that\r
1649                                                 is equal to or higher than the currently executing\r
1650                                                 task. */\r
1651                                                 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
1652                                                 {\r
1653                                                         xSwitchRequired = pdTRUE;\r
1654                                                 }\r
1655                                         }\r
1656                                         #endif /* configUSE_PREEMPTION */\r
1657                                 }\r
1658                         }\r
1659                 }\r
1660 \r
1661                 /* Tasks of equal priority to the currently running task will share\r
1662                 processing time (time slice) if preemption is on, and the application\r
1663                 writer has not explicitly turned time slicing off. */\r
1664                 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )\r
1665                 {\r
1666                         if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > 1 )\r
1667                         {\r
1668                                 xSwitchRequired = pdTRUE;\r
1669                         }\r
1670                 }\r
1671                 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */\r
1672         }\r
1673         else\r
1674         {\r
1675                 ++uxPendedTicks;\r
1676 \r
1677                 /* The tick hook gets called at regular intervals, even if the\r
1678                 scheduler is locked. */\r
1679                 #if ( configUSE_TICK_HOOK == 1 )\r
1680                 {\r
1681                         vApplicationTickHook();\r
1682                 }\r
1683                 #endif\r
1684         }\r
1685 \r
1686         #if ( configUSE_TICK_HOOK == 1 )\r
1687         {\r
1688                 /* Guard against the tick hook being called when the missed tick\r
1689                 count is being unwound (when the scheduler is being unlocked). */\r
1690                 if( uxPendedTicks == ( unsigned portBASE_TYPE ) 0U )\r
1691                 {\r
1692                         vApplicationTickHook();\r
1693                 }\r
1694         }\r
1695         #endif /* configUSE_TICK_HOOK */\r
1696 \r
1697         return xSwitchRequired;\r
1698 }\r
1699 /*-----------------------------------------------------------*/\r
1700 \r
1701 #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
1702 \r
1703         void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction )\r
1704         {\r
1705         tskTCB *xTCB;\r
1706 \r
1707                 /* If xTask is NULL then we are setting our own task hook. */\r
1708                 if( xTask == NULL )\r
1709                 {\r
1710                         xTCB = ( tskTCB * ) pxCurrentTCB;\r
1711                 }\r
1712                 else\r
1713                 {\r
1714                         xTCB = ( tskTCB * ) xTask;\r
1715                 }\r
1716 \r
1717                 /* Save the hook function in the TCB.  A critical section is required as\r
1718                 the value can be accessed from an interrupt. */\r
1719                 taskENTER_CRITICAL();\r
1720                         xTCB->pxTaskTag = pxHookFunction;\r
1721                 taskEXIT_CRITICAL();\r
1722         }\r
1723 \r
1724 #endif /* configUSE_APPLICATION_TASK_TAG */\r
1725 /*-----------------------------------------------------------*/\r
1726 \r
1727 #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
1728 \r
1729         pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )\r
1730         {\r
1731         tskTCB *xTCB;\r
1732         pdTASK_HOOK_CODE xReturn;\r
1733 \r
1734                 /* If xTask is NULL then we are setting our own task hook. */\r
1735                 if( xTask == NULL )\r
1736                 {\r
1737                         xTCB = ( tskTCB * ) pxCurrentTCB;\r
1738                 }\r
1739                 else\r
1740                 {\r
1741                         xTCB = ( tskTCB * ) xTask;\r
1742                 }\r
1743 \r
1744                 /* Save the hook function in the TCB.  A critical section is required as\r
1745                 the value can be accessed from an interrupt. */\r
1746                 taskENTER_CRITICAL();\r
1747                         xReturn = xTCB->pxTaskTag;\r
1748                 taskEXIT_CRITICAL();\r
1749 \r
1750                 return xReturn;\r
1751         }\r
1752 \r
1753 #endif /* configUSE_APPLICATION_TASK_TAG */\r
1754 /*-----------------------------------------------------------*/\r
1755 \r
1756 #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
1757 \r
1758         portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )\r
1759         {\r
1760         tskTCB *xTCB;\r
1761         portBASE_TYPE xReturn;\r
1762 \r
1763                 /* If xTask is NULL then we are calling our own task hook. */\r
1764                 if( xTask == NULL )\r
1765                 {\r
1766                         xTCB = ( tskTCB * ) pxCurrentTCB;\r
1767                 }\r
1768                 else\r
1769                 {\r
1770                         xTCB = ( tskTCB * ) xTask;\r
1771                 }\r
1772 \r
1773                 if( xTCB->pxTaskTag != NULL )\r
1774                 {\r
1775                         xReturn = xTCB->pxTaskTag( pvParameter );\r
1776                 }\r
1777                 else\r
1778                 {\r
1779                         xReturn = pdFAIL;\r
1780                 }\r
1781 \r
1782                 return xReturn;\r
1783         }\r
1784 \r
1785 #endif /* configUSE_APPLICATION_TASK_TAG */\r
1786 /*-----------------------------------------------------------*/\r
1787 \r
1788 void vTaskSwitchContext( void )\r
1789 {\r
1790         if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )\r
1791         {\r
1792                 /* The scheduler is currently suspended - do not allow a context\r
1793                 switch. */\r
1794                 xYieldPending = pdTRUE;\r
1795         }\r
1796         else\r
1797         {\r
1798                 traceTASK_SWITCHED_OUT();\r
1799 \r
1800                 #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
1801                 {\r
1802                                 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE\r
1803                                         portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );\r
1804                                 #else\r
1805                                         ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();\r
1806                                 #endif\r
1807 \r
1808                                 /* Add the amount of time the task has been running to the\r
1809                                 accumulated     time so far.  The time the task started running was\r
1810                                 stored in ulTaskSwitchedInTime.  Note that there is no overflow\r
1811                                 protection here so count values are only valid until the timer\r
1812                                 overflows.  The guard against negative values is to protect\r
1813                                 against suspect run time stat counter implementations - which\r
1814                                 are provided by the application, not the kernel. */\r
1815                                 if( ulTotalRunTime > ulTaskSwitchedInTime )\r
1816                                 {\r
1817                                         pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );\r
1818                                 }\r
1819                                 ulTaskSwitchedInTime = ulTotalRunTime;\r
1820                 }\r
1821                 #endif /* configGENERATE_RUN_TIME_STATS */\r
1822 \r
1823                 taskFIRST_CHECK_FOR_STACK_OVERFLOW();\r
1824                 taskSECOND_CHECK_FOR_STACK_OVERFLOW();\r
1825 \r
1826                 taskSELECT_HIGHEST_PRIORITY_TASK();\r
1827 \r
1828                 traceTASK_SWITCHED_IN();\r
1829 \r
1830                 #if ( configUSE_NEWLIB_REENTRANT == 1 )\r
1831                 {\r
1832                         /* Switch Newlib's _impure_ptr variable to point to the _reent\r
1833                         structure specific to this task. */\r
1834                         _impure_ptr = &( pxCurrentTCB->xNewLib_reent );\r
1835                 }\r
1836                 #endif /* configUSE_NEWLIB_REENTRANT */\r
1837         }\r
1838 }\r
1839 /*-----------------------------------------------------------*/\r
1840 \r
1841 void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )\r
1842 {\r
1843 portTickType xTimeToWake;\r
1844 \r
1845         configASSERT( pxEventList );\r
1846 \r
1847         /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE\r
1848         SCHEDULER SUSPENDED. */\r
1849 \r
1850         /* Place the event list item of the TCB in the appropriate event list.\r
1851         This is placed in the list in priority order so the highest priority task\r
1852         is the first to be woken by the event. */\r
1853         vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );\r
1854 \r
1855         /* We must remove ourselves from the ready list before adding ourselves\r
1856         to the blocked list as the same list item is used for both lists.  We have\r
1857         exclusive access to the ready lists as the scheduler is locked. */\r
1858         if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )\r
1859         {\r
1860                 /* The current task must be in a ready list, so there is no need to\r
1861                 check, and the port reset macro can be called directly. */\r
1862                 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );\r
1863         }\r
1864 \r
1865         #if ( INCLUDE_vTaskSuspend == 1 )\r
1866         {\r
1867                 if( xTicksToWait == portMAX_DELAY )\r
1868                 {\r
1869                         /* Add ourselves to the suspended task list instead of a delayed task\r
1870                         list to ensure we are not woken by a timing event.  We will block\r
1871                         indefinitely. */\r
1872                         vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
1873                 }\r
1874                 else\r
1875                 {\r
1876                         /* Calculate the time at which the task should be woken if the event does\r
1877                         not occur.  This may overflow but this doesn't matter. */\r
1878                         xTimeToWake = xTickCount + xTicksToWait;\r
1879                         prvAddCurrentTaskToDelayedList( xTimeToWake );\r
1880                 }\r
1881         }\r
1882         #else /* INCLUDE_vTaskSuspend */\r
1883         {\r
1884                         /* Calculate the time at which the task should be woken if the event does\r
1885                         not occur.  This may overflow but this doesn't matter. */\r
1886                         xTimeToWake = xTickCount + xTicksToWait;\r
1887                         prvAddCurrentTaskToDelayedList( xTimeToWake );\r
1888         }\r
1889         #endif /* INCLUDE_vTaskSuspend */\r
1890 }\r
1891 /*-----------------------------------------------------------*/\r
1892 \r
1893 #if configUSE_TIMERS == 1\r
1894 \r
1895         void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait )\r
1896         {\r
1897         portTickType xTimeToWake;\r
1898 \r
1899                 configASSERT( pxEventList );\r
1900 \r
1901                 /* This function should not be called by application code hence the\r
1902                 'Restricted' in its name.  It is not part of the public API.  It is\r
1903                 designed for use by kernel code, and has special calling requirements -\r
1904                 it should be called from a critical section. */\r
1905 \r
1906 \r
1907                 /* Place the event list item of the TCB in the appropriate event list.\r
1908                 In this case it is assume that this is the only task that is going to\r
1909                 be waiting on this event list, so the faster vListInsertEnd() function\r
1910                 can be used in place of vListInsert. */\r
1911                 vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );\r
1912 \r
1913                 /* We must remove this task from the ready list before adding it to the\r
1914                 blocked list as the same list item is used for both lists.  This\r
1915                 function is called form a critical section. */\r
1916                 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )\r
1917                 {\r
1918                         /* The current task must be in a ready list, so there is no need to\r
1919                         check, and the port reset macro can be called directly. */\r
1920                         portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );\r
1921                 }\r
1922 \r
1923                 /* Calculate the time at which the task should be woken if the event does\r
1924                 not occur.  This may overflow but this doesn't matter. */\r
1925                 xTimeToWake = xTickCount + xTicksToWait;\r
1926 \r
1927                 traceTASK_DELAY_UNTIL();\r
1928                 prvAddCurrentTaskToDelayedList( xTimeToWake );\r
1929         }\r
1930 \r
1931 #endif /* configUSE_TIMERS */\r
1932 /*-----------------------------------------------------------*/\r
1933 \r
1934 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )\r
1935 {\r
1936 tskTCB *pxUnblockedTCB;\r
1937 portBASE_TYPE xReturn;\r
1938 \r
1939         /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE\r
1940         SCHEDULER SUSPENDED.  It can also be called from within an ISR. */\r
1941 \r
1942         /* The event list is sorted in priority order, so we can remove the\r
1943         first in the list, remove the TCB from the delayed list, and add\r
1944         it to the ready list.\r
1945 \r
1946         If an event is for a queue that is locked then this function will never\r
1947         get called - the lock count on the queue will get modified instead.  This\r
1948         means we can always expect exclusive access to the event list here.\r
1949 \r
1950         This function assumes that a check has already been made to ensure that\r
1951         pxEventList is not empty. */\r
1952         pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );\r
1953         configASSERT( pxUnblockedTCB );\r
1954         uxListRemove( &( pxUnblockedTCB->xEventListItem ) );\r
1955 \r
1956         if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1957         {\r
1958                 uxListRemove( &( pxUnblockedTCB->xGenericListItem ) );\r
1959                 prvAddTaskToReadyList( pxUnblockedTCB );\r
1960         }\r
1961         else\r
1962         {\r
1963                 /* We cannot access the delayed or ready lists, so will hold this\r
1964                 task pending until the scheduler is resumed. */\r
1965                 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );\r
1966         }\r
1967 \r
1968         if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
1969         {\r
1970                 /* Return true if the task removed from the event list has\r
1971                 a higher priority than the calling task.  This allows\r
1972                 the calling task to know if it should force a context\r
1973                 switch now. */\r
1974                 xReturn = pdTRUE;\r
1975         }\r
1976         else\r
1977         {\r
1978                 xReturn = pdFALSE;\r
1979         }\r
1980 \r
1981         return xReturn;\r
1982 }\r
1983 /*-----------------------------------------------------------*/\r
1984 \r
1985 void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )\r
1986 {\r
1987         configASSERT( pxTimeOut );\r
1988         pxTimeOut->xOverflowCount = xNumOfOverflows;\r
1989         pxTimeOut->xTimeOnEntering = xTickCount;\r
1990 }\r
1991 /*-----------------------------------------------------------*/\r
1992 \r
1993 portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )\r
1994 {\r
1995 portBASE_TYPE xReturn;\r
1996 \r
1997         configASSERT( pxTimeOut );\r
1998         configASSERT( pxTicksToWait );\r
1999 \r
2000         taskENTER_CRITICAL();\r
2001         {\r
2002                 #if ( INCLUDE_vTaskSuspend == 1 )\r
2003                         /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is\r
2004                         the maximum block time then the task should block indefinitely, and\r
2005                         therefore never time out. */\r
2006                         if( *pxTicksToWait == portMAX_DELAY )\r
2007                         {\r
2008                                 xReturn = pdFALSE;\r
2009                         }\r
2010                         else /* We are not blocking indefinitely, perform the checks below. */\r
2011                 #endif\r
2012 \r
2013                 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )\r
2014                 {\r
2015                         /* The tick count is greater than the time at which vTaskSetTimeout()\r
2016                         was called, but has also overflowed since vTaskSetTimeOut() was called.\r
2017                         It must have wrapped all the way around and gone past us again. This\r
2018                         passed since vTaskSetTimeout() was called. */\r
2019                         xReturn = pdTRUE;\r
2020                 }\r
2021                 else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )\r
2022                 {\r
2023                         /* Not a genuine timeout. Adjust parameters for time remaining. */\r
2024                         *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );\r
2025                         vTaskSetTimeOutState( pxTimeOut );\r
2026                         xReturn = pdFALSE;\r
2027                 }\r
2028                 else\r
2029                 {\r
2030                         xReturn = pdTRUE;\r
2031                 }\r
2032         }\r
2033         taskEXIT_CRITICAL();\r
2034 \r
2035         return xReturn;\r
2036 }\r
2037 /*-----------------------------------------------------------*/\r
2038 \r
2039 void vTaskMissedYield( void )\r
2040 {\r
2041         xYieldPending = pdTRUE;\r
2042 }\r
2043 /*-----------------------------------------------------------*/\r
2044 \r
2045 #if ( configUSE_TRACE_FACILITY == 1 )\r
2046 \r
2047         unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask )\r
2048         {\r
2049         unsigned portBASE_TYPE uxReturn;\r
2050         tskTCB *pxTCB;\r
2051 \r
2052                 if( xTask != NULL )\r
2053                 {\r
2054                         pxTCB = ( tskTCB * ) xTask;\r
2055                         uxReturn = pxTCB->uxTaskNumber;\r
2056                 }\r
2057                 else\r
2058                 {\r
2059                         uxReturn = 0U;\r
2060                 }\r
2061 \r
2062                 return uxReturn;\r
2063         }\r
2064 \r
2065 #endif /* configUSE_TRACE_FACILITY */\r
2066 /*-----------------------------------------------------------*/\r
2067 \r
2068 #if ( configUSE_TRACE_FACILITY == 1 )\r
2069 \r
2070         void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle )\r
2071         {\r
2072         tskTCB *pxTCB;\r
2073 \r
2074                 if( xTask != NULL )\r
2075                 {\r
2076                         pxTCB = ( tskTCB * ) xTask;\r
2077                         pxTCB->uxTaskNumber = uxHandle;\r
2078                 }\r
2079         }\r
2080 \r
2081 #endif /* configUSE_TRACE_FACILITY */\r
2082 \r
2083 /*\r
2084  * -----------------------------------------------------------\r
2085  * The Idle task.\r
2086  * ----------------------------------------------------------\r
2087  *\r
2088  * The portTASK_FUNCTION() macro is used to allow port/compiler specific\r
2089  * language extensions.  The equivalent prototype for this function is:\r
2090  *\r
2091  * void prvIdleTask( void *pvParameters );\r
2092  *\r
2093  */\r
2094 static portTASK_FUNCTION( prvIdleTask, pvParameters )\r
2095 {\r
2096         /* Stop warnings. */\r
2097         ( void ) pvParameters;\r
2098 \r
2099         for( ;; )\r
2100         {\r
2101                 /* See if any tasks have been deleted. */\r
2102                 prvCheckTasksWaitingTermination();\r
2103 \r
2104                 #if ( configUSE_PREEMPTION == 0 )\r
2105                 {\r
2106                         /* If we are not using preemption we keep forcing a task switch to\r
2107                         see if any other task has become available.  If we are using\r
2108                         preemption we don't need to do this as any task becoming available\r
2109                         will automatically get the processor anyway. */\r
2110                         taskYIELD();\r
2111                 }\r
2112                 #endif /* configUSE_PREEMPTION */\r
2113 \r
2114                 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )\r
2115                 {\r
2116                         /* When using preemption tasks of equal priority will be\r
2117                         timesliced.  If a task that is sharing the idle priority is ready\r
2118                         to run then the idle task should yield before the end of the\r
2119                         timeslice.\r
2120 \r
2121                         A critical region is not required here as we are just reading from\r
2122                         the list, and an occasional incorrect value will not matter.  If\r
2123                         the ready list at the idle priority contains more than one task\r
2124                         then a task other than the idle task is ready to execute. */\r
2125                         if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )\r
2126                         {\r
2127                                 taskYIELD();\r
2128                         }\r
2129                 }\r
2130                 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */\r
2131 \r
2132                 #if ( configUSE_IDLE_HOOK == 1 )\r
2133                 {\r
2134                         extern void vApplicationIdleHook( void );\r
2135 \r
2136                         /* Call the user defined function from within the idle task.  This\r
2137                         allows the application designer to add background functionality\r
2138                         without the overhead of a separate task.\r
2139                         NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,\r
2140                         CALL A FUNCTION THAT MIGHT BLOCK. */\r
2141                         vApplicationIdleHook();\r
2142                 }\r
2143                 #endif /* configUSE_IDLE_HOOK */\r
2144 \r
2145                 /* This conditional compilation should use inequality to 0, not equality\r
2146                 to 1.  This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when\r
2147                 user defined low power mode     implementations require\r
2148                 configUSE_TICKLESS_IDLE to be set to a value other than 1. */\r
2149                 #if ( configUSE_TICKLESS_IDLE != 0 )\r
2150                 {\r
2151                 portTickType xExpectedIdleTime;\r
2152 \r
2153                         /* It is not desirable to suspend then resume the scheduler on\r
2154                         each iteration of the idle task.  Therefore, a preliminary\r
2155                         test of the expected idle time is performed without the\r
2156                         scheduler suspended.  The result here is not necessarily\r
2157                         valid. */\r
2158                         xExpectedIdleTime = prvGetExpectedIdleTime();\r
2159 \r
2160                         if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )\r
2161                         {\r
2162                                 vTaskSuspendAll();\r
2163                                 {\r
2164                                         /* Now the scheduler is suspended, the expected idle\r
2165                                         time can be sampled again, and this time its value can\r
2166                                         be used. */\r
2167                                         configASSERT( xNextTaskUnblockTime >= xTickCount );\r
2168                                         xExpectedIdleTime = prvGetExpectedIdleTime();\r
2169 \r
2170                                         if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )\r
2171                                         {\r
2172                                                 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );\r
2173                                         }\r
2174                                 }\r
2175                                 xTaskResumeAll();\r
2176                         }\r
2177                 }\r
2178                 #endif /* configUSE_TICKLESS_IDLE */\r
2179         }\r
2180 } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */\r
2181 /*-----------------------------------------------------------*/\r
2182 \r
2183 #if configUSE_TICKLESS_IDLE != 0\r
2184 \r
2185         eSleepModeStatus eTaskConfirmSleepModeStatus( void )\r
2186         {\r
2187         eSleepModeStatus eReturn = eStandardSleep;\r
2188 \r
2189                 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )\r
2190                 {\r
2191                         /* A task was made ready while the scheduler was suspended. */\r
2192                         eReturn = eAbortSleep;\r
2193                 }\r
2194                 else if( xYieldPending != pdFALSE )\r
2195                 {\r
2196                         /* A yield was pended while the scheduler was suspended. */\r
2197                         eReturn = eAbortSleep;\r
2198                 }\r
2199                 else\r
2200                 {\r
2201                         #if configUSE_TIMERS == 0\r
2202                         {\r
2203                                 /* The idle task exists in addition to the application tasks. */\r
2204                                 const unsigned portBASE_TYPE uxNonApplicationTasks = 1;\r
2205 \r
2206                                 /* If timers are not being used and all the tasks are in the\r
2207                                 suspended list (which might mean they have an infinite block\r
2208                                 time rather than actually being suspended) then it is safe to\r
2209                                 turn all clocks off and just wait for external interrupts. */\r
2210                                 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )\r
2211                                 {\r
2212                                         eReturn = eNoTasksWaitingTimeout;\r
2213                                 }\r
2214                         }\r
2215                         #endif /* configUSE_TIMERS */\r
2216                 }\r
2217 \r
2218                 return eReturn;\r
2219         }\r
2220 #endif /* configUSE_TICKLESS_IDLE */\r
2221 /*-----------------------------------------------------------*/\r
2222 \r
2223 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )\r
2224 {\r
2225 portBASE_TYPE x;\r
2226 \r
2227         /* Store the task name in the TCB. */\r
2228         for( x = 0; x < configMAX_TASK_NAME_LEN; x++ )\r
2229         {\r
2230                 pxTCB->pcTaskName[ x ] = pcName[ x ];\r
2231 \r
2232                 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than\r
2233                 configMAX_TASK_NAME_LEN characters just in case the memory after the\r
2234                 string is not accessible (extremely unlikely). */\r
2235                 if( pcName[ x ] == 0x00 )\r
2236                 {\r
2237                         break;\r
2238                 }\r
2239         }\r
2240 \r
2241         /* Ensure the name string is terminated in the case that the string length\r
2242         was greater or equal to configMAX_TASK_NAME_LEN. */\r
2243         pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = ( signed char ) '\0';\r
2244 \r
2245         /* This is used as an array index so must ensure it's not too large.  First\r
2246         remove the privilege bit if one is present. */\r
2247         if( uxPriority >= configMAX_PRIORITIES )\r
2248         {\r
2249                 uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;\r
2250         }\r
2251 \r
2252         pxTCB->uxPriority = uxPriority;\r
2253         #if ( configUSE_MUTEXES == 1 )\r
2254         {\r
2255                 pxTCB->uxBasePriority = uxPriority;\r
2256         }\r
2257         #endif /* configUSE_MUTEXES */\r
2258 \r
2259         vListInitialiseItem( &( pxTCB->xGenericListItem ) );\r
2260         vListInitialiseItem( &( pxTCB->xEventListItem ) );\r
2261 \r
2262         /* Set the pxTCB as a link back from the xListItem.  This is so we can get\r
2263         back to the containing TCB from a generic item in a list. */\r
2264         listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );\r
2265 \r
2266         /* Event lists are always in priority order. */\r
2267         listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );\r
2268         listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );\r
2269 \r
2270         #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
2271         {\r
2272                 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0U;\r
2273         }\r
2274         #endif /* portCRITICAL_NESTING_IN_TCB */\r
2275 \r
2276         #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
2277         {\r
2278                 pxTCB->pxTaskTag = NULL;\r
2279         }\r
2280         #endif /* configUSE_APPLICATION_TASK_TAG */\r
2281 \r
2282         #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
2283         {\r
2284                 pxTCB->ulRunTimeCounter = 0UL;\r
2285         }\r
2286         #endif /* configGENERATE_RUN_TIME_STATS */\r
2287 \r
2288         #if ( portUSING_MPU_WRAPPERS == 1 )\r
2289         {\r
2290                 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );\r
2291         }\r
2292         #else /* portUSING_MPU_WRAPPERS */\r
2293         {\r
2294                 ( void ) xRegions;\r
2295                 ( void ) usStackDepth;\r
2296         }\r
2297         #endif /* portUSING_MPU_WRAPPERS */\r
2298 \r
2299         #if ( configUSE_NEWLIB_REENTRANT == 1 )\r
2300         {\r
2301                 /* Initialise this task's Newlib reent structure. */\r
2302                 _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) );\r
2303         }\r
2304         #endif /* configUSE_NEWLIB_REENTRANT */\r
2305 }\r
2306 /*-----------------------------------------------------------*/\r
2307 \r
2308 #if ( portUSING_MPU_WRAPPERS == 1 )\r
2309 \r
2310         void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )\r
2311         {\r
2312         tskTCB *pxTCB;\r
2313 \r
2314                 if( xTaskToModify == pxCurrentTCB )\r
2315                 {\r
2316                         xTaskToModify = NULL;\r
2317                 }\r
2318 \r
2319                 /* If null is passed in here then we are deleting ourselves. */\r
2320                 pxTCB = prvGetTCBFromHandle( xTaskToModify );\r
2321 \r
2322         vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );\r
2323         }\r
2324 \r
2325 #endif /* portUSING_MPU_WRAPPERS */\r
2326 /*-----------------------------------------------------------*/\r
2327 \r
2328 static void prvInitialiseTaskLists( void )\r
2329 {\r
2330 unsigned portBASE_TYPE uxPriority;\r
2331 \r
2332         for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < configMAX_PRIORITIES; uxPriority++ )\r
2333         {\r
2334                 vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );\r
2335         }\r
2336 \r
2337         vListInitialise( ( xList * ) &xDelayedTaskList1 );\r
2338         vListInitialise( ( xList * ) &xDelayedTaskList2 );\r
2339         vListInitialise( ( xList * ) &xPendingReadyList );\r
2340 \r
2341         #if ( INCLUDE_vTaskDelete == 1 )\r
2342         {\r
2343                 vListInitialise( ( xList * ) &xTasksWaitingTermination );\r
2344         }\r
2345         #endif /* INCLUDE_vTaskDelete */\r
2346 \r
2347         #if ( INCLUDE_vTaskSuspend == 1 )\r
2348         {\r
2349                 vListInitialise( ( xList * ) &xSuspendedTaskList );\r
2350         }\r
2351         #endif /* INCLUDE_vTaskSuspend */\r
2352 \r
2353         /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList\r
2354         using list2. */\r
2355         pxDelayedTaskList = &xDelayedTaskList1;\r
2356         pxOverflowDelayedTaskList = &xDelayedTaskList2;\r
2357 }\r
2358 /*-----------------------------------------------------------*/\r
2359 \r
2360 static void prvCheckTasksWaitingTermination( void )\r
2361 {\r
2362         #if ( INCLUDE_vTaskDelete == 1 )\r
2363         {\r
2364                 portBASE_TYPE xListIsEmpty;\r
2365 \r
2366                 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called\r
2367                 too often in the idle task. */\r
2368                 while( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0U )\r
2369                 {\r
2370                         vTaskSuspendAll();\r
2371                                 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );\r
2372                         xTaskResumeAll();\r
2373 \r
2374                         if( xListIsEmpty == pdFALSE )\r
2375                         {\r
2376                                 tskTCB *pxTCB;\r
2377 \r
2378                                 taskENTER_CRITICAL();\r
2379                                 {\r
2380                                         pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );\r
2381                                         uxListRemove( &( pxTCB->xGenericListItem ) );\r
2382                                         --uxCurrentNumberOfTasks;\r
2383                                         --uxTasksDeleted;\r
2384                                 }\r
2385                                 taskEXIT_CRITICAL();\r
2386 \r
2387                                 prvDeleteTCB( pxTCB );\r
2388                         }\r
2389                 }\r
2390         }\r
2391         #endif /* vTaskDelete */\r
2392 }\r
2393 /*-----------------------------------------------------------*/\r
2394 \r
2395 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake )\r
2396 {\r
2397         /* The list item will be inserted in wake time order. */\r
2398         listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );\r
2399 \r
2400         if( xTimeToWake < xTickCount )\r
2401         {\r
2402                 /* Wake time has overflowed.  Place this item in the overflow list. */\r
2403                 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
2404         }\r
2405         else\r
2406         {\r
2407                 /* The wake time has not overflowed, so we can use the current block list. */\r
2408                 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
2409 \r
2410                 /* If the task entering the blocked state was placed at the head of the\r
2411                 list of blocked tasks then xNextTaskUnblockTime needs to be updated\r
2412                 too. */\r
2413                 if( xTimeToWake < xNextTaskUnblockTime )\r
2414                 {\r
2415                         xNextTaskUnblockTime = xTimeToWake;\r
2416                 }\r
2417         }\r
2418 }\r
2419 /*-----------------------------------------------------------*/\r
2420 \r
2421 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )\r
2422 {\r
2423 tskTCB *pxNewTCB;\r
2424 \r
2425         /* Allocate space for the TCB.  Where the memory comes from depends on\r
2426         the implementation of the port malloc function. */\r
2427         pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );\r
2428 \r
2429         if( pxNewTCB != NULL )\r
2430         {\r
2431                 /* Allocate space for the stack used by the task being created.\r
2432                 The base of the stack memory stored in the TCB so the task can\r
2433                 be deleted later if required. */\r
2434                 pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );\r
2435 \r
2436                 if( pxNewTCB->pxStack == NULL )\r
2437                 {\r
2438                         /* Could not allocate the stack.  Delete the allocated TCB. */\r
2439                         vPortFree( pxNewTCB );\r
2440                         pxNewTCB = NULL;\r
2441                 }\r
2442                 else\r
2443                 {\r
2444                         /* Just to help debugging. */\r
2445                         memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( portSTACK_TYPE ) );\r
2446                 }\r
2447         }\r
2448 \r
2449         return pxNewTCB;\r
2450 }\r
2451 /*-----------------------------------------------------------*/\r
2452 \r
2453 #if ( configUSE_TRACE_FACILITY == 1 )\r
2454 \r
2455         static unsigned portBASE_TYPE prvListTaskWithinSingleList( xTaskStatusType *pxTaskStatusArray, xList *pxList, eTaskState eState )\r
2456         {\r
2457         volatile tskTCB *pxNextTCB, *pxFirstTCB;\r
2458         unsigned portBASE_TYPE uxTask = 0;\r
2459 \r
2460                 if( listCURRENT_LIST_LENGTH( pxList ) > 0 )\r
2461                 {                       \r
2462                         listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );\r
2463                         \r
2464                         /* Populate an xTaskStatusType structure within the \r
2465                         pxTaskStatusArray array for each task that is referenced from\r
2466                         pxList.  See the definition of xTaskStatusType in task.h for the\r
2467                         meaning of each xTaskStatusType structure member. */\r
2468                         do\r
2469                         {\r
2470                                 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );\r
2471 \r
2472                                 pxTaskStatusArray[ uxTask ].xHandle = ( xTaskHandle ) pxNextTCB;\r
2473                                 pxTaskStatusArray[ uxTask ].pcTaskName = ( const signed char * ) &( pxNextTCB->pcTaskName [ 0 ] );\r
2474                                 pxTaskStatusArray[ uxTask ].xTaskNumber = pxNextTCB->uxTCBNumber;\r
2475                                 pxTaskStatusArray[ uxTask ].eCurrentState = eState;\r
2476                                 pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority;\r
2477 \r
2478                                 #if ( configUSE_MUTEXES == 1 )\r
2479                                 {\r
2480                                         pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority;\r
2481                                 }\r
2482                                 #else\r
2483                                 {\r
2484                                         pxTaskStatusArray[ uxTask ].uxBasePriority = 0;\r
2485                                 }\r
2486                                 #endif\r
2487 \r
2488                                 #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
2489                                 {\r
2490                                         pxTaskStatusArray[ uxTask ].ulRunTimeCounter = pxNextTCB->ulRunTimeCounter;\r
2491                                 }\r
2492                                 #else\r
2493                                 {\r
2494                                         pxTaskStatusArray[ uxTask ].ulRunTimeCounter = 0;\r
2495                                 }\r
2496                                 #endif\r
2497 \r
2498                                 #if ( portSTACK_GROWTH > 0 )\r
2499                                 {\r
2500                                         ppxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );\r
2501                                 }\r
2502                                 #else\r
2503                                 {\r
2504                                         pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );\r
2505                                 }\r
2506                                 #endif\r
2507 \r
2508                                 uxTask++;\r
2509 \r
2510                         } while( pxNextTCB != pxFirstTCB );\r
2511                 }\r
2512 \r
2513                 return uxTask;\r
2514         }\r
2515 \r
2516 #endif /* configUSE_TRACE_FACILITY */\r
2517 /*-----------------------------------------------------------*/\r
2518 \r
2519 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )\r
2520 \r
2521         static unsigned short prvTaskCheckFreeStackSpace( const unsigned char * pucStackByte )\r
2522         {\r
2523         register unsigned short usCount = 0U;\r
2524 \r
2525                 while( *pucStackByte == tskSTACK_FILL_BYTE )\r
2526                 {\r
2527                         pucStackByte -= portSTACK_GROWTH;\r
2528                         usCount++;\r
2529                 }\r
2530 \r
2531                 usCount /= sizeof( portSTACK_TYPE );\r
2532 \r
2533                 return usCount;\r
2534         }\r
2535 \r
2536 #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */\r
2537 /*-----------------------------------------------------------*/\r
2538 \r
2539 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )\r
2540 \r
2541         unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )\r
2542         {\r
2543         tskTCB *pxTCB;\r
2544         unsigned char *pcEndOfStack;\r
2545         unsigned portBASE_TYPE uxReturn;\r
2546 \r
2547                 pxTCB = prvGetTCBFromHandle( xTask );\r
2548 \r
2549                 #if portSTACK_GROWTH < 0\r
2550                 {\r
2551                         pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;\r
2552                 }\r
2553                 #else\r
2554                 {\r
2555                         pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;\r
2556                 }\r
2557                 #endif\r
2558 \r
2559                 uxReturn = ( unsigned portBASE_TYPE ) prvTaskCheckFreeStackSpace( pcEndOfStack );\r
2560 \r
2561                 return uxReturn;\r
2562         }\r
2563 \r
2564 #endif /* INCLUDE_uxTaskGetStackHighWaterMark */\r
2565 /*-----------------------------------------------------------*/\r
2566 \r
2567 #if ( INCLUDE_vTaskDelete == 1 )\r
2568 \r
2569         static void prvDeleteTCB( tskTCB *pxTCB )\r
2570         {\r
2571                 /* This call is required specifically for the TriCore port.  It must be\r
2572                 above the vPortFree() calls.  The call is also used by ports/demos that\r
2573                 want to allocate and clean RAM statically. */\r
2574                 portCLEAN_UP_TCB( pxTCB );\r
2575 \r
2576                 /* Free up the memory allocated by the scheduler for the task.  It is up to\r
2577                 the task to free any memory allocated at the application level. */\r
2578                 vPortFreeAligned( pxTCB->pxStack );\r
2579                 vPortFree( pxTCB );\r
2580         }\r
2581 \r
2582 #endif /* INCLUDE_vTaskDelete */\r
2583 /*-----------------------------------------------------------*/\r
2584 \r
2585 #if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )\r
2586 \r
2587         xTaskHandle xTaskGetCurrentTaskHandle( void )\r
2588         {\r
2589         xTaskHandle xReturn;\r
2590 \r
2591                 /* A critical section is not required as this is not called from\r
2592                 an interrupt and the current TCB will always be the same for any\r
2593                 individual execution thread. */\r
2594                 xReturn = pxCurrentTCB;\r
2595 \r
2596                 return xReturn;\r
2597         }\r
2598 \r
2599 #endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */\r
2600 /*-----------------------------------------------------------*/\r
2601 \r
2602 #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )\r
2603 \r
2604         portBASE_TYPE xTaskGetSchedulerState( void )\r
2605         {\r
2606         portBASE_TYPE xReturn;\r
2607 \r
2608                 if( xSchedulerRunning == pdFALSE )\r
2609                 {\r
2610                         xReturn = taskSCHEDULER_NOT_STARTED;\r
2611                 }\r
2612                 else\r
2613                 {\r
2614                         if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
2615                         {\r
2616                                 xReturn = taskSCHEDULER_RUNNING;\r
2617                         }\r
2618                         else\r
2619                         {\r
2620                                 xReturn = taskSCHEDULER_SUSPENDED;\r
2621                         }\r
2622                 }\r
2623 \r
2624                 return xReturn;\r
2625         }\r
2626 \r
2627 #endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */\r
2628 /*-----------------------------------------------------------*/\r
2629 \r
2630 #if ( configUSE_MUTEXES == 1 )\r
2631 \r
2632         void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )\r
2633         {\r
2634         tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;\r
2635 \r
2636                 /* If the mutex was given back by an interrupt while the queue was\r
2637                 locked then the mutex holder might now be NULL. */\r
2638                 if( pxMutexHolder != NULL )\r
2639                 {\r
2640                         if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )\r
2641                         {\r
2642                                 /* Adjust the mutex holder state to account for its new priority. */\r
2643                                 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );\r
2644 \r
2645                                 /* If the task being modified is in the ready state it will need to\r
2646                                 be moved into a new list. */\r
2647                                 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE )\r
2648                                 {\r
2649                                         if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )\r
2650                                         {\r
2651                                                 taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
2652                                         }\r
2653 \r
2654                                         /* Inherit the priority before being moved into the new list. */\r
2655                                         pxTCB->uxPriority = pxCurrentTCB->uxPriority;\r
2656                                         prvAddTaskToReadyList( pxTCB );\r
2657                                 }\r
2658                                 else\r
2659                                 {\r
2660                                         /* Just inherit the priority. */\r
2661                                         pxTCB->uxPriority = pxCurrentTCB->uxPriority;\r
2662                                 }\r
2663 \r
2664                                 traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );\r
2665                         }\r
2666                 }\r
2667         }\r
2668 \r
2669 #endif /* configUSE_MUTEXES */\r
2670 /*-----------------------------------------------------------*/\r
2671 \r
2672 #if ( configUSE_MUTEXES == 1 )\r
2673 \r
2674         void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )\r
2675         {\r
2676         tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;\r
2677 \r
2678                 if( pxMutexHolder != NULL )\r
2679                 {\r
2680                         if( pxTCB->uxPriority != pxTCB->uxBasePriority )\r
2681                         {\r
2682                                 /* We must be the running task to be able to give the mutex back.\r
2683                                 Remove ourselves from the ready list we currently appear in. */\r
2684                                 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )\r
2685                                 {\r
2686                                         taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
2687                                 }\r
2688 \r
2689                                 /* Disinherit the priority before adding the task into the new\r
2690                                 ready list. */\r
2691                                 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );\r
2692                                 pxTCB->uxPriority = pxTCB->uxBasePriority;\r
2693                                 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );\r
2694                                 prvAddTaskToReadyList( pxTCB );\r
2695                         }\r
2696                 }\r
2697         }\r
2698 \r
2699 #endif /* configUSE_MUTEXES */\r
2700 /*-----------------------------------------------------------*/\r
2701 \r
2702 #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
2703 \r
2704         void vTaskEnterCritical( void )\r
2705         {\r
2706                 portDISABLE_INTERRUPTS();\r
2707 \r
2708                 if( xSchedulerRunning != pdFALSE )\r
2709                 {\r
2710                         ( pxCurrentTCB->uxCriticalNesting )++;\r
2711                 }\r
2712         }\r
2713 \r
2714 #endif /* portCRITICAL_NESTING_IN_TCB */\r
2715 /*-----------------------------------------------------------*/\r
2716 \r
2717 #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
2718 \r
2719         void vTaskExitCritical( void )\r
2720         {\r
2721                 if( xSchedulerRunning != pdFALSE )\r
2722                 {\r
2723                         if( pxCurrentTCB->uxCriticalNesting > 0U )\r
2724                         {\r
2725                                 ( pxCurrentTCB->uxCriticalNesting )--;\r
2726 \r
2727                                 if( pxCurrentTCB->uxCriticalNesting == 0U )\r
2728                                 {\r
2729                                         portENABLE_INTERRUPTS();\r
2730                                 }\r
2731                         }\r
2732                 }\r
2733         }\r
2734 \r
2735 #endif /* portCRITICAL_NESTING_IN_TCB */\r
2736 /*-----------------------------------------------------------*/\r
2737 \r
2738 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configINCLUDE_STATS_FORMATTING_FUNCTIONS == 1 ) )\r
2739 \r
2740         void vTaskList( signed char *pcWriteBuffer )\r
2741         {\r
2742         xTaskStatusType *pxTaskStatusArray;\r
2743         volatile unsigned portBASE_TYPE uxArraySize, x;\r
2744         unsigned long ulTotalRunTime;\r
2745         char cStatus;\r
2746 \r
2747                 /*\r
2748                  * PLEASE NOTE:\r
2749                  *\r
2750                  * This function is provided for convenience only, and is used by many\r
2751                  * of the demo applications.  Do not consider it to be part of the\r
2752                  * scheduler.\r
2753                  *\r
2754                  * vTaskList() calls xTaskGetSystemState(), then formats part of the\r
2755                  * xTaskGetSystemState() output into a human readable table that\r
2756                  * displays task names, states and stack usage.\r
2757                  *\r
2758                  * vTaskList() has a dependency on the sprintf() C library function that\r
2759                  * might bloat the code size, use a lot of stack, and provide different\r
2760                  * results on different platforms.  An alternative, tiny, third party,\r
2761                  * and limited functionality implementation of sprintf() is provided in\r
2762                  * many of the FreeRTOS/Demo sub-directories in a file called\r
2763                  * printf-stdarg.c (note printf-stdarg.c does not provide a full\r
2764                  * snprintf() implementation!).\r
2765                  *\r
2766                  * It is recommended that production systems call xTaskGetSystemState()\r
2767                  * directly to get access to raw stats data, rather than indirectly\r
2768                  * through a call to vTaskList().\r
2769                  */\r
2770 \r
2771 \r
2772                 /* Make sure the write buffer does not contain a string. */\r
2773                 *pcWriteBuffer = 0x00;\r
2774 \r
2775                 /* Take a snapshot of the number of tasks in case it changes while this\r
2776                 function is executing. */\r
2777                 uxArraySize = uxCurrentNumberOfTasks;\r
2778 \r
2779                 /* Allocate an array index for each task. */\r
2780                 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) );\r
2781 \r
2782                 if( pxTaskStatusArray != NULL )\r
2783                 {\r
2784                         /* Generate the (binary) data. */\r
2785                         uxArraySize = xTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalRunTime );\r
2786 \r
2787                         /* Create a human readable table from the binary data. */\r
2788                         for( x = 0; x < uxArraySize; x++ )\r
2789                         {\r
2790                                 switch( pxTaskStatusArray[ x ].eCurrentState )\r
2791                                 {\r
2792                                 case eReady:            cStatus = tskREADY_CHAR;\r
2793                                                                         break;\r
2794 \r
2795                                 case eBlocked:          cStatus = tskBLOCKED_CHAR;\r
2796                                                                         break;\r
2797 \r
2798                                 case eSuspended:        cStatus = tskSUSPENDED_CHAR;\r
2799                                                                         break;\r
2800 \r
2801                                 case eDeleted:          cStatus = tskDELETED_CHAR;\r
2802                                                                         break;\r
2803 \r
2804                                 default:                        /* Should not get here, but it is included\r
2805                                                                         to prevent static checking errors. */\r
2806                                                                         cStatus = 0x00;\r
2807                                                                         break;\r
2808                                 }\r
2809 \r
2810                                 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
2811                                 pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );\r
2812                         }\r
2813 \r
2814                         /* Free the array again. */\r
2815                         vPortFree( pxTaskStatusArray );\r
2816                 }\r
2817         }\r
2818 \r
2819 #endif /* configUSE_TRACE_FACILITY */\r
2820 /*----------------------------------------------------------*/\r
2821 \r
2822 #if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configINCLUDE_STATS_FORMATTING_FUNCTIONS == 1 ) )\r
2823 \r
2824         void vTaskGetRunTimeStats( signed char *pcWriteBuffer )\r
2825         {\r
2826         xTaskStatusType *pxTaskStatusArray;\r
2827         volatile unsigned portBASE_TYPE uxArraySize, x;\r
2828         unsigned long ulTotalRunTime, ulStatsAsPercentage;\r
2829 \r
2830                 /*\r
2831                  * PLEASE NOTE:\r
2832                  *\r
2833                  * This function is provided for convenience only, and is used by many\r
2834                  * of the demo applications.  Do not consider it to be part of the\r
2835                  * scheduler.\r
2836                  *\r
2837                  * vTaskGetRunTimeStats() calls xTaskGetSystemState(), then formats part\r
2838                  * of the xTaskGetSystemState() output into a human readable table that\r
2839                  * displays the amount of time each task has spent in the Running state\r
2840                  * in both absolute and percentage terms.\r
2841                  *\r
2842                  * vTaskGetRunTimeStats() has a dependency on the sprintf() C library\r
2843                  * function that might bloat the code size, use a lot of stack, and\r
2844                  * provide different results on different platforms.  An alternative,\r
2845                  * tiny, third party, and limited functionality implementation of\r
2846                  * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in\r
2847                  * a file called printf-stdarg.c (note printf-stdarg.c does not provide\r
2848                  * a full snprintf() implementation!).\r
2849                  *\r
2850                  * It is recommended that production systems call xTaskGetSystemState()\r
2851                  * directly to get access to raw stats data, rather than indirectly\r
2852                  * through a call to vTaskGetRunTimeStats().\r
2853                  */\r
2854 \r
2855                 /* Make sure the write buffer does not contain a string. */\r
2856                 *pcWriteBuffer = 0x00;\r
2857 \r
2858                 /* Take a snapshot of the number of tasks in case it changes while this\r
2859                 function is executing. */\r
2860                 uxArraySize = uxCurrentNumberOfTasks;\r
2861 \r
2862                 /* Allocate an array index for each task. */\r
2863                 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) );\r
2864 \r
2865                 if( pxTaskStatusArray != NULL )\r
2866                 {\r
2867                         /* Generate the (binary) data. */\r
2868                         uxArraySize = xTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalRunTime );\r
2869 \r
2870                         /* For percentage calculations. */\r
2871                         ulTotalRunTime /= 100UL;\r
2872 \r
2873                         /* Avoid divide by zero errors. */\r
2874                         if( ulTotalRunTime > 0 )\r
2875                         {\r
2876                                 /* Create a human readable table from the binary data. */\r
2877                                 for( x = 0; x < uxArraySize; x++ )\r
2878                                 {\r
2879                                         /* What percentage of the total run time has the task used?\r
2880                                         This will always be rounded down to the nearest integer.\r
2881                                         ulTotalRunTimeDiv100 has already been divided by 100. */\r
2882                                         ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalRunTime;\r
2883 \r
2884                                         if( ulStatsAsPercentage > 0UL )\r
2885                                         {\r
2886                                                 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED\r
2887                                                 {\r
2888                                                         sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );\r
2889                                                 }\r
2890                                                 #else\r
2891                                                 {\r
2892                                                         /* sizeof( int ) == sizeof( long ) so a smaller\r
2893                                                         printf() library can be used. */\r
2894                                                         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
2895                                                 }\r
2896                                                 #endif\r
2897                                         }\r
2898                                         else\r
2899                                         {\r
2900                                                 /* If the percentage is zero here then the task has\r
2901                                                 consumed less than 1% of the total run time. */\r
2902                                                 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED\r
2903                                                 {\r
2904                                                         sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter );\r
2905                                                 }\r
2906                                                 #else\r
2907                                                 {\r
2908                                                         /* sizeof( int ) == sizeof( long ) so a smaller\r
2909                                                         printf() library can be used. */\r
2910                                                         sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter );\r
2911                                                 }\r
2912                                                 #endif\r
2913                                         }\r
2914 \r
2915                                         pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );\r
2916                                 }\r
2917                         }\r
2918 \r
2919                         /* Free the array again. */\r
2920                         vPortFree( pxTaskStatusArray );\r
2921                 }\r
2922         }\r
2923 \r
2924 #endif /* configGENERATE_RUN_TIME_STATS */\r
2925 \r
2926 \r
2927 \r