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
149 #if ( configUSE_NEWLIB_REENTRANT == 1 )
\r
150 /* Allocate a Newlib reent structure that is specific to this task.
\r
151 Note Newlib support has been included by popular demand, but is not
\r
152 used by the FreeRTOS maintainers themselves, and therefore receives
\r
153 less rigorous testing than the rest of the FreeRTOS code. */
\r
154 struct _reent xNewLib_reent;
\r
161 * Some kernel aware debuggers require the data the debugger needs access to to
\r
162 * be global, rather than file scope.
\r
164 #ifdef portREMOVE_STATIC_QUALIFIER
\r
169 PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
\r
171 /* Lists for ready and blocked tasks. --------------------*/
\r
172 PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
\r
173 PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */
\r
174 PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
\r
175 PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */
\r
176 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
177 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
179 #if ( INCLUDE_vTaskDelete == 1 )
\r
181 PRIVILEGED_DATA static xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
\r
182 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0U;
\r
186 #if ( INCLUDE_vTaskSuspend == 1 )
\r
188 PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
\r
192 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
\r
194 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
198 /* File private variables. --------------------------------*/
\r
199 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0U;
\r
200 PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0U;
\r
201 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
\r
202 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
\r
203 PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
\r
204 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
\r
205 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxPendedTicks = ( unsigned portBASE_TYPE ) 0U;
\r
206 PRIVILEGED_DATA static volatile portBASE_TYPE xYieldPending = ( portBASE_TYPE ) pdFALSE;
\r
207 PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
\r
208 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0U;
\r
209 PRIVILEGED_DATA static volatile portTickType xNextTaskUnblockTime = ( portTickType ) portMAX_DELAY;
\r
211 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
213 PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
\r
214 PRIVILEGED_DATA static unsigned long ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */
\r
215 static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTimeDiv100 ) PRIVILEGED_FUNCTION;
\r
219 /* Debugging and trace facilities private variables and macros. ------------*/
\r
222 * The value used to fill the stack of a task when the task is created. This
\r
223 * is used purely for checking the high water mark for tasks.
\r
225 #define tskSTACK_FILL_BYTE ( 0xa5U )
\r
228 * Macros used by vListTask to indicate which state a task is in.
\r
230 #define tskBLOCKED_CHAR ( ( signed char ) 'B' )
\r
231 #define tskREADY_CHAR ( ( signed char ) 'R' )
\r
232 #define tskDELETED_CHAR ( ( signed char ) 'D' )
\r
233 #define tskSUSPENDED_CHAR ( ( signed char ) 'S' )
\r
235 /*-----------------------------------------------------------*/
\r
237 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
\r
239 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
\r
240 performed in a generic way that is not optimised to any particular
\r
241 microcontroller architecture. */
\r
243 /* uxTopReadyPriority holds the priority of the highest priority ready
\r
245 #define taskRECORD_READY_PRIORITY( uxPriority ) \
\r
247 if( ( uxPriority ) > uxTopReadyPriority ) \
\r
249 uxTopReadyPriority = ( uxPriority ); \
\r
251 } /* taskRECORD_READY_PRIORITY */
\r
253 /*-----------------------------------------------------------*/
\r
255 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
\r
257 /* Find the highest priority queue that contains ready tasks. */ \
\r
258 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) \
\r
260 configASSERT( uxTopReadyPriority ); \
\r
261 --uxTopReadyPriority; \
\r
264 /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
\r
265 the same priority get an equal share of the processor time. */ \
\r
266 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \
\r
267 } /* taskSELECT_HIGHEST_PRIORITY_TASK */
\r
269 /*-----------------------------------------------------------*/
\r
271 /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as
\r
272 they are only required when a port optimised method of task selection is
\r
274 #define taskRESET_READY_PRIORITY( uxPriority )
\r
275 #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
\r
277 #else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
\r
279 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is
\r
280 performed in a way that is tailored to the particular microcontroller
\r
281 architecture being used. */
\r
283 /* A port optimised version is provided. Call the port defined macros. */
\r
284 #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
\r
286 /*-----------------------------------------------------------*/
\r
288 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
\r
290 unsigned portBASE_TYPE uxTopPriority; \
\r
292 /* Find the highest priority queue that contains ready tasks. */ \
\r
293 portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
\r
294 configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
\r
295 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
\r
296 } /* taskSELECT_HIGHEST_PRIORITY_TASK() */
\r
298 /*-----------------------------------------------------------*/
\r
300 /* A port optimised version is provided, call it only if the TCB being reset
\r
301 is being referenced from a ready list. If it is referenced from a delayed
\r
302 or suspended list then it won't be in a ready list. */
\r
303 #define taskRESET_READY_PRIORITY( uxPriority ) \
\r
305 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == 0 ) \
\r
307 portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \
\r
311 #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
\r
313 /*-----------------------------------------------------------*/
\r
315 /* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
\r
316 count overflows. */
\r
317 #define taskSWITCH_DELAYED_LISTS() \
\r
321 /* The delayed tasks list should be empty when the lists are switched. */ \
\r
322 configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \
\r
324 pxTemp = pxDelayedTaskList; \
\r
325 pxDelayedTaskList = pxOverflowDelayedTaskList; \
\r
326 pxOverflowDelayedTaskList = pxTemp; \
\r
327 xNumOfOverflows++; \
\r
329 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \
\r
331 /* The new current delayed list is empty. Set \
\r
332 xNextTaskUnblockTime to the maximum possible value so it is \
\r
333 extremely unlikely that the \
\r
334 if( xTickCount >= xNextTaskUnblockTime ) test will pass until \
\r
335 there is an item in the delayed list. */ \
\r
336 xNextTaskUnblockTime = portMAX_DELAY; \
\r
340 /* The new current delayed list is not empty, get the value of \
\r
341 the item at the head of the delayed list. This is the time at \
\r
342 which the task at the head of the delayed list should be removed \
\r
343 from the Blocked state. */ \
\r
344 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \
\r
345 xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \
\r
349 /*-----------------------------------------------------------*/
\r
352 * Place the task represented by pxTCB into the appropriate ready list for
\r
353 * the task. It is inserted at the end of the list.
\r
355 #define prvAddTaskToReadyList( pxTCB ) \
\r
356 traceMOVED_TASK_TO_READY_STATE( pxTCB ) \
\r
357 taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
\r
358 vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
\r
359 /*-----------------------------------------------------------*/
\r
362 * Several functions take an xTaskHandle parameter that can optionally be NULL,
\r
363 * where NULL is used to indicate that the handle of the currently executing
\r
364 * task should be used in place of the parameter. This macro simply checks to
\r
365 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
\r
367 #define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) )
\r
369 /* Callback function prototypes. --------------------------*/
\r
370 extern void vApplicationStackOverflowHook( xTaskHandle xTask, signed char *pcTaskName );
\r
371 extern void vApplicationTickHook( void );
\r
373 /* File private functions. --------------------------------*/
\r
376 * Utility to ready a TCB for a given task. Mainly just copies the parameters
\r
377 * into the TCB structure.
\r
379 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;
\r
382 * Utility to ready all the lists used by the scheduler. This is called
\r
383 * automatically upon the creation of the first task.
\r
385 static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
\r
388 * The idle task, which as all tasks is implemented as a never ending loop.
\r
389 * The idle task is automatically created and added to the ready lists upon
\r
390 * creation of the first user task.
\r
392 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
\r
393 * language extensions. The equivalent prototype for this function is:
\r
395 * void prvIdleTask( void *pvParameters );
\r
398 static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
\r
401 * Utility to free all memory allocated by the scheduler to hold a TCB,
\r
402 * including the stack pointed to by the TCB.
\r
404 * This does not free memory allocated by the task itself (i.e. memory
\r
405 * allocated by calls to pvPortMalloc from within the tasks application code).
\r
407 #if ( INCLUDE_vTaskDelete == 1 )
\r
409 static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;
\r
414 * Used only by the idle task. This checks to see if anything has been placed
\r
415 * in the list of tasks waiting to be deleted. If so the task is cleaned up
\r
416 * and its TCB deleted.
\r
418 static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
\r
421 * The currently executing task is entering the Blocked state. Add the task to
\r
422 * either the current or the overflow delayed task list.
\r
424 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION;
\r
427 * Allocates memory from the heap for a TCB and associated stack. Checks the
\r
428 * allocation was successful.
\r
430 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;
\r
433 * Called from vTaskList. vListTasks details all the tasks currently under
\r
434 * control of the scheduler. The tasks may be in one of a number of lists.
\r
435 * prvListTaskWithinSingleList accepts a list and details the tasks from
\r
436 * within just that list.
\r
438 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
\r
439 * NORMAL APPLICATION CODE.
\r
441 #if ( configUSE_TRACE_FACILITY == 1 )
\r
443 static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus ) PRIVILEGED_FUNCTION;
\r
448 * When a task is created, the stack of the task is filled with a known value.
\r
449 * This function determines the 'high water mark' of the task stack by
\r
450 * determining how much of the stack remains at the original preset value.
\r
452 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
454 static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;
\r
459 * Return the amount of time, in ticks, that will pass before the kernel will
\r
460 * next move a task from the Blocked state to the Running state.
\r
462 * This conditional compilation should use inequality to 0, not equality to 1.
\r
463 * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user
\r
464 * defined low power mode implementations require configUSE_TICKLESS_IDLE to be
\r
465 * set to a value other than 1.
\r
467 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
469 static portTickType prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION;
\r
475 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
477 signed portBASE_TYPE xReturn;
\r
480 configASSERT( pxTaskCode );
\r
481 configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );
\r
483 /* Allocate the memory required by the TCB and stack for the new task,
\r
484 checking that the allocation was successful. */
\r
485 pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
\r
487 if( pxNewTCB != NULL )
\r
489 portSTACK_TYPE *pxTopOfStack;
\r
491 #if( portUSING_MPU_WRAPPERS == 1 )
\r
492 /* Should the task be created in privileged mode? */
\r
493 portBASE_TYPE xRunPrivileged;
\r
494 if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
\r
496 xRunPrivileged = pdTRUE;
\r
500 xRunPrivileged = pdFALSE;
\r
502 uxPriority &= ~portPRIVILEGE_BIT;
\r
503 #endif /* portUSING_MPU_WRAPPERS == 1 */
\r
505 /* Calculate the top of stack address. This depends on whether the
\r
506 stack grows from high memory to low (as per the 80x86) or visa versa.
\r
507 portSTACK_GROWTH is used to make the result positive or negative as
\r
508 required by the port. */
\r
509 #if( portSTACK_GROWTH < 0 )
\r
511 pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );
\r
512 pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK ) );
\r
514 /* Check the alignment of the calculated top of stack is correct. */
\r
515 configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
\r
517 #else /* portSTACK_GROWTH */
\r
519 pxTopOfStack = pxNewTCB->pxStack;
\r
521 /* Check the alignment of the stack buffer is correct. */
\r
522 configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
\r
524 /* If we want to use stack checking on architectures that use
\r
525 a positive stack growth direction then we also need to store the
\r
526 other extreme of the stack space. */
\r
527 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
\r
529 #endif /* portSTACK_GROWTH */
\r
531 /* Setup the newly allocated TCB with the initial state of the task. */
\r
532 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
\r
534 /* Initialize the TCB stack to look as if the task was already running,
\r
535 but had been interrupted by the scheduler. The return address is set
\r
536 to the start of the task function. Once the stack has been initialised
\r
537 the top of stack variable is updated. */
\r
538 #if( portUSING_MPU_WRAPPERS == 1 )
\r
540 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
\r
542 #else /* portUSING_MPU_WRAPPERS */
\r
544 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
\r
546 #endif /* portUSING_MPU_WRAPPERS */
\r
548 if( ( void * ) pxCreatedTask != NULL )
\r
550 /* Pass the TCB out - in an anonymous way. The calling function/
\r
551 task can use this as a handle to delete the task later if
\r
553 *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
\r
556 /* Ensure interrupts don't access the task lists while they are being
\r
558 taskENTER_CRITICAL();
\r
560 uxCurrentNumberOfTasks++;
\r
561 if( pxCurrentTCB == NULL )
\r
563 /* There are no other tasks, or all the other tasks are in
\r
564 the suspended state - make this the current task. */
\r
565 pxCurrentTCB = pxNewTCB;
\r
567 if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
\r
569 /* This is the first task to be created so do the preliminary
\r
570 initialisation required. We will not recover if this call
\r
571 fails, but we will report the failure. */
\r
572 prvInitialiseTaskLists();
\r
577 /* If the scheduler is not already running, make this task the
\r
578 current task if it is the highest priority task to be created
\r
580 if( xSchedulerRunning == pdFALSE )
\r
582 if( pxCurrentTCB->uxPriority <= uxPriority )
\r
584 pxCurrentTCB = pxNewTCB;
\r
589 /* Remember the top priority to make context switching faster. Use
\r
590 the priority in pxNewTCB as this has been capped to a valid value. */
\r
591 if( pxNewTCB->uxPriority > uxTopUsedPriority )
\r
593 uxTopUsedPriority = pxNewTCB->uxPriority;
\r
598 #if ( configUSE_TRACE_FACILITY == 1 )
\r
600 /* Add a counter into the TCB for tracing only. */
\r
601 pxNewTCB->uxTCBNumber = uxTaskNumber;
\r
603 #endif /* configUSE_TRACE_FACILITY */
\r
604 traceTASK_CREATE( pxNewTCB );
\r
606 prvAddTaskToReadyList( pxNewTCB );
\r
609 portSETUP_TCB( pxNewTCB );
\r
611 taskEXIT_CRITICAL();
\r
615 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
\r
616 traceTASK_CREATE_FAILED();
\r
619 if( xReturn == pdPASS )
\r
621 if( xSchedulerRunning != pdFALSE )
\r
623 /* If the created task is of a higher priority than the current task
\r
624 then it should run now. */
\r
625 if( pxCurrentTCB->uxPriority < uxPriority )
\r
627 portYIELD_WITHIN_API();
\r
634 /*-----------------------------------------------------------*/
\r
636 #if ( INCLUDE_vTaskDelete == 1 )
\r
638 void vTaskDelete( xTaskHandle xTaskToDelete )
\r
642 taskENTER_CRITICAL();
\r
644 /* Ensure a yield is performed if the current task is being
\r
646 if( xTaskToDelete == pxCurrentTCB )
\r
648 xTaskToDelete = NULL;
\r
651 /* If null is passed in here then we are deleting ourselves. */
\r
652 pxTCB = prvGetTCBFromHandle( xTaskToDelete );
\r
654 /* Remove task from the ready list and place in the termination list.
\r
655 This will stop the task from be scheduled. The idle task will check
\r
656 the termination list and free up any memory allocated by the
\r
657 scheduler for the TCB and stack. */
\r
658 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
\r
660 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
663 /* Is the task waiting on an event also? */
\r
664 if( pxTCB->xEventListItem.pvContainer != NULL )
\r
666 uxListRemove( &( pxTCB->xEventListItem ) );
\r
669 vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
\r
671 /* Increment the ucTasksDeleted variable so the idle task knows
\r
672 there is a task that has been deleted and that it should therefore
\r
673 check the xTasksWaitingTermination list. */
\r
676 /* Increment the uxTaskNumberVariable also so kernel aware debuggers
\r
677 can detect that the task lists need re-generating. */
\r
680 traceTASK_DELETE( pxTCB );
\r
682 taskEXIT_CRITICAL();
\r
684 /* Force a reschedule if we have just deleted the current task. */
\r
685 if( xSchedulerRunning != pdFALSE )
\r
687 if( ( void * ) xTaskToDelete == NULL )
\r
689 portYIELD_WITHIN_API();
\r
694 #endif /* INCLUDE_vTaskDelete */
\r
695 /*-----------------------------------------------------------*/
\r
697 #if ( INCLUDE_vTaskDelayUntil == 1 )
\r
699 void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
\r
701 portTickType xTimeToWake;
\r
702 portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
\r
704 configASSERT( pxPreviousWakeTime );
\r
705 configASSERT( ( xTimeIncrement > 0U ) );
\r
709 /* Generate the tick time at which the task wants to wake. */
\r
710 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
\r
712 if( xTickCount < *pxPreviousWakeTime )
\r
714 /* The tick count has overflowed since this function was
\r
715 lasted called. In this case the only time we should ever
\r
716 actually delay is if the wake time has also overflowed,
\r
717 and the wake time is greater than the tick time. When this
\r
718 is the case it is as if neither time had overflowed. */
\r
719 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
\r
721 xShouldDelay = pdTRUE;
\r
726 /* The tick time has not overflowed. In this case we will
\r
727 delay if either the wake time has overflowed, and/or the
\r
728 tick time is less than the wake time. */
\r
729 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
\r
731 xShouldDelay = pdTRUE;
\r
735 /* Update the wake time ready for the next call. */
\r
736 *pxPreviousWakeTime = xTimeToWake;
\r
738 if( xShouldDelay != pdFALSE )
\r
740 traceTASK_DELAY_UNTIL();
\r
742 /* We must remove ourselves from the ready list before adding
\r
743 ourselves to the blocked list as the same list item is used for
\r
745 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )
\r
747 /* The current task must be in a ready list, so there is
\r
748 no need to check, and the port reset macro can be called
\r
750 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
753 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
756 xAlreadyYielded = xTaskResumeAll();
\r
758 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
759 have put ourselves to sleep. */
\r
760 if( xAlreadyYielded == pdFALSE )
\r
762 portYIELD_WITHIN_API();
\r
766 #endif /* INCLUDE_vTaskDelayUntil */
\r
767 /*-----------------------------------------------------------*/
\r
769 #if ( INCLUDE_vTaskDelay == 1 )
\r
771 void vTaskDelay( portTickType xTicksToDelay )
\r
773 portTickType xTimeToWake;
\r
774 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
776 /* A delay time of zero just forces a reschedule. */
\r
777 if( xTicksToDelay > ( portTickType ) 0U )
\r
783 /* A task that is removed from the event list while the
\r
784 scheduler is suspended will not get placed in the ready
\r
785 list or removed from the blocked list until the scheduler
\r
788 This task cannot be in an event list as it is the currently
\r
791 /* Calculate the time to wake - this may overflow but this is
\r
793 xTimeToWake = xTickCount + xTicksToDelay;
\r
795 /* We must remove ourselves from the ready list before adding
\r
796 ourselves to the blocked list as the same list item is used for
\r
798 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )
\r
800 /* The current task must be in a ready list, so there is
\r
801 no need to check, and the port reset macro can be called
\r
803 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
805 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
807 xAlreadyYielded = xTaskResumeAll();
\r
810 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
811 have put ourselves to sleep. */
\r
812 if( xAlreadyYielded == pdFALSE )
\r
814 portYIELD_WITHIN_API();
\r
818 #endif /* INCLUDE_vTaskDelay */
\r
819 /*-----------------------------------------------------------*/
\r
821 #if ( INCLUDE_eTaskGetState == 1 )
\r
823 eTaskState eTaskGetState( xTaskHandle xTask )
\r
825 eTaskState eReturn;
\r
826 xList *pxStateList;
\r
829 pxTCB = ( tskTCB * ) xTask;
\r
831 if( pxTCB == pxCurrentTCB )
\r
833 /* The task calling this function is querying its own state. */
\r
834 eReturn = eRunning;
\r
838 taskENTER_CRITICAL();
\r
840 pxStateList = ( xList * ) listLIST_ITEM_CONTAINER( &( pxTCB->xGenericListItem ) );
\r
842 taskEXIT_CRITICAL();
\r
844 if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) )
\r
846 /* The task being queried is referenced from one of the Blocked
\r
848 eReturn = eBlocked;
\r
851 #if ( INCLUDE_vTaskSuspend == 1 )
\r
852 else if( pxStateList == &xSuspendedTaskList )
\r
854 /* The task being queried is referenced from the suspended
\r
856 eReturn = eSuspended;
\r
860 #if ( INCLUDE_vTaskDelete == 1 )
\r
861 else if( pxStateList == &xTasksWaitingTermination )
\r
863 /* The task being queried is referenced from the deleted
\r
865 eReturn = eDeleted;
\r
871 /* If the task is not in any other state, it must be in the
\r
872 Ready (including pending ready) state. */
\r
880 #endif /* INCLUDE_eTaskGetState */
\r
881 /*-----------------------------------------------------------*/
\r
883 #if ( INCLUDE_uxTaskPriorityGet == 1 )
\r
885 unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle xTask )
\r
888 unsigned portBASE_TYPE uxReturn;
\r
890 taskENTER_CRITICAL();
\r
892 /* If null is passed in here then we are changing the
\r
893 priority of the calling function. */
\r
894 pxTCB = prvGetTCBFromHandle( xTask );
\r
895 uxReturn = pxTCB->uxPriority;
\r
897 taskEXIT_CRITICAL();
\r
902 #endif /* INCLUDE_uxTaskPriorityGet */
\r
903 /*-----------------------------------------------------------*/
\r
905 #if ( INCLUDE_vTaskPrioritySet == 1 )
\r
907 void vTaskPrioritySet( xTaskHandle xTask, unsigned portBASE_TYPE uxNewPriority )
\r
910 unsigned portBASE_TYPE uxCurrentPriority, uxPriorityUsedOnEntry;
\r
911 portBASE_TYPE xYieldRequired = pdFALSE;
\r
913 configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
\r
915 /* Ensure the new priority is valid. */
\r
916 if( uxNewPriority >= configMAX_PRIORITIES )
\r
918 uxNewPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
\r
921 taskENTER_CRITICAL();
\r
923 if( xTask == ( xTaskHandle ) pxCurrentTCB )
\r
928 /* If null is passed in here then we are changing the
\r
929 priority of the calling function. */
\r
930 pxTCB = prvGetTCBFromHandle( xTask );
\r
932 traceTASK_PRIORITY_SET( pxTCB, uxNewPriority );
\r
934 #if ( configUSE_MUTEXES == 1 )
\r
936 uxCurrentPriority = pxTCB->uxBasePriority;
\r
940 uxCurrentPriority = pxTCB->uxPriority;
\r
944 if( uxCurrentPriority != uxNewPriority )
\r
946 /* The priority change may have readied a task of higher
\r
947 priority than the calling task. */
\r
948 if( uxNewPriority > uxCurrentPriority )
\r
950 if( xTask != NULL )
\r
952 /* The priority of another task is being raised. If we
\r
953 were raising the priority of the currently running task
\r
954 there would be no need to switch as it must have already
\r
955 been the highest priority task. */
\r
956 xYieldRequired = pdTRUE;
\r
959 else if( xTask == NULL )
\r
961 /* Setting our own priority down means there may now be another
\r
962 task of higher priority that is ready to execute. */
\r
963 xYieldRequired = pdTRUE;
\r
966 /* Remember the ready list the task might be referenced from
\r
967 before its uxPriority member is changed so the
\r
968 taskRESET_READY_PRIORITY() macro can function correctly. */
\r
969 uxPriorityUsedOnEntry = pxTCB->uxPriority;
\r
971 #if ( configUSE_MUTEXES == 1 )
\r
973 /* Only change the priority being used if the task is not
\r
974 currently using an inherited priority. */
\r
975 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
\r
977 pxTCB->uxPriority = uxNewPriority;
\r
980 /* The base priority gets set whatever. */
\r
981 pxTCB->uxBasePriority = uxNewPriority;
\r
985 pxTCB->uxPriority = uxNewPriority;
\r
989 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
\r
991 /* If the task is in the blocked or suspended list we need do
\r
992 nothing more than change it's priority variable. However, if
\r
993 the task is in a ready list it needs to be removed and placed
\r
994 in the queue appropriate to its new priority. */
\r
995 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
\r
997 /* The task is currently in its ready list - remove before adding
\r
998 it to it's new ready list. As we are in a critical section we
\r
999 can do this even if the scheduler is suspended. */
\r
1000 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
\r
1002 taskRESET_READY_PRIORITY( uxPriorityUsedOnEntry );
\r
1004 prvAddTaskToReadyList( pxTCB );
\r
1007 if( xYieldRequired == pdTRUE )
\r
1009 portYIELD_WITHIN_API();
\r
1012 /* Remove compiler warning about unused variables when the port
\r
1013 optimised task selection is not being used. */
\r
1014 ( void ) uxPriorityUsedOnEntry;
\r
1017 taskEXIT_CRITICAL();
\r
1020 #endif /* INCLUDE_vTaskPrioritySet */
\r
1021 /*-----------------------------------------------------------*/
\r
1023 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1025 void vTaskSuspend( xTaskHandle xTaskToSuspend )
\r
1029 taskENTER_CRITICAL();
\r
1031 /* Ensure a yield is performed if the current task is being
\r
1033 if( xTaskToSuspend == ( xTaskHandle ) pxCurrentTCB )
\r
1035 xTaskToSuspend = NULL;
\r
1038 /* If null is passed in here then we are suspending ourselves. */
\r
1039 pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
\r
1041 traceTASK_SUSPEND( pxTCB );
\r
1043 /* Remove task from the ready/delayed list and place in the suspended list. */
\r
1044 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
\r
1046 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
1049 /* Is the task waiting on an event also? */
\r
1050 if( pxTCB->xEventListItem.pvContainer != NULL )
\r
1052 uxListRemove( &( pxTCB->xEventListItem ) );
\r
1055 vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
\r
1057 taskEXIT_CRITICAL();
\r
1059 if( ( void * ) xTaskToSuspend == NULL )
\r
1061 if( xSchedulerRunning != pdFALSE )
\r
1063 /* We have just suspended the current task. */
\r
1064 portYIELD_WITHIN_API();
\r
1068 /* The scheduler is not running, but the task that was pointed
\r
1069 to by pxCurrentTCB has just been suspended and pxCurrentTCB
\r
1070 must be adjusted to point to a different task. */
\r
1071 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
\r
1073 /* No other tasks are ready, so set pxCurrentTCB back to
\r
1074 NULL so when the next task is created pxCurrentTCB will
\r
1075 be set to point to it no matter what its relative priority
\r
1077 pxCurrentTCB = NULL;
\r
1081 vTaskSwitchContext();
\r
1087 #endif /* INCLUDE_vTaskSuspend */
\r
1088 /*-----------------------------------------------------------*/
\r
1090 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1092 signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
\r
1094 portBASE_TYPE xReturn = pdFALSE;
\r
1095 const tskTCB * const pxTCB = ( tskTCB * ) xTask;
\r
1097 /* It does not make sense to check if the calling task is suspended. */
\r
1098 configASSERT( xTask );
\r
1100 /* Is the task we are attempting to resume actually in the
\r
1101 suspended list? */
\r
1102 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
\r
1104 /* Has the task already been resumed from within an ISR? */
\r
1105 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
\r
1107 /* Is it in the suspended list because it is in the
\r
1108 Suspended state? It is possible to be in the suspended
\r
1109 list because it is blocked on a task with no timeout
\r
1111 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
\r
1121 #endif /* INCLUDE_vTaskSuspend */
\r
1122 /*-----------------------------------------------------------*/
\r
1124 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1126 void vTaskResume( xTaskHandle xTaskToResume )
\r
1130 /* It does not make sense to resume the calling task. */
\r
1131 configASSERT( xTaskToResume );
\r
1133 /* Remove the task from whichever list it is currently in, and place
\r
1134 it in the ready list. */
\r
1135 pxTCB = ( tskTCB * ) xTaskToResume;
\r
1137 /* The parameter cannot be NULL as it is impossible to resume the
\r
1138 currently executing task. */
\r
1139 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
\r
1141 taskENTER_CRITICAL();
\r
1143 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
1145 traceTASK_RESUME( pxTCB );
\r
1147 /* As we are in a critical section we can access the ready
\r
1148 lists even if the scheduler is suspended. */
\r
1149 uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1150 prvAddTaskToReadyList( pxTCB );
\r
1152 /* We may have just resumed a higher priority task. */
\r
1153 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1155 /* This yield may not cause the task just resumed to run, but
\r
1156 will leave the lists in the correct state for the next yield. */
\r
1157 portYIELD_WITHIN_API();
\r
1161 taskEXIT_CRITICAL();
\r
1165 #endif /* INCLUDE_vTaskSuspend */
\r
1167 /*-----------------------------------------------------------*/
\r
1169 #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
\r
1171 portBASE_TYPE xTaskResumeFromISR( xTaskHandle xTaskToResume )
\r
1173 portBASE_TYPE xYieldRequired = pdFALSE;
\r
1175 unsigned portBASE_TYPE uxSavedInterruptStatus;
\r
1177 configASSERT( xTaskToResume );
\r
1179 pxTCB = ( tskTCB * ) xTaskToResume;
\r
1181 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
\r
1183 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
1185 traceTASK_RESUME_FROM_ISR( pxTCB );
\r
1187 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1189 xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
\r
1190 uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1191 prvAddTaskToReadyList( pxTCB );
\r
1195 /* We cannot access the delayed or ready lists, so will hold this
\r
1196 task pending until the scheduler is resumed, at which point a
\r
1197 yield will be performed if necessary. */
\r
1198 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
\r
1202 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
\r
1204 return xYieldRequired;
\r
1207 #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */
\r
1208 /*-----------------------------------------------------------*/
\r
1210 void vTaskStartScheduler( void )
\r
1212 portBASE_TYPE xReturn;
\r
1214 /* Add the idle task at the lowest priority. */
\r
1215 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
\r
1217 /* Create the idle task, storing its handle in xIdleTaskHandle so it can
\r
1218 be returned by the xTaskGetIdleTaskHandle() function. */
\r
1219 xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle );
\r
1223 /* Create the idle task without storing its handle. */
\r
1224 xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL );
\r
1226 #endif /* INCLUDE_xTaskGetIdleTaskHandle */
\r
1228 #if ( configUSE_TIMERS == 1 )
\r
1230 if( xReturn == pdPASS )
\r
1232 xReturn = xTimerCreateTimerTask();
\r
1235 #endif /* configUSE_TIMERS */
\r
1237 if( xReturn == pdPASS )
\r
1239 /* Interrupts are turned off here, to ensure a tick does not occur
\r
1240 before or during the call to xPortStartScheduler(). The stacks of
\r
1241 the created tasks contain a status word with interrupts switched on
\r
1242 so interrupts will automatically get re-enabled when the first task
\r
1245 STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
\r
1246 DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
\r
1247 portDISABLE_INTERRUPTS();
\r
1249 xSchedulerRunning = pdTRUE;
\r
1250 xTickCount = ( portTickType ) 0U;
\r
1252 /* If configGENERATE_RUN_TIME_STATS is defined then the following
\r
1253 macro must be defined to configure the timer/counter used to generate
\r
1254 the run time counter time base. */
\r
1255 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
\r
1257 /* Setting up the timer tick is hardware specific and thus in the
\r
1258 portable interface. */
\r
1259 if( xPortStartScheduler() != pdFALSE )
\r
1261 /* Should not reach here as if the scheduler is running the
\r
1262 function will not return. */
\r
1266 /* Should only reach here if a task calls xTaskEndScheduler(). */
\r
1271 /* This line will only be reached if the kernel could not be started,
\r
1272 because there was not enough FreeRTOS heap to create the idle task
\r
1273 or the timer task. */
\r
1274 configASSERT( xReturn );
\r
1277 /*-----------------------------------------------------------*/
\r
1279 void vTaskEndScheduler( void )
\r
1281 /* Stop the scheduler interrupts and call the portable scheduler end
\r
1282 routine so the original ISRs can be restored if necessary. The port
\r
1283 layer must ensure interrupts enable bit is left in the correct state. */
\r
1284 portDISABLE_INTERRUPTS();
\r
1285 xSchedulerRunning = pdFALSE;
\r
1286 vPortEndScheduler();
\r
1288 /*----------------------------------------------------------*/
\r
1290 void vTaskSuspendAll( void )
\r
1292 /* A critical section is not required as the variable is of type
\r
1294 ++uxSchedulerSuspended;
\r
1296 /*----------------------------------------------------------*/
\r
1298 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
1300 static portTickType prvGetExpectedIdleTime( void )
\r
1302 portTickType xReturn;
\r
1304 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )
\r
1308 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )
\r
1310 /* There are other idle priority tasks in the ready state. If
\r
1311 time slicing is used then the very next tick interrupt must be
\r
1317 xReturn = xNextTaskUnblockTime - xTickCount;
\r
1323 #endif /* configUSE_TICKLESS_IDLE */
\r
1324 /*----------------------------------------------------------*/
\r
1326 signed portBASE_TYPE xTaskResumeAll( void )
\r
1328 register tskTCB *pxTCB;
\r
1329 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
1330 portBASE_TYPE xYieldRequired = pdFALSE;
\r
1332 /* If uxSchedulerSuspended is zero then this function does not match a
\r
1333 previous call to vTaskSuspendAll(). */
\r
1334 configASSERT( uxSchedulerSuspended );
\r
1336 /* It is possible that an ISR caused a task to be removed from an event
\r
1337 list while the scheduler was suspended. If this was the case then the
\r
1338 removed task will have been added to the xPendingReadyList. Once the
\r
1339 scheduler has been resumed it is safe to move all the pending ready
\r
1340 tasks from this list into their appropriate ready list. */
\r
1341 taskENTER_CRITICAL();
\r
1343 --uxSchedulerSuspended;
\r
1345 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1347 if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0U )
\r
1349 /* Move any readied tasks from the pending list into the
\r
1350 appropriate ready list. */
\r
1351 while( listLIST_IS_EMPTY( ( xList * ) &xPendingReadyList ) == pdFALSE )
\r
1353 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) );
\r
1354 uxListRemove( &( pxTCB->xEventListItem ) );
\r
1355 uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1356 prvAddTaskToReadyList( pxTCB );
\r
1358 /* If we have moved a task that has a priority higher than
\r
1359 the current task then we should yield. */
\r
1360 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1362 xYieldRequired = pdTRUE;
\r
1366 /* If any ticks occurred while the scheduler was suspended then
\r
1367 they should be processed now. This ensures the tick count does not
\r
1368 slip, and that any delayed tasks are resumed at the correct time. */
\r
1369 if( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U )
\r
1371 while( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U )
\r
1373 if( xTaskIncrementTick() != pdFALSE )
\r
1375 xYieldRequired = pdTRUE;
\r
1381 if( ( xYieldRequired == pdTRUE ) || ( xYieldPending == pdTRUE ) )
\r
1383 xAlreadyYielded = pdTRUE;
\r
1384 xYieldPending = pdFALSE;
\r
1385 portYIELD_WITHIN_API();
\r
1390 taskEXIT_CRITICAL();
\r
1392 return xAlreadyYielded;
\r
1394 /*-----------------------------------------------------------*/
\r
1396 portTickType xTaskGetTickCount( void )
\r
1398 portTickType xTicks;
\r
1400 /* Critical section required if running on a 16 bit processor. */
\r
1401 taskENTER_CRITICAL();
\r
1403 xTicks = xTickCount;
\r
1405 taskEXIT_CRITICAL();
\r
1409 /*-----------------------------------------------------------*/
\r
1411 portTickType xTaskGetTickCountFromISR( void )
\r
1413 portTickType xReturn;
\r
1414 unsigned portBASE_TYPE uxSavedInterruptStatus;
\r
1416 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
\r
1417 xReturn = xTickCount;
\r
1418 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
\r
1422 /*-----------------------------------------------------------*/
\r
1424 unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
\r
1426 /* A critical section is not required because the variables are of type
\r
1428 return uxCurrentNumberOfTasks;
\r
1430 /*-----------------------------------------------------------*/
\r
1432 #if ( INCLUDE_pcTaskGetTaskName == 1 )
\r
1434 signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery )
\r
1438 /* If null is passed in here then the name of the calling task is being queried. */
\r
1439 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
\r
1440 configASSERT( pxTCB );
\r
1441 return &( pxTCB->pcTaskName[ 0 ] );
\r
1444 #endif /* INCLUDE_pcTaskGetTaskName */
\r
1445 /*-----------------------------------------------------------*/
\r
1447 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1449 void vTaskList( signed char *pcWriteBuffer )
\r
1451 unsigned portBASE_TYPE uxQueue;
\r
1453 /* This is a VERY costly function that should be used for debug only.
\r
1454 It leaves interrupts disabled for a LONG time. */
\r
1456 vTaskSuspendAll();
\r
1458 /* Run through all the lists that could potentially contain a TCB and
\r
1459 report the task name, state and stack high water mark. */
\r
1461 *pcWriteBuffer = ( signed char ) 0x00;
\r
1462 strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
\r
1464 uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;
\r
1470 if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )
\r
1472 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
\r
1474 }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
\r
1476 if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )
\r
1478 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
\r
1481 if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )
\r
1483 prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
\r
1486 #if( INCLUDE_vTaskDelete == 1 )
\r
1488 if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )
\r
1490 prvListTaskWithinSingleList( pcWriteBuffer, &xTasksWaitingTermination, tskDELETED_CHAR );
\r
1495 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1497 if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
\r
1499 prvListTaskWithinSingleList( pcWriteBuffer, &xSuspendedTaskList, tskSUSPENDED_CHAR );
\r
1507 #endif /* configUSE_TRACE_FACILITY */
\r
1508 /*----------------------------------------------------------*/
\r
1510 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1512 void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
\r
1514 unsigned portBASE_TYPE uxQueue;
\r
1515 unsigned long ulTotalRunTimeDiv100;
\r
1517 /* This is a VERY costly function that should be used for debug only.
\r
1518 It leaves interrupts disabled for a LONG time. */
\r
1520 vTaskSuspendAll();
\r
1522 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
\r
1523 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
\r
1525 ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
\r
1528 /* Divide ulTotalRunTime by 100 to make the percentage caluclations
\r
1529 simpler in the prvGenerateRunTimeStatsForTasksInList() function. */
\r
1530 ulTotalRunTimeDiv100 = ulTotalRunTime / 100UL;
\r
1532 /* Run through all the lists that could potentially contain a TCB,
\r
1533 generating a table of run timer percentages in the provided
\r
1536 *pcWriteBuffer = ( signed char ) 0x00;
\r
1537 strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
\r
1539 uxQueue = uxTopUsedPriority + ( unsigned portBASE_TYPE ) 1U;
\r
1545 if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) == pdFALSE )
\r
1547 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTimeDiv100 );
\r
1549 }while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
\r
1551 if( listLIST_IS_EMPTY( pxDelayedTaskList ) == pdFALSE )
\r
1553 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTimeDiv100 );
\r
1556 if( listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) == pdFALSE )
\r
1558 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTimeDiv100 );
\r
1561 #if ( INCLUDE_vTaskDelete == 1 )
\r
1563 if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE )
\r
1565 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, &xTasksWaitingTermination, ulTotalRunTimeDiv100 );
\r
1570 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1572 if( listLIST_IS_EMPTY( &xSuspendedTaskList ) == pdFALSE )
\r
1574 prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, &xSuspendedTaskList, ulTotalRunTimeDiv100 );
\r
1582 #endif /* configGENERATE_RUN_TIME_STATS */
\r
1583 /*----------------------------------------------------------*/
\r
1585 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
\r
1587 xTaskHandle xTaskGetIdleTaskHandle( void )
\r
1589 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been
\r
1590 started, then xIdleTaskHandle will be NULL. */
\r
1591 configASSERT( ( xIdleTaskHandle != NULL ) );
\r
1592 return xIdleTaskHandle;
\r
1595 #endif /* INCLUDE_xTaskGetIdleTaskHandle */
\r
1596 /*----------------------------------------------------------*/
\r
1598 /* This conditional compilation should use inequality to 0, not equality to 1.
\r
1599 This is to ensure vTaskStepTick() is available when user defined low power mode
\r
1600 implementations require configUSE_TICKLESS_IDLE to be set to a value other than
\r
1602 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
1604 void vTaskStepTick( portTickType xTicksToJump )
\r
1606 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );
\r
1607 xTickCount += xTicksToJump;
\r
1610 #endif /* configUSE_TICKLESS_IDLE */
\r
1611 /*----------------------------------------------------------*/
\r
1613 portBASE_TYPE xTaskIncrementTick( void )
\r
1616 portTickType xItemValue;
\r
1617 portBASE_TYPE xSwitchRequired = pdFALSE;
\r
1619 /* Called by the portable layer each time a tick interrupt occurs.
\r
1620 Increments the tick then checks to see if the new tick value will cause any
\r
1621 tasks to be unblocked. */
\r
1622 traceTASK_INCREMENT_TICK( xTickCount );
\r
1623 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1625 /* Increment the RTOS tick, switching the delayed and overflowed
\r
1626 delayed lists if it wraps to 0. */
\r
1628 if( xTickCount == ( portTickType ) 0U )
\r
1630 taskSWITCH_DELAYED_LISTS();
\r
1633 /* See if this tick has made a timeout expire. Tasks are stored in the
\r
1634 queue in the order of their wake time - meaning once one tasks has been
\r
1635 found whose block time has not expired there is no need not look any
\r
1636 further down the list. */
\r
1637 if( xTickCount >= xNextTaskUnblockTime )
\r
1641 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
\r
1643 /* The delayed list is empty. Set xNextTaskUnblockTime to
\r
1644 the maximum possible value so it is extremely unlikely that
\r
1645 the if( xTickCount >= xNextTaskUnblockTime ) test will pass
\r
1646 next time through. */
\r
1647 xNextTaskUnblockTime = portMAX_DELAY;
\r
1652 /* The delayed list is not empty, get the value of the item
\r
1653 at the head of the delayed list. This is the time at which
\r
1654 the task at the head of the delayed list must be removed
\r
1655 from the Blocked state. */
\r
1656 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
\r
1657 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );
\r
1659 if( xTickCount < xItemValue )
\r
1661 /* It is not time to unblock this item yet, but the item
\r
1662 value is the time at which the task at the head of the
\r
1663 blocked list must be removed from the Blocked state -
\r
1664 so record the item value in xNextTaskUnblockTime. */
\r
1665 xNextTaskUnblockTime = xItemValue;
\r
1669 /* It is time to remove the item from the Blocked state. */
\r
1670 uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1672 /* Is the task waiting on an event also? If so remove it
\r
1673 from the event list. */
\r
1674 if( pxTCB->xEventListItem.pvContainer != NULL )
\r
1676 uxListRemove( &( pxTCB->xEventListItem ) );
\r
1679 /* Place the unblocked task into the appropriate ready
\r
1681 prvAddTaskToReadyList( pxTCB );
\r
1683 /* A task being unblocked cannot cause an immediate context
\r
1684 switch if preemption is turned off. */
\r
1685 #if ( configUSE_PREEMPTION == 1 )
\r
1687 /* Preemption is on, but a context switch should only
\r
1688 be performed if the unblocked task has a priority that
\r
1689 is equal to or higher than the currently executing
\r
1691 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1693 xSwitchRequired = pdTRUE;
\r
1696 #endif /* configUSE_PREEMPTION */
\r
1701 /* Tasks of equal priority to the currently running task will share
\r
1702 processing time (time slice) if preemption is on, and the application
\r
1703 writer has not explicitly turned time slicing off. */
\r
1704 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
\r
1706 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > 1 )
\r
1708 xSwitchRequired = pdTRUE;
\r
1711 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
\r
1717 /* The tick hook gets called at regular intervals, even if the
\r
1718 scheduler is locked. */
\r
1719 #if ( configUSE_TICK_HOOK == 1 )
\r
1721 vApplicationTickHook();
\r
1726 #if ( configUSE_TICK_HOOK == 1 )
\r
1728 /* Guard against the tick hook being called when the missed tick
\r
1729 count is being unwound (when the scheduler is being unlocked). */
\r
1730 if( uxPendedTicks == ( unsigned portBASE_TYPE ) 0U )
\r
1732 vApplicationTickHook();
\r
1735 #endif /* configUSE_TICK_HOOK */
\r
1737 return xSwitchRequired;
\r
1739 /*-----------------------------------------------------------*/
\r
1741 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1743 void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction )
\r
1747 /* If xTask is NULL then we are setting our own task hook. */
\r
1748 if( xTask == NULL )
\r
1750 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1754 xTCB = ( tskTCB * ) xTask;
\r
1757 /* Save the hook function in the TCB. A critical section is required as
\r
1758 the value can be accessed from an interrupt. */
\r
1759 taskENTER_CRITICAL();
\r
1760 xTCB->pxTaskTag = pxHookFunction;
\r
1761 taskEXIT_CRITICAL();
\r
1764 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
1765 /*-----------------------------------------------------------*/
\r
1767 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1769 pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
\r
1772 pdTASK_HOOK_CODE xReturn;
\r
1774 /* If xTask is NULL then we are setting our own task hook. */
\r
1775 if( xTask == NULL )
\r
1777 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1781 xTCB = ( tskTCB * ) xTask;
\r
1784 /* Save the hook function in the TCB. A critical section is required as
\r
1785 the value can be accessed from an interrupt. */
\r
1786 taskENTER_CRITICAL();
\r
1787 xReturn = xTCB->pxTaskTag;
\r
1788 taskEXIT_CRITICAL();
\r
1793 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
1794 /*-----------------------------------------------------------*/
\r
1796 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1798 portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
\r
1801 portBASE_TYPE xReturn;
\r
1803 /* If xTask is NULL then we are calling our own task hook. */
\r
1804 if( xTask == NULL )
\r
1806 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1810 xTCB = ( tskTCB * ) xTask;
\r
1813 if( xTCB->pxTaskTag != NULL )
\r
1815 xReturn = xTCB->pxTaskTag( pvParameter );
\r
1825 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
1826 /*-----------------------------------------------------------*/
\r
1828 void vTaskSwitchContext( void )
\r
1830 if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
\r
1832 /* The scheduler is currently suspended - do not allow a context
\r
1834 xYieldPending = pdTRUE;
\r
1838 traceTASK_SWITCHED_OUT();
\r
1840 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1842 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
\r
1843 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
\r
1845 ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
\r
1848 /* Add the amount of time the task has been running to the
\r
1849 accumulated time so far. The time the task started running was
\r
1850 stored in ulTaskSwitchedInTime. Note that there is no overflow
\r
1851 protection here so count values are only valid until the timer
\r
1852 overflows. The guard against negative values is to protect
\r
1853 against suspect run time stat counter implementations - which
\r
1854 are provided by the application, not the kernel. */
\r
1855 if( ulTotalRunTime > ulTaskSwitchedInTime )
\r
1857 pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
\r
1859 ulTaskSwitchedInTime = ulTotalRunTime;
\r
1861 #endif /* configGENERATE_RUN_TIME_STATS */
\r
1863 taskFIRST_CHECK_FOR_STACK_OVERFLOW();
\r
1864 taskSECOND_CHECK_FOR_STACK_OVERFLOW();
\r
1866 taskSELECT_HIGHEST_PRIORITY_TASK();
\r
1868 traceTASK_SWITCHED_IN();
\r
1870 #if ( configUSE_NEWLIB_REENTRANT == 1 )
\r
1872 /* Switch Newlib's _impure_ptr variable to point to the _reent
\r
1873 structure specific to this task. */
\r
1874 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
\r
1876 #endif /* configUSE_NEWLIB_REENTRANT */
\r
1879 /*-----------------------------------------------------------*/
\r
1881 void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
\r
1883 portTickType xTimeToWake;
\r
1885 configASSERT( pxEventList );
\r
1887 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1888 SCHEDULER SUSPENDED. */
\r
1890 /* Place the event list item of the TCB in the appropriate event list.
\r
1891 This is placed in the list in priority order so the highest priority task
\r
1892 is the first to be woken by the event. */
\r
1893 vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
\r
1895 /* We must remove ourselves from the ready list before adding ourselves
\r
1896 to the blocked list as the same list item is used for both lists. We have
\r
1897 exclusive access to the ready lists as the scheduler is locked. */
\r
1898 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )
\r
1900 /* The current task must be in a ready list, so there is no need to
\r
1901 check, and the port reset macro can be called directly. */
\r
1902 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
1905 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1907 if( xTicksToWait == portMAX_DELAY )
\r
1909 /* Add ourselves to the suspended task list instead of a delayed task
\r
1910 list to ensure we are not woken by a timing event. We will block
\r
1912 vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
1916 /* Calculate the time at which the task should be woken if the event does
\r
1917 not occur. This may overflow but this doesn't matter. */
\r
1918 xTimeToWake = xTickCount + xTicksToWait;
\r
1919 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
1922 #else /* INCLUDE_vTaskSuspend */
\r
1924 /* Calculate the time at which the task should be woken if the event does
\r
1925 not occur. This may overflow but this doesn't matter. */
\r
1926 xTimeToWake = xTickCount + xTicksToWait;
\r
1927 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
1929 #endif /* INCLUDE_vTaskSuspend */
\r
1931 /*-----------------------------------------------------------*/
\r
1933 #if configUSE_TIMERS == 1
\r
1935 void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait )
\r
1937 portTickType xTimeToWake;
\r
1939 configASSERT( pxEventList );
\r
1941 /* This function should not be called by application code hence the
\r
1942 'Restricted' in its name. It is not part of the public API. It is
\r
1943 designed for use by kernel code, and has special calling requirements -
\r
1944 it should be called from a critical section. */
\r
1947 /* Place the event list item of the TCB in the appropriate event list.
\r
1948 In this case it is assume that this is the only task that is going to
\r
1949 be waiting on this event list, so the faster vListInsertEnd() function
\r
1950 can be used in place of vListInsert. */
\r
1951 vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
\r
1953 /* We must remove this task from the ready list before adding it to the
\r
1954 blocked list as the same list item is used for both lists. This
\r
1955 function is called form a critical section. */
\r
1956 if( uxListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ) == 0 )
\r
1958 /* The current task must be in a ready list, so there is no need to
\r
1959 check, and the port reset macro can be called directly. */
\r
1960 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
1963 /* Calculate the time at which the task should be woken if the event does
\r
1964 not occur. This may overflow but this doesn't matter. */
\r
1965 xTimeToWake = xTickCount + xTicksToWait;
\r
1967 traceTASK_DELAY_UNTIL();
\r
1968 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
1971 #endif /* configUSE_TIMERS */
\r
1972 /*-----------------------------------------------------------*/
\r
1974 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
\r
1976 tskTCB *pxUnblockedTCB;
\r
1977 portBASE_TYPE xReturn;
\r
1979 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1980 SCHEDULER SUSPENDED. It can also be called from within an ISR. */
\r
1982 /* The event list is sorted in priority order, so we can remove the
\r
1983 first in the list, remove the TCB from the delayed list, and add
\r
1984 it to the ready list.
\r
1986 If an event is for a queue that is locked then this function will never
\r
1987 get called - the lock count on the queue will get modified instead. This
\r
1988 means we can always expect exclusive access to the event list here.
\r
1990 This function assumes that a check has already been made to ensure that
\r
1991 pxEventList is not empty. */
\r
1992 pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
\r
1993 configASSERT( pxUnblockedTCB );
\r
1994 uxListRemove( &( pxUnblockedTCB->xEventListItem ) );
\r
1996 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1998 uxListRemove( &( pxUnblockedTCB->xGenericListItem ) );
\r
1999 prvAddTaskToReadyList( pxUnblockedTCB );
\r
2003 /* We cannot access the delayed or ready lists, so will hold this
\r
2004 task pending until the scheduler is resumed. */
\r
2005 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
\r
2008 if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
2010 /* Return true if the task removed from the event list has
\r
2011 a higher priority than the calling task. This allows
\r
2012 the calling task to know if it should force a context
\r
2018 xReturn = pdFALSE;
\r
2023 /*-----------------------------------------------------------*/
\r
2025 void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
\r
2027 configASSERT( pxTimeOut );
\r
2028 pxTimeOut->xOverflowCount = xNumOfOverflows;
\r
2029 pxTimeOut->xTimeOnEntering = xTickCount;
\r
2031 /*-----------------------------------------------------------*/
\r
2033 portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
\r
2035 portBASE_TYPE xReturn;
\r
2037 configASSERT( pxTimeOut );
\r
2038 configASSERT( pxTicksToWait );
\r
2040 taskENTER_CRITICAL();
\r
2042 #if ( INCLUDE_vTaskSuspend == 1 )
\r
2043 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
\r
2044 the maximum block time then the task should block indefinitely, and
\r
2045 therefore never time out. */
\r
2046 if( *pxTicksToWait == portMAX_DELAY )
\r
2048 xReturn = pdFALSE;
\r
2050 else /* We are not blocking indefinitely, perform the checks below. */
\r
2053 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )
\r
2055 /* The tick count is greater than the time at which vTaskSetTimeout()
\r
2056 was called, but has also overflowed since vTaskSetTimeOut() was called.
\r
2057 It must have wrapped all the way around and gone past us again. This
\r
2058 passed since vTaskSetTimeout() was called. */
\r
2061 else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )
\r
2063 /* Not a genuine timeout. Adjust parameters for time remaining. */
\r
2064 *pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );
\r
2065 vTaskSetTimeOutState( pxTimeOut );
\r
2066 xReturn = pdFALSE;
\r
2073 taskEXIT_CRITICAL();
\r
2077 /*-----------------------------------------------------------*/
\r
2079 void vTaskMissedYield( void )
\r
2081 xYieldPending = pdTRUE;
\r
2083 /*-----------------------------------------------------------*/
\r
2085 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2087 unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask )
\r
2089 unsigned portBASE_TYPE uxReturn;
\r
2092 if( xTask != NULL )
\r
2094 pxTCB = ( tskTCB * ) xTask;
\r
2095 uxReturn = pxTCB->uxTaskNumber;
\r
2105 #endif /* configUSE_TRACE_FACILITY */
\r
2106 /*-----------------------------------------------------------*/
\r
2108 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2110 void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle )
\r
2114 if( xTask != NULL )
\r
2116 pxTCB = ( tskTCB * ) xTask;
\r
2117 pxTCB->uxTaskNumber = uxHandle;
\r
2121 #endif /* configUSE_TRACE_FACILITY */
\r
2124 * -----------------------------------------------------------
\r
2126 * ----------------------------------------------------------
\r
2128 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
\r
2129 * language extensions. The equivalent prototype for this function is:
\r
2131 * void prvIdleTask( void *pvParameters );
\r
2134 static portTASK_FUNCTION( prvIdleTask, pvParameters )
\r
2136 /* Stop warnings. */
\r
2137 ( void ) pvParameters;
\r
2141 /* See if any tasks have been deleted. */
\r
2142 prvCheckTasksWaitingTermination();
\r
2144 #if ( configUSE_PREEMPTION == 0 )
\r
2146 /* If we are not using preemption we keep forcing a task switch to
\r
2147 see if any other task has become available. If we are using
\r
2148 preemption we don't need to do this as any task becoming available
\r
2149 will automatically get the processor anyway. */
\r
2152 #endif /* configUSE_PREEMPTION */
\r
2154 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
\r
2156 /* When using preemption tasks of equal priority will be
\r
2157 timesliced. If a task that is sharing the idle priority is ready
\r
2158 to run then the idle task should yield before the end of the
\r
2161 A critical region is not required here as we are just reading from
\r
2162 the list, and an occasional incorrect value will not matter. If
\r
2163 the ready list at the idle priority contains more than one task
\r
2164 then a task other than the idle task is ready to execute. */
\r
2165 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
\r
2170 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
\r
2172 #if ( configUSE_IDLE_HOOK == 1 )
\r
2174 extern void vApplicationIdleHook( void );
\r
2176 /* Call the user defined function from within the idle task. This
\r
2177 allows the application designer to add background functionality
\r
2178 without the overhead of a separate task.
\r
2179 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
\r
2180 CALL A FUNCTION THAT MIGHT BLOCK. */
\r
2181 vApplicationIdleHook();
\r
2183 #endif /* configUSE_IDLE_HOOK */
\r
2185 /* This conditional compilation should use inequality to 0, not equality
\r
2186 to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
\r
2187 user defined low power mode implementations require
\r
2188 configUSE_TICKLESS_IDLE to be set to a value other than 1. */
\r
2189 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
2191 portTickType xExpectedIdleTime;
\r
2193 /* It is not desirable to suspend then resume the scheduler on
\r
2194 each iteration of the idle task. Therefore, a preliminary
\r
2195 test of the expected idle time is performed without the
\r
2196 scheduler suspended. The result here is not necessarily
\r
2198 xExpectedIdleTime = prvGetExpectedIdleTime();
\r
2200 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
\r
2202 vTaskSuspendAll();
\r
2204 /* Now the scheduler is suspended, the expected idle
\r
2205 time can be sampled again, and this time its value can
\r
2207 configASSERT( xNextTaskUnblockTime >= xTickCount );
\r
2208 xExpectedIdleTime = prvGetExpectedIdleTime();
\r
2210 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
\r
2212 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
\r
2218 #endif /* configUSE_TICKLESS_IDLE */
\r
2220 } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
\r
2221 /*-----------------------------------------------------------*/
\r
2223 #if configUSE_TICKLESS_IDLE != 0
\r
2225 eSleepModeStatus eTaskConfirmSleepModeStatus( void )
\r
2227 eSleepModeStatus eReturn = eStandardSleep;
\r
2229 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )
\r
2231 /* A task was made ready while the scheduler was suspended. */
\r
2232 eReturn = eAbortSleep;
\r
2234 else if( xYieldPending != pdFALSE )
\r
2236 /* A yield was pended while the scheduler was suspended. */
\r
2237 eReturn = eAbortSleep;
\r
2241 #if configUSE_TIMERS == 0
\r
2243 /* The idle task exists in addition to the application tasks. */
\r
2244 const unsigned portBASE_TYPE uxNonApplicationTasks = 1;
\r
2246 /* If timers are not being used and all the tasks are in the
\r
2247 suspended list (which might mean they have an infinite block
\r
2248 time rather than actually being suspended) then it is safe to
\r
2249 turn all clocks off and just wait for external interrupts. */
\r
2250 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
\r
2252 eReturn = eNoTasksWaitingTimeout;
\r
2255 #endif /* configUSE_TIMERS */
\r
2260 #endif /* configUSE_TICKLESS_IDLE */
\r
2261 /*-----------------------------------------------------------*/
\r
2263 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
\r
2267 /* Store the task name in the TCB. */
\r
2268 for( x = 0; x < configMAX_TASK_NAME_LEN; x++ )
\r
2270 pxTCB->pcTaskName[ x ] = pcName[ x ];
\r
2272 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
\r
2273 configMAX_TASK_NAME_LEN characters just in case the memory after the
\r
2274 string is not accessible (extremely unlikely). */
\r
2275 if( pcName[ x ] == 0x00 )
\r
2281 /* Ensure the name string is terminated in the case that the string length
\r
2282 was greater or equal to configMAX_TASK_NAME_LEN. */
\r
2283 pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = ( signed char ) '\0';
\r
2285 /* This is used as an array index so must ensure it's not too large. First
\r
2286 remove the privilege bit if one is present. */
\r
2287 if( uxPriority >= configMAX_PRIORITIES )
\r
2289 uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
\r
2292 pxTCB->uxPriority = uxPriority;
\r
2293 #if ( configUSE_MUTEXES == 1 )
\r
2295 pxTCB->uxBasePriority = uxPriority;
\r
2297 #endif /* configUSE_MUTEXES */
\r
2299 vListInitialiseItem( &( pxTCB->xGenericListItem ) );
\r
2300 vListInitialiseItem( &( pxTCB->xEventListItem ) );
\r
2302 /* Set the pxTCB as a link back from the xListItem. This is so we can get
\r
2303 back to the containing TCB from a generic item in a list. */
\r
2304 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
\r
2306 /* Event lists are always in priority order. */
\r
2307 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
\r
2308 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
\r
2310 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2312 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0U;
\r
2314 #endif /* portCRITICAL_NESTING_IN_TCB */
\r
2316 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
2318 pxTCB->pxTaskTag = NULL;
\r
2320 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
2322 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
2324 pxTCB->ulRunTimeCounter = 0UL;
\r
2326 #endif /* configGENERATE_RUN_TIME_STATS */
\r
2328 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
2330 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
\r
2332 #else /* portUSING_MPU_WRAPPERS */
\r
2334 ( void ) xRegions;
\r
2335 ( void ) usStackDepth;
\r
2337 #endif /* portUSING_MPU_WRAPPERS */
\r
2339 #if ( configUSE_NEWLIB_REENTRANT == 1 )
\r
2341 /* Initialise this task's Newlib reent structure. */
\r
2342 _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) );
\r
2344 #endif /* configUSE_NEWLIB_REENTRANT */
\r
2346 /*-----------------------------------------------------------*/
\r
2348 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
2350 void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
\r
2354 if( xTaskToModify == pxCurrentTCB )
\r
2356 xTaskToModify = NULL;
\r
2359 /* If null is passed in here then we are deleting ourselves. */
\r
2360 pxTCB = prvGetTCBFromHandle( xTaskToModify );
\r
2362 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
\r
2365 #endif /* portUSING_MPU_WRAPPERS */
\r
2366 /*-----------------------------------------------------------*/
\r
2368 static void prvInitialiseTaskLists( void )
\r
2370 unsigned portBASE_TYPE uxPriority;
\r
2372 for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < configMAX_PRIORITIES; uxPriority++ )
\r
2374 vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
\r
2377 vListInitialise( ( xList * ) &xDelayedTaskList1 );
\r
2378 vListInitialise( ( xList * ) &xDelayedTaskList2 );
\r
2379 vListInitialise( ( xList * ) &xPendingReadyList );
\r
2381 #if ( INCLUDE_vTaskDelete == 1 )
\r
2383 vListInitialise( ( xList * ) &xTasksWaitingTermination );
\r
2385 #endif /* INCLUDE_vTaskDelete */
\r
2387 #if ( INCLUDE_vTaskSuspend == 1 )
\r
2389 vListInitialise( ( xList * ) &xSuspendedTaskList );
\r
2391 #endif /* INCLUDE_vTaskSuspend */
\r
2393 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
\r
2395 pxDelayedTaskList = &xDelayedTaskList1;
\r
2396 pxOverflowDelayedTaskList = &xDelayedTaskList2;
\r
2398 /*-----------------------------------------------------------*/
\r
2400 static void prvCheckTasksWaitingTermination( void )
\r
2402 #if ( INCLUDE_vTaskDelete == 1 )
\r
2404 portBASE_TYPE xListIsEmpty;
\r
2406 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
\r
2407 too often in the idle task. */
\r
2408 while( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0U )
\r
2410 vTaskSuspendAll();
\r
2411 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
\r
2414 if( xListIsEmpty == pdFALSE )
\r
2418 taskENTER_CRITICAL();
\r
2420 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
\r
2421 uxListRemove( &( pxTCB->xGenericListItem ) );
\r
2422 --uxCurrentNumberOfTasks;
\r
2425 taskEXIT_CRITICAL();
\r
2427 prvDeleteTCB( pxTCB );
\r
2431 #endif /* vTaskDelete */
\r
2433 /*-----------------------------------------------------------*/
\r
2435 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake )
\r
2437 /* The list item will be inserted in wake time order. */
\r
2438 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
2440 if( xTimeToWake < xTickCount )
\r
2442 /* Wake time has overflowed. Place this item in the overflow list. */
\r
2443 vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
2447 /* The wake time has not overflowed, so we can use the current block list. */
\r
2448 vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
\r
2450 /* If the task entering the blocked state was placed at the head of the
\r
2451 list of blocked tasks then xNextTaskUnblockTime needs to be updated
\r
2453 if( xTimeToWake < xNextTaskUnblockTime )
\r
2455 xNextTaskUnblockTime = xTimeToWake;
\r
2459 /*-----------------------------------------------------------*/
\r
2461 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
\r
2465 /* Allocate space for the TCB. Where the memory comes from depends on
\r
2466 the implementation of the port malloc function. */
\r
2467 pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
\r
2469 if( pxNewTCB != NULL )
\r
2471 /* Allocate space for the stack used by the task being created.
\r
2472 The base of the stack memory stored in the TCB so the task can
\r
2473 be deleted later if required. */
\r
2474 pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );
\r
2476 if( pxNewTCB->pxStack == NULL )
\r
2478 /* Could not allocate the stack. Delete the allocated TCB. */
\r
2479 vPortFree( pxNewTCB );
\r
2484 /* Just to help debugging. */
\r
2485 memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( portSTACK_TYPE ) );
\r
2491 /*-----------------------------------------------------------*/
\r
2493 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2495 static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus )
\r
2497 volatile tskTCB *pxNextTCB, *pxFirstTCB;
\r
2498 unsigned short usStackRemaining;
\r
2499 PRIVILEGED_DATA static char pcStatusString[ configMAX_TASK_NAME_LEN + 30 ];
\r
2501 /* Write the details of all the TCB's in pxList into the buffer. */
\r
2502 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
\r
2505 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
\r
2506 #if ( portSTACK_GROWTH > 0 )
\r
2508 usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );
\r
2512 usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );
\r
2516 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
2517 strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString );
\r
2519 } while( pxNextTCB != pxFirstTCB );
\r
2522 #endif /* configUSE_TRACE_FACILITY */
\r
2523 /*-----------------------------------------------------------*/
\r
2525 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
2527 static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTimeDiv100 )
\r
2529 volatile tskTCB *pxNextTCB, *pxFirstTCB;
\r
2530 unsigned long ulStatsAsPercentage;
\r
2531 size_t xExistingStringLength;
\r
2533 /* Write the run time stats of all the TCB's in pxList into the buffer. */
\r
2534 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
\r
2537 /* Get next TCB from the list. */
\r
2538 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
\r
2540 /* Divide by zero check. */
\r
2541 if( ulTotalRunTimeDiv100 > 0UL )
\r
2543 xExistingStringLength = strlen( ( char * ) pcWriteBuffer );
\r
2545 /* Has the task run at all? */
\r
2546 if( pxNextTCB->ulRunTimeCounter == 0UL )
\r
2548 /* The task has used no CPU time at all. */
\r
2549 sprintf( ( char * ) &( pcWriteBuffer[ xExistingStringLength ] ), ( char * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
\r
2553 /* What percentage of the total run time has the task used?
\r
2554 This will always be rounded down to the nearest integer.
\r
2555 ulTotalRunTimeDiv100 has already been divided by 100. */
\r
2556 ulStatsAsPercentage = pxNextTCB->ulRunTimeCounter / ulTotalRunTimeDiv100;
\r
2558 if( ulStatsAsPercentage > 0UL )
\r
2560 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
\r
2562 sprintf( ( char * ) &( pcWriteBuffer[ xExistingStringLength ] ), ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter, ulStatsAsPercentage );
\r
2566 /* sizeof( int ) == sizeof( long ) so a smaller
\r
2567 printf() library can be used. */
\r
2568 sprintf( ( char * ) &( pcWriteBuffer[ xExistingStringLength ] ), ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
\r
2574 /* If the percentage is zero here then the task has
\r
2575 consumed less than 1% of the total run time. */
\r
2576 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
\r
2578 sprintf( ( char * ) &( pcWriteBuffer[ xExistingStringLength ] ), ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter );
\r
2582 /* sizeof( int ) == sizeof( long ) so a smaller
\r
2583 printf() library can be used. */
\r
2584 sprintf( ( char * ) &( pcWriteBuffer[ xExistingStringLength ] ), ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
\r
2591 } while( pxNextTCB != pxFirstTCB );
\r
2594 #endif /* configGENERATE_RUN_TIME_STATS */
\r
2595 /*-----------------------------------------------------------*/
\r
2597 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
2599 static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte )
\r
2601 register unsigned short usCount = 0U;
\r
2603 while( *pucStackByte == tskSTACK_FILL_BYTE )
\r
2605 pucStackByte -= portSTACK_GROWTH;
\r
2609 usCount /= sizeof( portSTACK_TYPE );
\r
2614 #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */
\r
2615 /*-----------------------------------------------------------*/
\r
2617 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
\r
2619 unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
\r
2622 unsigned char *pcEndOfStack;
\r
2623 unsigned portBASE_TYPE uxReturn;
\r
2625 pxTCB = prvGetTCBFromHandle( xTask );
\r
2627 #if portSTACK_GROWTH < 0
\r
2629 pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;
\r
2633 pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;
\r
2637 uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );
\r
2642 #endif /* INCLUDE_uxTaskGetStackHighWaterMark */
\r
2643 /*-----------------------------------------------------------*/
\r
2645 #if ( INCLUDE_vTaskDelete == 1 )
\r
2647 static void prvDeleteTCB( tskTCB *pxTCB )
\r
2649 /* This call is required specifically for the TriCore port. It must be
\r
2650 above the vPortFree() calls. The call is also used by ports/demos that
\r
2651 want to allocate and clean RAM statically. */
\r
2652 portCLEAN_UP_TCB( pxTCB );
\r
2654 /* Free up the memory allocated by the scheduler for the task. It is up to
\r
2655 the task to free any memory allocated at the application level. */
\r
2656 vPortFreeAligned( pxTCB->pxStack );
\r
2657 vPortFree( pxTCB );
\r
2660 #endif /* INCLUDE_vTaskDelete */
\r
2661 /*-----------------------------------------------------------*/
\r
2663 #if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
\r
2665 xTaskHandle xTaskGetCurrentTaskHandle( void )
\r
2667 xTaskHandle xReturn;
\r
2669 /* A critical section is not required as this is not called from
\r
2670 an interrupt and the current TCB will always be the same for any
\r
2671 individual execution thread. */
\r
2672 xReturn = pxCurrentTCB;
\r
2677 #endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
\r
2678 /*-----------------------------------------------------------*/
\r
2680 #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
\r
2682 portBASE_TYPE xTaskGetSchedulerState( void )
\r
2684 portBASE_TYPE xReturn;
\r
2686 if( xSchedulerRunning == pdFALSE )
\r
2688 xReturn = taskSCHEDULER_NOT_STARTED;
\r
2692 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
2694 xReturn = taskSCHEDULER_RUNNING;
\r
2698 xReturn = taskSCHEDULER_SUSPENDED;
\r
2705 #endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */
\r
2706 /*-----------------------------------------------------------*/
\r
2708 #if ( configUSE_MUTEXES == 1 )
\r
2710 void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
\r
2712 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2714 /* If the mutex was given back by an interrupt while the queue was
\r
2715 locked then the mutex holder might now be NULL. */
\r
2716 if( pxMutexHolder != NULL )
\r
2718 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
\r
2720 /* Adjust the mutex holder state to account for its new priority. */
\r
2721 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
\r
2723 /* If the task being modified is in the ready state it will need to
\r
2724 be moved into a new list. */
\r
2725 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE )
\r
2727 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
\r
2729 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
2732 /* Inherit the priority before being moved into the new list. */
\r
2733 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2734 prvAddTaskToReadyList( pxTCB );
\r
2738 /* Just inherit the priority. */
\r
2739 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2742 traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );
\r
2747 #endif /* configUSE_MUTEXES */
\r
2748 /*-----------------------------------------------------------*/
\r
2750 #if ( configUSE_MUTEXES == 1 )
\r
2752 void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
\r
2754 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2756 if( pxMutexHolder != NULL )
\r
2758 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
\r
2760 /* We must be the running task to be able to give the mutex back.
\r
2761 Remove ourselves from the ready list we currently appear in. */
\r
2762 if( uxListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) ) == 0 )
\r
2764 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
2767 /* Disinherit the priority before adding the task into the new
\r
2769 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
\r
2770 pxTCB->uxPriority = pxTCB->uxBasePriority;
\r
2771 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
\r
2772 prvAddTaskToReadyList( pxTCB );
\r
2777 #endif /* configUSE_MUTEXES */
\r
2778 /*-----------------------------------------------------------*/
\r
2780 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2782 void vTaskEnterCritical( void )
\r
2784 portDISABLE_INTERRUPTS();
\r
2786 if( xSchedulerRunning != pdFALSE )
\r
2788 ( pxCurrentTCB->uxCriticalNesting )++;
\r
2792 #endif /* portCRITICAL_NESTING_IN_TCB */
\r
2793 /*-----------------------------------------------------------*/
\r
2795 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2797 void vTaskExitCritical( void )
\r
2799 if( xSchedulerRunning != pdFALSE )
\r
2801 if( pxCurrentTCB->uxCriticalNesting > 0U )
\r
2803 ( pxCurrentTCB->uxCriticalNesting )--;
\r
2805 if( pxCurrentTCB->uxCriticalNesting == 0U )
\r
2807 portENABLE_INTERRUPTS();
\r
2813 #endif /* portCRITICAL_NESTING_IN_TCB */
\r
2814 /*-----------------------------------------------------------*/
\r