]> git.sur5r.net Git - freertos/blob - Source/tasks.c
vTaskList() now works for architectures where the stack grows up from low memory.
[freertos] / Source / tasks.c
1 /*\r
2     FreeRTOS V6.0.1 - Copyright (C) 2009 Real Time Engineers Ltd.\r
3 \r
4     ***************************************************************************\r
5     *                                                                         *\r
6     * If you are:                                                             *\r
7     *                                                                         *\r
8     *    + New to FreeRTOS,                                                   *\r
9     *    + Wanting to learn FreeRTOS or multitasking in general quickly       *\r
10     *    + Looking for basic training,                                        *\r
11     *    + Wanting to improve your FreeRTOS skills and productivity           *\r
12     *                                                                         *\r
13     * then take a look at the FreeRTOS eBook                                  *\r
14     *                                                                         *\r
15     *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *\r
16     *                  http://www.FreeRTOS.org/Documentation                  *\r
17     *                                                                         *\r
18     * A pdf reference manual is also available.  Both are usually delivered   *\r
19     * to your inbox within 20 minutes to two hours when purchased between 8am *\r
20     * and 8pm GMT (although please allow up to 24 hours in case of            *\r
21     * exceptional circumstances).  Thank you for your support!                *\r
22     *                                                                         *\r
23     ***************************************************************************\r
24 \r
25     This file is part of the FreeRTOS distribution.\r
26 \r
27     FreeRTOS is free software; you can redistribute it and/or modify it under\r
28     the terms of the GNU General Public License (version 2) as published by the\r
29     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
30     ***NOTE*** The exception to the GPL is included to allow you to distribute\r
31     a combined work that includes FreeRTOS without being obliged to provide the\r
32     source code for proprietary components outside of the FreeRTOS kernel.\r
33     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT\r
34     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
35     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
36     more details. You should have received a copy of the GNU General Public \r
37     License and the FreeRTOS license exception along with FreeRTOS; if not it \r
38     can be viewed here: http://www.freertos.org/a00114.html and also obtained \r
39     by writing to Richard Barry, contact details for whom are available on the\r
40     FreeRTOS WEB site.\r
41 \r
42     1 tab == 4 spaces!\r
43 \r
44     http://www.FreeRTOS.org - Documentation, latest information, license and\r
45     contact details.\r
46 \r
47     http://www.SafeRTOS.com - A version that is certified for use in safety\r
48     critical systems.\r
49 \r
50     http://www.OpenRTOS.com - Commercial support, development, porting,\r
51     licensing and training services.\r
52 */\r
53 \r
54 \r
55 #include <stdio.h>\r
56 #include <stdlib.h>\r
57 #include <string.h>\r
58 \r
59 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
60 all the API functions to use the MPU wrappers.  That should only be done when\r
61 task.h is included from an application file. */\r
62 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
63 \r
64 #include "FreeRTOS.h"\r
65 #include "task.h"\r
66 #include "StackMacros.h"\r
67 \r
68 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
69 \r
70 /*\r
71  * Macro to define the amount of stack available to the idle task.\r
72  */\r
73 #define tskIDLE_STACK_SIZE      configMINIMAL_STACK_SIZE\r
74 \r
75 #define tskIDLE_PRIORITY                        ( ( unsigned portBASE_TYPE ) 0 )\r
76 \r
77 /*\r
78  * Task control block.  A task control block (TCB) is allocated to each task,\r
79  * and stores the context of the task.\r
80  */\r
81 typedef struct tskTaskControlBlock\r
82 {\r
83         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 STRUCT. */\r
84 \r
85         #if ( portUSING_MPU_WRAPPERS == 1 )\r
86                 xMPU_SETTINGS xMPUSettings;                             /*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */\r
87         #endif  \r
88         \r
89         xListItem                               xGenericListItem;       /*< List item used to place the TCB in ready and blocked queues. */\r
90         xListItem                               xEventListItem;         /*< List item used to place the TCB in event lists. */\r
91         unsigned portBASE_TYPE  uxPriority;                     /*< The priority of the task where 0 is the lowest priority. */\r
92         portSTACK_TYPE                  *pxStack;                       /*< Points to the start of the stack. */\r
93         signed char                             pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */\r
94 \r
95         #if ( portSTACK_GROWTH > 0 )\r
96                 portSTACK_TYPE *pxEndOfStack;                   /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */\r
97         #endif\r
98 \r
99         #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
100                 unsigned portBASE_TYPE uxCriticalNesting;\r
101         #endif\r
102 \r
103         #if ( configUSE_TRACE_FACILITY == 1 )\r
104                 unsigned portBASE_TYPE  uxTCBNumber;    /*< This is used for tracing the scheduler and making debugging easier only. */\r
105         #endif\r
106 \r
107         #if ( configUSE_MUTEXES == 1 )\r
108                 unsigned portBASE_TYPE uxBasePriority;  /*< The priority last assigned to the task - used by the priority inheritance mechanism. */\r
109         #endif\r
110 \r
111         #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
112                 pdTASK_HOOK_CODE pxTaskTag;\r
113         #endif\r
114 \r
115         #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
116                 unsigned long ulRunTimeCounter;         /*< Used for calculating how much CPU time each task is utilising. */\r
117         #endif\r
118 \r
119 } tskTCB;\r
120 \r
121 \r
122 /*\r
123  * Some kernel aware debuggers require data to be viewed to be global, rather\r
124  * than file scope.\r
125  */\r
126 #ifdef portREMOVE_STATIC_QUALIFIER\r
127         #define static\r
128 #endif\r
129 \r
130 /*lint -e956 */\r
131 PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;\r
132 \r
133 /* Lists for ready and blocked tasks. --------------------*/\r
134 \r
135 PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */\r
136 PRIVILEGED_DATA static xList xDelayedTaskList1;                                                 /*< Delayed tasks. */\r
137 PRIVILEGED_DATA static xList xDelayedTaskList2;                                                 /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */\r
138 PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ;                             /*< Points to the delayed task list currently being used. */\r
139 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
140 PRIVILEGED_DATA static xList xPendingReadyList;                                                 /*< Tasks that have been readied while the scheduler was suspended.  They will be moved to the ready queue when the scheduler is resumed. */\r
141 \r
142 #if ( INCLUDE_vTaskDelete == 1 )\r
143 \r
144         PRIVILEGED_DATA static volatile xList xTasksWaitingTermination;         /*< Tasks that have been deleted - but the their memory not yet freed. */\r
145         PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;\r
146 \r
147 #endif\r
148 \r
149 #if ( INCLUDE_vTaskSuspend == 1 )\r
150 \r
151         PRIVILEGED_DATA static xList xSuspendedTaskList;                                        /*< Tasks that are currently suspended. */\r
152 \r
153 #endif\r
154 \r
155 /* File private variables. --------------------------------*/\r
156 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks   = ( unsigned portBASE_TYPE ) 0;\r
157 PRIVILEGED_DATA static volatile portTickType xTickCount                                                 = ( portTickType ) 0;\r
158 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority                                 = tskIDLE_PRIORITY;\r
159 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority               = tskIDLE_PRIORITY;\r
160 PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning                  = pdFALSE;\r
161 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended             = ( unsigned portBASE_TYPE ) pdFALSE;\r
162 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks                    = ( unsigned portBASE_TYPE ) 0;\r
163 PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield                                              = ( portBASE_TYPE ) pdFALSE;\r
164 PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows                                   = ( portBASE_TYPE ) 0;\r
165 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber                                              = ( unsigned portBASE_TYPE ) 0;\r
166 \r
167 #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
168 \r
169         PRIVILEGED_DATA static char pcStatsString[ 50 ] ;\r
170         PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL;        /*< Holds the value of a timer/counter the last time a task was switched in. */\r
171         static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime ) PRIVILEGED_FUNCTION;\r
172 \r
173 #endif\r
174 \r
175 /* Debugging and trace facilities private variables and macros. ------------*/\r
176 \r
177 /*\r
178  * The value used to fill the stack of a task when the task is created.  This\r
179  * is used purely for checking the high water mark for tasks.\r
180  */\r
181 #define tskSTACK_FILL_BYTE      ( 0xa5 )\r
182 \r
183 /*\r
184  * Macros used by vListTask to indicate which state a task is in.\r
185  */\r
186 #define tskBLOCKED_CHAR         ( ( signed char ) 'B' )\r
187 #define tskREADY_CHAR           ( ( signed char ) 'R' )\r
188 #define tskDELETED_CHAR         ( ( signed char ) 'D' )\r
189 #define tskSUSPENDED_CHAR       ( ( signed char ) 'S' )\r
190 \r
191 /*\r
192  * Macros and private variables used by the trace facility.\r
193  */\r
194 #if ( configUSE_TRACE_FACILITY == 1 )\r
195 \r
196         #define tskSIZE_OF_EACH_TRACE_LINE                      ( ( unsigned long ) ( sizeof( unsigned long ) + sizeof( unsigned long ) ) )\r
197         PRIVILEGED_DATA static volatile signed char * volatile pcTraceBuffer;\r
198         PRIVILEGED_DATA static signed char *pcTraceBufferStart;\r
199         PRIVILEGED_DATA static signed char *pcTraceBufferEnd;\r
200         PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE;\r
201         static unsigned portBASE_TYPE uxPreviousTask = 255;\r
202         PRIVILEGED_DATA static char pcStatusString[ 50 ];\r
203 \r
204 #endif\r
205 \r
206 /*-----------------------------------------------------------*/\r
207 \r
208 /*\r
209  * Macro that writes a trace of scheduler activity to a buffer.  This trace\r
210  * shows which task is running when and is very useful as a debugging tool.\r
211  * As this macro is called each context switch it is a good idea to undefine\r
212  * it if not using the facility.\r
213  */\r
214 #if ( configUSE_TRACE_FACILITY == 1 )\r
215 \r
216         #define vWriteTraceToBuffer()                                                                                                                                   \\r
217         {                                                                                                                                                                                               \\r
218                 if( xTracing )                                                                                                                                                          \\r
219                 {                                                                                                                                                                                       \\r
220                         if( uxPreviousTask != pxCurrentTCB->uxTCBNumber )                                                                               \\r
221                         {                                                                                                                                                                               \\r
222                                 if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd )                         \\r
223                                 {                                                                                                                                                                       \\r
224                                         uxPreviousTask = pxCurrentTCB->uxTCBNumber;                                                                             \\r
225                                         *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount;              \\r
226                                         pcTraceBuffer += sizeof( unsigned long );                                                                       \\r
227                                         *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask;  \\r
228                                         pcTraceBuffer += sizeof( unsigned long );                                                                       \\r
229                                 }                                                                                                                                                                       \\r
230                                 else                                                                                                                                                            \\r
231                                 {                                                                                                                                                                       \\r
232                                         xTracing = pdFALSE;                                                                                                                             \\r
233                                 }                                                                                                                                                                       \\r
234                         }                                                                                                                                                                               \\r
235                 }                                                                                                                                                                                       \\r
236         }\r
237 \r
238 #else\r
239 \r
240         #define vWriteTraceToBuffer()\r
241 \r
242 #endif\r
243 /*-----------------------------------------------------------*/\r
244 \r
245 /*\r
246  * Place the task represented by pxTCB into the appropriate ready queue for\r
247  * the task.  It is inserted at the end of the list.  One quirk of this is\r
248  * that if the task being inserted is at the same priority as the currently\r
249  * executing task, then it will only be rescheduled after the currently\r
250  * executing task has been rescheduled.\r
251  */\r
252 #define prvAddTaskToReadyQueue( pxTCB )                                                                                                                                                 \\r
253 {                                                                                                                                                                                                                               \\r
254         if( pxTCB->uxPriority > uxTopReadyPriority )                                                                                                                            \\r
255         {                                                                                                                                                                                                                       \\r
256                 uxTopReadyPriority = pxTCB->uxPriority;                                                                                                                                 \\r
257         }                                                                                                                                                                                                                       \\r
258         vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) );        \\r
259 }\r
260 /*-----------------------------------------------------------*/\r
261 \r
262 /*\r
263  * Macro that looks at the list of tasks that are currently delayed to see if\r
264  * any require waking.\r
265  *\r
266  * Tasks are stored in the queue in the order of their wake time - meaning\r
267  * once one tasks has been found whose timer has not expired we need not look\r
268  * any further down the list.\r
269  */\r
270 #define prvCheckDelayedTasks()                                                                                                                                                                          \\r
271 {                                                                                                                                                                                                                                       \\r
272 register tskTCB *pxTCB;                                                                                                                                                                                         \\r
273                                                                                                                                                                                                                                         \\r
274         while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL )                                              \\r
275         {                                                                                                                                                                                                                               \\r
276                 if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) )                                                                      \\r
277                 {                                                                                                                                                                                                                       \\r
278                         break;                                                                                                                                                                                                  \\r
279                 }                                                                                                                                                                                                                       \\r
280                 vListRemove( &( pxTCB->xGenericListItem ) );                                                                                                                            \\r
281                 /* Is the task waiting on an event also? */                                                                                                                                     \\r
282                 if( pxTCB->xEventListItem.pvContainer )                                                                                                                                         \\r
283                 {                                                                                                                                                                                                                       \\r
284                         vListRemove( &( pxTCB->xEventListItem ) );                                                                                                                              \\r
285                 }                                                                                                                                                                                                                       \\r
286                 prvAddTaskToReadyQueue( pxTCB );                                                                                                                                                        \\r
287         }                                                                                                                                                                                                                               \\r
288 }\r
289 /*-----------------------------------------------------------*/\r
290 \r
291 /*\r
292  * Several functions take an xTaskHandle parameter that can optionally be NULL,\r
293  * where NULL is used to indicate that the handle of the currently executing\r
294  * task should be used in place of the parameter.  This macro simply checks to\r
295  * see if the parameter is NULL and returns a pointer to the appropriate TCB.\r
296  */\r
297 #define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )\r
298 \r
299 \r
300 /* File private functions. --------------------------------*/\r
301 \r
302 /*\r
303  * Utility to ready a TCB for a given task.  Mainly just copies the parameters\r
304  * into the TCB structure.\r
305  */\r
306 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;\r
307 \r
308 /*\r
309  * Utility to ready all the lists used by the scheduler.  This is called\r
310  * automatically upon the creation of the first task.\r
311  */\r
312 static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;\r
313 \r
314 /*\r
315  * The idle task, which as all tasks is implemented as a never ending loop.\r
316  * The idle task is automatically created and added to the ready lists upon\r
317  * creation of the first user task.\r
318  *\r
319  * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific\r
320  * language extensions.  The equivalent prototype for this function is:\r
321  *\r
322  * void prvIdleTask( void *pvParameters );\r
323  *\r
324  */\r
325 static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );\r
326 \r
327 /*\r
328  * Utility to free all memory allocated by the scheduler to hold a TCB,\r
329  * including the stack pointed to by the TCB.\r
330  *\r
331  * This does not free memory allocated by the task itself (i.e. memory\r
332  * allocated by calls to pvPortMalloc from within the tasks application code).\r
333  */\r
334 #if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )\r
335 \r
336         static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;\r
337 \r
338 #endif\r
339 \r
340 /*\r
341  * Used only by the idle task.  This checks to see if anything has been placed\r
342  * in the list of tasks waiting to be deleted.  If so the task is cleaned up\r
343  * and its TCB deleted.\r
344  */\r
345 static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;\r
346 \r
347 /*\r
348  * Allocates memory from the heap for a TCB and associated stack.  Checks the\r
349  * allocation was successful.\r
350  */\r
351 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;\r
352 \r
353 /*\r
354  * Called from vTaskList.  vListTasks details all the tasks currently under\r
355  * control of the scheduler.  The tasks may be in one of a number of lists.\r
356  * prvListTaskWithinSingleList accepts a list and details the tasks from\r
357  * within just that list.\r
358  *\r
359  * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM\r
360  * NORMAL APPLICATION CODE.\r
361  */\r
362 #if ( configUSE_TRACE_FACILITY == 1 )\r
363 \r
364         static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus ) PRIVILEGED_FUNCTION;\r
365 \r
366 #endif\r
367 \r
368 /*\r
369  * When a task is created, the stack of the task is filled with a known value.\r
370  * This function determines the 'high water mark' of the task stack by\r
371  * determining how much of the stack remains at the original preset value.\r
372  */\r
373 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )\r
374 \r
375         static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;\r
376 \r
377 #endif\r
378 \r
379 \r
380 /*lint +e956 */\r
381 \r
382 \r
383 \r
384 /*-----------------------------------------------------------\r
385  * TASK CREATION API documented in task.h\r
386  *----------------------------------------------------------*/\r
387 \r
388 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
389 {\r
390 signed portBASE_TYPE xReturn;\r
391 tskTCB * pxNewTCB;\r
392 \r
393         /* Allocate the memory required by the TCB and stack for the new task,\r
394         checking that the allocation was successful. */\r
395         pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );\r
396 \r
397         if( pxNewTCB != NULL )\r
398         {\r
399                 portSTACK_TYPE *pxTopOfStack;\r
400 \r
401                 #if( portUSING_MPU_WRAPPERS == 1 )\r
402                         /* Should the task be created in privileged mode? */\r
403                         portBASE_TYPE xRunPrivileged;\r
404                         if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 )\r
405                         {\r
406                                 xRunPrivileged = pdTRUE;\r
407                         }\r
408                         else\r
409                         {\r
410                                 xRunPrivileged = pdFALSE;\r
411                         }\r
412                         uxPriority &= ~portPRIVILEGE_BIT;\r
413                 #endif /* portUSING_MPU_WRAPPERS == 1 */\r
414 \r
415                 /* Calculate the top of stack address.  This depends on whether the\r
416                 stack grows from high memory to low (as per the 80x86) or visa versa.\r
417                 portSTACK_GROWTH is used to make the result positive or negative as\r
418                 required by the port. */\r
419                 #if( portSTACK_GROWTH < 0 )\r
420                 {\r
421                         pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );\r
422                         pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned long ) pxTopOfStack ) & ( ( unsigned long ) ~portBYTE_ALIGNMENT_MASK  ) );\r
423                 }\r
424                 #else\r
425                 {\r
426                         pxTopOfStack = pxNewTCB->pxStack;\r
427 \r
428                         /* If we want to use stack checking on architectures that use\r
429                         a positive stack growth direction then we also need to store the\r
430                         other extreme of the stack space. */\r
431                         pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );\r
432                 }\r
433                 #endif\r
434 \r
435                 /* Setup the newly allocated TCB with the initial state of the task. */\r
436                 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );\r
437 \r
438                 /* Initialize the TCB stack to look as if the task was already running,\r
439                 but had been interrupted by the scheduler.  The return address is set\r
440                 to the start of the task function. Once the stack has been initialised\r
441                 the     top of stack variable is updated. */\r
442                 #if( portUSING_MPU_WRAPPERS == 1 )\r
443                 {\r
444                         pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );\r
445                 }\r
446                 #else\r
447                 {\r
448                         pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );\r
449                 }\r
450                 #endif\r
451 \r
452                 /* We are going to manipulate the task queues to add this task to a\r
453                 ready list, so must make sure no interrupts occur. */\r
454                 portENTER_CRITICAL();\r
455                 {\r
456                         uxCurrentNumberOfTasks++;\r
457                         if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )\r
458                         {\r
459                                 /* As this is the first task it must also be the current task. */\r
460                                 pxCurrentTCB =  pxNewTCB;\r
461 \r
462                                 /* This is the first task to be created so do the preliminary\r
463                                 initialisation required.  We will not recover if this call\r
464                                 fails, but we will report the failure. */\r
465                                 prvInitialiseTaskLists();\r
466                         }\r
467                         else\r
468                         {\r
469                                 /* If the scheduler is not already running, make this task the\r
470                                 current task if it is the highest priority task to be created\r
471                                 so far. */\r
472                                 if( xSchedulerRunning == pdFALSE )\r
473                                 {\r
474                                         if( pxCurrentTCB->uxPriority <= uxPriority )\r
475                                         {\r
476                                                 pxCurrentTCB = pxNewTCB;\r
477                                         }\r
478                                 }\r
479                         }\r
480 \r
481                         /* Remember the top priority to make context switching faster.  Use\r
482                         the priority in pxNewTCB as this has been capped to a valid value. */\r
483                         if( pxNewTCB->uxPriority > uxTopUsedPriority )\r
484                         {\r
485                                 uxTopUsedPriority = pxNewTCB->uxPriority;\r
486                         }\r
487 \r
488                         #if ( configUSE_TRACE_FACILITY == 1 )\r
489                         {\r
490                                 /* Add a counter into the TCB for tracing only. */\r
491                                 pxNewTCB->uxTCBNumber = uxTaskNumber;\r
492                         }\r
493                         #endif\r
494                         uxTaskNumber++;\r
495 \r
496                         prvAddTaskToReadyQueue( pxNewTCB );\r
497 \r
498                         xReturn = pdPASS;\r
499                         traceTASK_CREATE( pxNewTCB );\r
500                 }\r
501                 portEXIT_CRITICAL();\r
502         }\r
503         else\r
504         {\r
505                 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;\r
506                 traceTASK_CREATE_FAILED( pxNewTCB );\r
507         }\r
508 \r
509         if( xReturn == pdPASS )\r
510         {\r
511                 if( ( void * ) pxCreatedTask != NULL )\r
512                 {\r
513                         /* Pass the TCB out - in an anonymous way.  The calling function/\r
514                         task can use this as a handle to delete the task later if\r
515                         required.*/\r
516                         *pxCreatedTask = ( xTaskHandle ) pxNewTCB;\r
517                 }\r
518 \r
519                 if( xSchedulerRunning != pdFALSE )\r
520                 {\r
521                         /* If the created task is of a higher priority than the current task\r
522                         then it should run now. */\r
523                         if( pxCurrentTCB->uxPriority < uxPriority )\r
524                         {\r
525                                 portYIELD_WITHIN_API();\r
526                         }\r
527                 }\r
528         }\r
529 \r
530         return xReturn;\r
531 }\r
532 /*-----------------------------------------------------------*/\r
533 \r
534 #if ( INCLUDE_vTaskDelete == 1 )\r
535 \r
536         void vTaskDelete( xTaskHandle pxTaskToDelete )\r
537         {\r
538         tskTCB *pxTCB;\r
539 \r
540                 portENTER_CRITICAL();\r
541                 {\r
542                         /* Ensure a yield is performed if the current task is being\r
543                         deleted. */\r
544                         if( pxTaskToDelete == pxCurrentTCB )\r
545                         {\r
546                                 pxTaskToDelete = NULL;\r
547                         }\r
548 \r
549                         /* If null is passed in here then we are deleting ourselves. */\r
550                         pxTCB = prvGetTCBFromHandle( pxTaskToDelete );\r
551 \r
552                         /* Remove task from the ready list and place in the     termination list.\r
553                         This will stop the task from be scheduled.  The idle task will check\r
554                         the termination list and free up any memory allocated by the\r
555                         scheduler for the TCB and stack. */\r
556                         vListRemove( &( pxTCB->xGenericListItem ) );\r
557 \r
558                         /* Is the task waiting on an event also? */\r
559                         if( pxTCB->xEventListItem.pvContainer )\r
560                         {\r
561                                 vListRemove( &( pxTCB->xEventListItem ) );\r
562                         }\r
563 \r
564                         vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );\r
565 \r
566                         /* Increment the ucTasksDeleted variable so the idle task knows\r
567                         there is a task that has been deleted and that it should therefore\r
568                         check the xTasksWaitingTermination list. */\r
569                         ++uxTasksDeleted;\r
570 \r
571                         /* Increment the uxTaskNumberVariable also so kernel aware debuggers\r
572                         can detect that the task lists need re-generating. */\r
573                         uxTaskNumber++;\r
574 \r
575                         traceTASK_DELETE( pxTCB );\r
576                 }\r
577                 portEXIT_CRITICAL();\r
578 \r
579                 /* Force a reschedule if we have just deleted the current task. */\r
580                 if( xSchedulerRunning != pdFALSE )\r
581                 {\r
582                         if( ( void * ) pxTaskToDelete == NULL )\r
583                         {\r
584                                 portYIELD_WITHIN_API();\r
585                         }\r
586                 }\r
587         }\r
588 \r
589 #endif\r
590 \r
591 \r
592 \r
593 \r
594 \r
595 \r
596 /*-----------------------------------------------------------\r
597  * TASK CONTROL API documented in task.h\r
598  *----------------------------------------------------------*/\r
599 \r
600 #if ( INCLUDE_vTaskDelayUntil == 1 )\r
601 \r
602         void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )\r
603         {\r
604         portTickType xTimeToWake;\r
605         portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;\r
606 \r
607                 vTaskSuspendAll();\r
608                 {\r
609                         /* Generate the tick time at which the task wants to wake. */\r
610                         xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;\r
611 \r
612                         if( xTickCount < *pxPreviousWakeTime )\r
613                         {\r
614                                 /* The tick count has overflowed since this function was\r
615                                 lasted called.  In this case the only time we should ever\r
616                                 actually delay is if the wake time has also     overflowed,\r
617                                 and the wake time is greater than the tick time.  When this\r
618                                 is the case it is as if neither time had overflowed. */\r
619                                 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )\r
620                                 {\r
621                                         xShouldDelay = pdTRUE;\r
622                                 }\r
623                         }\r
624                         else\r
625                         {\r
626                                 /* The tick time has not overflowed.  In this case we will\r
627                                 delay if either the wake time has overflowed, and/or the\r
628                                 tick time is less than the wake time. */\r
629                                 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )\r
630                                 {\r
631                                         xShouldDelay = pdTRUE;\r
632                                 }\r
633                         }\r
634 \r
635                         /* Update the wake time ready for the next call. */\r
636                         *pxPreviousWakeTime = xTimeToWake;\r
637 \r
638                         if( xShouldDelay )\r
639                         {\r
640                                 traceTASK_DELAY_UNTIL();\r
641 \r
642                                 /* We must remove ourselves from the ready list before adding\r
643                                 ourselves to the blocked list as the same list item is used for\r
644                                 both lists. */\r
645                                 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
646 \r
647                                 /* The list item will be inserted in wake time order. */\r
648                                 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );\r
649 \r
650                                 if( xTimeToWake < xTickCount )\r
651                                 {\r
652                                         /* Wake time has overflowed.  Place this item in the\r
653                                         overflow list. */\r
654                                         vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
655                                 }\r
656                                 else\r
657                                 {\r
658                                         /* The wake time has not overflowed, so we can use the\r
659                                         current block list. */\r
660                                         vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
661                                 }\r
662                         }\r
663                 }\r
664                 xAlreadyYielded = xTaskResumeAll();\r
665 \r
666                 /* Force a reschedule if xTaskResumeAll has not already done so, we may\r
667                 have put ourselves to sleep. */\r
668                 if( !xAlreadyYielded )\r
669                 {\r
670                         portYIELD_WITHIN_API();\r
671                 }\r
672         }\r
673 \r
674 #endif\r
675 /*-----------------------------------------------------------*/\r
676 \r
677 #if ( INCLUDE_vTaskDelay == 1 )\r
678 \r
679         void vTaskDelay( portTickType xTicksToDelay )\r
680         {\r
681         portTickType xTimeToWake;\r
682         signed portBASE_TYPE xAlreadyYielded = pdFALSE;\r
683 \r
684                 /* A delay time of zero just forces a reschedule. */\r
685                 if( xTicksToDelay > ( portTickType ) 0 )\r
686                 {\r
687                         vTaskSuspendAll();\r
688                         {\r
689                                 traceTASK_DELAY();\r
690 \r
691                                 /* A task that is removed from the event list while the\r
692                                 scheduler is suspended will not get placed in the ready\r
693                                 list or removed from the blocked list until the scheduler\r
694                                 is resumed.\r
695 \r
696                                 This task cannot be in an event list as it is the currently\r
697                                 executing task. */\r
698 \r
699                                 /* Calculate the time to wake - this may overflow but this is\r
700                                 not a problem. */\r
701                                 xTimeToWake = xTickCount + xTicksToDelay;\r
702 \r
703                                 /* We must remove ourselves from the ready list before adding\r
704                                 ourselves to the blocked list as the same list item is used for\r
705                                 both lists. */\r
706                                 vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
707 \r
708                                 /* The list item will be inserted in wake time order. */\r
709                                 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );\r
710 \r
711                                 if( xTimeToWake < xTickCount )\r
712                                 {\r
713                                         /* Wake time has overflowed.  Place this item in the\r
714                                         overflow list. */\r
715                                         vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
716                                 }\r
717                                 else\r
718                                 {\r
719                                         /* The wake time has not overflowed, so we can use the\r
720                                         current block list. */\r
721                                         vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
722                                 }\r
723                         }\r
724                         xAlreadyYielded = xTaskResumeAll();\r
725                 }\r
726 \r
727                 /* Force a reschedule if xTaskResumeAll has not already done so, we may\r
728                 have put ourselves to sleep. */\r
729                 if( !xAlreadyYielded )\r
730                 {\r
731                         portYIELD_WITHIN_API();\r
732                 }\r
733         }\r
734 \r
735 #endif\r
736 /*-----------------------------------------------------------*/\r
737 \r
738 #if ( INCLUDE_uxTaskPriorityGet == 1 )\r
739 \r
740         unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )\r
741         {\r
742         tskTCB *pxTCB;\r
743         unsigned portBASE_TYPE uxReturn;\r
744 \r
745                 portENTER_CRITICAL();\r
746                 {\r
747                         /* If null is passed in here then we are changing the\r
748                         priority of the calling function. */\r
749                         pxTCB = prvGetTCBFromHandle( pxTask );\r
750                         uxReturn = pxTCB->uxPriority;\r
751                 }\r
752                 portEXIT_CRITICAL();\r
753 \r
754                 return uxReturn;\r
755         }\r
756 \r
757 #endif\r
758 /*-----------------------------------------------------------*/\r
759 \r
760 #if ( INCLUDE_vTaskPrioritySet == 1 )\r
761 \r
762         void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )\r
763         {\r
764         tskTCB *pxTCB;\r
765         unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;\r
766 \r
767                 /* Ensure the new priority is valid. */\r
768                 if( uxNewPriority >= configMAX_PRIORITIES )\r
769                 {\r
770                         uxNewPriority = configMAX_PRIORITIES - 1;\r
771                 }\r
772 \r
773                 portENTER_CRITICAL();\r
774                 {\r
775                         if( pxTask == pxCurrentTCB )\r
776                         {\r
777                                 pxTask = NULL;\r
778                         }\r
779 \r
780                         /* If null is passed in here then we are changing the\r
781                         priority of the calling function. */\r
782                         pxTCB = prvGetTCBFromHandle( pxTask );\r
783 \r
784                         traceTASK_PRIORITY_SET( pxTask, uxNewPriority );\r
785 \r
786                         #if ( configUSE_MUTEXES == 1 )\r
787                         {\r
788                                 uxCurrentPriority = pxTCB->uxBasePriority;\r
789                         }\r
790                         #else\r
791                         {\r
792                                 uxCurrentPriority = pxTCB->uxPriority;\r
793                         }\r
794                         #endif\r
795 \r
796                         if( uxCurrentPriority != uxNewPriority )\r
797                         {\r
798                                 /* The priority change may have readied a task of higher\r
799                                 priority than the calling task. */\r
800                                 if( uxNewPriority > uxCurrentPriority )\r
801                                 {\r
802                                         if( pxTask != NULL )\r
803                                         {\r
804                                                 /* The priority of another task is being raised.  If we\r
805                                                 were raising the priority of the currently running task\r
806                                                 there would be no need to switch as it must have already\r
807                                                 been the highest priority task. */\r
808                                                 xYieldRequired = pdTRUE;\r
809                                         }\r
810                                 }\r
811                                 else if( pxTask == NULL )\r
812                                 {\r
813                                         /* Setting our own priority down means there may now be another\r
814                                         task of higher priority that is ready to execute. */\r
815                                         xYieldRequired = pdTRUE;\r
816                                 }\r
817 \r
818 \r
819 \r
820                                 #if ( configUSE_MUTEXES == 1 )\r
821                                 {\r
822                                         /* Only change the priority being used if the task is not\r
823                                         currently using an inherited priority. */\r
824                                         if( pxTCB->uxBasePriority == pxTCB->uxPriority )\r
825                                         {\r
826                                                 pxTCB->uxPriority = uxNewPriority;\r
827                                         }\r
828 \r
829                                         /* The base priority gets set whatever. */\r
830                                         pxTCB->uxBasePriority = uxNewPriority;\r
831                                 }\r
832                                 #else\r
833                                 {\r
834                                         pxTCB->uxPriority = uxNewPriority;\r
835                                 }\r
836                                 #endif\r
837 \r
838                                 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );\r
839 \r
840                                 /* If the task is in the blocked or suspended list we need do\r
841                                 nothing more than change it's priority variable. However, if\r
842                                 the task is in a ready list it needs to be removed and placed\r
843                                 in the queue appropriate to its new priority. */\r
844                                 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )\r
845                                 {\r
846                                         /* The task is currently in its ready list - remove before adding\r
847                                         it to it's new ready list.  As we are in a critical section we\r
848                                         can do this even if the scheduler is suspended. */\r
849                                         vListRemove( &( pxTCB->xGenericListItem ) );\r
850                                         prvAddTaskToReadyQueue( pxTCB );\r
851                                 }\r
852 \r
853                                 if( xYieldRequired == pdTRUE )\r
854                                 {\r
855                                         portYIELD_WITHIN_API();\r
856                                 }\r
857                         }\r
858                 }\r
859                 portEXIT_CRITICAL();\r
860         }\r
861 \r
862 #endif\r
863 /*-----------------------------------------------------------*/\r
864 \r
865 #if ( INCLUDE_vTaskSuspend == 1 )\r
866 \r
867         void vTaskSuspend( xTaskHandle pxTaskToSuspend )\r
868         {\r
869         tskTCB *pxTCB;\r
870 \r
871                 portENTER_CRITICAL();\r
872                 {\r
873                         /* Ensure a yield is performed if the current task is being\r
874                         suspended. */\r
875                         if( pxTaskToSuspend == pxCurrentTCB )\r
876                         {\r
877                                 pxTaskToSuspend = NULL;\r
878                         }\r
879 \r
880                         /* If null is passed in here then we are suspending ourselves. */\r
881                         pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );\r
882 \r
883                         traceTASK_SUSPEND( pxTCB );\r
884 \r
885                         /* Remove task from the ready/delayed list and place in the     suspended list. */\r
886                         vListRemove( &( pxTCB->xGenericListItem ) );\r
887 \r
888                         /* Is the task waiting on an event also? */\r
889                         if( pxTCB->xEventListItem.pvContainer )\r
890                         {\r
891                                 vListRemove( &( pxTCB->xEventListItem ) );\r
892                         }\r
893 \r
894                         vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );\r
895                 }\r
896                 portEXIT_CRITICAL();\r
897 \r
898                 /* We may have just suspended the current task. */\r
899                 if( ( void * ) pxTaskToSuspend == NULL )\r
900                 {\r
901                         portYIELD_WITHIN_API();\r
902                 }\r
903         }\r
904 \r
905 #endif\r
906 /*-----------------------------------------------------------*/\r
907 \r
908 #if ( INCLUDE_vTaskSuspend == 1 )\r
909 \r
910         signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )\r
911         {\r
912         portBASE_TYPE xReturn = pdFALSE;\r
913         const tskTCB * const pxTCB = ( tskTCB * ) xTask;\r
914 \r
915                 /* Is the task we are attempting to resume actually in the\r
916                 suspended list? */\r
917                 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )\r
918                 {\r
919                         /* Has the task already been resumed from within an ISR? */\r
920                         if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )\r
921                         {\r
922                                 /* Is it in the suspended list because it is in the\r
923                                 Suspended state?  It is possible to be in the suspended\r
924                                 list because it is blocked on a task with no timeout\r
925                                 specified. */\r
926                                 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )\r
927                                 {\r
928                                         xReturn = pdTRUE;\r
929                                 }\r
930                         }\r
931                 }\r
932 \r
933                 return xReturn;\r
934         }\r
935 \r
936 #endif\r
937 /*-----------------------------------------------------------*/\r
938 \r
939 #if ( INCLUDE_vTaskSuspend == 1 )\r
940 \r
941         void vTaskResume( xTaskHandle pxTaskToResume )\r
942         {\r
943         tskTCB *pxTCB;\r
944 \r
945                 /* Remove the task from whichever list it is currently in, and place\r
946                 it in the ready list. */\r
947                 pxTCB = ( tskTCB * ) pxTaskToResume;\r
948 \r
949                 /* The parameter cannot be NULL as it is impossible to resume the\r
950                 currently executing task. */\r
951                 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )\r
952                 {\r
953                         portENTER_CRITICAL();\r
954                         {\r
955                                 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )\r
956                                 {\r
957                                         traceTASK_RESUME( pxTCB );\r
958 \r
959                                         /* As we are in a critical section we can access the ready\r
960                                         lists even if the scheduler is suspended. */\r
961                                         vListRemove(  &( pxTCB->xGenericListItem ) );\r
962                                         prvAddTaskToReadyQueue( pxTCB );\r
963 \r
964                                         /* We may have just resumed a higher priority task. */\r
965                                         if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
966                                         {\r
967                                                 /* This yield may not cause the task just resumed to run, but\r
968                                                 will leave the lists in the correct state for the next yield. */\r
969                                                 portYIELD_WITHIN_API();\r
970                                         }\r
971                                 }\r
972                         }\r
973                         portEXIT_CRITICAL();\r
974                 }\r
975         }\r
976 \r
977 #endif\r
978 \r
979 /*-----------------------------------------------------------*/\r
980 \r
981 #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )\r
982 \r
983         portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )\r
984         {\r
985         portBASE_TYPE xYieldRequired = pdFALSE;\r
986         tskTCB *pxTCB;\r
987 \r
988                 pxTCB = ( tskTCB * ) pxTaskToResume;\r
989 \r
990                 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )\r
991                 {\r
992                         traceTASK_RESUME_FROM_ISR( pxTCB );\r
993 \r
994                         if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
995                         {\r
996                                 xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );\r
997                                 vListRemove(  &( pxTCB->xGenericListItem ) );\r
998                                 prvAddTaskToReadyQueue( pxTCB );\r
999                         }\r
1000                         else\r
1001                         {\r
1002                                 /* We cannot access the delayed or ready lists, so will hold this\r
1003                                 task pending until the scheduler is resumed, at which point a\r
1004                                 yield will be performed if necessary. */\r
1005                                 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );\r
1006                         }\r
1007                 }\r
1008 \r
1009                 return xYieldRequired;\r
1010         }\r
1011 \r
1012 #endif\r
1013 \r
1014 \r
1015 \r
1016 \r
1017 /*-----------------------------------------------------------\r
1018  * PUBLIC SCHEDULER CONTROL documented in task.h\r
1019  *----------------------------------------------------------*/\r
1020 \r
1021 \r
1022 void vTaskStartScheduler( void )\r
1023 {\r
1024 portBASE_TYPE xReturn;\r
1025 \r
1026         /* Add the idle task at the lowest priority. */\r
1027         xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );\r
1028 \r
1029         if( xReturn == pdPASS )\r
1030         {\r
1031                 /* Interrupts are turned off here, to ensure a tick does not occur\r
1032                 before or during the call to xPortStartScheduler().  The stacks of\r
1033                 the created tasks contain a status word with interrupts switched on\r
1034                 so interrupts will automatically get re-enabled when the first task\r
1035                 starts to run.\r
1036 \r
1037                 STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE\r
1038                 DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */\r
1039                 portDISABLE_INTERRUPTS();\r
1040 \r
1041                 xSchedulerRunning = pdTRUE;\r
1042                 xTickCount = ( portTickType ) 0;\r
1043 \r
1044                 /* If configGENERATE_RUN_TIME_STATS is defined then the following\r
1045                 macro must be defined to configure the timer/counter used to generate\r
1046                 the run time counter time base. */\r
1047                 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();\r
1048 \r
1049                 /* Setting up the timer tick is hardware specific and thus in the\r
1050                 portable interface. */\r
1051                 if( xPortStartScheduler() )\r
1052                 {\r
1053                         /* Should not reach here as if the scheduler is running the\r
1054                         function will not return. */\r
1055                 }\r
1056                 else\r
1057                 {\r
1058                         /* Should only reach here if a task calls xTaskEndScheduler(). */\r
1059                 }\r
1060         }\r
1061 }\r
1062 /*-----------------------------------------------------------*/\r
1063 \r
1064 void vTaskEndScheduler( void )\r
1065 {\r
1066         /* Stop the scheduler interrupts and call the portable scheduler end\r
1067         routine so the original ISRs can be restored if necessary.  The port\r
1068         layer must ensure interrupts enable     bit is left in the correct state. */\r
1069         portDISABLE_INTERRUPTS();\r
1070         xSchedulerRunning = pdFALSE;\r
1071         vPortEndScheduler();\r
1072 }\r
1073 /*----------------------------------------------------------*/\r
1074 \r
1075 void vTaskSuspendAll( void )\r
1076 {\r
1077         /* A critical section is not required as the variable is of type\r
1078         portBASE_TYPE. */\r
1079         ++uxSchedulerSuspended;\r
1080 }\r
1081 /*----------------------------------------------------------*/\r
1082 \r
1083 signed portBASE_TYPE xTaskResumeAll( void )\r
1084 {\r
1085 register tskTCB *pxTCB;\r
1086 signed portBASE_TYPE xAlreadyYielded = pdFALSE;\r
1087 \r
1088         /* It is possible that an ISR caused a task to be removed from an event\r
1089         list while the scheduler was suspended.  If this was the case then the\r
1090         removed task will have been added to the xPendingReadyList.  Once the\r
1091         scheduler has been resumed it is safe to move all the pending ready\r
1092         tasks from this list into their appropriate ready list. */\r
1093         portENTER_CRITICAL();\r
1094         {\r
1095                 --uxSchedulerSuspended;\r
1096 \r
1097                 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1098                 {\r
1099                         if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )\r
1100                         {\r
1101                                 portBASE_TYPE xYieldRequired = pdFALSE;\r
1102 \r
1103                                 /* Move any readied tasks from the pending list into the\r
1104                                 appropriate ready list. */\r
1105                                 while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY(  ( ( xList * ) &xPendingReadyList ) ) ) != NULL )\r
1106                                 {\r
1107                                         vListRemove( &( pxTCB->xEventListItem ) );\r
1108                                         vListRemove( &( pxTCB->xGenericListItem ) );\r
1109                                         prvAddTaskToReadyQueue( pxTCB );\r
1110 \r
1111                                         /* If we have moved a task that has a priority higher than\r
1112                                         the current task then we should yield. */\r
1113                                         if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
1114                                         {\r
1115                                                 xYieldRequired = pdTRUE;\r
1116                                         }\r
1117                                 }\r
1118 \r
1119                                 /* If any ticks occurred while the scheduler was suspended then\r
1120                                 they should be processed now.  This ensures the tick count does not\r
1121                                 slip, and that any delayed tasks are resumed at the correct time. */\r
1122                                 if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )\r
1123                                 {\r
1124                                         while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )\r
1125                                         {\r
1126                                                 vTaskIncrementTick();\r
1127                                                 --uxMissedTicks;\r
1128                                         }\r
1129 \r
1130                                         /* As we have processed some ticks it is appropriate to yield\r
1131                                         to ensure the highest priority task that is ready to run is\r
1132                                         the task actually running. */\r
1133                                         #if configUSE_PREEMPTION == 1\r
1134                                         {\r
1135                                                 xYieldRequired = pdTRUE;\r
1136                                         }\r
1137                                         #endif\r
1138                                 }\r
1139 \r
1140                                 if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )\r
1141                                 {\r
1142                                         xAlreadyYielded = pdTRUE;\r
1143                                         xMissedYield = pdFALSE;\r
1144                                         portYIELD_WITHIN_API();\r
1145                                 }\r
1146                         }\r
1147                 }\r
1148         }\r
1149         portEXIT_CRITICAL();\r
1150 \r
1151         return xAlreadyYielded;\r
1152 }\r
1153 \r
1154 \r
1155 \r
1156 \r
1157 \r
1158 \r
1159 /*-----------------------------------------------------------\r
1160  * PUBLIC TASK UTILITIES documented in task.h\r
1161  *----------------------------------------------------------*/\r
1162 \r
1163 \r
1164 \r
1165 portTickType xTaskGetTickCount( void )\r
1166 {\r
1167 portTickType xTicks;\r
1168 \r
1169         /* Critical section required if running on a 16 bit processor. */\r
1170         portENTER_CRITICAL();\r
1171         {\r
1172                 xTicks = xTickCount;\r
1173         }\r
1174         portEXIT_CRITICAL();\r
1175 \r
1176         return xTicks;\r
1177 }\r
1178 /*-----------------------------------------------------------*/\r
1179 \r
1180 unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )\r
1181 {\r
1182         /* A critical section is not required because the variables are of type\r
1183         portBASE_TYPE. */\r
1184         return uxCurrentNumberOfTasks;\r
1185 }\r
1186 /*-----------------------------------------------------------*/\r
1187 \r
1188 #if ( configUSE_TRACE_FACILITY == 1 )\r
1189 \r
1190         void vTaskList( signed char *pcWriteBuffer )\r
1191         {\r
1192         unsigned portBASE_TYPE uxQueue;\r
1193 \r
1194                 /* This is a VERY costly function that should be used for debug only.\r
1195                 It leaves interrupts disabled for a LONG time. */\r
1196 \r
1197                 vTaskSuspendAll();\r
1198                 {\r
1199                         /* Run through all the lists that could potentially contain a TCB and\r
1200                         report the task name, state and stack high water mark. */\r
1201 \r
1202                         pcWriteBuffer[ 0 ] = ( signed char ) 0x00;\r
1203                         strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );\r
1204 \r
1205                         uxQueue = uxTopUsedPriority + 1;\r
1206 \r
1207                         do\r
1208                         {\r
1209                                 uxQueue--;\r
1210 \r
1211                                 if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )\r
1212                                 {\r
1213                                         prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );\r
1214                                 }\r
1215                         }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );\r
1216 \r
1217                         if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )\r
1218                         {\r
1219                                 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );\r
1220                         }\r
1221 \r
1222                         if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )\r
1223                         {\r
1224                                 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );\r
1225                         }\r
1226 \r
1227                         #if( INCLUDE_vTaskDelete == 1 )\r
1228                         {\r
1229                                 if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )\r
1230                                 {\r
1231                                         prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );\r
1232                                 }\r
1233                         }\r
1234                         #endif\r
1235 \r
1236                         #if ( INCLUDE_vTaskSuspend == 1 )\r
1237                         {\r
1238                                 if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )\r
1239                                 {\r
1240                                         prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );\r
1241                                 }\r
1242                         }\r
1243                         #endif\r
1244                 }\r
1245                 xTaskResumeAll();\r
1246         }\r
1247 \r
1248 #endif\r
1249 /*----------------------------------------------------------*/\r
1250 \r
1251 #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
1252 \r
1253         void vTaskGetRunTimeStats( signed char *pcWriteBuffer )\r
1254         {\r
1255         unsigned portBASE_TYPE uxQueue;\r
1256         unsigned long ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();\r
1257 \r
1258                 /* This is a VERY costly function that should be used for debug only.\r
1259                 It leaves interrupts disabled for a LONG time. */\r
1260 \r
1261                 vTaskSuspendAll();\r
1262                 {\r
1263                         /* Run through all the lists that could potentially contain a TCB,\r
1264                         generating a table of run timer percentages in the provided\r
1265                         buffer. */\r
1266 \r
1267                         pcWriteBuffer[ 0 ] = ( signed char ) 0x00;\r
1268                         strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );\r
1269 \r
1270                         uxQueue = uxTopUsedPriority + 1;\r
1271 \r
1272                         do\r
1273                         {\r
1274                                 uxQueue--;\r
1275 \r
1276                                 if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )\r
1277                                 {\r
1278                                         prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );\r
1279                                 }\r
1280                         }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );\r
1281 \r
1282                         if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )\r
1283                         {\r
1284                                 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );\r
1285                         }\r
1286 \r
1287                         if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )\r
1288                         {\r
1289                                 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );\r
1290                         }\r
1291 \r
1292                         #if ( INCLUDE_vTaskDelete == 1 )\r
1293                         {\r
1294                                 if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )\r
1295                                 {\r
1296                                         prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );\r
1297                                 }\r
1298                         }\r
1299                         #endif\r
1300 \r
1301                         #if ( INCLUDE_vTaskSuspend == 1 )\r
1302                         {\r
1303                                 if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )\r
1304                                 {\r
1305                                         prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );\r
1306                                 }\r
1307                         }\r
1308                         #endif\r
1309                 }\r
1310                 xTaskResumeAll();\r
1311         }\r
1312 \r
1313 #endif\r
1314 /*----------------------------------------------------------*/\r
1315 \r
1316 #if ( configUSE_TRACE_FACILITY == 1 )\r
1317 \r
1318         void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize )\r
1319         {\r
1320                 portENTER_CRITICAL();\r
1321                 {\r
1322                         pcTraceBuffer = ( signed char * )pcBuffer;\r
1323                         pcTraceBufferStart = pcBuffer;\r
1324                         pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );\r
1325                         xTracing = pdTRUE;\r
1326                 }\r
1327                 portEXIT_CRITICAL();\r
1328         }\r
1329 \r
1330 #endif\r
1331 /*----------------------------------------------------------*/\r
1332 \r
1333 #if ( configUSE_TRACE_FACILITY == 1 )\r
1334 \r
1335         unsigned long ulTaskEndTrace( void )\r
1336         {\r
1337         unsigned long ulBufferLength;\r
1338 \r
1339                 portENTER_CRITICAL();\r
1340                         xTracing = pdFALSE;\r
1341                 portEXIT_CRITICAL();\r
1342 \r
1343                 ulBufferLength = ( unsigned long ) ( pcTraceBuffer - pcTraceBufferStart );\r
1344 \r
1345                 return ulBufferLength;\r
1346         }\r
1347 \r
1348 #endif\r
1349 \r
1350 \r
1351 \r
1352 /*-----------------------------------------------------------\r
1353  * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES\r
1354  * documented in task.h\r
1355  *----------------------------------------------------------*/\r
1356 \r
1357 \r
1358 void vTaskIncrementTick( void )\r
1359 {\r
1360         /* Called by the portable layer each time a tick interrupt occurs.\r
1361         Increments the tick then checks to see if the new tick value will cause any\r
1362         tasks to be unblocked. */\r
1363         if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1364         {\r
1365                 ++xTickCount;\r
1366                 if( xTickCount == ( portTickType ) 0 )\r
1367                 {\r
1368                         xList *pxTemp;\r
1369 \r
1370                         /* Tick count has overflowed so we need to swap the delay lists.\r
1371                         If there are any items in pxDelayedTaskList here then there is\r
1372                         an error! */\r
1373                         pxTemp = pxDelayedTaskList;\r
1374                         pxDelayedTaskList = pxOverflowDelayedTaskList;\r
1375                         pxOverflowDelayedTaskList = pxTemp;\r
1376                         xNumOfOverflows++;\r
1377                 }\r
1378 \r
1379                 /* See if this tick has made a timeout expire. */\r
1380                 prvCheckDelayedTasks();\r
1381         }\r
1382         else\r
1383         {\r
1384                 ++uxMissedTicks;\r
1385 \r
1386                 /* The tick hook gets called at regular intervals, even if the\r
1387                 scheduler is locked. */\r
1388                 #if ( configUSE_TICK_HOOK == 1 )\r
1389                 {\r
1390                         extern void vApplicationTickHook( void );\r
1391 \r
1392                         vApplicationTickHook();\r
1393                 }\r
1394                 #endif\r
1395         }\r
1396 \r
1397         #if ( configUSE_TICK_HOOK == 1 )\r
1398         {\r
1399                 extern void vApplicationTickHook( void );\r
1400 \r
1401                 /* Guard against the tick hook being called when the missed tick\r
1402                 count is being unwound (when the scheduler is being unlocked. */\r
1403                 if( uxMissedTicks == 0 )\r
1404                 {\r
1405                         vApplicationTickHook();\r
1406                 }\r
1407         }\r
1408         #endif\r
1409 \r
1410         traceTASK_INCREMENT_TICK( xTickCount );\r
1411 }\r
1412 /*-----------------------------------------------------------*/\r
1413 \r
1414 #if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )\r
1415 \r
1416         void vTaskCleanUpResources( void )\r
1417         {\r
1418         unsigned short usQueue;\r
1419         volatile tskTCB *pxTCB;\r
1420 \r
1421                 usQueue = ( unsigned short ) uxTopUsedPriority + ( unsigned short ) 1;\r
1422 \r
1423                 /* Remove any TCB's from the ready queues. */\r
1424                 do\r
1425                 {\r
1426                         usQueue--;\r
1427 \r
1428                         while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )\r
1429                         {\r
1430                                 listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );\r
1431                                 vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );\r
1432 \r
1433                                 prvDeleteTCB( ( tskTCB * ) pxTCB );\r
1434                         }\r
1435                 }while( usQueue > ( unsigned short ) tskIDLE_PRIORITY );\r
1436 \r
1437                 /* Remove any TCB's from the delayed queue. */\r
1438                 while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )\r
1439                 {\r
1440                         listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );\r
1441                         vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );\r
1442 \r
1443                         prvDeleteTCB( ( tskTCB * ) pxTCB );\r
1444                 }\r
1445 \r
1446                 /* Remove any TCB's from the overflow delayed queue. */\r
1447                 while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) )\r
1448                 {\r
1449                         listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );\r
1450                         vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );\r
1451 \r
1452                         prvDeleteTCB( ( tskTCB * ) pxTCB );\r
1453                 }\r
1454 \r
1455                 while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )\r
1456                 {\r
1457                         listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );\r
1458                         vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );\r
1459 \r
1460                         prvDeleteTCB( ( tskTCB * ) pxTCB );\r
1461                 }\r
1462         }\r
1463 \r
1464 #endif\r
1465 /*-----------------------------------------------------------*/\r
1466 \r
1467 #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
1468 \r
1469         void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxTagValue )\r
1470         {\r
1471         tskTCB *xTCB;\r
1472 \r
1473                 /* If xTask is NULL then we are setting our own task hook. */\r
1474                 if( xTask == NULL )\r
1475                 {\r
1476                         xTCB = ( tskTCB * ) pxCurrentTCB;\r
1477                 }\r
1478                 else\r
1479                 {\r
1480                         xTCB = ( tskTCB * ) xTask;\r
1481                 }\r
1482 \r
1483                 /* Save the hook function in the TCB.  A critical section is required as\r
1484                 the value can be accessed from an interrupt. */\r
1485                 portENTER_CRITICAL();\r
1486                         xTCB->pxTaskTag = pxTagValue;\r
1487                 portEXIT_CRITICAL();\r
1488         }\r
1489 \r
1490 #endif\r
1491 /*-----------------------------------------------------------*/\r
1492 \r
1493 #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
1494 \r
1495         pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )\r
1496         {\r
1497         tskTCB *xTCB;\r
1498         pdTASK_HOOK_CODE xReturn;\r
1499 \r
1500                 /* If xTask is NULL then we are setting our own task hook. */\r
1501                 if( xTask == NULL )\r
1502                 {\r
1503                         xTCB = ( tskTCB * ) pxCurrentTCB;\r
1504                 }\r
1505                 else\r
1506                 {\r
1507                         xTCB = ( tskTCB * ) xTask;\r
1508                 }\r
1509 \r
1510                 /* Save the hook function in the TCB.  A critical section is required as\r
1511                 the value can be accessed from an interrupt. */\r
1512                 portENTER_CRITICAL();\r
1513                         xReturn = xTCB->pxTaskTag;\r
1514                 portEXIT_CRITICAL();\r
1515 \r
1516                 return xReturn;\r
1517         }\r
1518 \r
1519 #endif\r
1520 /*-----------------------------------------------------------*/\r
1521 \r
1522 #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
1523 \r
1524         portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )\r
1525         {\r
1526         tskTCB *xTCB;\r
1527         portBASE_TYPE xReturn;\r
1528 \r
1529                 /* If xTask is NULL then we are calling our own task hook. */\r
1530                 if( xTask == NULL )\r
1531                 {\r
1532                         xTCB = ( tskTCB * ) pxCurrentTCB;\r
1533                 }\r
1534                 else\r
1535                 {\r
1536                         xTCB = ( tskTCB * ) xTask;\r
1537                 }\r
1538 \r
1539                 if( xTCB->pxTaskTag != NULL )\r
1540                 {\r
1541                         xReturn = xTCB->pxTaskTag( pvParameter );\r
1542                 }\r
1543                 else\r
1544                 {\r
1545                         xReturn = pdFAIL;\r
1546                 }\r
1547 \r
1548                 return xReturn;\r
1549         }\r
1550 \r
1551 #endif\r
1552 /*-----------------------------------------------------------*/\r
1553 \r
1554 void vTaskSwitchContext( void )\r
1555 {\r
1556         if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )\r
1557         {\r
1558                 /* The scheduler is currently suspended - do not allow a context\r
1559                 switch. */\r
1560                 xMissedYield = pdTRUE;\r
1561                 return;\r
1562         }\r
1563 \r
1564         traceTASK_SWITCHED_OUT();\r
1565 \r
1566         #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
1567         {\r
1568                 unsigned long ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();\r
1569 \r
1570                         /* Add the amount of time the task has been running to the accumulated\r
1571                         time so far.  The time the task started running was stored in\r
1572                         ulTaskSwitchedInTime.  Note that there is no overflow protection here\r
1573                         so count values are only valid until the timer overflows.  Generally\r
1574                         this will be about 1 hour assuming a 1uS timer increment. */\r
1575                         pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );\r
1576                         ulTaskSwitchedInTime = ulTempCounter;\r
1577         }\r
1578         #endif\r
1579 \r
1580         taskFIRST_CHECK_FOR_STACK_OVERFLOW();\r
1581         taskSECOND_CHECK_FOR_STACK_OVERFLOW();\r
1582 \r
1583         /* Find the highest priority queue that contains ready tasks. */\r
1584         while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )\r
1585         {\r
1586                 --uxTopReadyPriority;\r
1587         }\r
1588 \r
1589         /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the\r
1590         same priority get an equal share of the processor time. */\r
1591         listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );\r
1592 \r
1593         traceTASK_SWITCHED_IN();\r
1594         vWriteTraceToBuffer();\r
1595 }\r
1596 /*-----------------------------------------------------------*/\r
1597 \r
1598 void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )\r
1599 {\r
1600 portTickType xTimeToWake;\r
1601 \r
1602         /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE\r
1603         SCHEDULER SUSPENDED. */\r
1604 \r
1605         /* Place the event list item of the TCB in the appropriate event list.\r
1606         This is placed in the list in priority order so the highest priority task\r
1607         is the first to be woken by the event. */\r
1608         vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );\r
1609 \r
1610         /* We must remove ourselves from the ready list before adding ourselves\r
1611         to the blocked list as the same list item is used for both lists.  We have\r
1612         exclusive access to the ready lists as the scheduler is locked. */\r
1613         vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
1614 \r
1615 \r
1616         #if ( INCLUDE_vTaskSuspend == 1 )\r
1617         {\r
1618                 if( xTicksToWait == portMAX_DELAY )\r
1619                 {\r
1620                         /* Add ourselves to the suspended task list instead of a delayed task\r
1621                         list to ensure we are not woken by a timing event.  We will block\r
1622                         indefinitely. */\r
1623                         vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
1624                 }\r
1625                 else\r
1626                 {\r
1627                         /* Calculate the time at which the task should be woken if the event does\r
1628                         not occur.  This may overflow but this doesn't matter. */\r
1629                         xTimeToWake = xTickCount + xTicksToWait;\r
1630 \r
1631                         listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );\r
1632 \r
1633                         if( xTimeToWake < xTickCount )\r
1634                         {\r
1635                                 /* Wake time has overflowed.  Place this item in the overflow list. */\r
1636                                 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
1637                         }\r
1638                         else\r
1639                         {\r
1640                                 /* The wake time has not overflowed, so we can use the current block list. */\r
1641                                 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
1642                         }\r
1643                 }\r
1644         }\r
1645         #else\r
1646         {\r
1647                         /* Calculate the time at which the task should be woken if the event does\r
1648                         not occur.  This may overflow but this doesn't matter. */\r
1649                         xTimeToWake = xTickCount + xTicksToWait;\r
1650 \r
1651                         listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );\r
1652 \r
1653                         if( xTimeToWake < xTickCount )\r
1654                         {\r
1655                                 /* Wake time has overflowed.  Place this item in the overflow list. */\r
1656                                 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
1657                         }\r
1658                         else\r
1659                         {\r
1660                                 /* The wake time has not overflowed, so we can use the current block list. */\r
1661                                 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
1662                         }\r
1663         }\r
1664         #endif\r
1665 }\r
1666 /*-----------------------------------------------------------*/\r
1667 \r
1668 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )\r
1669 {\r
1670 tskTCB *pxUnblockedTCB;\r
1671 portBASE_TYPE xReturn;\r
1672 \r
1673         /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE\r
1674         SCHEDULER SUSPENDED.  It can also be called from within an ISR. */\r
1675 \r
1676         /* The event list is sorted in priority order, so we can remove the\r
1677         first in the list, remove the TCB from the delayed list, and add\r
1678         it to the ready list.\r
1679 \r
1680         If an event is for a queue that is locked then this function will never\r
1681         get called - the lock count on the queue will get modified instead.  This\r
1682         means we can always expect exclusive access to the event list here. */\r
1683         pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );\r
1684         vListRemove( &( pxUnblockedTCB->xEventListItem ) );\r
1685 \r
1686         if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
1687         {\r
1688                 vListRemove( &( pxUnblockedTCB->xGenericListItem ) );\r
1689                 prvAddTaskToReadyQueue( pxUnblockedTCB );\r
1690         }\r
1691         else\r
1692         {\r
1693                 /* We cannot access the delayed or ready lists, so will hold this\r
1694                 task pending until the scheduler is resumed. */\r
1695                 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );\r
1696         }\r
1697 \r
1698         if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
1699         {\r
1700                 /* Return true if the task removed from the event list has\r
1701                 a higher priority than the calling task.  This allows\r
1702                 the calling task to know if it should force a context\r
1703                 switch now. */\r
1704                 xReturn = pdTRUE;\r
1705         }\r
1706         else\r
1707         {\r
1708                 xReturn = pdFALSE;\r
1709         }\r
1710 \r
1711         return xReturn;\r
1712 }\r
1713 /*-----------------------------------------------------------*/\r
1714 \r
1715 void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )\r
1716 {\r
1717         pxTimeOut->xOverflowCount = xNumOfOverflows;\r
1718         pxTimeOut->xTimeOnEntering = xTickCount;\r
1719 }\r
1720 /*-----------------------------------------------------------*/\r
1721 \r
1722 portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )\r
1723 {\r
1724 portBASE_TYPE xReturn;\r
1725 \r
1726         portENTER_CRITICAL();\r
1727         {\r
1728                 #if ( INCLUDE_vTaskSuspend == 1 )\r
1729                         /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is\r
1730                         the maximum block time then the task should block indefinitely, and\r
1731                         therefore never time out. */\r
1732                         if( *pxTicksToWait == portMAX_DELAY )\r
1733                         {\r
1734                                 xReturn = pdFALSE;\r
1735                         }\r
1736                         else /* We are not blocking indefinitely, perform the checks below. */\r
1737                 #endif\r
1738 \r
1739                 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )\r
1740                 {\r
1741                         /* The tick count is greater than the time at which vTaskSetTimeout()\r
1742                         was called, but has also overflowed since vTaskSetTimeOut() was called.\r
1743                         It must have wrapped all the way around and gone past us again. This\r
1744                         passed since vTaskSetTimeout() was called. */\r
1745                         xReturn = pdTRUE;\r
1746                 }\r
1747                 else if( ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) < ( portTickType ) *pxTicksToWait )\r
1748                 {\r
1749                         /* Not a genuine timeout. Adjust parameters for time remaining. */\r
1750                         *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );\r
1751                         vTaskSetTimeOutState( pxTimeOut );\r
1752                         xReturn = pdFALSE;\r
1753                 }\r
1754                 else\r
1755                 {\r
1756                         xReturn = pdTRUE;\r
1757                 }\r
1758         }\r
1759         portEXIT_CRITICAL();\r
1760 \r
1761         return xReturn;\r
1762 }\r
1763 /*-----------------------------------------------------------*/\r
1764 \r
1765 void vTaskMissedYield( void )\r
1766 {\r
1767         xMissedYield = pdTRUE;\r
1768 }\r
1769 \r
1770 /*\r
1771  * -----------------------------------------------------------\r
1772  * The Idle task.\r
1773  * ----------------------------------------------------------\r
1774  *\r
1775  * The portTASK_FUNCTION() macro is used to allow port/compiler specific\r
1776  * language extensions.  The equivalent prototype for this function is:\r
1777  *\r
1778  * void prvIdleTask( void *pvParameters );\r
1779  *\r
1780  */\r
1781 static portTASK_FUNCTION( prvIdleTask, pvParameters )\r
1782 {\r
1783         /* Stop warnings. */\r
1784         ( void ) pvParameters;\r
1785 \r
1786         for( ;; )\r
1787         {\r
1788                 /* See if any tasks have been deleted. */\r
1789                 prvCheckTasksWaitingTermination();\r
1790 \r
1791                 #if ( configUSE_PREEMPTION == 0 )\r
1792                 {\r
1793                         /* If we are not using preemption we keep forcing a task switch to\r
1794                         see if any other task has become available.  If we are using\r
1795                         preemption we don't need to do this as any task becoming available\r
1796                         will automatically get the processor anyway. */\r
1797                         taskYIELD();\r
1798                 }\r
1799                 #endif\r
1800 \r
1801                 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )\r
1802                 {\r
1803                         /* When using preemption tasks of equal priority will be\r
1804                         timesliced.  If a task that is sharing the idle priority is ready\r
1805                         to run then the idle task should yield before the end of the\r
1806                         timeslice.\r
1807 \r
1808                         A critical region is not required here as we are just reading from\r
1809                         the list, and an occasional incorrect value will not matter.  If\r
1810                         the ready list at the idle priority contains more than one task\r
1811                         then a task other than the idle task is ready to execute. */\r
1812                         if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )\r
1813                         {\r
1814                                 taskYIELD();\r
1815                         }\r
1816                 }\r
1817                 #endif\r
1818 \r
1819                 #if ( configUSE_IDLE_HOOK == 1 )\r
1820                 {\r
1821                         extern void vApplicationIdleHook( void );\r
1822 \r
1823                         /* Call the user defined function from within the idle task.  This\r
1824                         allows the application designer to add background functionality\r
1825                         without the overhead of a separate task.\r
1826                         NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,\r
1827                         CALL A FUNCTION THAT MIGHT BLOCK. */\r
1828                         vApplicationIdleHook();\r
1829                 }\r
1830                 #endif\r
1831         }\r
1832 } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */\r
1833 \r
1834 \r
1835 \r
1836 \r
1837 \r
1838 \r
1839 \r
1840 /*-----------------------------------------------------------\r
1841  * File private functions documented at the top of the file.\r
1842  *----------------------------------------------------------*/\r
1843 \r
1844 \r
1845 \r
1846 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )\r
1847 {\r
1848         /* Store the function name in the TCB. */\r
1849         #if configMAX_TASK_NAME_LEN > 1\r
1850         {\r
1851                 /* Don't bring strncpy into the build unnecessarily. */\r
1852                 strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN );\r
1853         }\r
1854         #endif\r
1855         pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = '\0';\r
1856 \r
1857         /* This is used as an array index so must ensure it's not too large.  First\r
1858         remove the privilege bit if one is present. */\r
1859         if( uxPriority >= configMAX_PRIORITIES )\r
1860         {\r
1861                 uxPriority = configMAX_PRIORITIES - 1;\r
1862         }\r
1863 \r
1864         pxTCB->uxPriority = uxPriority;\r
1865         #if ( configUSE_MUTEXES == 1 )\r
1866         {\r
1867                 pxTCB->uxBasePriority = uxPriority;\r
1868         }\r
1869         #endif\r
1870 \r
1871         vListInitialiseItem( &( pxTCB->xGenericListItem ) );\r
1872         vListInitialiseItem( &( pxTCB->xEventListItem ) );\r
1873 \r
1874         /* Set the pxTCB as a link back from the xListItem.  This is so we can get\r
1875         back to the containing TCB from a generic item in a list. */\r
1876         listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );\r
1877 \r
1878         /* Event lists are always in priority order. */\r
1879         listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );\r
1880         listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );\r
1881 \r
1882         #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
1883         {\r
1884                 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;\r
1885         }\r
1886         #endif\r
1887 \r
1888         #if ( configUSE_APPLICATION_TASK_TAG == 1 )\r
1889         {\r
1890                 pxTCB->pxTaskTag = NULL;\r
1891         }\r
1892         #endif\r
1893 \r
1894         #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
1895         {\r
1896                 pxTCB->ulRunTimeCounter = 0UL;\r
1897         }\r
1898         #endif\r
1899 \r
1900         #if ( portUSING_MPU_WRAPPERS == 1 )\r
1901         {\r
1902                 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );\r
1903         }\r
1904         #else\r
1905         {\r
1906                 ( void ) xRegions;\r
1907                 ( void ) usStackDepth;\r
1908         }\r
1909         #endif\r
1910 }\r
1911 /*-----------------------------------------------------------*/\r
1912 \r
1913 #if ( portUSING_MPU_WRAPPERS == 1 )\r
1914 \r
1915         void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )\r
1916         {\r
1917         tskTCB *pxTCB;\r
1918         \r
1919                 if( xTaskToModify == pxCurrentTCB )\r
1920                 {\r
1921                         xTaskToModify = NULL;\r
1922                 }\r
1923 \r
1924                 /* If null is passed in here then we are deleting ourselves. */\r
1925                 pxTCB = prvGetTCBFromHandle( xTaskToModify );\r
1926 \r
1927         vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );\r
1928         }\r
1929         /*-----------------------------------------------------------*/\r
1930 #endif\r
1931 \r
1932 static void prvInitialiseTaskLists( void )\r
1933 {\r
1934 unsigned portBASE_TYPE uxPriority;\r
1935 \r
1936         for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ )\r
1937         {\r
1938                 vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );\r
1939         }\r
1940 \r
1941         vListInitialise( ( xList * ) &xDelayedTaskList1 );\r
1942         vListInitialise( ( xList * ) &xDelayedTaskList2 );\r
1943         vListInitialise( ( xList * ) &xPendingReadyList );\r
1944 \r
1945         #if ( INCLUDE_vTaskDelete == 1 )\r
1946         {\r
1947                 vListInitialise( ( xList * ) &xTasksWaitingTermination );\r
1948         }\r
1949         #endif\r
1950 \r
1951         #if ( INCLUDE_vTaskSuspend == 1 )\r
1952         {\r
1953                 vListInitialise( ( xList * ) &xSuspendedTaskList );\r
1954         }\r
1955         #endif\r
1956 \r
1957         /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList\r
1958         using list2. */\r
1959         pxDelayedTaskList = &xDelayedTaskList1;\r
1960         pxOverflowDelayedTaskList = &xDelayedTaskList2;\r
1961 }\r
1962 /*-----------------------------------------------------------*/\r
1963 \r
1964 static void prvCheckTasksWaitingTermination( void )\r
1965 {\r
1966         #if ( INCLUDE_vTaskDelete == 1 )\r
1967         {\r
1968                 portBASE_TYPE xListIsEmpty;\r
1969 \r
1970                 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called\r
1971                 too often in the idle task. */\r
1972                 if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )\r
1973                 {\r
1974                         vTaskSuspendAll();\r
1975                                 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );\r
1976                         xTaskResumeAll();\r
1977 \r
1978                         if( !xListIsEmpty )\r
1979                         {\r
1980                                 tskTCB *pxTCB;\r
1981 \r
1982                                 portENTER_CRITICAL();\r
1983                                 {\r
1984                                         pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );\r
1985                                         vListRemove( &( pxTCB->xGenericListItem ) );\r
1986                                         --uxCurrentNumberOfTasks;\r
1987                                         --uxTasksDeleted;\r
1988                                 }\r
1989                                 portEXIT_CRITICAL();\r
1990 \r
1991                                 prvDeleteTCB( pxTCB );\r
1992                         }\r
1993                 }\r
1994         }\r
1995         #endif\r
1996 }\r
1997 /*-----------------------------------------------------------*/\r
1998 \r
1999 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )\r
2000 {\r
2001 tskTCB *pxNewTCB;\r
2002 \r
2003         /* Allocate space for the TCB.  Where the memory comes from depends on\r
2004         the implementation of the port malloc function. */\r
2005         pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );\r
2006 \r
2007         if( pxNewTCB != NULL )\r
2008         {\r
2009                 /* Allocate space for the stack used by the task being created.\r
2010                 The base of the stack memory stored in the TCB so the task can\r
2011                 be deleted later if required. */\r
2012                 pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );\r
2013 \r
2014                 if( pxNewTCB->pxStack == NULL )\r
2015                 {\r
2016                         /* Could not allocate the stack.  Delete the allocated TCB. */\r
2017                         vPortFree( pxNewTCB );\r
2018                         pxNewTCB = NULL;\r
2019                 }\r
2020                 else\r
2021                 {\r
2022                         /* Just to help debugging. */\r
2023                         memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );\r
2024                 }\r
2025         }\r
2026 \r
2027         return pxNewTCB;\r
2028 }\r
2029 /*-----------------------------------------------------------*/\r
2030 \r
2031 #if ( configUSE_TRACE_FACILITY == 1 )\r
2032 \r
2033         static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus )\r
2034         {\r
2035         volatile tskTCB *pxNextTCB, *pxFirstTCB;\r
2036         unsigned short usStackRemaining;\r
2037 \r
2038                 /* Write the details of all the TCB's in pxList into the buffer. */\r
2039                 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );\r
2040                 do\r
2041                 {\r
2042                         listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );\r
2043                         #if ( portSTACK_GROWTH > 0 )\r
2044                         {\r
2045                                 usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );\r
2046                         }\r
2047                         #else\r
2048                         {\r
2049                                 usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );\r
2050                         }\r
2051                         #endif                  \r
2052                         \r
2053                         sprintf( pcStatusString, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );\r
2054                         strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString );\r
2055 \r
2056                 } while( pxNextTCB != pxFirstTCB );\r
2057         }\r
2058 \r
2059 #endif\r
2060 /*-----------------------------------------------------------*/\r
2061 \r
2062 #if ( configGENERATE_RUN_TIME_STATS == 1 )\r
2063 \r
2064         static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime )\r
2065         {\r
2066         volatile tskTCB *pxNextTCB, *pxFirstTCB;\r
2067         unsigned long ulStatsAsPercentage;\r
2068 \r
2069                 /* Write the run time stats of all the TCB's in pxList into the buffer. */\r
2070                 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );\r
2071                 do\r
2072                 {\r
2073                         /* Get next TCB in from the list. */\r
2074                         listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );\r
2075 \r
2076                         /* Divide by zero check. */\r
2077                         if( ulTotalRunTime > 0UL )\r
2078                         {\r
2079                                 /* Has the task run at all? */\r
2080                                 if( pxNextTCB->ulRunTimeCounter == 0 )\r
2081                                 {\r
2082                                         /* The task has used no CPU time at all. */\r
2083                                         sprintf( pcStatsString, ( char * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );\r
2084                                 }\r
2085                                 else\r
2086                                 {\r
2087                                         /* What percentage of the total run time as the task used?\r
2088                                         This will always be rounded down to the nearest integer. */\r
2089                                         ulStatsAsPercentage = ( 100UL * pxNextTCB->ulRunTimeCounter ) / ulTotalRunTime;\r
2090 \r
2091                                         if( ulStatsAsPercentage > 0UL )\r
2092                                         {\r
2093                                                 sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );\r
2094                                         }\r
2095                                         else\r
2096                                         {\r
2097                                                 /* If the percentage is zero here then the task has\r
2098                                                 consumed less than 1% of the total run time. */\r
2099                                                 sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );\r
2100                                         }\r
2101                                 }\r
2102 \r
2103                                 strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatsString );\r
2104                         }\r
2105 \r
2106                 } while( pxNextTCB != pxFirstTCB );\r
2107         }\r
2108 \r
2109 #endif\r
2110 /*-----------------------------------------------------------*/\r
2111 \r
2112 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )\r
2113 \r
2114         static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte )\r
2115         {\r
2116         register unsigned short usCount = 0;\r
2117 \r
2118                 while( *pucStackByte == tskSTACK_FILL_BYTE )\r
2119                 {\r
2120                         pucStackByte -= portSTACK_GROWTH;\r
2121                         usCount++;\r
2122                 }\r
2123 \r
2124                 usCount /= sizeof( portSTACK_TYPE );\r
2125 \r
2126                 return usCount;\r
2127         }\r
2128 \r
2129 #endif\r
2130 /*-----------------------------------------------------------*/\r
2131 \r
2132 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )\r
2133 \r
2134         unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )\r
2135         {\r
2136         tskTCB *pxTCB;\r
2137         unsigned char *pcEndOfStack;\r
2138         unsigned portBASE_TYPE uxReturn;\r
2139 \r
2140                 pxTCB = prvGetTCBFromHandle( xTask );\r
2141 \r
2142                 #if portSTACK_GROWTH < 0\r
2143                 {\r
2144                         pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;\r
2145                 }\r
2146                 #else\r
2147                 {\r
2148                         pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;\r
2149                 }\r
2150                 #endif\r
2151 \r
2152                 uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );\r
2153 \r
2154                 return uxReturn;\r
2155         }\r
2156 \r
2157 #endif\r
2158 /*-----------------------------------------------------------*/\r
2159 \r
2160 #if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )\r
2161 \r
2162         static void prvDeleteTCB( tskTCB *pxTCB )\r
2163         {\r
2164                 /* Free up the memory allocated by the scheduler for the task.  It is up to\r
2165                 the task to free any memory allocated at the application level. */\r
2166                 vPortFreeAligned( pxTCB->pxStack );\r
2167                 vPortFree( pxTCB );\r
2168         }\r
2169 \r
2170 #endif\r
2171 \r
2172 \r
2173 /*-----------------------------------------------------------*/\r
2174 \r
2175 #if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )\r
2176 \r
2177         xTaskHandle xTaskGetCurrentTaskHandle( void )\r
2178         {\r
2179         xTaskHandle xReturn;\r
2180 \r
2181                 /* A critical section is not required as this is not called from\r
2182                 an interrupt and the current TCB will always be the same for any\r
2183                 individual execution thread. */\r
2184                 xReturn = pxCurrentTCB;\r
2185 \r
2186                 return xReturn;\r
2187         }\r
2188 \r
2189 #endif\r
2190 \r
2191 /*-----------------------------------------------------------*/\r
2192 \r
2193 #if ( INCLUDE_xTaskGetSchedulerState == 1 )\r
2194 \r
2195         portBASE_TYPE xTaskGetSchedulerState( void )\r
2196         {\r
2197         portBASE_TYPE xReturn;\r
2198 \r
2199                 if( xSchedulerRunning == pdFALSE )\r
2200                 {\r
2201                         xReturn = taskSCHEDULER_NOT_STARTED;\r
2202                 }\r
2203                 else\r
2204                 {\r
2205                         if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
2206                         {\r
2207                                 xReturn = taskSCHEDULER_RUNNING;\r
2208                         }\r
2209                         else\r
2210                         {\r
2211                                 xReturn = taskSCHEDULER_SUSPENDED;\r
2212                         }\r
2213                 }\r
2214 \r
2215                 return xReturn;\r
2216         }\r
2217 \r
2218 #endif\r
2219 /*-----------------------------------------------------------*/\r
2220 \r
2221 #if ( configUSE_MUTEXES == 1 )\r
2222 \r
2223         void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )\r
2224         {\r
2225         tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;\r
2226 \r
2227                 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )\r
2228                 {\r
2229                         /* Adjust the mutex holder state to account for its new priority. */\r
2230                         listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );\r
2231 \r
2232                         /* If the task being modified is in the ready state it will need to\r
2233                         be moved in to a new list. */\r
2234                         if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )\r
2235                         {\r
2236                                 vListRemove( &( pxTCB->xGenericListItem ) );\r
2237 \r
2238                                 /* Inherit the priority before being moved into the new list. */\r
2239                                 pxTCB->uxPriority = pxCurrentTCB->uxPriority;\r
2240                                 prvAddTaskToReadyQueue( pxTCB );\r
2241                         }\r
2242                         else\r
2243                         {\r
2244                                 /* Just inherit the priority. */\r
2245                                 pxTCB->uxPriority = pxCurrentTCB->uxPriority;\r
2246                         }\r
2247                 }\r
2248         }\r
2249 \r
2250 #endif\r
2251 /*-----------------------------------------------------------*/\r
2252 \r
2253 #if ( configUSE_MUTEXES == 1 )\r
2254 \r
2255         void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )\r
2256         {\r
2257         tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;\r
2258 \r
2259                 if( pxMutexHolder != NULL )\r
2260                 {\r
2261                         if( pxTCB->uxPriority != pxTCB->uxBasePriority )\r
2262                         {\r
2263                                 /* We must be the running task to be able to give the mutex back.\r
2264                                 Remove ourselves from the ready list we currently appear in. */\r
2265                                 vListRemove( &( pxTCB->xGenericListItem ) );\r
2266 \r
2267                                 /* Disinherit the priority before adding ourselves into the new\r
2268                                 ready list. */\r
2269                                 pxTCB->uxPriority = pxTCB->uxBasePriority;\r
2270                                 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );\r
2271                                 prvAddTaskToReadyQueue( pxTCB );\r
2272                         }\r
2273                 }\r
2274         }\r
2275 \r
2276 #endif\r
2277 /*-----------------------------------------------------------*/\r
2278 \r
2279 #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
2280 \r
2281         void vTaskEnterCritical( void )\r
2282         {\r
2283                 portDISABLE_INTERRUPTS();\r
2284 \r
2285                 if( xSchedulerRunning != pdFALSE )\r
2286                 {\r
2287                         pxCurrentTCB->uxCriticalNesting++;\r
2288                 }\r
2289         }\r
2290 \r
2291 #endif\r
2292 /*-----------------------------------------------------------*/\r
2293 \r
2294 #if ( portCRITICAL_NESTING_IN_TCB == 1 )\r
2295 \r
2296 void vTaskExitCritical( void )\r
2297 {\r
2298         if( xSchedulerRunning != pdFALSE )\r
2299         {\r
2300                 if( pxCurrentTCB->uxCriticalNesting > 0 )\r
2301                 {\r
2302                         pxCurrentTCB->uxCriticalNesting--;\r
2303 \r
2304                         if( pxCurrentTCB->uxCriticalNesting == 0 )\r
2305                         {\r
2306                                 portENABLE_INTERRUPTS();\r
2307                         }\r
2308                 }\r
2309         }\r
2310 }\r
2311 \r
2312 #endif\r
2313 /*-----------------------------------------------------------*/\r
2314 \r
2315 \r
2316 \r
2317 \r