2 FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS provides completely free yet professionally developed, *
\r
10 * robust, strictly quality controlled, supported, and cross *
\r
11 * platform software that has become a de facto standard. *
\r
13 * Help yourself get started quickly and support the FreeRTOS *
\r
14 * project by purchasing a FreeRTOS tutorial book, reference *
\r
15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
19 ***************************************************************************
\r
21 This file is part of the FreeRTOS distribution.
\r
23 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
24 the terms of the GNU General Public License (version 2) as published by the
\r
25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
27 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
28 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
29 >>! the source code for proprietary components outside of the FreeRTOS
\r
32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
35 link: http://www.freertos.org/a00114.html
\r
39 ***************************************************************************
\r
41 * Having a problem? Start by reading the FAQ "My application does *
\r
42 * not run, what could be wrong?" *
\r
44 * http://www.FreeRTOS.org/FAQHelp.html *
\r
46 ***************************************************************************
\r
48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
49 license and Real Time Engineers Ltd. contact details.
\r
51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
57 licenses offer ticketed support, indemnification and middleware.
\r
59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
60 engineered and independently SIL3 certified version for use in safety and
\r
61 mission critical applications that require provable dependability.
\r
66 /* Standard includes. */
\r
70 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
\r
71 all the API functions to use the MPU wrappers. That should only be done when
\r
72 task.h is included from an application file. */
\r
73 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
\r
75 /* FreeRTOS includes. */
\r
76 #include "FreeRTOS.h"
\r
79 #include "StackMacros.h"
\r
81 /* Lint e961 and e750 are suppressed as a MISRA exception justified because the
\r
82 MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
\r
83 header files above, but not in this file, in order to generate the correct
\r
84 privileged Vs unprivileged linkage and placement. */
\r
85 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
\r
87 #if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 )
\r
88 /* At the bottom of this file are two optional functions that can be used
\r
89 to generate human readable text from the raw data generated by the
\r
90 uxTaskGetSystemState() function. Note the formatting functions are provided
\r
91 for convenience only, and are NOT considered part of the kernel. */
\r
93 #endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
\r
95 /* Sanity check the configuration. */
\r
96 #if configUSE_TICKLESS_IDLE != 0
\r
97 #if INCLUDE_vTaskSuspend != 1
\r
98 #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0
\r
99 #endif /* INCLUDE_vTaskSuspend */
\r
100 #endif /* configUSE_TICKLESS_IDLE */
\r
103 * Defines the size, in words, of the stack allocated to the idle task.
\r
105 #define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
\r
107 #if( configUSE_PREEMPTION == 0 )
\r
108 /* If the cooperative scheduler is being used then a yield should not be
\r
109 performed just because a higher priority task has been woken. */
\r
110 #define taskYIELD_IF_USING_PREEMPTION()
\r
112 #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
\r
116 * Task control block. A task control block (TCB) is allocated for each task,
\r
117 * and stores task state information, including a pointer to the task's context
\r
118 * (the task's run time environment, including register values)
\r
120 typedef struct tskTaskControlBlock
\r
122 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
124 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
125 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
128 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
129 xListItem xEventListItem; /*< Used to reference a task from an event list. */
\r
130 unsigned portBASE_TYPE uxPriority; /*< The priority of the task. 0 is the lowest priority. */
\r
131 portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
\r
132 signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
\r
134 #if ( portSTACK_GROWTH > 0 )
\r
135 portSTACK_TYPE *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */
\r
138 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
139 unsigned portBASE_TYPE uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
\r
142 #if ( configUSE_TRACE_FACILITY == 1 )
\r
143 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
144 unsigned portBASE_TYPE uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
\r
147 #if ( configUSE_MUTEXES == 1 )
\r
148 unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
\r
151 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
152 pdTASK_HOOK_CODE pxTaskTag;
\r
155 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
156 unsigned long ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
\r
159 #if ( configUSE_NEWLIB_REENTRANT == 1 )
\r
160 /* Allocate a Newlib reent structure that is specific to this task.
\r
161 Note Newlib support has been included by popular demand, but is not
\r
162 used by the FreeRTOS maintainers themselves. FreeRTOS is not
\r
163 responsible for resulting newlib operation. User must be familiar with
\r
164 newlib and must provide system-wide implementations of the necessary
\r
165 stubs. Be warned that (at the time of writing) the current newlib design
\r
166 implements a system-wide malloc() that must be provided with locks. */
\r
167 struct _reent xNewLib_reent;
\r
174 * Some kernel aware debuggers require the data the debugger needs access to to
\r
175 * be global, rather than file scope.
\r
177 #ifdef portREMOVE_STATIC_QUALIFIER
\r
181 /*lint -e956 A manual analysis and inspection has been used to determine which
\r
182 static variables must be declared volatile. */
\r
184 PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
\r
186 /* Lists for ready and blocked tasks. --------------------*/
\r
187 PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
\r
188 PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */
\r
189 PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
\r
190 PRIVILEGED_DATA static xList * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */
\r
191 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
192 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
194 #if ( INCLUDE_vTaskDelete == 1 )
\r
196 PRIVILEGED_DATA static xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
\r
197 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0U;
\r
201 #if ( INCLUDE_vTaskSuspend == 1 )
\r
203 PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
\r
207 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
\r
209 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
213 /* Other file private variables. --------------------------------*/
\r
214 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0U;
\r
215 PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0U;
\r
216 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
\r
217 PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
\r
218 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
\r
219 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxPendedTicks = ( unsigned portBASE_TYPE ) 0U;
\r
220 PRIVILEGED_DATA static volatile portBASE_TYPE xYieldPending = pdFALSE;
\r
221 PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
\r
222 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0U;
\r
223 PRIVILEGED_DATA static volatile portTickType xNextTaskUnblockTime = portMAX_DELAY;
\r
225 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
227 PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
\r
228 PRIVILEGED_DATA static unsigned long ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */
\r
234 /* Debugging and trace facilities private variables and macros. ------------*/
\r
237 * The value used to fill the stack of a task when the task is created. This
\r
238 * is used purely for checking the high water mark for tasks.
\r
240 #define tskSTACK_FILL_BYTE ( 0xa5U )
\r
243 * Macros used by vListTask to indicate which state a task is in.
\r
245 #define tskBLOCKED_CHAR ( ( signed char ) 'B' )
\r
246 #define tskREADY_CHAR ( ( signed char ) 'R' )
\r
247 #define tskDELETED_CHAR ( ( signed char ) 'D' )
\r
248 #define tskSUSPENDED_CHAR ( ( signed char ) 'S' )
\r
250 /*-----------------------------------------------------------*/
\r
252 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
\r
254 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
\r
255 performed in a generic way that is not optimised to any particular
\r
256 microcontroller architecture. */
\r
258 /* uxTopReadyPriority holds the priority of the highest priority ready
\r
260 #define taskRECORD_READY_PRIORITY( uxPriority ) \
\r
262 if( ( uxPriority ) > uxTopReadyPriority ) \
\r
264 uxTopReadyPriority = ( uxPriority ); \
\r
266 } /* taskRECORD_READY_PRIORITY */
\r
268 /*-----------------------------------------------------------*/
\r
270 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
\r
272 /* Find the highest priority queue that contains ready tasks. */ \
\r
273 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) \
\r
275 configASSERT( uxTopReadyPriority ); \
\r
276 --uxTopReadyPriority; \
\r
279 /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
\r
280 the same priority get an equal share of the processor time. */ \
\r
281 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \
\r
282 } /* taskSELECT_HIGHEST_PRIORITY_TASK */
\r
284 /*-----------------------------------------------------------*/
\r
286 /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as
\r
287 they are only required when a port optimised method of task selection is
\r
289 #define taskRESET_READY_PRIORITY( uxPriority )
\r
290 #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
\r
292 #else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
\r
294 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is
\r
295 performed in a way that is tailored to the particular microcontroller
\r
296 architecture being used. */
\r
298 /* A port optimised version is provided. Call the port defined macros. */
\r
299 #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
\r
301 /*-----------------------------------------------------------*/
\r
303 #define taskSELECT_HIGHEST_PRIORITY_TASK() \
\r
305 unsigned portBASE_TYPE uxTopPriority; \
\r
307 /* Find the highest priority queue that contains ready tasks. */ \
\r
308 portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
\r
309 configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
\r
310 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
\r
311 } /* taskSELECT_HIGHEST_PRIORITY_TASK() */
\r
313 /*-----------------------------------------------------------*/
\r
315 /* A port optimised version is provided, call it only if the TCB being reset
\r
316 is being referenced from a ready list. If it is referenced from a delayed
\r
317 or suspended list then it won't be in a ready list. */
\r
318 #define taskRESET_READY_PRIORITY( uxPriority ) \
\r
320 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == 0 ) \
\r
322 portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \
\r
326 #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
\r
328 /*-----------------------------------------------------------*/
\r
330 /* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
\r
331 count overflows. */
\r
332 #define taskSWITCH_DELAYED_LISTS() \
\r
336 /* The delayed tasks list should be empty when the lists are switched. */ \
\r
337 configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \
\r
339 pxTemp = pxDelayedTaskList; \
\r
340 pxDelayedTaskList = pxOverflowDelayedTaskList; \
\r
341 pxOverflowDelayedTaskList = pxTemp; \
\r
342 xNumOfOverflows++; \
\r
344 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \
\r
346 /* The new current delayed list is empty. Set \
\r
347 xNextTaskUnblockTime to the maximum possible value so it is \
\r
348 extremely unlikely that the \
\r
349 if( xTickCount >= xNextTaskUnblockTime ) test will pass until \
\r
350 there is an item in the delayed list. */ \
\r
351 xNextTaskUnblockTime = portMAX_DELAY; \
\r
355 /* The new current delayed list is not empty, get the value of \
\r
356 the item at the head of the delayed list. This is the time at \
\r
357 which the task at the head of the delayed list should be removed \
\r
358 from the Blocked state. */ \
\r
359 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \
\r
360 xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \
\r
364 /*-----------------------------------------------------------*/
\r
367 * Place the task represented by pxTCB into the appropriate ready list for
\r
368 * the task. It is inserted at the end of the list.
\r
370 #define prvAddTaskToReadyList( pxTCB ) \
\r
371 traceMOVED_TASK_TO_READY_STATE( pxTCB ) \
\r
372 taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
\r
373 vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
\r
374 /*-----------------------------------------------------------*/
\r
377 * Several functions take an xTaskHandle parameter that can optionally be NULL,
\r
378 * where NULL is used to indicate that the handle of the currently executing
\r
379 * task should be used in place of the parameter. This macro simply checks to
\r
380 * see if the parameter is NULL and returns a pointer to the appropriate TCB.
\r
382 #define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) )
\r
384 /* Callback function prototypes. --------------------------*/
\r
385 extern void vApplicationStackOverflowHook( xTaskHandle xTask, signed char *pcTaskName );
\r
386 extern void vApplicationTickHook( void );
\r
388 /* File private functions. --------------------------------*/
\r
391 * Utility to ready a TCB for a given task. Mainly just copies the parameters
\r
392 * into the TCB structure.
\r
394 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;
\r
397 * Utility to ready all the lists used by the scheduler. This is called
\r
398 * automatically upon the creation of the first task.
\r
400 static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
\r
403 * The idle task, which as all tasks is implemented as a never ending loop.
\r
404 * The idle task is automatically created and added to the ready lists upon
\r
405 * creation of the first user task.
\r
407 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
\r
408 * language extensions. The equivalent prototype for this function is:
\r
410 * void prvIdleTask( void *pvParameters );
\r
413 static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
\r
416 * Utility to free all memory allocated by the scheduler to hold a TCB,
\r
417 * including the stack pointed to by the TCB.
\r
419 * This does not free memory allocated by the task itself (i.e. memory
\r
420 * allocated by calls to pvPortMalloc from within the tasks application code).
\r
422 #if ( INCLUDE_vTaskDelete == 1 )
\r
424 static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;
\r
429 * Used only by the idle task. This checks to see if anything has been placed
\r
430 * in the list of tasks waiting to be deleted. If so the task is cleaned up
\r
431 * and its TCB deleted.
\r
433 static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
\r
436 * The currently executing task is entering the Blocked state. Add the task to
\r
437 * either the current or the overflow delayed task list.
\r
439 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION;
\r
442 * Allocates memory from the heap for a TCB and associated stack. Checks the
\r
443 * allocation was successful.
\r
445 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;
\r
448 * Fills an xTaskStatusType structure with information on each task that is
\r
449 * referenced from the pxList list (which may be a ready list, a delayed list,
\r
450 * a suspended list, etc.).
\r
452 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
\r
453 * NORMAL APPLICATION CODE.
\r
455 #if ( configUSE_TRACE_FACILITY == 1 )
\r
457 static unsigned portBASE_TYPE prvListTaskWithinSingleList( xTaskStatusType *pxTaskStatusArray, xList *pxList, eTaskState eState ) PRIVILEGED_FUNCTION;
\r
462 * When a task is created, the stack of the task is filled with a known value.
\r
463 * This function determines the 'high water mark' of the task stack by
\r
464 * determining how much of the stack remains at the original preset value.
\r
466 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
468 static unsigned short prvTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;
\r
473 * Return the amount of time, in ticks, that will pass before the kernel will
\r
474 * next move a task from the Blocked state to the Running state.
\r
476 * This conditional compilation should use inequality to 0, not equality to 1.
\r
477 * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user
\r
478 * defined low power mode implementations require configUSE_TICKLESS_IDLE to be
\r
479 * set to a value other than 1.
\r
481 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
483 static portTickType prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION;
\r
487 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
489 signed portBASE_TYPE xReturn;
\r
492 configASSERT( pxTaskCode );
\r
493 configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );
\r
495 /* Allocate the memory required by the TCB and stack for the new task,
\r
496 checking that the allocation was successful. */
\r
497 pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
\r
499 if( pxNewTCB != NULL )
\r
501 portSTACK_TYPE *pxTopOfStack;
\r
503 #if( portUSING_MPU_WRAPPERS == 1 )
\r
504 /* Should the task be created in privileged mode? */
\r
505 portBASE_TYPE xRunPrivileged;
\r
506 if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
\r
508 xRunPrivileged = pdTRUE;
\r
512 xRunPrivileged = pdFALSE;
\r
514 uxPriority &= ~portPRIVILEGE_BIT;
\r
515 #endif /* portUSING_MPU_WRAPPERS == 1 */
\r
517 /* Calculate the top of stack address. This depends on whether the
\r
518 stack grows from high memory to low (as per the 80x86) or visa versa.
\r
519 portSTACK_GROWTH is used to make the result positive or negative as
\r
520 required by the port. */
\r
521 #if( portSTACK_GROWTH < 0 )
\r
523 pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );
\r
524 pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */
\r
526 /* Check the alignment of the calculated top of stack is correct. */
\r
527 configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
\r
529 #else /* portSTACK_GROWTH */
\r
531 pxTopOfStack = pxNewTCB->pxStack;
\r
533 /* Check the alignment of the stack buffer is correct. */
\r
534 configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
\r
536 /* If we want to use stack checking on architectures that use
\r
537 a positive stack growth direction then we also need to store the
\r
538 other extreme of the stack space. */
\r
539 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
\r
541 #endif /* portSTACK_GROWTH */
\r
543 /* Setup the newly allocated TCB with the initial state of the task. */
\r
544 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
\r
546 /* Initialize the TCB stack to look as if the task was already running,
\r
547 but had been interrupted by the scheduler. The return address is set
\r
548 to the start of the task function. Once the stack has been initialised
\r
549 the top of stack variable is updated. */
\r
550 #if( portUSING_MPU_WRAPPERS == 1 )
\r
552 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
\r
554 #else /* portUSING_MPU_WRAPPERS */
\r
556 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
\r
558 #endif /* portUSING_MPU_WRAPPERS */
\r
560 if( ( void * ) pxCreatedTask != NULL )
\r
562 /* Pass the TCB out - in an anonymous way. The calling function/
\r
563 task can use this as a handle to delete the task later if
\r
565 *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
\r
568 /* Ensure interrupts don't access the task lists while they are being
\r
570 taskENTER_CRITICAL();
\r
572 uxCurrentNumberOfTasks++;
\r
573 if( pxCurrentTCB == NULL )
\r
575 /* There are no other tasks, or all the other tasks are in
\r
576 the suspended state - make this the current task. */
\r
577 pxCurrentTCB = pxNewTCB;
\r
579 if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
\r
581 /* This is the first task to be created so do the preliminary
\r
582 initialisation required. We will not recover if this call
\r
583 fails, but we will report the failure. */
\r
584 prvInitialiseTaskLists();
\r
589 /* If the scheduler is not already running, make this task the
\r
590 current task if it is the highest priority task to be created
\r
592 if( xSchedulerRunning == pdFALSE )
\r
594 if( pxCurrentTCB->uxPriority <= uxPriority )
\r
596 pxCurrentTCB = pxNewTCB;
\r
603 #if ( configUSE_TRACE_FACILITY == 1 )
\r
605 /* Add a counter into the TCB for tracing only. */
\r
606 pxNewTCB->uxTCBNumber = uxTaskNumber;
\r
608 #endif /* configUSE_TRACE_FACILITY */
\r
609 traceTASK_CREATE( pxNewTCB );
\r
611 prvAddTaskToReadyList( pxNewTCB );
\r
614 portSETUP_TCB( pxNewTCB );
\r
616 taskEXIT_CRITICAL();
\r
620 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
\r
621 traceTASK_CREATE_FAILED();
\r
624 if( xReturn == pdPASS )
\r
626 if( xSchedulerRunning != pdFALSE )
\r
628 /* If the created task is of a higher priority than the current task
\r
629 then it should run now. */
\r
630 if( pxCurrentTCB->uxPriority < uxPriority )
\r
632 taskYIELD_IF_USING_PREEMPTION();
\r
639 /*-----------------------------------------------------------*/
\r
641 #if ( INCLUDE_vTaskDelete == 1 )
\r
643 void vTaskDelete( xTaskHandle xTaskToDelete )
\r
647 taskENTER_CRITICAL();
\r
649 /* If null is passed in here then we are deleting ourselves. */
\r
650 pxTCB = prvGetTCBFromHandle( xTaskToDelete );
\r
652 /* Remove task from the ready list and place in the termination list.
\r
653 This will stop the task from be scheduled. The idle task will check
\r
654 the termination list and free up any memory allocated by the
\r
655 scheduler for the TCB and stack. */
\r
656 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 )
\r
658 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
661 /* Is the task waiting on an event also? */
\r
662 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
\r
664 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
\r
667 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
\r
669 /* Increment the ucTasksDeleted variable so the idle task knows
\r
670 there is a task that has been deleted and that it should therefore
\r
671 check the xTasksWaitingTermination list. */
\r
674 /* Increment the uxTaskNumberVariable also so kernel aware debuggers
\r
675 can detect that the task lists need re-generating. */
\r
678 traceTASK_DELETE( pxTCB );
\r
680 taskEXIT_CRITICAL();
\r
682 /* Force a reschedule if we have just deleted the current task. */
\r
683 if( xSchedulerRunning != pdFALSE )
\r
685 if( pxTCB == pxCurrentTCB )
\r
687 portYIELD_WITHIN_API();
\r
692 #endif /* INCLUDE_vTaskDelete */
\r
693 /*-----------------------------------------------------------*/
\r
695 #if ( INCLUDE_vTaskDelayUntil == 1 )
\r
697 void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
\r
699 portTickType xTimeToWake;
\r
700 portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
\r
702 configASSERT( pxPreviousWakeTime );
\r
703 configASSERT( ( xTimeIncrement > 0U ) );
\r
707 /* Minor optimisation. The tick count cannot change in this
\r
709 const portTickType xConstTickCount = xTickCount;
\r
711 /* Generate the tick time at which the task wants to wake. */
\r
712 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
\r
714 if( xConstTickCount < *pxPreviousWakeTime )
\r
716 /* The tick count has overflowed since this function was
\r
717 lasted called. In this case the only time we should ever
\r
718 actually delay is if the wake time has also overflowed,
\r
719 and the wake time is greater than the tick time. When this
\r
720 is the case it is as if neither time had overflowed. */
\r
721 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
\r
723 xShouldDelay = pdTRUE;
\r
728 /* The tick time has not overflowed. In this case we will
\r
729 delay if either the wake time has overflowed, and/or the
\r
730 tick time is less than the wake time. */
\r
731 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
\r
733 xShouldDelay = pdTRUE;
\r
737 /* Update the wake time ready for the next call. */
\r
738 *pxPreviousWakeTime = xTimeToWake;
\r
740 if( xShouldDelay != pdFALSE )
\r
742 traceTASK_DELAY_UNTIL();
\r
744 /* We must remove ourselves from the ready list before adding
\r
745 ourselves to the blocked list as the same list item is used for
\r
747 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 )
\r
749 /* The current task must be in a ready list, so there is
\r
750 no need to check, and the port reset macro can be called
\r
752 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
755 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
758 xAlreadyYielded = xTaskResumeAll();
\r
760 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
761 have put ourselves to sleep. */
\r
762 if( xAlreadyYielded == pdFALSE )
\r
764 portYIELD_WITHIN_API();
\r
768 #endif /* INCLUDE_vTaskDelayUntil */
\r
769 /*-----------------------------------------------------------*/
\r
771 #if ( INCLUDE_vTaskDelay == 1 )
\r
773 void vTaskDelay( portTickType xTicksToDelay )
\r
775 portTickType xTimeToWake;
\r
776 signed portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
778 /* A delay time of zero just forces a reschedule. */
\r
779 if( xTicksToDelay > ( portTickType ) 0U )
\r
785 /* A task that is removed from the event list while the
\r
786 scheduler is suspended will not get placed in the ready
\r
787 list or removed from the blocked list until the scheduler
\r
790 This task cannot be in an event list as it is the currently
\r
793 /* Calculate the time to wake - this may overflow but this is
\r
795 xTimeToWake = xTickCount + xTicksToDelay;
\r
797 /* We must remove ourselves from the ready list before adding
\r
798 ourselves to the blocked list as the same list item is used for
\r
800 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 )
\r
802 /* The current task must be in a ready list, so there is
\r
803 no need to check, and the port reset macro can be called
\r
805 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
807 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
809 xAlreadyYielded = xTaskResumeAll();
\r
812 /* Force a reschedule if xTaskResumeAll has not already done so, we may
\r
813 have put ourselves to sleep. */
\r
814 if( xAlreadyYielded == pdFALSE )
\r
816 portYIELD_WITHIN_API();
\r
820 #endif /* INCLUDE_vTaskDelay */
\r
821 /*-----------------------------------------------------------*/
\r
823 #if ( INCLUDE_eTaskGetState == 1 )
\r
825 eTaskState eTaskGetState( xTaskHandle xTask )
\r
827 eTaskState eReturn;
\r
828 xList *pxStateList;
\r
829 const tskTCB * const 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
855 list. Is it genuinely suspended or is it block
\r
857 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL )
\r
859 eReturn = eSuspended;
\r
863 eReturn = eBlocked;
\r
868 #if ( INCLUDE_vTaskDelete == 1 )
\r
869 else if( pxStateList == &xTasksWaitingTermination )
\r
871 /* The task being queried is referenced from the deleted
\r
873 eReturn = eDeleted;
\r
879 /* If the task is not in any other state, it must be in the
\r
880 Ready (including pending ready) state. */
\r
888 #endif /* INCLUDE_eTaskGetState */
\r
889 /*-----------------------------------------------------------*/
\r
891 #if ( INCLUDE_uxTaskPriorityGet == 1 )
\r
893 unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle xTask )
\r
896 unsigned portBASE_TYPE uxReturn;
\r
898 taskENTER_CRITICAL();
\r
900 /* If null is passed in here then we are changing the
\r
901 priority of the calling function. */
\r
902 pxTCB = prvGetTCBFromHandle( xTask );
\r
903 uxReturn = pxTCB->uxPriority;
\r
905 taskEXIT_CRITICAL();
\r
910 #endif /* INCLUDE_uxTaskPriorityGet */
\r
911 /*-----------------------------------------------------------*/
\r
913 #if ( INCLUDE_vTaskPrioritySet == 1 )
\r
915 void vTaskPrioritySet( xTaskHandle xTask, unsigned portBASE_TYPE uxNewPriority )
\r
918 unsigned portBASE_TYPE uxCurrentBasePriority, uxPriorityUsedOnEntry;
\r
919 portBASE_TYPE xYieldRequired = pdFALSE;
\r
921 configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );
\r
923 /* Ensure the new priority is valid. */
\r
924 if( uxNewPriority >= ( unsigned portBASE_TYPE ) configMAX_PRIORITIES )
\r
926 uxNewPriority = ( unsigned portBASE_TYPE ) configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
\r
929 taskENTER_CRITICAL();
\r
931 /* If null is passed in here then it is the priority of the calling
\r
932 task that is being changed. */
\r
933 pxTCB = prvGetTCBFromHandle( xTask );
\r
935 traceTASK_PRIORITY_SET( pxTCB, uxNewPriority );
\r
937 #if ( configUSE_MUTEXES == 1 )
\r
939 uxCurrentBasePriority = pxTCB->uxBasePriority;
\r
943 uxCurrentBasePriority = pxTCB->uxPriority;
\r
947 if( uxCurrentBasePriority != uxNewPriority )
\r
949 /* The priority change may have readied a task of higher
\r
950 priority than the calling task. */
\r
951 if( uxNewPriority > uxCurrentBasePriority )
\r
953 if( pxTCB != pxCurrentTCB )
\r
955 /* The priority of a task other than the currently
\r
956 running task is being raised. Is the priority being
\r
957 raised above that of the running task? */
\r
958 if( uxNewPriority >= pxCurrentTCB->uxPriority )
\r
960 xYieldRequired = pdTRUE;
\r
965 /* The priority of the running task is being raised,
\r
966 but the running task must already be the highest
\r
967 priority task able to run so no yield is required. */
\r
970 else if( pxTCB == pxCurrentTCB )
\r
972 /* Setting the priority of the running task down means
\r
973 there may now be another task of higher priority that
\r
974 is ready to execute. */
\r
975 xYieldRequired = pdTRUE;
\r
979 /* Setting the priority of any other task down does not
\r
980 require a yield as the running task must be above the
\r
981 new priority of the task being modified. */
\r
984 /* Remember the ready list the task might be referenced from
\r
985 before its uxPriority member is changed so the
\r
986 taskRESET_READY_PRIORITY() macro can function correctly. */
\r
987 uxPriorityUsedOnEntry = pxTCB->uxPriority;
\r
989 #if ( configUSE_MUTEXES == 1 )
\r
991 /* Only change the priority being used if the task is not
\r
992 currently using an inherited priority. */
\r
993 if( pxTCB->uxBasePriority == pxTCB->uxPriority )
\r
995 pxTCB->uxPriority = uxNewPriority;
\r
998 /* The base priority gets set whatever. */
\r
999 pxTCB->uxBasePriority = uxNewPriority;
\r
1003 pxTCB->uxPriority = uxNewPriority;
\r
1007 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( portTickType ) configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
\r
1009 /* If the task is in the blocked or suspended list we need do
\r
1010 nothing more than change it's priority variable. However, if
\r
1011 the task is in a ready list it needs to be removed and placed
\r
1012 in the list appropriate to its new priority. */
\r
1013 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE )
\r
1015 /* The task is currently in its ready list - remove before adding
\r
1016 it to it's new ready list. As we are in a critical section we
\r
1017 can do this even if the scheduler is suspended. */
\r
1018 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 )
\r
1020 /* It is known that the task is in its ready list so
\r
1021 there is no need to check again and the port level
\r
1022 reset macro can be called directly. */
\r
1023 portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );
\r
1025 prvAddTaskToReadyList( pxTCB );
\r
1028 if( xYieldRequired == pdTRUE )
\r
1030 taskYIELD_IF_USING_PREEMPTION();
\r
1033 /* Remove compiler warning about unused variables when the port
\r
1034 optimised task selection is not being used. */
\r
1035 ( void ) uxPriorityUsedOnEntry;
\r
1038 taskEXIT_CRITICAL();
\r
1041 #endif /* INCLUDE_vTaskPrioritySet */
\r
1042 /*-----------------------------------------------------------*/
\r
1044 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1046 void vTaskSuspend( xTaskHandle xTaskToSuspend )
\r
1050 taskENTER_CRITICAL();
\r
1052 /* If null is passed in here then it is the running task that is
\r
1053 being suspended. */
\r
1054 pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
\r
1056 traceTASK_SUSPEND( pxTCB );
\r
1058 /* Remove task from the ready/delayed list and place in the suspended list. */
\r
1059 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 )
\r
1061 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
1064 /* Is the task waiting on an event also? */
\r
1065 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
\r
1067 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
\r
1070 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
\r
1072 taskEXIT_CRITICAL();
\r
1074 if( pxTCB == pxCurrentTCB )
\r
1076 if( xSchedulerRunning != pdFALSE )
\r
1078 /* The current task has just been suspended. */
\r
1079 portYIELD_WITHIN_API();
\r
1083 /* The scheduler is not running, but the task that was pointed
\r
1084 to by pxCurrentTCB has just been suspended and pxCurrentTCB
\r
1085 must be adjusted to point to a different task. */
\r
1086 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
\r
1088 /* No other tasks are ready, so set pxCurrentTCB back to
\r
1089 NULL so when the next task is created pxCurrentTCB will
\r
1090 be set to point to it no matter what its relative priority
\r
1092 pxCurrentTCB = NULL;
\r
1096 vTaskSwitchContext();
\r
1102 #endif /* INCLUDE_vTaskSuspend */
\r
1103 /*-----------------------------------------------------------*/
\r
1105 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1107 signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
\r
1109 portBASE_TYPE xReturn = pdFALSE;
\r
1110 const tskTCB * const pxTCB = ( tskTCB * ) xTask;
\r
1112 /* It does not make sense to check if the calling task is suspended. */
\r
1113 configASSERT( xTask );
\r
1115 /* Is the task we are attempting to resume actually in the
\r
1116 suspended list? */
\r
1117 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
\r
1119 /* Has the task already been resumed from within an ISR? */
\r
1120 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE )
\r
1122 /* Is it in the suspended list because it is in the
\r
1123 Suspended state? It is possible to be in the suspended
\r
1124 list because it is blocked on a task with no timeout
\r
1126 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE )
\r
1134 } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */
\r
1136 #endif /* INCLUDE_vTaskSuspend */
\r
1137 /*-----------------------------------------------------------*/
\r
1139 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1141 void vTaskResume( xTaskHandle xTaskToResume )
\r
1143 tskTCB * const pxTCB = ( tskTCB * ) xTaskToResume;
\r
1145 /* It does not make sense to resume the calling task. */
\r
1146 configASSERT( xTaskToResume );
\r
1148 /* The parameter cannot be NULL as it is impossible to resume the
\r
1149 currently executing task. */
\r
1150 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
\r
1152 taskENTER_CRITICAL();
\r
1154 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
1156 traceTASK_RESUME( pxTCB );
\r
1158 /* As we are in a critical section we can access the ready
\r
1159 lists even if the scheduler is suspended. */
\r
1160 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1161 prvAddTaskToReadyList( pxTCB );
\r
1163 /* We may have just resumed a higher priority task. */
\r
1164 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1166 /* This yield may not cause the task just resumed to run,
\r
1167 but will leave the lists in the correct state for the
\r
1169 taskYIELD_IF_USING_PREEMPTION();
\r
1173 taskEXIT_CRITICAL();
\r
1177 #endif /* INCLUDE_vTaskSuspend */
\r
1179 /*-----------------------------------------------------------*/
\r
1181 #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
\r
1183 portBASE_TYPE xTaskResumeFromISR( xTaskHandle xTaskToResume )
\r
1185 portBASE_TYPE xYieldRequired = pdFALSE;
\r
1186 tskTCB * const pxTCB = ( tskTCB * ) xTaskToResume;
\r
1187 unsigned portBASE_TYPE uxSavedInterruptStatus;
\r
1189 configASSERT( xTaskToResume );
\r
1191 /* RTOS ports that support interrupt nesting have the concept of a
\r
1192 maximum system call (or maximum API call) interrupt priority.
\r
1193 Interrupts that are above the maximum system call priority are keep
\r
1194 permanently enabled, even when the RTOS kernel is in a critical section,
\r
1195 but cannot make any calls to FreeRTOS API functions. If configASSERT()
\r
1196 is defined in FreeRTOSConfig.h then
\r
1197 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
\r
1198 failure if a FreeRTOS API function is called from an interrupt that has
\r
1199 been assigned a priority above the configured maximum system call
\r
1200 priority. Only FreeRTOS functions that end in FromISR can be called
\r
1201 from interrupts that have been assigned a priority at or (logically)
\r
1202 below the maximum system call interrupt priority. FreeRTOS maintains a
\r
1203 separate interrupt safe API to ensure interrupt entry is as fast and as
\r
1204 simple as possible. More information (albeit Cortex-M specific) is
\r
1205 provided on the following link:
\r
1206 http://www.freertos.org/RTOS-Cortex-M3-M4.html */
\r
1207 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
\r
1209 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
\r
1211 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
\r
1213 traceTASK_RESUME_FROM_ISR( pxTCB );
\r
1215 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1217 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1219 xYieldRequired = pdTRUE;
\r
1222 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1223 prvAddTaskToReadyList( pxTCB );
\r
1227 /* We cannot access the delayed or ready lists, so will hold this
\r
1228 task pending until the scheduler is resumed, at which point a
\r
1229 yield will be performed if necessary. */
\r
1230 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
\r
1234 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
\r
1236 return xYieldRequired;
\r
1239 #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */
\r
1240 /*-----------------------------------------------------------*/
\r
1242 void vTaskStartScheduler( void )
\r
1244 portBASE_TYPE xReturn;
\r
1246 /* Add the idle task at the lowest priority. */
\r
1247 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
\r
1249 /* Create the idle task, storing its handle in xIdleTaskHandle so it can
\r
1250 be returned by the xTaskGetIdleTaskHandle() function. */
\r
1251 xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
\r
1255 /* Create the idle task without storing its handle. */
\r
1256 xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
\r
1258 #endif /* INCLUDE_xTaskGetIdleTaskHandle */
\r
1260 #if ( configUSE_TIMERS == 1 )
\r
1262 if( xReturn == pdPASS )
\r
1264 xReturn = xTimerCreateTimerTask();
\r
1267 #endif /* configUSE_TIMERS */
\r
1269 if( xReturn == pdPASS )
\r
1271 /* Interrupts are turned off here, to ensure a tick does not occur
\r
1272 before or during the call to xPortStartScheduler(). The stacks of
\r
1273 the created tasks contain a status word with interrupts switched on
\r
1274 so interrupts will automatically get re-enabled when the first task
\r
1276 portDISABLE_INTERRUPTS();
\r
1278 #if ( configUSE_NEWLIB_REENTRANT == 1 )
\r
1280 /* Switch Newlib's _impure_ptr variable to point to the _reent
\r
1281 structure specific to the task that will run first. */
\r
1282 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
\r
1284 #endif /* configUSE_NEWLIB_REENTRANT */
\r
1286 xSchedulerRunning = pdTRUE;
\r
1287 xTickCount = ( portTickType ) 0U;
\r
1289 /* If configGENERATE_RUN_TIME_STATS is defined then the following
\r
1290 macro must be defined to configure the timer/counter used to generate
\r
1291 the run time counter time base. */
\r
1292 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
\r
1294 /* Setting up the timer tick is hardware specific and thus in the
\r
1295 portable interface. */
\r
1296 if( xPortStartScheduler() != pdFALSE )
\r
1298 /* Should not reach here as if the scheduler is running the
\r
1299 function will not return. */
\r
1303 /* Should only reach here if a task calls xTaskEndScheduler(). */
\r
1308 /* This line will only be reached if the kernel could not be started,
\r
1309 because there was not enough FreeRTOS heap to create the idle task
\r
1310 or the timer task. */
\r
1311 configASSERT( xReturn );
\r
1314 /*-----------------------------------------------------------*/
\r
1316 void vTaskEndScheduler( void )
\r
1318 /* Stop the scheduler interrupts and call the portable scheduler end
\r
1319 routine so the original ISRs can be restored if necessary. The port
\r
1320 layer must ensure interrupts enable bit is left in the correct state. */
\r
1321 portDISABLE_INTERRUPTS();
\r
1322 xSchedulerRunning = pdFALSE;
\r
1323 vPortEndScheduler();
\r
1325 /*----------------------------------------------------------*/
\r
1327 void vTaskSuspendAll( void )
\r
1329 /* A critical section is not required as the variable is of type
\r
1331 ++uxSchedulerSuspended;
\r
1333 /*----------------------------------------------------------*/
\r
1335 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
1337 static portTickType prvGetExpectedIdleTime( void )
\r
1339 portTickType xReturn;
\r
1341 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )
\r
1345 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )
\r
1347 /* There are other idle priority tasks in the ready state. If
\r
1348 time slicing is used then the very next tick interrupt must be
\r
1354 xReturn = xNextTaskUnblockTime - xTickCount;
\r
1360 #endif /* configUSE_TICKLESS_IDLE */
\r
1361 /*----------------------------------------------------------*/
\r
1363 signed portBASE_TYPE xTaskResumeAll( void )
\r
1366 portBASE_TYPE xAlreadyYielded = pdFALSE;
\r
1368 /* If uxSchedulerSuspended is zero then this function does not match a
\r
1369 previous call to vTaskSuspendAll(). */
\r
1370 configASSERT( uxSchedulerSuspended );
\r
1372 /* It is possible that an ISR caused a task to be removed from an event
\r
1373 list while the scheduler was suspended. If this was the case then the
\r
1374 removed task will have been added to the xPendingReadyList. Once the
\r
1375 scheduler has been resumed it is safe to move all the pending ready
\r
1376 tasks from this list into their appropriate ready list. */
\r
1377 taskENTER_CRITICAL();
\r
1379 --uxSchedulerSuspended;
\r
1381 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1383 if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0U )
\r
1385 /* Move any readied tasks from the pending list into the
\r
1386 appropriate ready list. */
\r
1387 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
\r
1389 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
\r
1390 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
\r
1391 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1392 prvAddTaskToReadyList( pxTCB );
\r
1394 /* If we have moved a task that has a priority higher than
\r
1395 the current task then we should yield. */
\r
1396 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1398 xYieldPending = pdTRUE;
\r
1402 /* If any ticks occurred while the scheduler was suspended then
\r
1403 they should be processed now. This ensures the tick count does not
\r
1404 slip, and that any delayed tasks are resumed at the correct time. */
\r
1405 if( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U )
\r
1407 while( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U )
\r
1409 if( xTaskIncrementTick() != pdFALSE )
\r
1411 xYieldPending = pdTRUE;
\r
1417 if( xYieldPending == pdTRUE )
\r
1419 #if( configUSE_PREEMPTION != 0 )
\r
1421 xAlreadyYielded = pdTRUE;
\r
1424 taskYIELD_IF_USING_PREEMPTION();
\r
1429 taskEXIT_CRITICAL();
\r
1431 return xAlreadyYielded;
\r
1433 /*-----------------------------------------------------------*/
\r
1435 portTickType xTaskGetTickCount( void )
\r
1437 portTickType xTicks;
\r
1439 /* Critical section required if running on a 16 bit processor. */
\r
1440 taskENTER_CRITICAL();
\r
1442 xTicks = xTickCount;
\r
1444 taskEXIT_CRITICAL();
\r
1448 /*-----------------------------------------------------------*/
\r
1450 portTickType xTaskGetTickCountFromISR( void )
\r
1452 portTickType xReturn;
\r
1453 unsigned portBASE_TYPE uxSavedInterruptStatus;
\r
1455 /* RTOS ports that support interrupt nesting have the concept of a maximum
\r
1456 system call (or maximum API call) interrupt priority. Interrupts that are
\r
1457 above the maximum system call priority are keep permanently enabled, even
\r
1458 when the RTOS kernel is in a critical section, but cannot make any calls to
\r
1459 FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h
\r
1460 then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion
\r
1461 failure if a FreeRTOS API function is called from an interrupt that has been
\r
1462 assigned a priority above the configured maximum system call priority.
\r
1463 Only FreeRTOS functions that end in FromISR can be called from interrupts
\r
1464 that have been assigned a priority at or (logically) below the maximum
\r
1465 system call interrupt priority. FreeRTOS maintains a separate interrupt
\r
1466 safe API to ensure interrupt entry is as fast and as simple as possible.
\r
1467 More information (albeit Cortex-M specific) is provided on the following
\r
1468 link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */
\r
1469 portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
\r
1471 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
\r
1472 xReturn = xTickCount;
\r
1473 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
\r
1477 /*-----------------------------------------------------------*/
\r
1479 unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
\r
1481 /* A critical section is not required because the variables are of type
\r
1483 return uxCurrentNumberOfTasks;
\r
1485 /*-----------------------------------------------------------*/
\r
1487 #if ( INCLUDE_pcTaskGetTaskName == 1 )
\r
1489 signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery )
\r
1493 /* If null is passed in here then the name of the calling task is being queried. */
\r
1494 pxTCB = prvGetTCBFromHandle( xTaskToQuery );
\r
1495 configASSERT( pxTCB );
\r
1496 return &( pxTCB->pcTaskName[ 0 ] );
\r
1499 #endif /* INCLUDE_pcTaskGetTaskName */
\r
1500 /*-----------------------------------------------------------*/
\r
1502 #if ( configUSE_TRACE_FACILITY == 1 )
\r
1504 unsigned portBASE_TYPE uxTaskGetSystemState( xTaskStatusType *pxTaskStatusArray, unsigned portBASE_TYPE uxArraySize, unsigned long *pulTotalRunTime )
\r
1506 unsigned portBASE_TYPE uxTask = 0, uxQueue = configMAX_PRIORITIES;
\r
1508 vTaskSuspendAll();
\r
1510 /* Is there a space in the array for each task in the system? */
\r
1511 if( uxArraySize >= uxCurrentNumberOfTasks )
\r
1513 /* Fill in an xTaskStatusType structure with information on each
\r
1514 task in the Ready state. */
\r
1518 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady );
\r
1520 } while( uxQueue > ( unsigned portBASE_TYPE ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
\r
1522 /* Fill in an xTaskStatusType structure with information on each
\r
1523 task in the Blocked state. */
\r
1524 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) pxDelayedTaskList, eBlocked );
\r
1525 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) pxOverflowDelayedTaskList, eBlocked );
\r
1527 #if( INCLUDE_vTaskDelete == 1 )
\r
1529 /* Fill in an xTaskStatusType structure with information on
\r
1530 each task that has been deleted but not yet cleaned up. */
\r
1531 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted );
\r
1535 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1537 /* Fill in an xTaskStatusType structure with information on
\r
1538 each task in the Suspended state. */
\r
1539 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended );
\r
1543 #if ( configGENERATE_RUN_TIME_STATS == 1)
\r
1545 if( pulTotalRunTime != NULL )
\r
1547 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
\r
1548 portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) );
\r
1550 *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
\r
1556 if( pulTotalRunTime != NULL )
\r
1558 *pulTotalRunTime = 0;
\r
1564 ( void ) xTaskResumeAll();
\r
1569 #endif /* configUSE_TRACE_FACILITY */
\r
1570 /*----------------------------------------------------------*/
\r
1572 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
\r
1574 xTaskHandle xTaskGetIdleTaskHandle( void )
\r
1576 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been
\r
1577 started, then xIdleTaskHandle will be NULL. */
\r
1578 configASSERT( ( xIdleTaskHandle != NULL ) );
\r
1579 return xIdleTaskHandle;
\r
1582 #endif /* INCLUDE_xTaskGetIdleTaskHandle */
\r
1583 /*----------------------------------------------------------*/
\r
1585 /* This conditional compilation should use inequality to 0, not equality to 1.
\r
1586 This is to ensure vTaskStepTick() is available when user defined low power mode
\r
1587 implementations require configUSE_TICKLESS_IDLE to be set to a value other than
\r
1589 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
1591 void vTaskStepTick( portTickType xTicksToJump )
\r
1593 /* Correct the tick count value after a period during which the tick
\r
1594 was suppressed. Note this does *not* call the tick hook function for
\r
1595 each stepped tick. */
\r
1596 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime );
\r
1597 xTickCount += xTicksToJump;
\r
1598 traceINCREASE_TICK_COUNT( xTicksToJump );
\r
1601 #endif /* configUSE_TICKLESS_IDLE */
\r
1602 /*----------------------------------------------------------*/
\r
1604 portBASE_TYPE xTaskIncrementTick( void )
\r
1607 portTickType xItemValue;
\r
1608 portBASE_TYPE xSwitchRequired = pdFALSE;
\r
1610 /* Called by the portable layer each time a tick interrupt occurs.
\r
1611 Increments the tick then checks to see if the new tick value will cause any
\r
1612 tasks to be unblocked. */
\r
1613 traceTASK_INCREMENT_TICK( xTickCount );
\r
1614 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
1616 /* Increment the RTOS tick, switching the delayed and overflowed
\r
1617 delayed lists if it wraps to 0. */
\r
1621 /* Minor optimisation. The tick count cannot change in this
\r
1623 const portTickType xConstTickCount = xTickCount;
\r
1625 if( xConstTickCount == ( portTickType ) 0U )
\r
1627 taskSWITCH_DELAYED_LISTS();
\r
1630 /* See if this tick has made a timeout expire. Tasks are stored in the
\r
1631 queue in the order of their wake time - meaning once one tasks has been
\r
1632 found whose block time has not expired there is no need not look any
\r
1633 further down the list. */
\r
1634 if( xConstTickCount >= xNextTaskUnblockTime )
\r
1638 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
\r
1640 /* The delayed list is empty. Set xNextTaskUnblockTime to
\r
1641 the maximum possible value so it is extremely unlikely that
\r
1642 the if( xTickCount >= xNextTaskUnblockTime ) test will pass
\r
1643 next time through. */
\r
1644 xNextTaskUnblockTime = portMAX_DELAY;
\r
1649 /* The delayed list is not empty, get the value of the item
\r
1650 at the head of the delayed list. This is the time at which
\r
1651 the task at the head of the delayed list must be removed
\r
1652 from the Blocked state. */
\r
1653 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
\r
1654 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) );
\r
1656 if( xConstTickCount < xItemValue )
\r
1658 /* It is not time to unblock this item yet, but the item
\r
1659 value is the time at which the task at the head of the
\r
1660 blocked list must be removed from the Blocked state -
\r
1661 so record the item value in xNextTaskUnblockTime. */
\r
1662 xNextTaskUnblockTime = xItemValue;
\r
1666 /* It is time to remove the item from the Blocked state. */
\r
1667 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
\r
1669 /* Is the task waiting on an event also? If so remove it
\r
1670 from the event list. */
\r
1671 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
\r
1673 ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
\r
1676 /* Place the unblocked task into the appropriate ready
\r
1678 prvAddTaskToReadyList( pxTCB );
\r
1680 /* A task being unblocked cannot cause an immediate context
\r
1681 switch if preemption is turned off. */
\r
1682 #if ( configUSE_PREEMPTION == 1 )
\r
1684 /* Preemption is on, but a context switch should only
\r
1685 be performed if the unblocked task has a priority that
\r
1686 is equal to or higher than the currently executing
\r
1688 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
1690 xSwitchRequired = pdTRUE;
\r
1693 #endif /* configUSE_PREEMPTION */
\r
1699 /* Tasks of equal priority to the currently running task will share
\r
1700 processing time (time slice) if preemption is on, and the application
\r
1701 writer has not explicitly turned time slicing off. */
\r
1702 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
\r
1704 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( unsigned portBASE_TYPE ) 1 )
\r
1706 xSwitchRequired = pdTRUE;
\r
1709 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
\r
1711 #if ( configUSE_TICK_HOOK == 1 )
\r
1713 /* Guard against the tick hook being called when the pended tick
\r
1714 count is being unwound (when the scheduler is being unlocked). */
\r
1715 if( uxPendedTicks == ( unsigned portBASE_TYPE ) 0U )
\r
1717 vApplicationTickHook();
\r
1720 #endif /* configUSE_TICK_HOOK */
\r
1726 /* The tick hook gets called at regular intervals, even if the
\r
1727 scheduler is locked. */
\r
1728 #if ( configUSE_TICK_HOOK == 1 )
\r
1730 vApplicationTickHook();
\r
1735 #if ( configUSE_PREEMPTION == 1 )
\r
1737 if( xYieldPending != pdFALSE )
\r
1739 xSwitchRequired = pdTRUE;
\r
1742 #endif /* configUSE_PREEMPTION */
\r
1744 return xSwitchRequired;
\r
1746 /*-----------------------------------------------------------*/
\r
1748 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1750 void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction )
\r
1754 /* If xTask is NULL then we are setting our own task hook. */
\r
1755 if( xTask == NULL )
\r
1757 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1761 xTCB = ( tskTCB * ) xTask;
\r
1764 /* Save the hook function in the TCB. A critical section is required as
\r
1765 the value can be accessed from an interrupt. */
\r
1766 taskENTER_CRITICAL();
\r
1767 xTCB->pxTaskTag = pxHookFunction;
\r
1768 taskEXIT_CRITICAL();
\r
1771 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
1772 /*-----------------------------------------------------------*/
\r
1774 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1776 pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
\r
1779 pdTASK_HOOK_CODE xReturn;
\r
1781 /* If xTask is NULL then we are setting our own task hook. */
\r
1782 if( xTask == NULL )
\r
1784 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1788 xTCB = ( tskTCB * ) xTask;
\r
1791 /* Save the hook function in the TCB. A critical section is required as
\r
1792 the value can be accessed from an interrupt. */
\r
1793 taskENTER_CRITICAL();
\r
1794 xReturn = xTCB->pxTaskTag;
\r
1795 taskEXIT_CRITICAL();
\r
1800 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
1801 /*-----------------------------------------------------------*/
\r
1803 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
1805 portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
\r
1808 portBASE_TYPE xReturn;
\r
1810 /* If xTask is NULL then we are calling our own task hook. */
\r
1811 if( xTask == NULL )
\r
1813 xTCB = ( tskTCB * ) pxCurrentTCB;
\r
1817 xTCB = ( tskTCB * ) xTask;
\r
1820 if( xTCB->pxTaskTag != NULL )
\r
1822 xReturn = xTCB->pxTaskTag( pvParameter );
\r
1832 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
1833 /*-----------------------------------------------------------*/
\r
1835 void vTaskSwitchContext( void )
\r
1837 if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
\r
1839 /* The scheduler is currently suspended - do not allow a context
\r
1841 xYieldPending = pdTRUE;
\r
1845 xYieldPending = pdFALSE;
\r
1846 traceTASK_SWITCHED_OUT();
\r
1848 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
1850 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
\r
1851 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
\r
1853 ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
\r
1856 /* Add the amount of time the task has been running to the
\r
1857 accumulated time so far. The time the task started running was
\r
1858 stored in ulTaskSwitchedInTime. Note that there is no overflow
\r
1859 protection here so count values are only valid until the timer
\r
1860 overflows. The guard against negative values is to protect
\r
1861 against suspect run time stat counter implementations - which
\r
1862 are provided by the application, not the kernel. */
\r
1863 if( ulTotalRunTime > ulTaskSwitchedInTime )
\r
1865 pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
\r
1867 ulTaskSwitchedInTime = ulTotalRunTime;
\r
1869 #endif /* configGENERATE_RUN_TIME_STATS */
\r
1871 taskFIRST_CHECK_FOR_STACK_OVERFLOW();
\r
1872 taskSECOND_CHECK_FOR_STACK_OVERFLOW();
\r
1874 taskSELECT_HIGHEST_PRIORITY_TASK();
\r
1876 traceTASK_SWITCHED_IN();
\r
1878 #if ( configUSE_NEWLIB_REENTRANT == 1 )
\r
1880 /* Switch Newlib's _impure_ptr variable to point to the _reent
\r
1881 structure specific to this task. */
\r
1882 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
\r
1884 #endif /* configUSE_NEWLIB_REENTRANT */
\r
1887 /*-----------------------------------------------------------*/
\r
1889 void vTaskPlaceOnEventList( xList * const pxEventList, portTickType xTicksToWait )
\r
1891 portTickType xTimeToWake;
\r
1893 configASSERT( pxEventList );
\r
1895 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1896 SCHEDULER SUSPENDED. */
\r
1898 /* Place the event list item of the TCB in the appropriate event list.
\r
1899 This is placed in the list in priority order so the highest priority task
\r
1900 is the first to be woken by the event. */
\r
1901 vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );
\r
1903 /* We must remove ourselves from the ready list before adding ourselves
\r
1904 to the blocked list as the same list item is used for both lists. We have
\r
1905 exclusive access to the ready lists as the scheduler is locked. */
\r
1906 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 )
\r
1908 /* The current task must be in a ready list, so there is no need to
\r
1909 check, and the port reset macro can be called directly. */
\r
1910 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
1913 #if ( INCLUDE_vTaskSuspend == 1 )
\r
1915 if( xTicksToWait == portMAX_DELAY )
\r
1917 /* Add ourselves to the suspended task list instead of a delayed task
\r
1918 list to ensure we are not woken by a timing event. We will block
\r
1920 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
\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
1930 #else /* INCLUDE_vTaskSuspend */
\r
1932 /* Calculate the time at which the task should be woken if the event does
\r
1933 not occur. This may overflow but this doesn't matter. */
\r
1934 xTimeToWake = xTickCount + xTicksToWait;
\r
1935 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
1937 #endif /* INCLUDE_vTaskSuspend */
\r
1939 /*-----------------------------------------------------------*/
\r
1941 #if configUSE_TIMERS == 1
\r
1943 void vTaskPlaceOnEventListRestricted( xList * const pxEventList, portTickType xTicksToWait )
\r
1945 portTickType xTimeToWake;
\r
1947 configASSERT( pxEventList );
\r
1949 /* This function should not be called by application code hence the
\r
1950 'Restricted' in its name. It is not part of the public API. It is
\r
1951 designed for use by kernel code, and has special calling requirements -
\r
1952 it should be called from a critical section. */
\r
1955 /* Place the event list item of the TCB in the appropriate event list.
\r
1956 In this case it is assume that this is the only task that is going to
\r
1957 be waiting on this event list, so the faster vListInsertEnd() function
\r
1958 can be used in place of vListInsert. */
\r
1959 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );
\r
1961 /* We must remove this task from the ready list before adding it to the
\r
1962 blocked list as the same list item is used for both lists. This
\r
1963 function is called form a critical section. */
\r
1964 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 )
\r
1966 /* The current task must be in a ready list, so there is no need to
\r
1967 check, and the port reset macro can be called directly. */
\r
1968 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
\r
1971 /* Calculate the time at which the task should be woken if the event does
\r
1972 not occur. This may overflow but this doesn't matter. */
\r
1973 xTimeToWake = xTickCount + xTicksToWait;
\r
1975 traceTASK_DELAY_UNTIL();
\r
1976 prvAddCurrentTaskToDelayedList( xTimeToWake );
\r
1979 #endif /* configUSE_TIMERS */
\r
1980 /*-----------------------------------------------------------*/
\r
1982 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
\r
1984 tskTCB *pxUnblockedTCB;
\r
1985 portBASE_TYPE xReturn;
\r
1987 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
\r
1988 SCHEDULER SUSPENDED. It can also be called from within an ISR. */
\r
1990 /* The event list is sorted in priority order, so we can remove the
\r
1991 first in the list, remove the TCB from the delayed list, and add
\r
1992 it to the ready list.
\r
1994 If an event is for a queue that is locked then this function will never
\r
1995 get called - the lock count on the queue will get modified instead. This
\r
1996 means we can always expect exclusive access to the event list here.
\r
1998 This function assumes that a check has already been made to ensure that
\r
1999 pxEventList is not empty. */
\r
2000 pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
\r
2001 configASSERT( pxUnblockedTCB );
\r
2002 ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) );
\r
2004 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
2006 ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) );
\r
2007 prvAddTaskToReadyList( pxUnblockedTCB );
\r
2011 /* We cannot access the delayed or ready lists, so will hold this
\r
2012 task pending until the scheduler is resumed. */
\r
2013 vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
\r
2016 if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
\r
2018 /* Return true if the task removed from the event list has
\r
2019 a higher priority than the calling task. This allows
\r
2020 the calling task to know if it should force a context
\r
2024 /* Mark that a yield is pending in case the user is not using the
\r
2025 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
\r
2026 xYieldPending = pdTRUE;
\r
2030 xReturn = pdFALSE;
\r
2035 /*-----------------------------------------------------------*/
\r
2037 void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
\r
2039 configASSERT( pxTimeOut );
\r
2040 pxTimeOut->xOverflowCount = xNumOfOverflows;
\r
2041 pxTimeOut->xTimeOnEntering = xTickCount;
\r
2043 /*-----------------------------------------------------------*/
\r
2045 portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
\r
2047 portBASE_TYPE xReturn;
\r
2049 configASSERT( pxTimeOut );
\r
2050 configASSERT( pxTicksToWait );
\r
2052 taskENTER_CRITICAL();
\r
2054 /* Minor optimisation. The tick count cannot change in this block. */
\r
2055 const portTickType xConstTickCount = xTickCount;
\r
2057 #if ( INCLUDE_vTaskSuspend == 1 )
\r
2058 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
\r
2059 the maximum block time then the task should block indefinitely, and
\r
2060 therefore never time out. */
\r
2061 if( *pxTicksToWait == portMAX_DELAY )
\r
2063 xReturn = pdFALSE;
\r
2065 else /* We are not blocking indefinitely, perform the checks below. */
\r
2068 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */
\r
2070 /* The tick count is greater than the time at which vTaskSetTimeout()
\r
2071 was called, but has also overflowed since vTaskSetTimeOut() was called.
\r
2072 It must have wrapped all the way around and gone past us again. This
\r
2073 passed since vTaskSetTimeout() was called. */
\r
2076 else if( ( xConstTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait )
\r
2078 /* Not a genuine timeout. Adjust parameters for time remaining. */
\r
2079 *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering );
\r
2080 vTaskSetTimeOutState( pxTimeOut );
\r
2081 xReturn = pdFALSE;
\r
2088 taskEXIT_CRITICAL();
\r
2092 /*-----------------------------------------------------------*/
\r
2094 void vTaskMissedYield( void )
\r
2096 xYieldPending = pdTRUE;
\r
2098 /*-----------------------------------------------------------*/
\r
2100 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2102 unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask )
\r
2104 unsigned portBASE_TYPE uxReturn;
\r
2107 if( xTask != NULL )
\r
2109 pxTCB = ( tskTCB * ) xTask;
\r
2110 uxReturn = pxTCB->uxTaskNumber;
\r
2120 #endif /* configUSE_TRACE_FACILITY */
\r
2121 /*-----------------------------------------------------------*/
\r
2123 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2125 void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle )
\r
2129 if( xTask != NULL )
\r
2131 pxTCB = ( tskTCB * ) xTask;
\r
2132 pxTCB->uxTaskNumber = uxHandle;
\r
2136 #endif /* configUSE_TRACE_FACILITY */
\r
2139 * -----------------------------------------------------------
\r
2141 * ----------------------------------------------------------
\r
2143 * The portTASK_FUNCTION() macro is used to allow port/compiler specific
\r
2144 * language extensions. The equivalent prototype for this function is:
\r
2146 * void prvIdleTask( void *pvParameters );
\r
2149 static portTASK_FUNCTION( prvIdleTask, pvParameters )
\r
2151 /* Stop warnings. */
\r
2152 ( void ) pvParameters;
\r
2156 /* See if any tasks have been deleted. */
\r
2157 prvCheckTasksWaitingTermination();
\r
2159 #if ( configUSE_PREEMPTION == 0 )
\r
2161 /* If we are not using preemption we keep forcing a task switch to
\r
2162 see if any other task has become available. If we are using
\r
2163 preemption we don't need to do this as any task becoming available
\r
2164 will automatically get the processor anyway. */
\r
2167 #endif /* configUSE_PREEMPTION */
\r
2169 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
\r
2171 /* When using preemption tasks of equal priority will be
\r
2172 timesliced. If a task that is sharing the idle priority is ready
\r
2173 to run then the idle task should yield before the end of the
\r
2176 A critical region is not required here as we are just reading from
\r
2177 the list, and an occasional incorrect value will not matter. If
\r
2178 the ready list at the idle priority contains more than one task
\r
2179 then a task other than the idle task is ready to execute. */
\r
2180 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
\r
2185 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
\r
2187 #if ( configUSE_IDLE_HOOK == 1 )
\r
2189 extern void vApplicationIdleHook( void );
\r
2191 /* Call the user defined function from within the idle task. This
\r
2192 allows the application designer to add background functionality
\r
2193 without the overhead of a separate task.
\r
2194 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
\r
2195 CALL A FUNCTION THAT MIGHT BLOCK. */
\r
2196 vApplicationIdleHook();
\r
2198 #endif /* configUSE_IDLE_HOOK */
\r
2200 /* This conditional compilation should use inequality to 0, not equality
\r
2201 to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
\r
2202 user defined low power mode implementations require
\r
2203 configUSE_TICKLESS_IDLE to be set to a value other than 1. */
\r
2204 #if ( configUSE_TICKLESS_IDLE != 0 )
\r
2206 portTickType xExpectedIdleTime;
\r
2208 /* It is not desirable to suspend then resume the scheduler on
\r
2209 each iteration of the idle task. Therefore, a preliminary
\r
2210 test of the expected idle time is performed without the
\r
2211 scheduler suspended. The result here is not necessarily
\r
2213 xExpectedIdleTime = prvGetExpectedIdleTime();
\r
2215 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
\r
2217 vTaskSuspendAll();
\r
2219 /* Now the scheduler is suspended, the expected idle
\r
2220 time can be sampled again, and this time its value can
\r
2222 configASSERT( xNextTaskUnblockTime >= xTickCount );
\r
2223 xExpectedIdleTime = prvGetExpectedIdleTime();
\r
2225 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
\r
2227 traceLOW_POWER_IDLE_BEGIN();
\r
2228 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
\r
2229 traceLOW_POWER_IDLE_END();
\r
2232 ( void ) xTaskResumeAll();
\r
2235 #endif /* configUSE_TICKLESS_IDLE */
\r
2238 /*-----------------------------------------------------------*/
\r
2240 #if configUSE_TICKLESS_IDLE != 0
\r
2242 eSleepModeStatus eTaskConfirmSleepModeStatus( void )
\r
2244 eSleepModeStatus eReturn = eStandardSleep;
\r
2246 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )
\r
2248 /* A task was made ready while the scheduler was suspended. */
\r
2249 eReturn = eAbortSleep;
\r
2251 else if( xYieldPending != pdFALSE )
\r
2253 /* A yield was pended while the scheduler was suspended. */
\r
2254 eReturn = eAbortSleep;
\r
2258 #if configUSE_TIMERS == 0
\r
2260 /* The idle task exists in addition to the application tasks. */
\r
2261 const unsigned portBASE_TYPE uxNonApplicationTasks = 1;
\r
2263 /* If timers are not being used and all the tasks are in the
\r
2264 suspended list (which might mean they have an infinite block
\r
2265 time rather than actually being suspended) then it is safe to
\r
2266 turn all clocks off and just wait for external interrupts. */
\r
2267 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
\r
2269 eReturn = eNoTasksWaitingTimeout;
\r
2272 #endif /* configUSE_TIMERS */
\r
2277 #endif /* configUSE_TICKLESS_IDLE */
\r
2278 /*-----------------------------------------------------------*/
\r
2280 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
\r
2282 unsigned portBASE_TYPE x;
\r
2284 /* Store the task name in the TCB. */
\r
2285 for( x = ( unsigned portBASE_TYPE ) 0; x < ( unsigned portBASE_TYPE ) configMAX_TASK_NAME_LEN; x++ )
\r
2287 pxTCB->pcTaskName[ x ] = pcName[ x ];
\r
2289 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
\r
2290 configMAX_TASK_NAME_LEN characters just in case the memory after the
\r
2291 string is not accessible (extremely unlikely). */
\r
2292 if( pcName[ x ] == 0x00 )
\r
2298 /* Ensure the name string is terminated in the case that the string length
\r
2299 was greater or equal to configMAX_TASK_NAME_LEN. */
\r
2300 pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = ( signed char ) '\0';
\r
2302 /* This is used as an array index so must ensure it's not too large. First
\r
2303 remove the privilege bit if one is present. */
\r
2304 if( uxPriority >= ( unsigned portBASE_TYPE ) configMAX_PRIORITIES )
\r
2306 uxPriority = ( unsigned portBASE_TYPE ) configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U;
\r
2309 pxTCB->uxPriority = uxPriority;
\r
2310 #if ( configUSE_MUTEXES == 1 )
\r
2312 pxTCB->uxBasePriority = uxPriority;
\r
2314 #endif /* configUSE_MUTEXES */
\r
2316 vListInitialiseItem( &( pxTCB->xGenericListItem ) );
\r
2317 vListInitialiseItem( &( pxTCB->xEventListItem ) );
\r
2319 /* Set the pxTCB as a link back from the xListItem. This is so we can get
\r
2320 back to the containing TCB from a generic item in a list. */
\r
2321 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
\r
2323 /* Event lists are always in priority order. */
\r
2324 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( portTickType ) configMAX_PRIORITIES - ( portTickType ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
\r
2325 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
\r
2327 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2329 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0U;
\r
2331 #endif /* portCRITICAL_NESTING_IN_TCB */
\r
2333 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
2335 pxTCB->pxTaskTag = NULL;
\r
2337 #endif /* configUSE_APPLICATION_TASK_TAG */
\r
2339 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
2341 pxTCB->ulRunTimeCounter = 0UL;
\r
2343 #endif /* configGENERATE_RUN_TIME_STATS */
\r
2345 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
2347 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
\r
2349 #else /* portUSING_MPU_WRAPPERS */
\r
2351 ( void ) xRegions;
\r
2352 ( void ) usStackDepth;
\r
2354 #endif /* portUSING_MPU_WRAPPERS */
\r
2356 #if ( configUSE_NEWLIB_REENTRANT == 1 )
\r
2358 /* Initialise this task's Newlib reent structure. */
\r
2359 _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) );
\r
2361 #endif /* configUSE_NEWLIB_REENTRANT */
\r
2363 /*-----------------------------------------------------------*/
\r
2365 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
2367 void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
\r
2371 /* If null is passed in here then we are deleting ourselves. */
\r
2372 pxTCB = prvGetTCBFromHandle( xTaskToModify );
\r
2374 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
\r
2377 #endif /* portUSING_MPU_WRAPPERS */
\r
2378 /*-----------------------------------------------------------*/
\r
2380 static void prvInitialiseTaskLists( void )
\r
2382 unsigned portBASE_TYPE uxPriority;
\r
2384 for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < ( unsigned portBASE_TYPE ) configMAX_PRIORITIES; uxPriority++ )
\r
2386 vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
\r
2389 vListInitialise( &xDelayedTaskList1 );
\r
2390 vListInitialise( &xDelayedTaskList2 );
\r
2391 vListInitialise( &xPendingReadyList );
\r
2393 #if ( INCLUDE_vTaskDelete == 1 )
\r
2395 vListInitialise( &xTasksWaitingTermination );
\r
2397 #endif /* INCLUDE_vTaskDelete */
\r
2399 #if ( INCLUDE_vTaskSuspend == 1 )
\r
2401 vListInitialise( &xSuspendedTaskList );
\r
2403 #endif /* INCLUDE_vTaskSuspend */
\r
2405 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
\r
2407 pxDelayedTaskList = &xDelayedTaskList1;
\r
2408 pxOverflowDelayedTaskList = &xDelayedTaskList2;
\r
2410 /*-----------------------------------------------------------*/
\r
2412 static void prvCheckTasksWaitingTermination( void )
\r
2414 #if ( INCLUDE_vTaskDelete == 1 )
\r
2416 portBASE_TYPE xListIsEmpty;
\r
2418 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
\r
2419 too often in the idle task. */
\r
2420 while( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0U )
\r
2422 vTaskSuspendAll();
\r
2423 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
\r
2424 ( void ) xTaskResumeAll();
\r
2426 if( xListIsEmpty == pdFALSE )
\r
2430 taskENTER_CRITICAL();
\r
2432 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
\r
2433 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
\r
2434 --uxCurrentNumberOfTasks;
\r
2437 taskEXIT_CRITICAL();
\r
2439 prvDeleteTCB( pxTCB );
\r
2443 #endif /* vTaskDelete */
\r
2445 /*-----------------------------------------------------------*/
\r
2447 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake )
\r
2449 /* The list item will be inserted in wake time order. */
\r
2450 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
\r
2452 if( xTimeToWake < xTickCount )
\r
2454 /* Wake time has overflowed. Place this item in the overflow list. */
\r
2455 vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) );
\r
2459 /* The wake time has not overflowed, so we can use the current block list. */
\r
2460 vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) );
\r
2462 /* If the task entering the blocked state was placed at the head of the
\r
2463 list of blocked tasks then xNextTaskUnblockTime needs to be updated
\r
2465 if( xTimeToWake < xNextTaskUnblockTime )
\r
2467 xNextTaskUnblockTime = xTimeToWake;
\r
2471 /*-----------------------------------------------------------*/
\r
2473 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
\r
2477 /* Allocate space for the TCB. Where the memory comes from depends on
\r
2478 the implementation of the port malloc function. */
\r
2479 pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
\r
2481 if( pxNewTCB != NULL )
\r
2483 /* Allocate space for the stack used by the task being created.
\r
2484 The base of the stack memory stored in the TCB so the task can
\r
2485 be deleted later if required. */
\r
2486 pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
\r
2488 if( pxNewTCB->pxStack == NULL )
\r
2490 /* Could not allocate the stack. Delete the allocated TCB. */
\r
2491 vPortFree( pxNewTCB );
\r
2496 /* Just to help debugging. */
\r
2497 ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( portSTACK_TYPE ) );
\r
2503 /*-----------------------------------------------------------*/
\r
2505 #if ( configUSE_TRACE_FACILITY == 1 )
\r
2507 static unsigned portBASE_TYPE prvListTaskWithinSingleList( xTaskStatusType *pxTaskStatusArray, xList *pxList, eTaskState eState )
\r
2509 volatile tskTCB *pxNextTCB, *pxFirstTCB;
\r
2510 unsigned portBASE_TYPE uxTask = 0;
\r
2512 if( listCURRENT_LIST_LENGTH( pxList ) > ( unsigned portBASE_TYPE ) 0 )
\r
2514 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
\r
2516 /* Populate an xTaskStatusType structure within the
\r
2517 pxTaskStatusArray array for each task that is referenced from
\r
2518 pxList. See the definition of xTaskStatusType in task.h for the
\r
2519 meaning of each xTaskStatusType structure member. */
\r
2522 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
\r
2524 pxTaskStatusArray[ uxTask ].xHandle = ( xTaskHandle ) pxNextTCB;
\r
2525 pxTaskStatusArray[ uxTask ].pcTaskName = ( const signed char * ) &( pxNextTCB->pcTaskName [ 0 ] );
\r
2526 pxTaskStatusArray[ uxTask ].xTaskNumber = pxNextTCB->uxTCBNumber;
\r
2527 pxTaskStatusArray[ uxTask ].eCurrentState = eState;
\r
2528 pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority;
\r
2530 #if ( configUSE_MUTEXES == 1 )
\r
2532 pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority;
\r
2536 pxTaskStatusArray[ uxTask ].uxBasePriority = 0;
\r
2540 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
2542 pxTaskStatusArray[ uxTask ].ulRunTimeCounter = pxNextTCB->ulRunTimeCounter;
\r
2546 pxTaskStatusArray[ uxTask ].ulRunTimeCounter = 0;
\r
2550 #if ( portSTACK_GROWTH > 0 )
\r
2552 ppxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );
\r
2556 pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );
\r
2562 } while( pxNextTCB != pxFirstTCB );
\r
2568 #endif /* configUSE_TRACE_FACILITY */
\r
2569 /*-----------------------------------------------------------*/
\r
2571 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
\r
2573 static unsigned short prvTaskCheckFreeStackSpace( const unsigned char * pucStackByte )
\r
2575 unsigned short usCount = 0U;
\r
2577 while( *pucStackByte == tskSTACK_FILL_BYTE )
\r
2579 pucStackByte -= portSTACK_GROWTH;
\r
2583 usCount /= sizeof( portSTACK_TYPE );
\r
2588 #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */
\r
2589 /*-----------------------------------------------------------*/
\r
2591 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
\r
2593 unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
\r
2596 unsigned char *pcEndOfStack;
\r
2597 unsigned portBASE_TYPE uxReturn;
\r
2599 pxTCB = prvGetTCBFromHandle( xTask );
\r
2601 #if portSTACK_GROWTH < 0
\r
2603 pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;
\r
2607 pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;
\r
2611 uxReturn = ( unsigned portBASE_TYPE ) prvTaskCheckFreeStackSpace( pcEndOfStack );
\r
2616 #endif /* INCLUDE_uxTaskGetStackHighWaterMark */
\r
2617 /*-----------------------------------------------------------*/
\r
2619 #if ( INCLUDE_vTaskDelete == 1 )
\r
2621 static void prvDeleteTCB( tskTCB *pxTCB )
\r
2623 /* This call is required specifically for the TriCore port. It must be
\r
2624 above the vPortFree() calls. The call is also used by ports/demos that
\r
2625 want to allocate and clean RAM statically. */
\r
2626 portCLEAN_UP_TCB( pxTCB );
\r
2628 /* Free up the memory allocated by the scheduler for the task. It is up to
\r
2629 the task to free any memory allocated at the application level. */
\r
2630 vPortFreeAligned( pxTCB->pxStack );
\r
2631 vPortFree( pxTCB );
\r
2634 #endif /* INCLUDE_vTaskDelete */
\r
2635 /*-----------------------------------------------------------*/
\r
2637 #if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
\r
2639 xTaskHandle xTaskGetCurrentTaskHandle( void )
\r
2641 xTaskHandle xReturn;
\r
2643 /* A critical section is not required as this is not called from
\r
2644 an interrupt and the current TCB will always be the same for any
\r
2645 individual execution thread. */
\r
2646 xReturn = pxCurrentTCB;
\r
2651 #endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
\r
2652 /*-----------------------------------------------------------*/
\r
2654 #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
\r
2656 portBASE_TYPE xTaskGetSchedulerState( void )
\r
2658 portBASE_TYPE xReturn;
\r
2660 if( xSchedulerRunning == pdFALSE )
\r
2662 xReturn = taskSCHEDULER_NOT_STARTED;
\r
2666 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
\r
2668 xReturn = taskSCHEDULER_RUNNING;
\r
2672 xReturn = taskSCHEDULER_SUSPENDED;
\r
2679 #endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */
\r
2680 /*-----------------------------------------------------------*/
\r
2682 #if ( configUSE_MUTEXES == 1 )
\r
2684 void vTaskPriorityInherit( xTaskHandle const pxMutexHolder )
\r
2686 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2688 /* If the mutex was given back by an interrupt while the queue was
\r
2689 locked then the mutex holder might now be NULL. */
\r
2690 if( pxMutexHolder != NULL )
\r
2692 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
\r
2694 /* Adjust the mutex holder state to account for its new priority. */
\r
2695 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( portTickType ) configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
\r
2697 /* If the task being modified is in the ready state it will need to
\r
2698 be moved into a new list. */
\r
2699 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE )
\r
2701 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 )
\r
2703 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
2706 /* Inherit the priority before being moved into the new list. */
\r
2707 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2708 prvAddTaskToReadyList( pxTCB );
\r
2712 /* Just inherit the priority. */
\r
2713 pxTCB->uxPriority = pxCurrentTCB->uxPriority;
\r
2716 traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );
\r
2721 #endif /* configUSE_MUTEXES */
\r
2722 /*-----------------------------------------------------------*/
\r
2724 #if ( configUSE_MUTEXES == 1 )
\r
2726 void vTaskPriorityDisinherit( xTaskHandle const pxMutexHolder )
\r
2728 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
\r
2730 if( pxMutexHolder != NULL )
\r
2732 if( pxTCB->uxPriority != pxTCB->uxBasePriority )
\r
2734 /* We must be the running task to be able to give the mutex back.
\r
2735 Remove ourselves from the ready list we currently appear in. */
\r
2736 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 )
\r
2738 taskRESET_READY_PRIORITY( pxTCB->uxPriority );
\r
2741 /* Disinherit the priority before adding the task into the new
\r
2743 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
\r
2744 pxTCB->uxPriority = pxTCB->uxBasePriority;
\r
2745 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( portTickType ) configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
\r
2746 prvAddTaskToReadyList( pxTCB );
\r
2751 #endif /* configUSE_MUTEXES */
\r
2752 /*-----------------------------------------------------------*/
\r
2754 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2756 void vTaskEnterCritical( void )
\r
2758 portDISABLE_INTERRUPTS();
\r
2760 if( xSchedulerRunning != pdFALSE )
\r
2762 ( pxCurrentTCB->uxCriticalNesting )++;
\r
2766 #endif /* portCRITICAL_NESTING_IN_TCB */
\r
2767 /*-----------------------------------------------------------*/
\r
2769 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
2771 void vTaskExitCritical( void )
\r
2773 if( xSchedulerRunning != pdFALSE )
\r
2775 if( pxCurrentTCB->uxCriticalNesting > 0U )
\r
2777 ( pxCurrentTCB->uxCriticalNesting )--;
\r
2779 if( pxCurrentTCB->uxCriticalNesting == 0U )
\r
2781 portENABLE_INTERRUPTS();
\r
2787 #endif /* portCRITICAL_NESTING_IN_TCB */
\r
2788 /*-----------------------------------------------------------*/
\r
2790 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) )
\r
2792 void vTaskList( signed char *pcWriteBuffer )
\r
2794 xTaskStatusType *pxTaskStatusArray;
\r
2795 volatile unsigned portBASE_TYPE uxArraySize, x;
\r
2801 * This function is provided for convenience only, and is used by many
\r
2802 * of the demo applications. Do not consider it to be part of the
\r
2805 * vTaskList() calls uxTaskGetSystemState(), then formats part of the
\r
2806 * uxTaskGetSystemState() output into a human readable table that
\r
2807 * displays task names, states and stack usage.
\r
2809 * vTaskList() has a dependency on the sprintf() C library function that
\r
2810 * might bloat the code size, use a lot of stack, and provide different
\r
2811 * results on different platforms. An alternative, tiny, third party,
\r
2812 * and limited functionality implementation of sprintf() is provided in
\r
2813 * many of the FreeRTOS/Demo sub-directories in a file called
\r
2814 * printf-stdarg.c (note printf-stdarg.c does not provide a full
\r
2815 * snprintf() implementation!).
\r
2817 * It is recommended that production systems call uxTaskGetSystemState()
\r
2818 * directly to get access to raw stats data, rather than indirectly
\r
2819 * through a call to vTaskList().
\r
2823 /* Make sure the write buffer does not contain a string. */
\r
2824 *pcWriteBuffer = 0x00;
\r
2826 /* Take a snapshot of the number of tasks in case it changes while this
\r
2827 function is executing. */
\r
2828 uxArraySize = uxCurrentNumberOfTasks;
\r
2830 /* Allocate an array index for each task. */
\r
2831 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) );
\r
2833 if( pxTaskStatusArray != NULL )
\r
2835 /* Generate the (binary) data. */
\r
2836 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL );
\r
2838 /* Create a human readable table from the binary data. */
\r
2839 for( x = 0; x < uxArraySize; x++ )
\r
2841 switch( pxTaskStatusArray[ x ].eCurrentState )
\r
2843 case eReady: cStatus = tskREADY_CHAR;
\r
2846 case eBlocked: cStatus = tskBLOCKED_CHAR;
\r
2849 case eSuspended: cStatus = tskSUSPENDED_CHAR;
\r
2852 case eDeleted: cStatus = tskDELETED_CHAR;
\r
2855 default: /* Should not get here, but it is included
\r
2856 to prevent static checking errors. */
\r
2861 sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxTaskStatusArray[ x ].pcTaskName, cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber );
\r
2862 pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );
\r
2865 /* Free the array again. */
\r
2866 vPortFree( pxTaskStatusArray );
\r
2870 #endif /* configUSE_TRACE_FACILITY */
\r
2871 /*----------------------------------------------------------*/
\r
2873 #if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) )
\r
2875 void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
\r
2877 xTaskStatusType *pxTaskStatusArray;
\r
2878 volatile unsigned portBASE_TYPE uxArraySize, x;
\r
2879 unsigned long ulTotalTime, ulStatsAsPercentage;
\r
2884 * This function is provided for convenience only, and is used by many
\r
2885 * of the demo applications. Do not consider it to be part of the
\r
2888 * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part
\r
2889 * of the uxTaskGetSystemState() output into a human readable table that
\r
2890 * displays the amount of time each task has spent in the Running state
\r
2891 * in both absolute and percentage terms.
\r
2893 * vTaskGetRunTimeStats() has a dependency on the sprintf() C library
\r
2894 * function that might bloat the code size, use a lot of stack, and
\r
2895 * provide different results on different platforms. An alternative,
\r
2896 * tiny, third party, and limited functionality implementation of
\r
2897 * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in
\r
2898 * a file called printf-stdarg.c (note printf-stdarg.c does not provide
\r
2899 * a full snprintf() implementation!).
\r
2901 * It is recommended that production systems call uxTaskGetSystemState()
\r
2902 * directly to get access to raw stats data, rather than indirectly
\r
2903 * through a call to vTaskGetRunTimeStats().
\r
2906 /* Make sure the write buffer does not contain a string. */
\r
2907 *pcWriteBuffer = 0x00;
\r
2909 /* Take a snapshot of the number of tasks in case it changes while this
\r
2910 function is executing. */
\r
2911 uxArraySize = uxCurrentNumberOfTasks;
\r
2913 /* Allocate an array index for each task. */
\r
2914 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) );
\r
2916 if( pxTaskStatusArray != NULL )
\r
2918 /* Generate the (binary) data. */
\r
2919 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime );
\r
2921 /* For percentage calculations. */
\r
2922 ulTotalTime /= 100UL;
\r
2924 /* Avoid divide by zero errors. */
\r
2925 if( ulTotalTime > 0 )
\r
2927 /* Create a human readable table from the binary data. */
\r
2928 for( x = 0; x < uxArraySize; x++ )
\r
2930 /* What percentage of the total run time has the task used?
\r
2931 This will always be rounded down to the nearest integer.
\r
2932 ulTotalRunTimeDiv100 has already been divided by 100. */
\r
2933 ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime;
\r
2935 if( ulStatsAsPercentage > 0UL )
\r
2937 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
\r
2939 sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
\r
2943 /* sizeof( int ) == sizeof( long ) so a smaller
\r
2944 printf() library can be used. */
\r
2945 sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
\r
2951 /* If the percentage is zero here then the task has
\r
2952 consumed less than 1% of the total run time. */
\r
2953 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED
\r
2955 sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter );
\r
2959 /* sizeof( int ) == sizeof( long ) so a smaller
\r
2960 printf() library can be used. */
\r
2961 sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter );
\r
2966 pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );
\r
2970 /* Free the array again. */
\r
2971 vPortFree( pxTaskStatusArray );
\r
2975 #endif /* configGENERATE_RUN_TIME_STATS */
\r