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