2 FreeRTOS V7.4.2 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
4 FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT
\r
5 http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
10 * Complete, revised, and edited pdf reference manuals are also *
\r
13 * Purchasing FreeRTOS documentation will not only help you, by *
\r
14 * ensuring you get running as quickly as possible and with an *
\r
15 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
16 * the FreeRTOS project to continue with its mission of providing *
\r
17 * professional grade, cross platform, de facto standard solutions *
\r
18 * for microcontrollers - completely free of charge! *
\r
20 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
22 * Thank you for using FreeRTOS, and thank you for your support! *
\r
24 ***************************************************************************
\r
27 This file is part of the FreeRTOS distribution.
\r
29 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
30 the terms of the GNU General Public License (version 2) as published by the
\r
31 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
33 >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to
\r
34 distribute a combined work that includes FreeRTOS without being obliged to
\r
35 provide the source code for proprietary components outside of the FreeRTOS
\r
38 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
39 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
40 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
\r
41 details. You should have received a copy of the GNU General Public License
\r
42 and the FreeRTOS license exception along with FreeRTOS; if not it can be
\r
43 viewed here: http://www.freertos.org/a00114.html and also obtained by
\r
44 writing to Real Time Engineers Ltd., contact details for whom are available
\r
45 on the FreeRTOS WEB site.
\r
49 ***************************************************************************
\r
51 * Having a problem? Start by reading the FAQ "My application does *
\r
52 * not run, what could be wrong?" *
\r
54 * http://www.FreeRTOS.org/FAQHelp.html *
\r
56 ***************************************************************************
\r
59 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
60 license and Real Time Engineers Ltd. contact details.
\r
62 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
63 including FreeRTOS+Trace - an indispensable productivity tool, and our new
\r
64 fully thread aware and reentrant UDP/IP stack.
\r
66 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
67 Integrity Systems, who sell the code with commercial support,
\r
68 indemnification and middleware, under the OpenRTOS brand.
\r
70 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
71 engineered and independently SIL3 certified version for use in safety and
\r
72 mission critical applications that require provable dependability.
\r
75 /* Standard includes. */
\r
80 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
\r
81 all the API functions to use the MPU wrappers. That should only be done when
\r
82 task.h is included from an application file. */
\r
83 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
\r
85 /* FreeRTOS includes. */
\r
86 #include "FreeRTOS.h"
\r
89 #include "StackMacros.h"
\r
91 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
\r
93 /* Sanity check the configuration. */
\r
94 #if configUSE_TICKLESS_IDLE != 0
\r
95 #if INCLUDE_vTaskSuspend != 1
\r
96 #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0
\r
97 #endif /* INCLUDE_vTaskSuspend */
\r
98 #endif /* configUSE_TICKLESS_IDLE */
\r
101 * Defines the size, in words, of the stack allocated to the idle task.
\r
103 #define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
\r
106 * Task control block. A task control block (TCB) is allocated for each task,
\r
107 * and stores task state information, including a pointer to the task's context
\r
108 * (the task's run time environment, including register values)
\r
110 typedef struct tskTaskControlBlock
\r
112 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 TCB STRUCT. */
\r
114 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
115 xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
\r
118 xListItem xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
\r
119 xListItem xEventListItem; /*< Used to reference a task from an event list. */
\r
120 unsigned portBASE_TYPE uxPriority; /*< The priority of the task. 0 is the lowest priority. */
\r
121 portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
\r
122 signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
\r
124 #if ( portSTACK_GROWTH > 0 )
\r
125 portSTACK_TYPE *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */
\r
128 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
129 unsigned portBASE_TYPE uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
\r
132 #if ( configUSE_TRACE_FACILITY == 1 )
\r
133 unsigned portBASE_TYPE uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */
\r
134 unsigned portBASE_TYPE uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
\r
137 #if ( configUSE_MUTEXES == 1 )
\r
138 unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
\r
141 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
142 pdTASK_HOOK_CODE pxTaskTag;
\r
145 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
146 unsigned long ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
\r
153 * Some kernel aware debuggers require the data the debugger needs access to to
\r
154 * be global, rather than file scope.
\r
156 #ifdef portREMOVE_STATIC_QUALIFIER
\r
161 PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
\r
163 /* Lists for ready and blocked tasks. --------------------*/
\r
164 PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
\r
165 PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */
\r
166 PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
\r
167 PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */
\r
168 PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
\r
169 PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */
\r
171 #if ( INCLUDE_vTaskDelete == 1 )
\r
173 PRIVILEGED_DATA static xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
\r
174 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0U;
\r
178 #if ( INCLUDE_vTaskSuspend == 1 )
\r
180 PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
\r
184 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
\r
186 PRIVILEGED_DATA static xTaskHandle xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */
\r
190 /* File private variables. --------------------------------*/
\r
191 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0U;
\r
192 PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0U;
\r
193 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
\r
194 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
\r
195 PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
\r
196 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
\r
197 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxPendedTicks = ( unsigned portBASE_TYPE ) 0U;
\r
198 PRIVILEGED_DATA static volatile portBASE_TYPE xYieldPending = ( portBASE_TYPE ) pdFALSE;
\r
199 PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
\r
200 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0U;
\r
201 PRIVILEGED_DATA static volatile portTickType xNextTaskUnblockTime = ( portTickType ) portMAX_DELAY;
\r
203 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
205 PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
\r
206 PRIVILEGED_DATA static unsigned long ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */
\r
207 static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTimeDiv100 ) PRIVILEGED_FUNCTION;
\r
211 /* Debugging and trace facilities private variables and macros. ------------*/
\r
214 * The value used to fill the stack of a task when the task is created. This
\r
215 * is used purely for checking the high water mark for tasks.
\r
217 #define tskSTACK_FILL_BYTE ( 0xa5U )
\r
220 * Macros used by vListTask to indicate which state a task is in.
\r
222 #define tskBLOCKED_CHAR ( ( signed char ) 'B' )
\r
223 #define tskREADY_CHAR ( ( signed char ) 'R' )
\r
224 #define tskDELETED_CHAR ( ( signed char ) 'D' )
\r
225 #define tskSUSPENDED_CHAR ( ( signed char ) 'S' )
\r
227 /*-----------------------------------------------------------*/
\r
229 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
\r
231 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
\r
232 performed in a generic way that is not optimised to any particular
\r
233 microcontroller architecture. */
\r
235 /* uxTopReadyPriority holds the priority of the highest priority ready
\r
237 #define taskRECORD_READY_PRIORITY( uxPriority ) \
\r
239 if( ( uxPriority ) > uxTopReadyPriority ) \
\r
241 uxTopReadyPriority = ( uxPriority ); \
\r
243 } /* taskRECORD_READY_PRIORITY */
\r
245 /*-----------------------------------------------------------*/
\r
247 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
\r
249 /* Find the highest priority queue that contains ready tasks. */ \
\r
250 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) \
\r
252 configASSERT( uxTopReadyPriority ); \
\r
253 --uxTopReadyPriority; \
\r
256 /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
\r
257 the same priority get an equal share of the processor time. */ \
\r
258 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \
\r
259 } /* taskSELECT_HIGHEST_PRIORITY_TASK */
\r
261 /*-----------------------------------------------------------*/
\r
263 /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as
\r
264 they are only required when a port optimised method of task selection is
\r
266 #define taskRESET_READY_PRIORITY( uxPriority )
\r
267 #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
\r
269 #else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
\r
271 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is
\r
272 performed in a way that is tailored to the particular microcontroller
\r
273 architecture being used. */
\r
275 /* A port optimised version is provided. Call the port defined macros. */
\r
276 #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
\r
278 /*-----------------------------------------------------------*/
\r
280 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
\r
282 unsigned portBASE_TYPE uxTopPriority; \
\r
284 /* Find the highest priority queue that contains ready tasks. */ \
\r
285 portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
\r
286 configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
\r
287 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
\r
288 } /* taskSELECT_HIGHEST_PRIORITY_TASK() */
\r
290 /*-----------------------------------------------------------*/
\r
292 /* A port optimised version is provided, call it only if the TCB being reset
\r
293 is being referenced from a ready list. If it is referenced from a delayed
\r
294 or suspended list then it won't be in a ready list. */
\r
295 #define taskRESET_READY_PRIORITY( uxPriority ) \
\r
297 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == 0 ) \
\r
299 portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \
\r
303 #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
\r
305 /*-----------------------------------------------------------*/
\r
307 /* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
\r
308 count overflows. */
\r
309 #define taskSWITCH_DELAYED_LISTS() \
\r
313 /* The delayed tasks list should be empty when the lists are switched. */ \
\r
314 configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \
\r
316 pxTemp = pxDelayedTaskList; \
\r
317 pxDelayedTaskList = pxOverflowDelayedTaskList; \
\r
318 pxOverflowDelayedTaskList = pxTemp; \
\r
319 xNumOfOverflows++; \
\r
321 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \
\r
323 /* The new current delayed list is empty. Set \
\r
324 xNextTaskUnblockTime to the maximum possible value so it is \
\r
325 extremely unlikely that the \
\r
326 if( xTickCount >= xNextTaskUnblockTime ) test will pass until \
\r
327 there is an item in the delayed list. */ \
\r
328 xNextTaskUnblockTime = portMAX_DELAY; \
\r
332 /* The new current delayed list is not empty, get the value of \
\r
333 the item at the head of the delayed list. This is the time at \
\r
334 which the task at the head of the delayed list should be removed \
\r
335 from the Blocked state. */ \
\r
336 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \
\r
337 xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \
\r
341 /*-----------------------------------------------------------*/
\r
344 * Place the task represented by pxTCB into the appropriate ready list for
\r
345 * the task. It is inserted at the end of the list.
\r
347 #define prvAddTaskToReadyList( pxTCB ) \
\r
348 traceMOVED_TASK_TO_READY_STATE( pxTCB ) \
\r
349 taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
\r
350 vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
\r
351 /*-----------------------------------------------------------*/
\r
354 * Several functions take an xTaskHandle parameter that can optionally be NULL,
\r
355 * where NULL is used to indicate that the handle of the currently executing
\r
356 * task should be used in place of the parameter. This macro simply checks to
\r
357 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
\r
359 #define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) )
\r
361 /* Callback function prototypes. --------------------------*/
\r
362 extern void vApplicationStackOverflowHook( xTaskHandle xTask, signed char *pcTaskName );
\r
363 extern void vApplicationTickHook( void );
\r
365 /* File private functions. --------------------------------*/
\r
368 * Utility to ready a TCB for a given task. Mainly just copies the parameters
\r
369 * into the TCB structure.
\r
371 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;
\r
374 * Utility to ready all the lists used by the scheduler. This is called
\r
375 * automatically upon the creation of the first task.
\r
377 static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
\r
380 * The idle task, which as all tasks is implemented as a never ending loop.
\r
381 * The idle task is automatically created and added to the ready lists upon
\r
382 * creation of the first user task.
\r
384 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
\r
385 * language extensions. The equivalent prototype for this function is:
\r
387 * void prvIdleTask( void *pvParameters );
\r
390 static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
\r
393 * Utility to free all memory allocated by the scheduler to hold a TCB,
\r
394 * including the stack pointed to by the TCB.
\r
396 * This does not free memory allocated by the task itself (i.e. memory
\r
397 * allocated by calls to pvPortMalloc from within the tasks application code).
\r
399 #if ( INCLUDE_vTaskDelete == 1 )
\r
401 static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;
\r
406 * Used only by the idle task. This checks to see if anything has been placed
\r
407 * in the list of tasks waiting to be deleted. If so the task is cleaned up
\r
408 * and its TCB deleted.
\r
410 static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
\r
413 * The currently executing task is entering the Blocked state. Add the task to
\r
414 * either the current or the overflow delayed task list.
\r
416 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION;
\r
419 * Allocates memory from the heap for a TCB and associated stack. Checks the
\r
420 * allocation was successful.
\r
422 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;
\r
425 * Called from vTaskList. vListTasks details all the tasks currently under
\r
426 * control of the scheduler. The tasks may be in one of a number of lists.
\r
427 * prvListTaskWithinSingleList accepts a list and details the tasks from
\r
428 * within just that list.
\r
430 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
\r
431 * NORMAL APPLICATION CODE.
\r
433 #if ( configUSE_TRACE_FACILITY == 1 )
\r
435 static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus ) PRIVILEGED_FUNCTION;
\r
440 * When a task is created, the stack of the task is filled with a known value.
\r
441 * This function determines the 'high water mark' of the task stack by
\r
442 * determining how much of the stack remains at the original preset value.
\r
444 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
446 static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;
\r
451 * Return the amount of time, in ticks, that will pass before the kernel will
\r
452 * next move a task from the Blocked state to the Running state.
\r
454 * This conditional compilation should use inequality to 0, not equality to 1.
\r
455 * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user
\r
456 * defined low power mode implementations require configUSE_TICKLESS_IDLE to be
\r
457 * set to a value other than 1.
\r
459 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
461 static portTickType prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION;
\r
467 signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
\r
469 signed portBASE_TYPE xReturn;
\r
472 configASSERT( pxTaskCode );
\r
473 configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );
\r
475 /* Allocate the memory required by the TCB and stack for the new task,
\r
476 checking that the allocation was successful. */
\r
477 pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
\r
479 if( pxNewTCB != NULL )
\r
481 portSTACK_TYPE *pxTopOfStack;
\r
483 #if( portUSING_MPU_WRAPPERS == 1 )
\r
484 /* Should the task be created in privileged mode? */
\r
485 portBASE_TYPE xRunPrivileged;
\r
486 if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
\r
488 xRunPrivileged = pdTRUE;
\r
492 xRunPrivileged = pdFALSE;
\r
494 uxPriority &= ~portPRIVILEGE_BIT;
\r
495 #endif /* portUSING_MPU_WRAPPERS == 1 */
\r
497 /* Calculate the top of stack address. This depends on whether the
\r
498 stack grows from high memory to low (as per the 80x86) or visa versa.
\r
499 portSTACK_GROWTH is used to make the result positive or negative as
\r
500 required by the port. */
\r
501 #if( portSTACK_GROWTH < 0 )
\r
503 pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );
\r
504 pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK ) );
\r
506 /* Check the alignment of the calculated top of stack is correct. */
\r
507 configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
\r
509 #else /* portSTACK_GROWTH */
\r
511 pxTopOfStack = pxNewTCB->pxStack;
\r
513 /* Check the alignment of the stack buffer is correct. */
\r
514 configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
\r
516 /* If we want to use stack checking on architectures that use
\r
517 a positive stack growth direction then we also need to store the
\r
518 other extreme of the stack space. */
\r
519 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
\r
521 #endif /* portSTACK_GROWTH */
\r
523 /* Setup the newly allocated TCB with the initial state of the task. */
\r
524 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
\r
526 /* Initialize the TCB stack to look as if the task was already running,
\r
527 but had been interrupted by the scheduler. The return address is set
\r
528 to the start of the task function. Once the stack has been initialised
\r
529 the top of stack variable is updated. */
\r
530 #if( portUSING_MPU_WRAPPERS == 1 )
\r
532 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
\r
534 #else /* portUSING_MPU_WRAPPERS */
\r
536 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
\r
538 #endif /* portUSING_MPU_WRAPPERS */
\r
540 if( ( void * ) pxCreatedTask != NULL )
\r
542 /* Pass the TCB out - in an anonymous way. The calling function/
\r
543 task can use this as a handle to delete the task later if
\r
545 *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
\r
548 /* Ensure interrupts don't access the task lists while they are being
\r
550 taskENTER_CRITICAL();
\r
552 uxCurrentNumberOfTasks++;
\r
553 if( pxCurrentTCB == NULL )
\r
555 /* There are no other tasks, or all the other tasks are in
\r
556 the suspended state - make this the current task. */
\r
557 pxCurrentTCB = pxNewTCB;
\r
559 if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
\r
561 /* This is the first task to be created so do the preliminary
\r
562 initialisation required. We will not recover if this call
\r
563 fails, but we will report the failure. */
\r
564 prvInitialiseTaskLists();
\r
569 /* If the scheduler is not already running, make this task the
\r
570 current task if it is the highest priority task to be created
\r
572 if( xSchedulerRunning == pdFALSE )
\r
574 if( pxCurrentTCB->uxPriority <= uxPriority )
\r
576 pxCurrentTCB = pxNewTCB;
\r
581 /* Remember the top priority to make context switching faster. Use
\r
582 the priority in pxNewTCB as this has been capped to a valid value. */
\r
583 if( pxNewTCB->uxPriority > uxTopUsedPriority )
\r
585 uxTopUsedPriority = pxNewTCB->uxPriority;
\r
590 #if ( configUSE_TRACE_FACILITY == 1 )
\r
592 /* Add a counter into the TCB for tracing only. */
\r
593 pxNewTCB->uxTCBNumber = uxTaskNumber;
\r
595 #endif /* configUSE_TRACE_FACILITY */
\r
596 traceTASK_CREATE( pxNewTCB );
\r
598 prvAddTaskToReadyList( pxNewTCB );
\r
601 portSETUP_TCB( pxNewTCB );
\r
603 taskEXIT_CRITICAL();
\r
607 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
\r
608 traceTASK_CREATE_FAILED();
\r
611 if( xReturn == pdPASS )
\r
613 if( xSchedulerRunning != pdFALSE )
\r
615 /* If the created task is of a higher priority than the current task
\r
616 then it should run now. */
\r
617 if( pxCurrentTCB->uxPriority < uxPriority )
\r
619 portYIELD_WITHIN_API();
\r
626 /*-----------------------------------------------------------*/
\r
628 #if ( INCLUDE_vTaskDelete == 1 )
\r
630 void vTaskDelete( xTaskHandle xTaskToDelete )
\r
634 taskENTER_CRITICAL();
\r
636 /* Ensure a yield is performed if the current task is being
\r
638 if( xTaskToDelete == pxCurrentTCB )
\r
640 xTaskToDelete = NULL;
\r
643 /* If null is passed in here then we are deleting ourselves. */
\r
644 pxTCB = prvGetTCBFromHandle( xTaskToDelete );
\r
646 /* Remove task from the ready list and place in the termination list.
\r
647 This will stop the task from be scheduled. The idle task will check
\r
648 the termination list and free up any memory allocated by the
\r
649 scheduler for the TCB and stack. */
\r
650 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
\r
652 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
655 /* Is the task waiting on an event also? */
\r
656 if( pxTCB->xEventListItem.pvContainer != NULL )
\r
658 uxListRemove( &( pxTCB->xEventListItem ) );
\r
661 vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
\r
663 /* Increment the ucTasksDeleted variable so the idle task knows
\r
664 there is a task that has been deleted and that it should therefore
\r
665 check the xTasksWaitingTermination list. */
\r
668 /* Increment the uxTaskNumberVariable also so kernel aware debuggers
\r
669 can detect that the task lists need re-generating. */
\r
672 traceTASK_DELETE( pxTCB );
\r
674 taskEXIT_CRITICAL();
\r
676 /* Force a reschedule if we have just deleted the current task. */
\r
677 if( xSchedulerRunning != pdFALSE )
\r
679 if( ( void * ) xTaskToDelete == NULL )
\r
681 portYIELD_WITHIN_API();
\r
686 #endif /* INCLUDE_vTaskDelete */
\r
687 /*-----------------------------------------------------------*/
\r
689 #if ( INCLUDE_vTaskDelayUntil == 1 )
\r
691 void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
\r
693 portTickType xTimeToWake;
\r
694 portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
\r
696 configASSERT( pxPreviousWakeTime );
\r
697 configASSERT( ( xTimeIncrement > 0U ) );
\r
701 /* Generate the tick time at which the task wants to wake. */
\r
702 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
\r
704 if( xTickCount < *pxPreviousWakeTime )
\r
706 /* The tick count has overflowed since this function was
\r
707 lasted called. In this case the only time we should ever
\r
708 actually delay is if the wake time has also overflowed,
\r
709 and the wake time is greater than the tick time. When this
\r
710 is the case it is as if neither time had overflowed. */
\r
711 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
\r
713 xShouldDelay = pdTRUE;
\r
718 /* The tick time has not overflowed. In this case we will
\r
719 delay if either the wake time has overflowed, and/or the
\r
720 tick time is less than the wake time. */
\r
721 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
\r
723 xShouldDelay = pdTRUE;
\r
727 /* Update the wake time ready for the next call. */
\r
728 *pxPreviousWakeTime = xTimeToWake;
\r
730 if( xShouldDelay != pdFALSE )
\r
732 traceTASK_DELAY_UNTIL();
\r
734 /* We must remove ourselves from the ready list before adding
\r
735 ourselves to the blocked list as the same list item is used for
\r
737 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )
\r
739 /* The current task must be in a ready list, so there is
\r
740 no need to check, and the port reset macro can be called
\r
742 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
745 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
748 xAlreadyYielded = xTaskResumeAll();
\r
750 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
751 have put ourselves to sleep. */
\r
752 if( xAlreadyYielded == pdFALSE )
\r
754 portYIELD_WITHIN_API();
\r
758 #endif /* INCLUDE_vTaskDelayUntil */
\r
759 /*-----------------------------------------------------------*/
\r
761 #if ( INCLUDE_vTaskDelay == 1 )
\r
763 void vTaskDelay( portTickType xTicksToDelay )
\r
765 portTickType xTimeToWake;
\r
766 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
768 /* A delay time of zero just forces a reschedule. */
\r
769 if( xTicksToDelay > ( portTickType ) 0U )
\r
775 /* A task that is removed from the event list while the
\r
776 scheduler is suspended will not get placed in the ready
\r
777 list or removed from the blocked list until the scheduler
\r
780 This task cannot be in an event list as it is the currently
\r
783 /* Calculate the time to wake - this may overflow but this is
\r
785 xTimeToWake = xTickCount + xTicksToDelay;
\r
787 /* We must remove ourselves from the ready list before adding
\r
788 ourselves to the blocked list as the same list item is used for
\r
790 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )
\r
792 /* The current task must be in a ready list, so there is
\r
793 no need to check, and the port reset macro can be called
\r
795 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
797 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
799 xAlreadyYielded = xTaskResumeAll();
\r
802 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
803 have put ourselves to sleep. */
\r
804 if( xAlreadyYielded == pdFALSE )
\r
806 portYIELD_WITHIN_API();
\r
810 #endif /* INCLUDE_vTaskDelay */
\r
811 /*-----------------------------------------------------------*/
\r
813 #if ( INCLUDE_eTaskGetState == 1 )
\r
815 eTaskState eTaskGetState( xTaskHandle xTask )
\r
817 eTaskState eReturn;
\r
818 xList *pxStateList;
\r
821 pxTCB = ( tskTCB * ) xTask;
\r
823 if( pxTCB == pxCurrentTCB )
\r
825 /* The task calling this function is querying its own state. */
\r
826 eReturn = eRunning;
\r
830 taskENTER_CRITICAL();
\r
832 pxStateList = ( xList * ) listLIST_ITEM_CONTAINER( &( pxTCB->xGenericListItem ) );
\r
834 taskEXIT_CRITICAL();
\r
836 if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) )
\r
838 /* The task being queried is referenced from one of the Blocked
\r
840 eReturn = eBlocked;
\r
843 #if ( INCLUDE_vTaskSuspend == 1 )
\r
844 else if( pxStateList == &xSuspendedTaskList )
\r
846 /* The task being queried is referenced from the suspended
\r
848 eReturn = eSuspended;
\r
852 #if ( INCLUDE_vTaskDelete == 1 )
\r
853 else if( pxStateList == &xTasksWaitingTermination )
\r
855 /* The task being queried is referenced from the deleted
\r
857 eReturn = eDeleted;
\r
863 /* If the task is not in any other state, it must be in the
\r
864 Ready (including pending ready) state. */
\r
872 #endif /* INCLUDE_eTaskGetState */
\r
873 /*-----------------------------------------------------------*/
\r
875 #if ( INCLUDE_uxTaskPriorityGet == 1 )
\r
877 unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle xTask )
\r
880 unsigned portBASE_TYPE uxReturn;
\r
882 taskENTER_CRITICAL();
\r
884 /* If null is passed in here then we are changing the
\r
885 priority of the calling function. */
\r
886 pxTCB = prvGetTCBFromHandle( xTask );
\r
887 uxReturn = pxTCB->uxPriority;
\r
889 taskEXIT_CRITICAL();
\r
894 #endif /* INCLUDE_uxTaskPriorityGet */
\r
895 /*-----------------------------------------------------------*/
\r
897 #if ( INCLUDE_vTaskPrioritySet == 1 )
\r
899 void vTaskPrioritySet( xTaskHandle xTask, unsigned portBASE_TYPE uxNewPriority )
\r
902 unsigned portBASE_TYPE uxCurrentPriority, uxPriorityUsedOnEntry;
\r
903 portBASE_TYPE xYieldRequired = pdFALSE;
\r
905 configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
\r
907 /* Ensure the new priority is valid. */
\r
908 if( uxNewPriority >= configMAX_PRIORITIES )
\r
910 uxNewPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
\r
913 taskENTER_CRITICAL();
\r
915 if( xTask == ( xTaskHandle ) pxCurrentTCB )
\r
920 /* If null is passed in here then we are changing the
\r
921 priority of the calling function. */
\r
922 pxTCB = prvGetTCBFromHandle( xTask );
\r
924 traceTASK_PRIORITY_SET( pxTCB, uxNewPriority );
\r
926 #if ( configUSE_MUTEXES == 1 )
\r
928 uxCurrentPriority = pxTCB->uxBasePriority;
\r
932 uxCurrentPriority = pxTCB->uxPriority;
\r
936 if( uxCurrentPriority != uxNewPriority )
\r
938 /* The priority change may have readied a task of higher
\r
939 priority than the calling task. */
\r
940 if( uxNewPriority > uxCurrentPriority )
\r
942 if( xTask != NULL )
\r
944 /* The priority of another task is being raised. If we
\r
945 were raising the priority of the currently running task
\r
946 there would be no need to switch as it must have already
\r
947 been the highest priority task. */
\r
948 xYieldRequired = pdTRUE;
\r
951 else if( xTask == NULL )
\r
953 /* Setting our own priority down means there may now be another
\r
954 task of higher priority that is ready to execute. */
\r
955 xYieldRequired = pdTRUE;
\r
958 /* Remember the ready list the task might be referenced from
\r
959 before its uxPriority member is changed so the
\r
960 taskRESET_READY_PRIORITY() macro can function correctly. */
\r
961 uxPriorityUsedOnEntry = pxTCB->uxPriority;
\r
963 #if ( configUSE_MUTEXES == 1 )
\r
965 /* Only change the priority being used if the task is not
\r
966 currently using an inherited priority. */
\r
967 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
\r
969 pxTCB->uxPriority = uxNewPriority;
\r
972 /* The base priority gets set whatever. */
\r
973 pxTCB->uxBasePriority = uxNewPriority;
\r
977 pxTCB->uxPriority = uxNewPriority;
\r
981 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
\r
983 /* If the task is in the blocked or suspended list we need do
\r
984 nothing more than change it's priority variable. However, if
\r
985 the task is in a ready list it needs to be removed and placed
\r
986 in the queue appropriate to its new priority. */
\r
987 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
\r
989 /* The task is currently in its ready list - remove before adding
\r
990 it to it's new ready list. As we are in a critical section we
\r
991 can do this even if the scheduler is suspended. */
\r
992 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
\r
994 taskRESET_READY_PRIORITY( uxPriorityUsedOnEntry );
\r
996 prvAddTaskToReadyList( pxTCB );
\r
999 if( xYieldRequired == pdTRUE )
\r
1001 portYIELD_WITHIN_API();
\r
1004 /* Remove compiler warning about unused variables when the port
\r
1005 optimised task selection is not being used. */
\r
1006 ( void ) uxPriorityUsedOnEntry;
\r
1009 taskEXIT_CRITICAL();
\r
1012 #endif /* INCLUDE_vTaskPrioritySet */
\r
1013 /*-----------------------------------------------------------*/
\r
1015 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1017 void vTaskSuspend( xTaskHandle xTaskToSuspend )
\r
1021 taskENTER_CRITICAL();
\r
1023 /* Ensure a yield is performed if the current task is being
\r
1025 if( xTaskToSuspend == ( xTaskHandle ) pxCurrentTCB )
\r
1027 xTaskToSuspend = NULL;
\r
1030 /* If null is passed in here then we are suspending ourselves. */
\r
1031 pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
\r
1033 traceTASK_SUSPEND( pxTCB );
\r
1035 /* Remove task from the ready/delayed list and place in the suspended list. */
\r
1036 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
\r
1038 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
1041 /* Is the task waiting on an event also? */
\r
1042 if( pxTCB->xEventListItem.pvContainer != NULL )
\r
1044 uxListRemove( &( pxTCB->xEventListItem ) );
\r
1047 vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
\r
1049 taskEXIT_CRITICAL();
\r
1051 if( ( void * ) xTaskToSuspend == NULL )
\r
1053 if( xSchedulerRunning != pdFALSE )
\r
1055 /* We have just suspended the current task. */
\r
1056 portYIELD_WITHIN_API();
\r
1060 /* The scheduler is not running, but the task that was pointed
\r
1061 to by pxCurrentTCB has just been suspended and pxCurrentTCB
\r
1062 must be adjusted to point to a different task. */
\r
1063 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
\r
1065 /* No other tasks are ready, so set pxCurrentTCB back to
\r
1066 NULL so when the next task is created pxCurrentTCB will
\r
1067 be set to point to it no matter what its relative priority
\r
1069 pxCurrentTCB = NULL;
\r
1073 vTaskSwitchContext();
\r
1079 #endif /* INCLUDE_vTaskSuspend */
\r
1080 /*-----------------------------------------------------------*/
\r
1082 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1084 signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
\r
1086 portBASE_TYPE xReturn = pdFALSE;
\r
1087 const tskTCB * const pxTCB = ( tskTCB * ) xTask;
\r
1089 /* It does not make sense to check if the calling task is suspended. */
\r
1090 configASSERT( xTask );
\r
1092 /* Is the task we are attempting to resume actually in the
\r
1093 suspended list? */
\r
1094 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
\r
1096 /* Has the task already been resumed from within an ISR? */
\r
1097 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
\r
1099 /* Is it in the suspended list because it is in the
\r
1100 Suspended state? It is possible to be in the suspended
\r
1101 list because it is blocked on a task with no timeout
\r
1103 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
\r
1113 #endif /* INCLUDE_vTaskSuspend */
\r
1114 /*-----------------------------------------------------------*/
\r
1116 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1118 void vTaskResume( xTaskHandle xTaskToResume )
\r
1122 /* It does not make sense to resume the calling task. */
\r
1123 configASSERT( xTaskToResume );
\r
1125 /* Remove the task from whichever list it is currently in, and place
\r
1126 it in the ready list. */
\r
1127 pxTCB = ( tskTCB * ) xTaskToResume;
\r
1129 /* The parameter cannot be NULL as it is impossible to resume the
\r
1130 currently executing task. */
\r
1131 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
\r
1133 taskENTER_CRITICAL();
\r
1135 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
1137 traceTASK_RESUME( pxTCB );
\r
1139 /* As we are in a critical section we can access the ready
\r
1140 lists even if the scheduler is suspended. */
\r
1141 uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1142 prvAddTaskToReadyList( pxTCB );
\r
1144 /* We may have just resumed a higher priority task. */
\r
1145 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1147 /* This yield may not cause the task just resumed to run, but
\r
1148 will leave the lists in the correct state for the next yield. */
\r
1149 portYIELD_WITHIN_API();
\r
1153 taskEXIT_CRITICAL();
\r
1157 #endif /* INCLUDE_vTaskSuspend */
\r
1159 /*-----------------------------------------------------------*/
\r
1161 #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
\r
1163 portBASE_TYPE xTaskResumeFromISR( xTaskHandle xTaskToResume )
\r
1165 portBASE_TYPE xYieldRequired = pdFALSE;
\r
1167 unsigned portBASE_TYPE uxSavedInterruptStatus;
\r
1169 configASSERT( xTaskToResume );
\r
1171 pxTCB = ( tskTCB * ) xTaskToResume;
\r
1173 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
\r
1175 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
1177 traceTASK_RESUME_FROM_ISR( pxTCB );
\r
1179 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1181 xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
\r
1182 uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1183 prvAddTaskToReadyList( pxTCB );
\r
1187 /* We cannot access the delayed or ready lists, so will hold this
\r
1188 task pending until the scheduler is resumed, at which point a
\r
1189 yield will be performed if necessary. */
\r
1190 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
\r
1194 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
\r
1196 return xYieldRequired;
\r
1199 #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */
\r
1200 /*-----------------------------------------------------------*/
\r
1202 void vTaskStartScheduler( void )
\r
1204 portBASE_TYPE xReturn;
\r
1206 /* Add the idle task at the lowest priority. */
\r
1207 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
\r
1209 /* Create the idle task, storing its handle in xIdleTaskHandle so it can
\r
1210 be returned by the xTaskGetIdleTaskHandle() function. */
\r
1211 xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle );
\r
1215 /* Create the idle task without storing its handle. */
\r
1216 xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL );
\r
1218 #endif /* INCLUDE_xTaskGetIdleTaskHandle */
\r
1220 #if ( configUSE_TIMERS == 1 )
\r
1222 if( xReturn == pdPASS )
\r
1224 xReturn = xTimerCreateTimerTask();
\r
1227 #endif /* configUSE_TIMERS */
\r
1229 if( xReturn == pdPASS )
\r
1231 /* Interrupts are turned off here, to ensure a tick does not occur
\r
1232 before or during the call to xPortStartScheduler(). The stacks of
\r
1233 the created tasks contain a status word with interrupts switched on
\r
1234 so interrupts will automatically get re-enabled when the first task
\r
1237 STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
\r
1238 DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
\r
1239 portDISABLE_INTERRUPTS();
\r
1241 xSchedulerRunning = pdTRUE;
\r
1242 xTickCount = ( portTickType ) 0U;
\r
1244 /* If configGENERATE_RUN_TIME_STATS is defined then the following
\r
1245 macro must be defined to configure the timer/counter used to generate
\r
1246 the run time counter time base. */
\r
1247 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
\r
1249 /* Setting up the timer tick is hardware specific and thus in the
\r
1250 portable interface. */
\r
1251 if( xPortStartScheduler() != pdFALSE )
\r
1253 /* Should not reach here as if the scheduler is running the
\r
1254 function will not return. */
\r
1258 /* Should only reach here if a task calls xTaskEndScheduler(). */
\r
1263 /* This line will only be reached if the kernel could not be started,
\r
1264 because there was not enough FreeRTOS heap to create the idle task
\r
1265 or the timer task. */
\r
1266 configASSERT( xReturn );
\r
1269 /*-----------------------------------------------------------*/
\r
1271 void vTaskEndScheduler( void )
\r
1273 /* Stop the scheduler interrupts and call the portable scheduler end
\r
1274 routine so the original ISRs can be restored if necessary. The port
\r
1275 layer must ensure interrupts enable bit is left in the correct state. */
\r
1276 portDISABLE_INTERRUPTS();
\r
1277 xSchedulerRunning = pdFALSE;
\r
1278 vPortEndScheduler();
\r
1280 /*----------------------------------------------------------*/
\r
1282 void vTaskSuspendAll( void )
\r
1284 /* A critical section is not required as the variable is of type
\r
1286 ++uxSchedulerSuspended;
\r
1288 /*----------------------------------------------------------*/
\r
1290 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
1292 static portTickType prvGetExpectedIdleTime( void )
\r
1294 portTickType xReturn;
\r
1296 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )
\r
1300 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )
\r
1302 /* There are other idle priority tasks in the ready state. If
\r
1303 time slicing is used then the very next tick interrupt must be
\r
1309 xReturn = xNextTaskUnblockTime - xTickCount;
\r
1315 #endif /* configUSE_TICKLESS_IDLE */
\r
1316 /*----------------------------------------------------------*/
\r
1318 signed portBASE_TYPE xTaskResumeAll( void )
\r
1320 register tskTCB *pxTCB;
\r
1321 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
1322 portBASE_TYPE xYieldRequired = pdFALSE;
\r
1324 /* If uxSchedulerSuspended is zero then this function does not match a
\r
1325 previous call to vTaskSuspendAll(). */
\r
1326 configASSERT( uxSchedulerSuspended );
\r
1328 /* It is possible that an ISR caused a task to be removed from an event
\r
1329 list while the scheduler was suspended. If this was the case then the
\r
1330 removed task will have been added to the xPendingReadyList. Once the
\r
1331 scheduler has been resumed it is safe to move all the pending ready
\r
1332 tasks from this list into their appropriate ready list. */
\r
1333 taskENTER_CRITICAL();
\r
1335 --uxSchedulerSuspended;
\r
1337 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1339 if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0U )
\r
1341 /* Move any readied tasks from the pending list into the
\r
1342 appropriate ready list. */
\r
1343 while( listLIST_IS_EMPTY( ( xList * ) &xPendingReadyList ) == pdFALSE )
\r
1345 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) );
\r
1346 uxListRemove( &( pxTCB->xEventListItem ) );
\r
1347 uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1348 prvAddTaskToReadyList( pxTCB );
\r
1350 /* If we have moved a task that has a priority higher than
\r
1351 the current task then we should yield. */
\r
1352 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1354 xYieldRequired = pdTRUE;
\r
1358 /* If any ticks occurred while the scheduler was suspended then
\r
1359 they should be processed now. This ensures the tick count does not
\r
1360 slip, and that any delayed tasks are resumed at the correct time. */
\r
1361 if( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U )
\r
1363 while( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U )
\r
1365 if( xTaskIncrementTick() != pdFALSE )
\r
1367 xYieldRequired = pdTRUE;
\r
1373 if( ( xYieldRequired == pdTRUE ) || ( xYieldPending == pdTRUE ) )
\r
1375 xAlreadyYielded = pdTRUE;
\r
1376 xYieldPending = pdFALSE;
\r
1377 portYIELD_WITHIN_API();
\r
1382 taskEXIT_CRITICAL();
\r
1384 return xAlreadyYielded;
\r
1386 /*-----------------------------------------------------------*/
\r
1388 portTickType xTaskGetTickCount( void )
\r
1390 portTickType xTicks;
\r
1392 /* Critical section required if running on a 16 bit processor. */
\r
1393 taskENTER_CRITICAL();
\r
1395 xTicks = xTickCount;
\r
1397 taskEXIT_CRITICAL();
\r
1401 /*-----------------------------------------------------------*/
\r
1403 portTickType xTaskGetTickCountFromISR( void )
\r
1405 portTickType xReturn;
\r
1406 unsigned portBASE_TYPE uxSavedInterruptStatus;
\r
1408 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
\r
1409 xReturn = xTickCount;
\r
1410 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
\r
1414 /*-----------------------------------------------------------*/
\r
1416 unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
\r
1418 /* A critical section is not required because the variables are of type
\r
1420 return uxCurrentNumberOfTasks;
\r
1422 /*-----------------------------------------------------------*/
\r
1424 #if ( INCLUDE_pcTaskGetTaskName == 1 )
\r
1426 signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery )
\r
1430 /* If null is passed in here then the name of the calling task is being queried. */
\r
1431 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
\r
1432 configASSERT( pxTCB );
\r
1433 return &( pxTCB->pcTaskName[ 0 ] );
\r
1436 #endif /* INCLUDE_pcTaskGetTaskName */
\r
1437 /*-----------------------------------------------------------*/
\r
1439 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1441 void vTaskList( signed char *pcWriteBuffer )
\r
1443 unsigned portBASE_TYPE uxQueue;
\r
1445 /* This is a VERY costly function that should be used for debug only.
\r
1446 It leaves interrupts disabled for a LONG time. */
\r
1448 vTaskSuspendAll();
\r
1450 /* Run through all the lists that could potentially contain a TCB and
\r
1451 report the task name, state and stack high water mark. */
\r
1453 *pcWriteBuffer = ( signed char ) 0x00;
\r
1454 strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
\r
1456 uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;
\r
1462 if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )
\r
1464 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
\r
1466 }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
\r
1468 if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )
\r
1470 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
\r
1473 if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )
\r
1475 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
\r
1478 #if( INCLUDE_vTaskDelete == 1 )
\r
1480 if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )
\r
1482 prvListTaskWithinSingleList( pcWriteBuffer, &xTasksWaitingTermination, tskDELETED_CHAR );
\r
1487 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1489 if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
\r
1491 prvListTaskWithinSingleList( pcWriteBuffer, &xSuspendedTaskList, tskSUSPENDED_CHAR );
\r
1499 #endif /* configUSE_TRACE_FACILITY */
\r
1500 /*----------------------------------------------------------*/
\r
1502 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1504 void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
\r
1506 unsigned portBASE_TYPE uxQueue;
\r
1507 unsigned long ulTotalRunTimeDiv100;
\r
1509 /* This is a VERY costly function that should be used for debug only.
\r
1510 It leaves interrupts disabled for a LONG time. */
\r
1512 vTaskSuspendAll();
\r
1514 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
\r
1515 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
\r
1517 ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
\r
1520 /* Divide ulTotalRunTime by 100 to make the percentage caluclations
\r
1521 simpler in the prvGenerateRunTimeStatsForTasksInList() function. */
\r
1522 ulTotalRunTimeDiv100 = ulTotalRunTime / 100UL;
\r
1524 /* Run through all the lists that could potentially contain a TCB,
\r
1525 generating a table of run timer percentages in the provided
\r
1528 *pcWriteBuffer = ( signed char ) 0x00;
\r
1529 strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
\r
1531 uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;
\r
1537 if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )
\r
1539 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTimeDiv100 );
\r
1541 }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
\r
1543 if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )
\r
1545 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTimeDiv100 );
\r
1548 if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )
\r
1550 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTimeDiv100 );
\r
1553 #if ( INCLUDE_vTaskDelete == 1 )
\r
1555 if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )
\r
1557 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, &xTasksWaitingTermination, ulTotalRunTimeDiv100 );
\r
1562 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1564 if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
\r
1566 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, &xSuspendedTaskList, ulTotalRunTimeDiv100 );
\r
1574 #endif /* configGENERATE_RUN_TIME_STATS */
\r
1575 /*----------------------------------------------------------*/
\r
1577 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
\r
1579 xTaskHandle xTaskGetIdleTaskHandle( void )
\r
1581 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been
\r
1582 started, then xIdleTaskHandle will be NULL. */
\r
1583 configASSERT( ( xIdleTaskHandle != NULL ) );
\r
1584 return xIdleTaskHandle;
\r
1587 #endif /* INCLUDE_xTaskGetIdleTaskHandle */
\r
1588 /*----------------------------------------------------------*/
\r
1590 /* This conditional compilation should use inequality to 0, not equality to 1.
\r
1591 This is to ensure vTaskStepTick() is available when user defined low power mode
\r
1592 implementations require configUSE_TICKLESS_IDLE to be set to a value other than
\r
1594 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
1596 void vTaskStepTick( portTickType xTicksToJump )
\r
1598 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );
\r
1599 xTickCount += xTicksToJump;
\r
1602 #endif /* configUSE_TICKLESS_IDLE */
\r
1603 /*----------------------------------------------------------*/
\r
1605 portBASE_TYPE xTaskIncrementTick( void )
\r
1608 portTickType xItemValue;
\r
1609 portBASE_TYPE xSwitchRequired = pdFALSE;
\r
1611 /* Called by the portable layer each time a tick interrupt occurs.
\r
1612 Increments the tick then checks to see if the new tick value will cause any
\r
1613 tasks to be unblocked. */
\r
1614 traceTASK_INCREMENT_TICK( xTickCount );
\r
1615 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1617 /* Increment the RTOS tick, switching the delayed and overflowed
\r
1618 delayed lists if it wraps to 0. */
\r
1620 if( xTickCount == ( portTickType ) 0U )
\r
1622 taskSWITCH_DELAYED_LISTS();
\r
1625 /* See if this tick has made a timeout expire. Tasks are stored in the
\r
1626 queue in the order of their wake time - meaning once one tasks has been
\r
1627 found whose block time has not expired there is no need not look any
\r
1628 further down the list. */
\r
1629 if( xTickCount >= xNextTaskUnblockTime )
\r
1633 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
\r
1635 /* The delayed list is empty. Set xNextTaskUnblockTime to
\r
1636 the maximum possible value so it is extremely unlikely that
\r
1637 the if( xTickCount >= xNextTaskUnblockTime ) test will pass
\r
1638 next time through. */
\r
1639 xNextTaskUnblockTime = portMAX_DELAY;
\r
1644 /* The delayed list is not empty, get the value of the item
\r
1645 at the head of the delayed list. This is the time at which
\r
1646 the task at the head of the delayed list must be removed
\r
1647 from the Blocked state. */
\r
1648 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
\r
1649 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );
\r
1651 if( xTickCount < xItemValue )
\r
1653 /* It is not time to unblock this item yet, but the item
\r
1654 value is the time at which the task at the head of the
\r
1655 blocked list must be removed from the Blocked state -
\r
1656 so record the item value in xNextTaskUnblockTime. */
\r
1657 xNextTaskUnblockTime = xItemValue;
\r
1661 /* It is time to remove the item from the Blocked state. */
\r
1662 uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1664 /* Is the task waiting on an event also? If so remove it
\r
1665 from the event list. */
\r
1666 if( pxTCB->xEventListItem.pvContainer != NULL )
\r
1668 uxListRemove( &( pxTCB->xEventListItem ) );
\r
1671 /* Place the unblocked task into the appropriate ready
\r
1673 prvAddTaskToReadyList( pxTCB );
\r
1675 /* A task being unblocked cannot cause an immediate context
\r
1676 switch if preemption is turned off. */
\r
1677 #if ( configUSE_PREEMPTION == 1 )
\r
1679 /* Preemption is on, but a context switch should only
\r
1680 be performed if the unblocked task has a priority that
\r
1681 is equal to or higher than the currently executing
\r
1683 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1685 xSwitchRequired = pdTRUE;
\r
1688 #endif /* configUSE_PREEMPTION */
\r
1693 /* Tasks of equal priority to the currently running task will share
\r
1694 processing time (time slice) if preemption is on, and the application
\r
1695 writer has not explicitly turned time slicing off. */
\r
1696 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
\r
1698 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > 1 )
\r
1700 xSwitchRequired = pdTRUE;
\r
1703 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
\r
1709 /* The tick hook gets called at regular intervals, even if the
\r
1710 scheduler is locked. */
\r
1711 #if ( configUSE_TICK_HOOK == 1 )
\r
1713 vApplicationTickHook();
\r
1718 #if ( configUSE_TICK_HOOK == 1 )
\r
1720 /* Guard against the tick hook being called when the missed tick
\r
1721 count is being unwound (when the scheduler is being unlocked). */
\r
1722 if( uxPendedTicks == ( unsigned portBASE_TYPE ) 0U )
\r
1724 vApplicationTickHook();
\r
1727 #endif /* configUSE_TICK_HOOK */
\r
1729 return xSwitchRequired;
\r
1731 /*-----------------------------------------------------------*/
\r
1733 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1735 void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction )
\r
1739 /* If xTask is NULL then we are setting our own task hook. */
\r
1740 if( xTask == NULL )
\r
1742 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1746 xTCB = ( tskTCB * ) xTask;
\r
1749 /* Save the hook function in the TCB. A critical section is required as
\r
1750 the value can be accessed from an interrupt. */
\r
1751 taskENTER_CRITICAL();
\r
1752 xTCB->pxTaskTag = pxHookFunction;
\r
1753 taskEXIT_CRITICAL();
\r
1756 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
1757 /*-----------------------------------------------------------*/
\r
1759 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1761 pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
\r
1764 pdTASK_HOOK_CODE xReturn;
\r
1766 /* If xTask is NULL then we are setting our own task hook. */
\r
1767 if( xTask == NULL )
\r
1769 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1773 xTCB = ( tskTCB * ) xTask;
\r
1776 /* Save the hook function in the TCB. A critical section is required as
\r
1777 the value can be accessed from an interrupt. */
\r
1778 taskENTER_CRITICAL();
\r
1779 xReturn = xTCB->pxTaskTag;
\r
1780 taskEXIT_CRITICAL();
\r
1785 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
1786 /*-----------------------------------------------------------*/
\r
1788 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1790 portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
\r
1793 portBASE_TYPE xReturn;
\r
1795 /* If xTask is NULL then we are calling our own task hook. */
\r
1796 if( xTask == NULL )
\r
1798 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1802 xTCB = ( tskTCB * ) xTask;
\r
1805 if( xTCB->pxTaskTag != NULL )
\r
1807 xReturn = xTCB->pxTaskTag( pvParameter );
\r
1817 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
1818 /*-----------------------------------------------------------*/
\r
1820 void vTaskSwitchContext( void )
\r
1822 if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
\r
1824 /* The scheduler is currently suspended - do not allow a context
\r
1826 xYieldPending = pdTRUE;
\r
1830 traceTASK_SWITCHED_OUT();
\r
1832 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1834 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
\r
1835 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
\r
1837 ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
\r
1840 /* Add the amount of time the task has been running to the
\r
1841 accumulated time so far. The time the task started running was
\r
1842 stored in ulTaskSwitchedInTime. Note that there is no overflow
\r
1843 protection here so count values are only valid until the timer
\r
1844 overflows. The guard against negative values is to protect
\r
1845 against suspect run time stat counter implementations - which
\r
1846 are provided by the application, not the kernel. */
\r
1847 if( ulTotalRunTime > ulTaskSwitchedInTime )
\r
1849 pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
\r
1851 ulTaskSwitchedInTime = ulTotalRunTime;
\r
1853 #endif /* configGENERATE_RUN_TIME_STATS */
\r
1855 taskFIRST_CHECK_FOR_STACK_OVERFLOW();
\r
1856 taskSECOND_CHECK_FOR_STACK_OVERFLOW();
\r
1858 taskSELECT_HIGHEST_PRIORITY_TASK();
\r
1860 traceTASK_SWITCHED_IN();
\r
1863 /*-----------------------------------------------------------*/
\r
1865 void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
\r
1867 portTickType xTimeToWake;
\r
1869 configASSERT( pxEventList );
\r
1871 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1872 SCHEDULER SUSPENDED. */
\r
1874 /* Place the event list item of the TCB in the appropriate event list.
\r
1875 This is placed in the list in priority order so the highest priority task
\r
1876 is the first to be woken by the event. */
\r
1877 vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
\r
1879 /* We must remove ourselves from the ready list before adding ourselves
\r
1880 to the blocked list as the same list item is used for both lists. We have
\r
1881 exclusive access to the ready lists as the scheduler is locked. */
\r
1882 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )
\r
1884 /* The current task must be in a ready list, so there is no need to
\r
1885 check, and the port reset macro can be called directly. */
\r
1886 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
1889 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1891 if( xTicksToWait == portMAX_DELAY )
\r
1893 /* Add ourselves to the suspended task list instead of a delayed task
\r
1894 list to ensure we are not woken by a timing event. We will block
\r
1896 vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1900 /* Calculate the time at which the task should be woken if the event does
\r
1901 not occur. This may overflow but this doesn't matter. */
\r
1902 xTimeToWake = xTickCount + xTicksToWait;
\r
1903 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
1906 #else /* INCLUDE_vTaskSuspend */
\r
1908 /* Calculate the time at which the task should be woken if the event does
\r
1909 not occur. This may overflow but this doesn't matter. */
\r
1910 xTimeToWake = xTickCount + xTicksToWait;
\r
1911 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
1913 #endif /* INCLUDE_vTaskSuspend */
\r
1915 /*-----------------------------------------------------------*/
\r
1917 #if configUSE_TIMERS == 1
\r
1919 void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait )
\r
1921 portTickType xTimeToWake;
\r
1923 configASSERT( pxEventList );
\r
1925 /* This function should not be called by application code hence the
\r
1926 'Restricted' in its name. It is not part of the public API. It is
\r
1927 designed for use by kernel code, and has special calling requirements -
\r
1928 it should be called from a critical section. */
\r
1931 /* Place the event list item of the TCB in the appropriate event list.
\r
1932 In this case it is assume that this is the only task that is going to
\r
1933 be waiting on this event list, so the faster vListInsertEnd() function
\r
1934 can be used in place of vListInsert. */
\r
1935 vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
\r
1937 /* We must remove this task from the ready list before adding it to the
\r
1938 blocked list as the same list item is used for both lists. This
\r
1939 function is called form a critical section. */
\r
1940 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )
\r
1942 /* The current task must be in a ready list, so there is no need to
\r
1943 check, and the port reset macro can be called directly. */
\r
1944 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
1947 /* Calculate the time at which the task should be woken if the event does
\r
1948 not occur. This may overflow but this doesn't matter. */
\r
1949 xTimeToWake = xTickCount + xTicksToWait;
\r
1951 traceTASK_DELAY_UNTIL();
\r
1952 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
1955 #endif /* configUSE_TIMERS */
\r
1956 /*-----------------------------------------------------------*/
\r
1958 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
\r
1960 tskTCB *pxUnblockedTCB;
\r
1961 portBASE_TYPE xReturn;
\r
1963 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1964 SCHEDULER SUSPENDED. It can also be called from within an ISR. */
\r
1966 /* The event list is sorted in priority order, so we can remove the
\r
1967 first in the list, remove the TCB from the delayed list, and add
\r
1968 it to the ready list.
\r
1970 If an event is for a queue that is locked then this function will never
\r
1971 get called - the lock count on the queue will get modified instead. This
\r
1972 means we can always expect exclusive access to the event list here.
\r
1974 This function assumes that a check has already been made to ensure that
\r
1975 pxEventList is not empty. */
\r
1976 pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
\r
1977 configASSERT( pxUnblockedTCB );
\r
1978 uxListRemove( &( pxUnblockedTCB->xEventListItem ) );
\r
1980 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1982 uxListRemove( &( pxUnblockedTCB->xGenericListItem ) );
\r
1983 prvAddTaskToReadyList( pxUnblockedTCB );
\r
1987 /* We cannot access the delayed or ready lists, so will hold this
\r
1988 task pending until the scheduler is resumed. */
\r
1989 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
\r
1992 if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1994 /* Return true if the task removed from the event list has
\r
1995 a higher priority than the calling task. This allows
\r
1996 the calling task to know if it should force a context
\r
2002 xReturn = pdFALSE;
\r
2007 /*-----------------------------------------------------------*/
\r
2009 void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
\r
2011 configASSERT( pxTimeOut );
\r
2012 pxTimeOut->xOverflowCount = xNumOfOverflows;
\r
2013 pxTimeOut->xTimeOnEntering = xTickCount;
\r
2015 /*-----------------------------------------------------------*/
\r
2017 portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
\r
2019 portBASE_TYPE xReturn;
\r
2021 configASSERT( pxTimeOut );
\r
2022 configASSERT( pxTicksToWait );
\r
2024 taskENTER_CRITICAL();
\r
2026 #if ( INCLUDE_vTaskSuspend == 1 )
\r
2027 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
\r
2028 the maximum block time then the task should block indefinitely, and
\r
2029 therefore never time out. */
\r
2030 if( *pxTicksToWait == portMAX_DELAY )
\r
2032 xReturn = pdFALSE;
\r
2034 else /* We are not blocking indefinitely, perform the checks below. */
\r
2037 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )
\r
2039 /* The tick count is greater than the time at which vTaskSetTimeout()
\r
2040 was called, but has also overflowed since vTaskSetTimeOut() was called.
\r
2041 It must have wrapped all the way around and gone past us again. This
\r
2042 passed since vTaskSetTimeout() was called. */
\r
2045 else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )
\r
2047 /* Not a genuine timeout. Adjust parameters for time remaining. */
\r
2048 *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );
\r
2049 vTaskSetTimeOutState( pxTimeOut );
\r
2050 xReturn = pdFALSE;
\r
2057 taskEXIT_CRITICAL();
\r
2061 /*-----------------------------------------------------------*/
\r
2063 void vTaskMissedYield( void )
\r
2065 xYieldPending = pdTRUE;
\r
2067 /*-----------------------------------------------------------*/
\r
2069 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2071 unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask )
\r
2073 unsigned portBASE_TYPE uxReturn;
\r
2076 if( xTask != NULL )
\r
2078 pxTCB = ( tskTCB * ) xTask;
\r
2079 uxReturn = pxTCB->uxTaskNumber;
\r
2089 #endif /* configUSE_TRACE_FACILITY */
\r
2090 /*-----------------------------------------------------------*/
\r
2092 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2094 void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle )
\r
2098 if( xTask != NULL )
\r
2100 pxTCB = ( tskTCB * ) xTask;
\r
2101 pxTCB->uxTaskNumber = uxHandle;
\r
2105 #endif /* configUSE_TRACE_FACILITY */
\r
2108 * -----------------------------------------------------------
\r
2110 * ----------------------------------------------------------
\r
2112 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
\r
2113 * language extensions. The equivalent prototype for this function is:
\r
2115 * void prvIdleTask( void *pvParameters );
\r
2118 static portTASK_FUNCTION( prvIdleTask, pvParameters )
\r
2120 /* Stop warnings. */
\r
2121 ( void ) pvParameters;
\r
2125 /* See if any tasks have been deleted. */
\r
2126 prvCheckTasksWaitingTermination();
\r
2128 #if ( configUSE_PREEMPTION == 0 )
\r
2130 /* If we are not using preemption we keep forcing a task switch to
\r
2131 see if any other task has become available. If we are using
\r
2132 preemption we don't need to do this as any task becoming available
\r
2133 will automatically get the processor anyway. */
\r
2136 #endif /* configUSE_PREEMPTION */
\r
2138 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
\r
2140 /* When using preemption tasks of equal priority will be
\r
2141 timesliced. If a task that is sharing the idle priority is ready
\r
2142 to run then the idle task should yield before the end of the
\r
2145 A critical region is not required here as we are just reading from
\r
2146 the list, and an occasional incorrect value will not matter. If
\r
2147 the ready list at the idle priority contains more than one task
\r
2148 then a task other than the idle task is ready to execute. */
\r
2149 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
\r
2154 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
\r
2156 #if ( configUSE_IDLE_HOOK == 1 )
\r
2158 extern void vApplicationIdleHook( void );
\r
2160 /* Call the user defined function from within the idle task. This
\r
2161 allows the application designer to add background functionality
\r
2162 without the overhead of a separate task.
\r
2163 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
\r
2164 CALL A FUNCTION THAT MIGHT BLOCK. */
\r
2165 vApplicationIdleHook();
\r
2167 #endif /* configUSE_IDLE_HOOK */
\r
2169 /* This conditional compilation should use inequality to 0, not equality
\r
2170 to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
\r
2171 user defined low power mode implementations require
\r
2172 configUSE_TICKLESS_IDLE to be set to a value other than 1. */
\r
2173 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
2175 portTickType xExpectedIdleTime;
\r
2177 /* It is not desirable to suspend then resume the scheduler on
\r
2178 each iteration of the idle task. Therefore, a preliminary
\r
2179 test of the expected idle time is performed without the
\r
2180 scheduler suspended. The result here is not necessarily
\r
2182 xExpectedIdleTime = prvGetExpectedIdleTime();
\r
2184 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
\r
2186 vTaskSuspendAll();
\r
2188 /* Now the scheduler is suspended, the expected idle
\r
2189 time can be sampled again, and this time its value can
\r
2191 configASSERT( xNextTaskUnblockTime >= xTickCount );
\r
2192 xExpectedIdleTime = prvGetExpectedIdleTime();
\r
2194 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
\r
2196 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
\r
2202 #endif /* configUSE_TICKLESS_IDLE */
\r
2204 } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
\r
2205 /*-----------------------------------------------------------*/
\r
2207 #if configUSE_TICKLESS_IDLE != 0
\r
2209 eSleepModeStatus eTaskConfirmSleepModeStatus( void )
\r
2211 eSleepModeStatus eReturn = eStandardSleep;
\r
2213 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )
\r
2215 /* A task was made ready while the scheduler was suspended. */
\r
2216 eReturn = eAbortSleep;
\r
2218 else if( xYieldPending != pdFALSE )
\r
2220 /* A yield was pended while the scheduler was suspended. */
\r
2221 eReturn = eAbortSleep;
\r
2225 #if configUSE_TIMERS == 0
\r
2227 /* The idle task exists in addition to the application tasks. */
\r
2228 const unsigned portBASE_TYPE uxNonApplicationTasks = 1;
\r
2230 /* If timers are not being used and all the tasks are in the
\r
2231 suspended list (which might mean they have an infinite block
\r
2232 time rather than actually being suspended) then it is safe to
\r
2233 turn all clocks off and just wait for external interrupts. */
\r
2234 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
\r
2236 eReturn = eNoTasksWaitingTimeout;
\r
2239 #endif /* configUSE_TIMERS */
\r
2244 #endif /* configUSE_TICKLESS_IDLE */
\r
2245 /*-----------------------------------------------------------*/
\r
2247 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
\r
2251 /* Store the task name in the TCB. */
\r
2252 for( x = 0; x < configMAX_TASK_NAME_LEN; x++ )
\r
2254 pxTCB->pcTaskName[ x ] = pcName[ x ];
\r
2256 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
\r
2257 configMAX_TASK_NAME_LEN characters just in case the memory after the
\r
2258 string is not accessible (extremely unlikely). */
\r
2259 if( pcName[ x ] == 0x00 )
\r
2265 /* Ensure the name string is terminated in the case that the string length
\r
2266 was greater or equal to configMAX_TASK_NAME_LEN. */
\r
2267 pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = ( signed char ) '\0';
\r
2269 /* This is used as an array index so must ensure it's not too large. First
\r
2270 remove the privilege bit if one is present. */
\r
2271 if( uxPriority >= configMAX_PRIORITIES )
\r
2273 uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
\r
2276 pxTCB->uxPriority = uxPriority;
\r
2277 #if ( configUSE_MUTEXES == 1 )
\r
2279 pxTCB->uxBasePriority = uxPriority;
\r
2281 #endif /* configUSE_MUTEXES */
\r
2283 vListInitialiseItem( &( pxTCB->xGenericListItem ) );
\r
2284 vListInitialiseItem( &( pxTCB->xEventListItem ) );
\r
2286 /* Set the pxTCB as a link back from the xListItem. This is so we can get
\r
2287 back to the containing TCB from a generic item in a list. */
\r
2288 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
\r
2290 /* Event lists are always in priority order. */
\r
2291 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
\r
2292 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
\r
2294 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2296 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0U;
\r
2298 #endif /* portCRITICAL_NESTING_IN_TCB */
\r
2300 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
2302 pxTCB->pxTaskTag = NULL;
\r
2304 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
2306 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
2308 pxTCB->ulRunTimeCounter = 0UL;
\r
2310 #endif /* configGENERATE_RUN_TIME_STATS */
\r
2312 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
2314 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
\r
2316 #else /* portUSING_MPU_WRAPPERS */
\r
2318 ( void ) xRegions;
\r
2319 ( void ) usStackDepth;
\r
2321 #endif /* portUSING_MPU_WRAPPERS */
\r
2323 /*-----------------------------------------------------------*/
\r
2325 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
2327 void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
\r
2331 if( xTaskToModify == pxCurrentTCB )
\r
2333 xTaskToModify = NULL;
\r
2336 /* If null is passed in here then we are deleting ourselves. */
\r
2337 pxTCB = prvGetTCBFromHandle( xTaskToModify );
\r
2339 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
\r
2342 #endif /* portUSING_MPU_WRAPPERS */
\r
2343 /*-----------------------------------------------------------*/
\r
2345 static void prvInitialiseTaskLists( void )
\r
2347 unsigned portBASE_TYPE uxPriority;
\r
2349 for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < configMAX_PRIORITIES; uxPriority++ )
\r
2351 vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
\r
2354 vListInitialise( ( xList * ) &xDelayedTaskList1 );
\r
2355 vListInitialise( ( xList * ) &xDelayedTaskList2 );
\r
2356 vListInitialise( ( xList * ) &xPendingReadyList );
\r
2358 #if ( INCLUDE_vTaskDelete == 1 )
\r
2360 vListInitialise( ( xList * ) &xTasksWaitingTermination );
\r
2362 #endif /* INCLUDE_vTaskDelete */
\r
2364 #if ( INCLUDE_vTaskSuspend == 1 )
\r
2366 vListInitialise( ( xList * ) &xSuspendedTaskList );
\r
2368 #endif /* INCLUDE_vTaskSuspend */
\r
2370 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
\r
2372 pxDelayedTaskList = &xDelayedTaskList1;
\r
2373 pxOverflowDelayedTaskList = &xDelayedTaskList2;
\r
2375 /*-----------------------------------------------------------*/
\r
2377 static void prvCheckTasksWaitingTermination( void )
\r
2379 #if ( INCLUDE_vTaskDelete == 1 )
\r
2381 portBASE_TYPE xListIsEmpty;
\r
2383 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
\r
2384 too often in the idle task. */
\r
2385 while( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0U )
\r
2387 vTaskSuspendAll();
\r
2388 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
\r
2391 if( xListIsEmpty == pdFALSE )
\r
2395 taskENTER_CRITICAL();
\r
2397 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
\r
2398 uxListRemove( &( pxTCB->xGenericListItem ) );
\r
2399 --uxCurrentNumberOfTasks;
\r
2402 taskEXIT_CRITICAL();
\r
2404 prvDeleteTCB( pxTCB );
\r
2408 #endif /* vTaskDelete */
\r
2410 /*-----------------------------------------------------------*/
\r
2412 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake )
\r
2414 /* The list item will be inserted in wake time order. */
\r
2415 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
2417 if( xTimeToWake < xTickCount )
\r
2419 /* Wake time has overflowed. Place this item in the overflow list. */
\r
2420 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
2424 /* The wake time has not overflowed, so we can use the current block list. */
\r
2425 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
2427 /* If the task entering the blocked state was placed at the head of the
\r
2428 list of blocked tasks then xNextTaskUnblockTime needs to be updated
\r
2430 if( xTimeToWake < xNextTaskUnblockTime )
\r
2432 xNextTaskUnblockTime = xTimeToWake;
\r
2436 /*-----------------------------------------------------------*/
\r
2438 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
\r
2442 /* Allocate space for the TCB. Where the memory comes from depends on
\r
2443 the implementation of the port malloc function. */
\r
2444 pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
\r
2446 if( pxNewTCB != NULL )
\r
2448 /* Allocate space for the stack used by the task being created.
\r
2449 The base of the stack memory stored in the TCB so the task can
\r
2450 be deleted later if required. */
\r
2451 pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );
\r
2453 if( pxNewTCB->pxStack == NULL )
\r
2455 /* Could not allocate the stack. Delete the allocated TCB. */
\r
2456 vPortFree( pxNewTCB );
\r
2461 /* Just to help debugging. */
\r
2462 memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( portSTACK_TYPE ) );
\r
2468 /*-----------------------------------------------------------*/
\r
2470 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2472 static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus )
\r
2474 volatile tskTCB *pxNextTCB, *pxFirstTCB;
\r
2475 unsigned short usStackRemaining;
\r
2476 PRIVILEGED_DATA static char pcStatusString[ configMAX_TASK_NAME_LEN + 30 ];
\r
2478 /* Write the details of all the TCB's in pxList into the buffer. */
\r
2479 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
\r
2482 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
\r
2483 #if ( portSTACK_GROWTH > 0 )
\r
2485 usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );
\r
2489 usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );
\r
2493 sprintf( pcStatusString, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, ( unsigned int ) usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );
\r
2494 strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString );
\r
2496 } while( pxNextTCB != pxFirstTCB );
\r
2499 #endif /* configUSE_TRACE_FACILITY */
\r
2500 /*-----------------------------------------------------------*/
\r
2502 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
2504 static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTimeDiv100 )
\r
2506 volatile tskTCB *pxNextTCB, *pxFirstTCB;
\r
2507 unsigned long ulStatsAsPercentage;
\r
2508 size_t xExistingStringLength;
\r
2510 /* Write the run time stats of all the TCB's in pxList into the buffer. */
\r
2511 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
\r
2514 /* Get next TCB from the list. */
\r
2515 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
\r
2517 /* Divide by zero check. */
\r
2518 if( ulTotalRunTimeDiv100 > 0UL )
\r
2520 xExistingStringLength = strlen( ( char * ) pcWriteBuffer );
\r
2522 /* Has the task run at all? */
\r
2523 if( pxNextTCB->ulRunTimeCounter == 0UL )
\r
2525 /* The task has used no CPU time at all. */
\r
2526 sprintf( ( char * ) &( pcWriteBuffer[ xExistingStringLength ] ), ( char * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
\r
2530 /* What percentage of the total run time has the task used?
\r
2531 This will always be rounded down to the nearest integer.
\r
2532 ulTotalRunTimeDiv100 has already been divided by 100. */
\r
2533 ulStatsAsPercentage = pxNextTCB->ulRunTimeCounter / ulTotalRunTimeDiv100;
\r
2535 if( ulStatsAsPercentage > 0UL )
\r
2537 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
\r
2539 sprintf( ( char * ) &( pcWriteBuffer[ xExistingStringLength ] ), ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter, ulStatsAsPercentage );
\r
2543 /* sizeof( int ) == sizeof( long ) so a smaller
\r
2544 printf() library can be used. */
\r
2545 sprintf( ( char * ) &( pcWriteBuffer[ xExistingStringLength ] ), ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
\r
2551 /* If the percentage is zero here then the task has
\r
2552 consumed less than 1% of the total run time. */
\r
2553 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
\r
2555 sprintf( ( char * ) &( pcWriteBuffer[ xExistingStringLength ] ), ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter );
\r
2559 /* sizeof( int ) == sizeof( long ) so a smaller
\r
2560 printf() library can be used. */
\r
2561 sprintf( ( char * ) &( pcWriteBuffer[ xExistingStringLength ] ), ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
\r
2568 } while( pxNextTCB != pxFirstTCB );
\r
2571 #endif /* configGENERATE_RUN_TIME_STATS */
\r
2572 /*-----------------------------------------------------------*/
\r
2574 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
2576 static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte )
\r
2578 register unsigned short usCount = 0U;
\r
2580 while( *pucStackByte == tskSTACK_FILL_BYTE )
\r
2582 pucStackByte -= portSTACK_GROWTH;
\r
2586 usCount /= sizeof( portSTACK_TYPE );
\r
2591 #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */
\r
2592 /*-----------------------------------------------------------*/
\r
2594 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
\r
2596 unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
\r
2599 unsigned char *pcEndOfStack;
\r
2600 unsigned portBASE_TYPE uxReturn;
\r
2602 pxTCB = prvGetTCBFromHandle( xTask );
\r
2604 #if portSTACK_GROWTH < 0
\r
2606 pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;
\r
2610 pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;
\r
2614 uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );
\r
2619 #endif /* INCLUDE_uxTaskGetStackHighWaterMark */
\r
2620 /*-----------------------------------------------------------*/
\r
2622 #if ( INCLUDE_vTaskDelete == 1 )
\r
2624 static void prvDeleteTCB( tskTCB *pxTCB )
\r
2626 /* This call is required specifically for the TriCore port. It must be
\r
2627 above the vPortFree() calls. The call is also used by ports/demos that
\r
2628 want to allocate and clean RAM statically. */
\r
2629 portCLEAN_UP_TCB( pxTCB );
\r
2631 /* Free up the memory allocated by the scheduler for the task. It is up to
\r
2632 the task to free any memory allocated at the application level. */
\r
2633 vPortFreeAligned( pxTCB->pxStack );
\r
2634 vPortFree( pxTCB );
\r
2637 #endif /* INCLUDE_vTaskDelete */
\r
2638 /*-----------------------------------------------------------*/
\r
2640 #if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
\r
2642 xTaskHandle xTaskGetCurrentTaskHandle( void )
\r
2644 xTaskHandle xReturn;
\r
2646 /* A critical section is not required as this is not called from
\r
2647 an interrupt and the current TCB will always be the same for any
\r
2648 individual execution thread. */
\r
2649 xReturn = pxCurrentTCB;
\r
2654 #endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
\r
2655 /*-----------------------------------------------------------*/
\r
2657 #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
\r
2659 portBASE_TYPE xTaskGetSchedulerState( void )
\r
2661 portBASE_TYPE xReturn;
\r
2663 if( xSchedulerRunning == pdFALSE )
\r
2665 xReturn = taskSCHEDULER_NOT_STARTED;
\r
2669 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
2671 xReturn = taskSCHEDULER_RUNNING;
\r
2675 xReturn = taskSCHEDULER_SUSPENDED;
\r
2682 #endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */
\r
2683 /*-----------------------------------------------------------*/
\r
2685 #if ( configUSE_MUTEXES == 1 )
\r
2687 void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
\r
2689 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2691 /* If the mutex was given back by an interrupt while the queue was
\r
2692 locked then the mutex holder might now be NULL. */
\r
2693 if( pxMutexHolder != NULL )
\r
2695 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
\r
2697 /* Adjust the mutex holder state to account for its new priority. */
\r
2698 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
\r
2700 /* If the task being modified is in the ready state it will need to
\r
2701 be moved into a new list. */
\r
2702 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE )
\r
2704 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
\r
2706 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
2709 /* Inherit the priority before being moved into the new list. */
\r
2710 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2711 prvAddTaskToReadyList( pxTCB );
\r
2715 /* Just inherit the priority. */
\r
2716 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2719 traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );
\r
2724 #endif /* configUSE_MUTEXES */
\r
2725 /*-----------------------------------------------------------*/
\r
2727 #if ( configUSE_MUTEXES == 1 )
\r
2729 void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
\r
2731 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2733 if( pxMutexHolder != NULL )
\r
2735 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
\r
2737 /* We must be the running task to be able to give the mutex back.
\r
2738 Remove ourselves from the ready list we currently appear in. */
\r
2739 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
\r
2741 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
2744 /* Disinherit the priority before adding the task into the new
\r
2746 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
\r
2747 pxTCB->uxPriority = pxTCB->uxBasePriority;
\r
2748 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
\r
2749 prvAddTaskToReadyList( pxTCB );
\r
2754 #endif /* configUSE_MUTEXES */
\r
2755 /*-----------------------------------------------------------*/
\r
2757 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2759 void vTaskEnterCritical( void )
\r
2761 portDISABLE_INTERRUPTS();
\r
2763 if( xSchedulerRunning != pdFALSE )
\r
2765 ( pxCurrentTCB->uxCriticalNesting )++;
\r
2769 #endif /* portCRITICAL_NESTING_IN_TCB */
\r
2770 /*-----------------------------------------------------------*/
\r
2772 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2774 void vTaskExitCritical( void )
\r
2776 if( xSchedulerRunning != pdFALSE )
\r
2778 if( pxCurrentTCB->uxCriticalNesting > 0U )
\r
2780 ( pxCurrentTCB->uxCriticalNesting )--;
\r
2782 if( pxCurrentTCB->uxCriticalNesting == 0U )
\r
2784 portENABLE_INTERRUPTS();
\r
2790 #endif /* portCRITICAL_NESTING_IN_TCB */
\r
2791 /*-----------------------------------------------------------*/
\r