root/Examples_CP-JR_ARM7_LPC2368/FreeRTOS_Book/Source-Code-For-Examples/FreeRTOS_Source/tasks.c

Revision 36, 65.1 kB (checked in by phil, 15 years ago)

added purchased FreeRTOS book

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