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