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