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