Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Nucleo freertos_test FreeRTOS_test freertos_bluetooth ... more
tasks.c
00001 /* 00002 FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. 00003 All rights reserved 00004 00005 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. 00006 00007 *************************************************************************** 00008 * * 00009 * FreeRTOS provides completely free yet professionally developed, * 00010 * robust, strictly quality controlled, supported, and cross * 00011 * platform software that has become a de facto standard. * 00012 * * 00013 * Help yourself get started quickly and support the FreeRTOS * 00014 * project by purchasing a FreeRTOS tutorial book, reference * 00015 * manual, or both from: http://www.FreeRTOS.org/Documentation * 00016 * * 00017 * Thank you! * 00018 * * 00019 *************************************************************************** 00020 00021 This file is part of the FreeRTOS distribution. 00022 00023 FreeRTOS is free software; you can redistribute it and/or modify it under 00024 the terms of the GNU General Public License (version 2) as published by the 00025 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. 00026 00027 >>! NOTE: The modification to the GPL is included to allow you to distribute 00028 >>! a combined work that includes FreeRTOS without being obliged to provide 00029 >>! the source code for proprietary components outside of the FreeRTOS 00030 >>! kernel. 00031 00032 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY 00033 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00034 FOR A PARTICULAR PURPOSE. Full license text is available from the following 00035 link: http://www.freertos.org/a00114.html 00036 00037 1 tab == 4 spaces! 00038 00039 *************************************************************************** 00040 * * 00041 * Having a problem? Start by reading the FAQ "My application does * 00042 * not run, what could be wrong?" * 00043 * * 00044 * http://www.FreeRTOS.org/FAQHelp.html * 00045 * * 00046 *************************************************************************** 00047 00048 http://www.FreeRTOS.org - Documentation, books, training, latest versions, 00049 license and Real Time Engineers Ltd. contact details. 00050 00051 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, 00052 including FreeRTOS+Trace - an indispensable productivity tool, a DOS 00053 compatible FAT file system, and our tiny thread aware UDP/IP stack. 00054 00055 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High 00056 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS 00057 licenses offer ticketed support, indemnification and middleware. 00058 00059 http://www.SafeRTOS.com - High Integrity Systems also provide a safety 00060 engineered and independently SIL3 certified version for use in safety and 00061 mission critical applications that require provable dependability. 00062 00063 1 tab == 4 spaces! 00064 */ 00065 00066 /* Standard includes. */ 00067 #include <stdlib.h> 00068 #include <string.h> 00069 00070 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining 00071 all the API functions to use the MPU wrappers. That should only be done when 00072 task.h is included from an application file. */ 00073 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE 00074 00075 /* FreeRTOS includes. */ 00076 #include "FreeRTOS.h" 00077 #include "task.h" 00078 #include "timers.h" 00079 #include "StackMacros.h" 00080 00081 /* Lint e961 and e750 are suppressed as a MISRA exception justified because the 00082 MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the 00083 header files above, but not in this file, in order to generate the correct 00084 privileged Vs unprivileged linkage and placement. */ 00085 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ 00086 00087 #if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) 00088 /* At the bottom of this file are two optional functions that can be used 00089 to generate human readable text from the raw data generated by the 00090 uxTaskGetSystemState() function. Note the formatting functions are provided 00091 for convenience only, and are NOT considered part of the kernel. */ 00092 #include <stdio.h> 00093 #endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */ 00094 00095 /* Sanity check the configuration. */ 00096 #if configUSE_TICKLESS_IDLE != 0 00097 #if INCLUDE_vTaskSuspend != 1 00098 #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0 00099 #endif /* INCLUDE_vTaskSuspend */ 00100 #endif /* configUSE_TICKLESS_IDLE */ 00101 00102 /* 00103 * Defines the size, in words, of the stack allocated to the idle task. 00104 */ 00105 #define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE 00106 00107 #if( configUSE_PREEMPTION == 0 ) 00108 /* If the cooperative scheduler is being used then a yield should not be 00109 performed just because a higher priority task has been woken. */ 00110 #define taskYIELD_IF_USING_PREEMPTION() 00111 #else 00112 #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() 00113 #endif 00114 00115 /* 00116 * Task control block. A task control block (TCB) is allocated for each task, 00117 * and stores task state information, including a pointer to the task's context 00118 * (the task's run time environment, including register values) 00119 */ 00120 typedef struct tskTaskControlBlock 00121 { 00122 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. */ 00123 00124 #if ( portUSING_MPU_WRAPPERS == 1 ) 00125 xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ 00126 #endif 00127 00128 xListItem xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ 00129 xListItem xEventListItem; /*< Used to reference a task from an event list. */ 00130 unsigned portBASE_TYPE uxPriority; /*< The priority of the task. 0 is the lowest priority. */ 00131 portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */ 00132 signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ 00133 00134 #if ( portSTACK_GROWTH > 0 ) 00135 portSTACK_TYPE *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ 00136 #endif 00137 00138 #if ( portCRITICAL_NESTING_IN_TCB == 1 ) 00139 unsigned portBASE_TYPE uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ 00140 #endif 00141 00142 #if ( configUSE_TRACE_FACILITY == 1 ) 00143 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. */ 00144 unsigned portBASE_TYPE uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ 00145 #endif 00146 00147 #if ( configUSE_MUTEXES == 1 ) 00148 unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ 00149 #endif 00150 00151 #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 00152 pdTASK_HOOK_CODE pxTaskTag; 00153 #endif 00154 00155 #if ( configGENERATE_RUN_TIME_STATS == 1 ) 00156 unsigned long ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ 00157 #endif 00158 00159 #if ( configUSE_NEWLIB_REENTRANT == 1 ) 00160 /* Allocate a Newlib reent structure that is specific to this task. 00161 Note Newlib support has been included by popular demand, but is not 00162 used by the FreeRTOS maintainers themselves. FreeRTOS is not 00163 responsible for resulting newlib operation. User must be familiar with 00164 newlib and must provide system-wide implementations of the necessary 00165 stubs. Be warned that (at the time of writing) the current newlib design 00166 implements a system-wide malloc() that must be provided with locks. */ 00167 struct _reent xNewLib_reent; 00168 #endif 00169 00170 } tskTCB; 00171 00172 00173 /* 00174 * Some kernel aware debuggers require the data the debugger needs access to to 00175 * be global, rather than file scope. 00176 */ 00177 #ifdef portREMOVE_STATIC_QUALIFIER 00178 #define static 00179 #endif 00180 00181 /*lint -e956 A manual analysis and inspection has been used to determine which 00182 static variables must be declared volatile. */ 00183 00184 PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL; 00185 00186 /* Lists for ready and blocked tasks. --------------------*/ 00187 PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */ 00188 PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */ 00189 PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ 00190 PRIVILEGED_DATA static xList * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */ 00191 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. */ 00192 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. */ 00193 00194 #if ( INCLUDE_vTaskDelete == 1 ) 00195 00196 PRIVILEGED_DATA static xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */ 00197 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0U; 00198 00199 #endif 00200 00201 #if ( INCLUDE_vTaskSuspend == 1 ) 00202 00203 PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */ 00204 00205 #endif 00206 00207 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) 00208 00209 PRIVILEGED_DATA static xTaskHandle xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ 00210 00211 #endif 00212 00213 /* Other file private variables. --------------------------------*/ 00214 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0U; 00215 PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0U; 00216 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY; 00217 PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE; 00218 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE; 00219 PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxPendedTicks = ( unsigned portBASE_TYPE ) 0U; 00220 PRIVILEGED_DATA static volatile portBASE_TYPE xYieldPending = pdFALSE; 00221 PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0; 00222 PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0U; 00223 PRIVILEGED_DATA static volatile portTickType xNextTaskUnblockTime = portMAX_DELAY; 00224 00225 #if ( configGENERATE_RUN_TIME_STATS == 1 ) 00226 00227 PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ 00228 PRIVILEGED_DATA static unsigned long ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ 00229 00230 #endif 00231 00232 /*lint +e956 */ 00233 00234 /* Debugging and trace facilities private variables and macros. ------------*/ 00235 00236 /* 00237 * The value used to fill the stack of a task when the task is created. This 00238 * is used purely for checking the high water mark for tasks. 00239 */ 00240 #define tskSTACK_FILL_BYTE ( 0xa5U ) 00241 00242 /* 00243 * Macros used by vListTask to indicate which state a task is in. 00244 */ 00245 #define tskBLOCKED_CHAR ( ( signed char ) 'B' ) 00246 #define tskREADY_CHAR ( ( signed char ) 'R' ) 00247 #define tskDELETED_CHAR ( ( signed char ) 'D' ) 00248 #define tskSUSPENDED_CHAR ( ( signed char ) 'S' ) 00249 00250 /*-----------------------------------------------------------*/ 00251 00252 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) 00253 00254 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is 00255 performed in a generic way that is not optimised to any particular 00256 microcontroller architecture. */ 00257 00258 /* uxTopReadyPriority holds the priority of the highest priority ready 00259 state task. */ 00260 #define taskRECORD_READY_PRIORITY( uxPriority ) \ 00261 { \ 00262 if( ( uxPriority ) > uxTopReadyPriority ) \ 00263 { \ 00264 uxTopReadyPriority = ( uxPriority ); \ 00265 } \ 00266 } /* taskRECORD_READY_PRIORITY */ 00267 00268 /*-----------------------------------------------------------*/ 00269 00270 #define taskSELECT_HIGHEST_PRIORITY_TASK() \ 00271 { \ 00272 /* Find the highest priority queue that contains ready tasks. */ \ 00273 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) \ 00274 { \ 00275 configASSERT( uxTopReadyPriority ); \ 00276 --uxTopReadyPriority; \ 00277 } \ 00278 \ 00279 /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ 00280 the same priority get an equal share of the processor time. */ \ 00281 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \ 00282 } /* taskSELECT_HIGHEST_PRIORITY_TASK */ 00283 00284 /*-----------------------------------------------------------*/ 00285 00286 /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as 00287 they are only required when a port optimised method of task selection is 00288 being used. */ 00289 #define taskRESET_READY_PRIORITY( uxPriority ) 00290 #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority ) 00291 00292 #else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ 00293 00294 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is 00295 performed in a way that is tailored to the particular microcontroller 00296 architecture being used. */ 00297 00298 /* A port optimised version is provided. Call the port defined macros. */ 00299 #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority ) 00300 00301 /*-----------------------------------------------------------*/ 00302 00303 #define taskSELECT_HIGHEST_PRIORITY_TASK() \ 00304 { \ 00305 unsigned portBASE_TYPE uxTopPriority; \ 00306 \ 00307 /* Find the highest priority queue that contains ready tasks. */ \ 00308 portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ 00309 configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ 00310 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ 00311 } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ 00312 00313 /*-----------------------------------------------------------*/ 00314 00315 /* A port optimised version is provided, call it only if the TCB being reset 00316 is being referenced from a ready list. If it is referenced from a delayed 00317 or suspended list then it won't be in a ready list. */ 00318 #define taskRESET_READY_PRIORITY( uxPriority ) \ 00319 { \ 00320 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == 0 ) \ 00321 { \ 00322 portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \ 00323 } \ 00324 } 00325 00326 #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ 00327 00328 /*-----------------------------------------------------------*/ 00329 00330 /* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick 00331 count overflows. */ 00332 #define taskSWITCH_DELAYED_LISTS() \ 00333 { \ 00334 xList *pxTemp; \ 00335 \ 00336 /* The delayed tasks list should be empty when the lists are switched. */ \ 00337 configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \ 00338 \ 00339 pxTemp = pxDelayedTaskList; \ 00340 pxDelayedTaskList = pxOverflowDelayedTaskList; \ 00341 pxOverflowDelayedTaskList = pxTemp; \ 00342 xNumOfOverflows++; \ 00343 \ 00344 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \ 00345 { \ 00346 /* The new current delayed list is empty. Set \ 00347 xNextTaskUnblockTime to the maximum possible value so it is \ 00348 extremely unlikely that the \ 00349 if( xTickCount >= xNextTaskUnblockTime ) test will pass until \ 00350 there is an item in the delayed list. */ \ 00351 xNextTaskUnblockTime = portMAX_DELAY; \ 00352 } \ 00353 else \ 00354 { \ 00355 /* The new current delayed list is not empty, get the value of \ 00356 the item at the head of the delayed list. This is the time at \ 00357 which the task at the head of the delayed list should be removed \ 00358 from the Blocked state. */ \ 00359 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \ 00360 xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \ 00361 } \ 00362 } 00363 00364 /*-----------------------------------------------------------*/ 00365 00366 /* 00367 * Place the task represented by pxTCB into the appropriate ready list for 00368 * the task. It is inserted at the end of the list. 00369 */ 00370 #define prvAddTaskToReadyList( pxTCB ) \ 00371 traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ 00372 taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \ 00373 vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) ) 00374 /*-----------------------------------------------------------*/ 00375 00376 /* 00377 * Several functions take an xTaskHandle parameter that can optionally be NULL, 00378 * where NULL is used to indicate that the handle of the currently executing 00379 * task should be used in place of the parameter. This macro simply checks to 00380 * see if the parameter is NULL and returns a pointer to the appropriate TCB. 00381 */ 00382 #define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) ( pxHandle ) ) 00383 00384 /* Callback function prototypes. --------------------------*/ 00385 extern void vApplicationStackOverflowHook( xTaskHandle xTask, signed char *pcTaskName ); 00386 extern void vApplicationTickHook( void ); 00387 00388 /* File private functions. --------------------------------*/ 00389 00390 /* 00391 * Utility to ready a TCB for a given task. Mainly just copies the parameters 00392 * into the TCB structure. 00393 */ 00394 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION; 00395 00396 /* 00397 * Utility to ready all the lists used by the scheduler. This is called 00398 * automatically upon the creation of the first task. 00399 */ 00400 static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; 00401 00402 /* 00403 * The idle task, which as all tasks is implemented as a never ending loop. 00404 * The idle task is automatically created and added to the ready lists upon 00405 * creation of the first user task. 00406 * 00407 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific 00408 * language extensions. The equivalent prototype for this function is: 00409 * 00410 * void prvIdleTask( void *pvParameters ); 00411 * 00412 */ 00413 static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ); 00414 00415 /* 00416 * Utility to free all memory allocated by the scheduler to hold a TCB, 00417 * including the stack pointed to by the TCB. 00418 * 00419 * This does not free memory allocated by the task itself (i.e. memory 00420 * allocated by calls to pvPortMalloc from within the tasks application code). 00421 */ 00422 #if ( INCLUDE_vTaskDelete == 1 ) 00423 00424 static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION; 00425 00426 #endif 00427 00428 /* 00429 * Used only by the idle task. This checks to see if anything has been placed 00430 * in the list of tasks waiting to be deleted. If so the task is cleaned up 00431 * and its TCB deleted. 00432 */ 00433 static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; 00434 00435 /* 00436 * The currently executing task is entering the Blocked state. Add the task to 00437 * either the current or the overflow delayed task list. 00438 */ 00439 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION; 00440 00441 /* 00442 * Allocates memory from the heap for a TCB and associated stack. Checks the 00443 * allocation was successful. 00444 */ 00445 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION; 00446 00447 /* 00448 * Fills an xTaskStatusType structure with information on each task that is 00449 * referenced from the pxList list (which may be a ready list, a delayed list, 00450 * a suspended list, etc.). 00451 * 00452 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM 00453 * NORMAL APPLICATION CODE. 00454 */ 00455 #if ( configUSE_TRACE_FACILITY == 1 ) 00456 00457 static unsigned portBASE_TYPE prvListTaskWithinSingleList( xTaskStatusType *pxTaskStatusArray, xList *pxList, eTaskState eState ) PRIVILEGED_FUNCTION; 00458 00459 #endif 00460 00461 /* 00462 * When a task is created, the stack of the task is filled with a known value. 00463 * This function determines the 'high water mark' of the task stack by 00464 * determining how much of the stack remains at the original preset value. 00465 */ 00466 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) 00467 00468 static unsigned short prvTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION; 00469 00470 #endif 00471 00472 /* 00473 * Return the amount of time, in ticks, that will pass before the kernel will 00474 * next move a task from the Blocked state to the Running state. 00475 * 00476 * This conditional compilation should use inequality to 0, not equality to 1. 00477 * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user 00478 * defined low power mode implementations require configUSE_TICKLESS_IDLE to be 00479 * set to a value other than 1. 00480 */ 00481 #if ( configUSE_TICKLESS_IDLE != 0 ) 00482 00483 static portTickType prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION; 00484 00485 #endif 00486 00487 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 ) 00488 { 00489 signed portBASE_TYPE xReturn; 00490 tskTCB * pxNewTCB; 00491 00492 configASSERT( pxTaskCode ); 00493 configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) ); 00494 00495 /* Allocate the memory required by the TCB and stack for the new task, 00496 checking that the allocation was successful. */ 00497 pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer ); 00498 00499 if( pxNewTCB != NULL ) 00500 { 00501 portSTACK_TYPE *pxTopOfStack; 00502 00503 #if( portUSING_MPU_WRAPPERS == 1 ) 00504 /* Should the task be created in privileged mode? */ 00505 portBASE_TYPE xRunPrivileged; 00506 if( ( uxPriority & portPRIVILEGE_BIT ) != 0U ) 00507 { 00508 xRunPrivileged = pdTRUE; 00509 } 00510 else 00511 { 00512 xRunPrivileged = pdFALSE; 00513 } 00514 uxPriority &= ~portPRIVILEGE_BIT; 00515 #endif /* portUSING_MPU_WRAPPERS == 1 */ 00516 00517 /* Calculate the top of stack address. This depends on whether the 00518 stack grows from high memory to low (as per the 80x86) or visa versa. 00519 portSTACK_GROWTH is used to make the result positive or negative as 00520 required by the port. */ 00521 #if( portSTACK_GROWTH < 0 ) 00522 { 00523 pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 ); 00524 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. */ 00525 00526 /* Check the alignment of the calculated top of stack is correct. */ 00527 configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); 00528 } 00529 #else /* portSTACK_GROWTH */ 00530 { 00531 pxTopOfStack = pxNewTCB->pxStack; 00532 00533 /* Check the alignment of the stack buffer is correct. */ 00534 configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); 00535 00536 /* If we want to use stack checking on architectures that use 00537 a positive stack growth direction then we also need to store the 00538 other extreme of the stack space. */ 00539 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ); 00540 } 00541 #endif /* portSTACK_GROWTH */ 00542 00543 /* Setup the newly allocated TCB with the initial state of the task. */ 00544 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth ); 00545 00546 /* Initialize the TCB stack to look as if the task was already running, 00547 but had been interrupted by the scheduler. The return address is set 00548 to the start of the task function. Once the stack has been initialised 00549 the top of stack variable is updated. */ 00550 #if( portUSING_MPU_WRAPPERS == 1 ) 00551 { 00552 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); 00553 } 00554 #else /* portUSING_MPU_WRAPPERS */ 00555 { 00556 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); 00557 } 00558 #endif /* portUSING_MPU_WRAPPERS */ 00559 00560 if( ( void * ) pxCreatedTask != NULL ) 00561 { 00562 /* Pass the TCB out - in an anonymous way. The calling function/ 00563 task can use this as a handle to delete the task later if 00564 required.*/ 00565 *pxCreatedTask = ( xTaskHandle ) pxNewTCB; 00566 } 00567 00568 /* Ensure interrupts don't access the task lists while they are being 00569 updated. */ 00570 taskENTER_CRITICAL(); 00571 { 00572 uxCurrentNumberOfTasks++; 00573 if( pxCurrentTCB == NULL ) 00574 { 00575 /* There are no other tasks, or all the other tasks are in 00576 the suspended state - make this the current task. */ 00577 pxCurrentTCB = pxNewTCB; 00578 00579 if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 ) 00580 { 00581 /* This is the first task to be created so do the preliminary 00582 initialisation required. We will not recover if this call 00583 fails, but we will report the failure. */ 00584 prvInitialiseTaskLists(); 00585 } 00586 } 00587 else 00588 { 00589 /* If the scheduler is not already running, make this task the 00590 current task if it is the highest priority task to be created 00591 so far. */ 00592 if( xSchedulerRunning == pdFALSE ) 00593 { 00594 if( pxCurrentTCB->uxPriority <= uxPriority ) 00595 { 00596 pxCurrentTCB = pxNewTCB; 00597 } 00598 } 00599 } 00600 00601 uxTaskNumber++; 00602 00603 #if ( configUSE_TRACE_FACILITY == 1 ) 00604 { 00605 /* Add a counter into the TCB for tracing only. */ 00606 pxNewTCB->uxTCBNumber = uxTaskNumber; 00607 } 00608 #endif /* configUSE_TRACE_FACILITY */ 00609 traceTASK_CREATE( pxNewTCB ); 00610 00611 prvAddTaskToReadyList( pxNewTCB ); 00612 00613 xReturn = pdPASS; 00614 portSETUP_TCB( pxNewTCB ); 00615 } 00616 taskEXIT_CRITICAL(); 00617 } 00618 else 00619 { 00620 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; 00621 traceTASK_CREATE_FAILED(); 00622 } 00623 00624 if( xReturn == pdPASS ) 00625 { 00626 if( xSchedulerRunning != pdFALSE ) 00627 { 00628 /* If the created task is of a higher priority than the current task 00629 then it should run now. */ 00630 if( pxCurrentTCB->uxPriority < uxPriority ) 00631 { 00632 taskYIELD_IF_USING_PREEMPTION(); 00633 } 00634 } 00635 } 00636 00637 return xReturn; 00638 } 00639 /*-----------------------------------------------------------*/ 00640 00641 #if ( INCLUDE_vTaskDelete == 1 ) 00642 00643 void vTaskDelete( xTaskHandle xTaskToDelete ) 00644 { 00645 tskTCB *pxTCB; 00646 00647 taskENTER_CRITICAL(); 00648 { 00649 /* If null is passed in here then we are deleting ourselves. */ 00650 pxTCB = prvGetTCBFromHandle( xTaskToDelete ); 00651 00652 /* Remove task from the ready list and place in the termination list. 00653 This will stop the task from be scheduled. The idle task will check 00654 the termination list and free up any memory allocated by the 00655 scheduler for the TCB and stack. */ 00656 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) 00657 { 00658 taskRESET_READY_PRIORITY( pxTCB->uxPriority ); 00659 } 00660 00661 /* Is the task waiting on an event also? */ 00662 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) 00663 { 00664 ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); 00665 } 00666 00667 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) ); 00668 00669 /* Increment the ucTasksDeleted variable so the idle task knows 00670 there is a task that has been deleted and that it should therefore 00671 check the xTasksWaitingTermination list. */ 00672 ++uxTasksDeleted; 00673 00674 /* Increment the uxTaskNumberVariable also so kernel aware debuggers 00675 can detect that the task lists need re-generating. */ 00676 uxTaskNumber++; 00677 00678 traceTASK_DELETE( pxTCB ); 00679 } 00680 taskEXIT_CRITICAL(); 00681 00682 /* Force a reschedule if we have just deleted the current task. */ 00683 if( xSchedulerRunning != pdFALSE ) 00684 { 00685 if( pxTCB == pxCurrentTCB ) 00686 { 00687 portYIELD_WITHIN_API(); 00688 } 00689 } 00690 } 00691 00692 #endif /* INCLUDE_vTaskDelete */ 00693 /*-----------------------------------------------------------*/ 00694 00695 #if ( INCLUDE_vTaskDelayUntil == 1 ) 00696 00697 void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement ) 00698 { 00699 portTickType xTimeToWake; 00700 portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE; 00701 00702 configASSERT( pxPreviousWakeTime ); 00703 configASSERT( ( xTimeIncrement > 0U ) ); 00704 00705 vTaskSuspendAll(); 00706 { 00707 /* Minor optimisation. The tick count cannot change in this 00708 block. */ 00709 const portTickType xConstTickCount = xTickCount; 00710 00711 /* Generate the tick time at which the task wants to wake. */ 00712 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement; 00713 00714 if( xConstTickCount < *pxPreviousWakeTime ) 00715 { 00716 /* The tick count has overflowed since this function was 00717 lasted called. In this case the only time we should ever 00718 actually delay is if the wake time has also overflowed, 00719 and the wake time is greater than the tick time. When this 00720 is the case it is as if neither time had overflowed. */ 00721 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) ) 00722 { 00723 xShouldDelay = pdTRUE; 00724 } 00725 } 00726 else 00727 { 00728 /* The tick time has not overflowed. In this case we will 00729 delay if either the wake time has overflowed, and/or the 00730 tick time is less than the wake time. */ 00731 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) ) 00732 { 00733 xShouldDelay = pdTRUE; 00734 } 00735 } 00736 00737 /* Update the wake time ready for the next call. */ 00738 *pxPreviousWakeTime = xTimeToWake; 00739 00740 if( xShouldDelay != pdFALSE ) 00741 { 00742 traceTASK_DELAY_UNTIL(); 00743 00744 /* We must remove ourselves from the ready list before adding 00745 ourselves to the blocked list as the same list item is used for 00746 both lists. */ 00747 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) 00748 { 00749 /* The current task must be in a ready list, so there is 00750 no need to check, and the port reset macro can be called 00751 directly. */ 00752 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 00753 } 00754 00755 prvAddCurrentTaskToDelayedList( xTimeToWake ); 00756 } 00757 } 00758 xAlreadyYielded = xTaskResumeAll(); 00759 00760 /* Force a reschedule if xTaskResumeAll has not already done so, we may 00761 have put ourselves to sleep. */ 00762 if( xAlreadyYielded == pdFALSE ) 00763 { 00764 portYIELD_WITHIN_API(); 00765 } 00766 } 00767 00768 #endif /* INCLUDE_vTaskDelayUntil */ 00769 /*-----------------------------------------------------------*/ 00770 00771 #if ( INCLUDE_vTaskDelay == 1 ) 00772 00773 void vTaskDelay( portTickType xTicksToDelay ) 00774 { 00775 portTickType xTimeToWake; 00776 signed portBASE_TYPE xAlreadyYielded = pdFALSE; 00777 00778 /* A delay time of zero just forces a reschedule. */ 00779 if( xTicksToDelay > ( portTickType ) 0U ) 00780 { 00781 vTaskSuspendAll(); 00782 { 00783 traceTASK_DELAY(); 00784 00785 /* A task that is removed from the event list while the 00786 scheduler is suspended will not get placed in the ready 00787 list or removed from the blocked list until the scheduler 00788 is resumed. 00789 00790 This task cannot be in an event list as it is the currently 00791 executing task. */ 00792 00793 /* Calculate the time to wake - this may overflow but this is 00794 not a problem. */ 00795 xTimeToWake = xTickCount + xTicksToDelay; 00796 00797 /* We must remove ourselves from the ready list before adding 00798 ourselves to the blocked list as the same list item is used for 00799 both lists. */ 00800 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) 00801 { 00802 /* The current task must be in a ready list, so there is 00803 no need to check, and the port reset macro can be called 00804 directly. */ 00805 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 00806 } 00807 prvAddCurrentTaskToDelayedList( xTimeToWake ); 00808 } 00809 xAlreadyYielded = xTaskResumeAll(); 00810 } 00811 00812 /* Force a reschedule if xTaskResumeAll has not already done so, we may 00813 have put ourselves to sleep. */ 00814 if( xAlreadyYielded == pdFALSE ) 00815 { 00816 portYIELD_WITHIN_API(); 00817 } 00818 } 00819 00820 #endif /* INCLUDE_vTaskDelay */ 00821 /*-----------------------------------------------------------*/ 00822 00823 #if ( INCLUDE_eTaskGetState == 1 ) 00824 00825 eTaskState eTaskGetState( xTaskHandle xTask ) 00826 { 00827 eTaskState eReturn; 00828 xList *pxStateList; 00829 const tskTCB * const pxTCB = ( tskTCB * ) xTask; 00830 00831 if( pxTCB == pxCurrentTCB ) 00832 { 00833 /* The task calling this function is querying its own state. */ 00834 eReturn = eRunning; 00835 } 00836 else 00837 { 00838 taskENTER_CRITICAL(); 00839 { 00840 pxStateList = ( xList * ) listLIST_ITEM_CONTAINER( &( pxTCB->xGenericListItem ) ); 00841 } 00842 taskEXIT_CRITICAL(); 00843 00844 if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) ) 00845 { 00846 /* The task being queried is referenced from one of the Blocked 00847 lists. */ 00848 eReturn = eBlocked; 00849 } 00850 00851 #if ( INCLUDE_vTaskSuspend == 1 ) 00852 else if( pxStateList == &xSuspendedTaskList ) 00853 { 00854 /* The task being queried is referenced from the suspended 00855 list. Is it genuinely suspended or is it block 00856 indefinitely? */ 00857 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ) 00858 { 00859 eReturn = eSuspended; 00860 } 00861 else 00862 { 00863 eReturn = eBlocked; 00864 } 00865 } 00866 #endif 00867 00868 #if ( INCLUDE_vTaskDelete == 1 ) 00869 else if( pxStateList == &xTasksWaitingTermination ) 00870 { 00871 /* The task being queried is referenced from the deleted 00872 tasks list. */ 00873 eReturn = eDeleted; 00874 } 00875 #endif 00876 00877 else 00878 { 00879 /* If the task is not in any other state, it must be in the 00880 Ready (including pending ready) state. */ 00881 eReturn = eReady; 00882 } 00883 } 00884 00885 return eReturn; 00886 } 00887 00888 #endif /* INCLUDE_eTaskGetState */ 00889 /*-----------------------------------------------------------*/ 00890 00891 #if ( INCLUDE_uxTaskPriorityGet == 1 ) 00892 00893 unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle xTask ) 00894 { 00895 tskTCB *pxTCB; 00896 unsigned portBASE_TYPE uxReturn; 00897 00898 taskENTER_CRITICAL(); 00899 { 00900 /* If null is passed in here then we are changing the 00901 priority of the calling function. */ 00902 pxTCB = prvGetTCBFromHandle( xTask ); 00903 uxReturn = pxTCB->uxPriority; 00904 } 00905 taskEXIT_CRITICAL(); 00906 00907 return uxReturn; 00908 } 00909 00910 #endif /* INCLUDE_uxTaskPriorityGet */ 00911 /*-----------------------------------------------------------*/ 00912 00913 #if ( INCLUDE_vTaskPrioritySet == 1 ) 00914 00915 void vTaskPrioritySet( xTaskHandle xTask, unsigned portBASE_TYPE uxNewPriority ) 00916 { 00917 tskTCB *pxTCB; 00918 unsigned portBASE_TYPE uxCurrentBasePriority, uxPriorityUsedOnEntry; 00919 portBASE_TYPE xYieldRequired = pdFALSE; 00920 00921 configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); 00922 00923 /* Ensure the new priority is valid. */ 00924 if( uxNewPriority >= ( unsigned portBASE_TYPE ) configMAX_PRIORITIES ) 00925 { 00926 uxNewPriority = ( unsigned portBASE_TYPE ) configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U; 00927 } 00928 00929 taskENTER_CRITICAL(); 00930 { 00931 /* If null is passed in here then it is the priority of the calling 00932 task that is being changed. */ 00933 pxTCB = prvGetTCBFromHandle( xTask ); 00934 00935 traceTASK_PRIORITY_SET( pxTCB, uxNewPriority ); 00936 00937 #if ( configUSE_MUTEXES == 1 ) 00938 { 00939 uxCurrentBasePriority = pxTCB->uxBasePriority; 00940 } 00941 #else 00942 { 00943 uxCurrentBasePriority = pxTCB->uxPriority; 00944 } 00945 #endif 00946 00947 if( uxCurrentBasePriority != uxNewPriority ) 00948 { 00949 /* The priority change may have readied a task of higher 00950 priority than the calling task. */ 00951 if( uxNewPriority > uxCurrentBasePriority ) 00952 { 00953 if( pxTCB != pxCurrentTCB ) 00954 { 00955 /* The priority of a task other than the currently 00956 running task is being raised. Is the priority being 00957 raised above that of the running task? */ 00958 if( uxNewPriority >= pxCurrentTCB->uxPriority ) 00959 { 00960 xYieldRequired = pdTRUE; 00961 } 00962 } 00963 else 00964 { 00965 /* The priority of the running task is being raised, 00966 but the running task must already be the highest 00967 priority task able to run so no yield is required. */ 00968 } 00969 } 00970 else if( pxTCB == pxCurrentTCB ) 00971 { 00972 /* Setting the priority of the running task down means 00973 there may now be another task of higher priority that 00974 is ready to execute. */ 00975 xYieldRequired = pdTRUE; 00976 } 00977 else 00978 { 00979 /* Setting the priority of any other task down does not 00980 require a yield as the running task must be above the 00981 new priority of the task being modified. */ 00982 } 00983 00984 /* Remember the ready list the task might be referenced from 00985 before its uxPriority member is changed so the 00986 taskRESET_READY_PRIORITY() macro can function correctly. */ 00987 uxPriorityUsedOnEntry = pxTCB->uxPriority; 00988 00989 #if ( configUSE_MUTEXES == 1 ) 00990 { 00991 /* Only change the priority being used if the task is not 00992 currently using an inherited priority. */ 00993 if( pxTCB->uxBasePriority == pxTCB->uxPriority ) 00994 { 00995 pxTCB->uxPriority = uxNewPriority; 00996 } 00997 00998 /* The base priority gets set whatever. */ 00999 pxTCB->uxBasePriority = uxNewPriority; 01000 } 01001 #else 01002 { 01003 pxTCB->uxPriority = uxNewPriority; 01004 } 01005 #endif 01006 01007 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( portTickType ) configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 01008 01009 /* If the task is in the blocked or suspended list we need do 01010 nothing more than change it's priority variable. However, if 01011 the task is in a ready list it needs to be removed and placed 01012 in the list appropriate to its new priority. */ 01013 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE ) 01014 { 01015 /* The task is currently in its ready list - remove before adding 01016 it to it's new ready list. As we are in a critical section we 01017 can do this even if the scheduler is suspended. */ 01018 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) 01019 { 01020 /* It is known that the task is in its ready list so 01021 there is no need to check again and the port level 01022 reset macro can be called directly. */ 01023 portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); 01024 } 01025 prvAddTaskToReadyList( pxTCB ); 01026 } 01027 01028 if( xYieldRequired == pdTRUE ) 01029 { 01030 taskYIELD_IF_USING_PREEMPTION(); 01031 } 01032 01033 /* Remove compiler warning about unused variables when the port 01034 optimised task selection is not being used. */ 01035 ( void ) uxPriorityUsedOnEntry; 01036 } 01037 } 01038 taskEXIT_CRITICAL(); 01039 } 01040 01041 #endif /* INCLUDE_vTaskPrioritySet */ 01042 /*-----------------------------------------------------------*/ 01043 01044 #if ( INCLUDE_vTaskSuspend == 1 ) 01045 01046 void vTaskSuspend( xTaskHandle xTaskToSuspend ) 01047 { 01048 tskTCB *pxTCB; 01049 01050 taskENTER_CRITICAL(); 01051 { 01052 /* If null is passed in here then it is the running task that is 01053 being suspended. */ 01054 pxTCB = prvGetTCBFromHandle( xTaskToSuspend ); 01055 01056 traceTASK_SUSPEND( pxTCB ); 01057 01058 /* Remove task from the ready/delayed list and place in the suspended list. */ 01059 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) 01060 { 01061 taskRESET_READY_PRIORITY( pxTCB->uxPriority ); 01062 } 01063 01064 /* Is the task waiting on an event also? */ 01065 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) 01066 { 01067 ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); 01068 } 01069 01070 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ); 01071 } 01072 taskEXIT_CRITICAL(); 01073 01074 if( pxTCB == pxCurrentTCB ) 01075 { 01076 if( xSchedulerRunning != pdFALSE ) 01077 { 01078 /* The current task has just been suspended. */ 01079 portYIELD_WITHIN_API(); 01080 } 01081 else 01082 { 01083 /* The scheduler is not running, but the task that was pointed 01084 to by pxCurrentTCB has just been suspended and pxCurrentTCB 01085 must be adjusted to point to a different task. */ 01086 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) 01087 { 01088 /* No other tasks are ready, so set pxCurrentTCB back to 01089 NULL so when the next task is created pxCurrentTCB will 01090 be set to point to it no matter what its relative priority 01091 is. */ 01092 pxCurrentTCB = NULL; 01093 } 01094 else 01095 { 01096 vTaskSwitchContext(); 01097 } 01098 } 01099 } 01100 } 01101 01102 #endif /* INCLUDE_vTaskSuspend */ 01103 /*-----------------------------------------------------------*/ 01104 01105 #if ( INCLUDE_vTaskSuspend == 1 ) 01106 01107 signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask ) 01108 { 01109 portBASE_TYPE xReturn = pdFALSE; 01110 const tskTCB * const pxTCB = ( tskTCB * ) xTask; 01111 01112 /* It does not make sense to check if the calling task is suspended. */ 01113 configASSERT( xTask ); 01114 01115 /* Is the task we are attempting to resume actually in the 01116 suspended list? */ 01117 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE ) 01118 { 01119 /* Has the task already been resumed from within an ISR? */ 01120 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) 01121 { 01122 /* Is it in the suspended list because it is in the 01123 Suspended state? It is possible to be in the suspended 01124 list because it is blocked on a task with no timeout 01125 specified. */ 01126 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) 01127 { 01128 xReturn = pdTRUE; 01129 } 01130 } 01131 } 01132 01133 return xReturn; 01134 } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ 01135 01136 #endif /* INCLUDE_vTaskSuspend */ 01137 /*-----------------------------------------------------------*/ 01138 01139 #if ( INCLUDE_vTaskSuspend == 1 ) 01140 01141 void vTaskResume( xTaskHandle xTaskToResume ) 01142 { 01143 tskTCB * const pxTCB = ( tskTCB * ) xTaskToResume; 01144 01145 /* It does not make sense to resume the calling task. */ 01146 configASSERT( xTaskToResume ); 01147 01148 /* The parameter cannot be NULL as it is impossible to resume the 01149 currently executing task. */ 01150 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ) 01151 { 01152 taskENTER_CRITICAL(); 01153 { 01154 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE ) 01155 { 01156 traceTASK_RESUME( pxTCB ); 01157 01158 /* As we are in a critical section we can access the ready 01159 lists even if the scheduler is suspended. */ 01160 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 01161 prvAddTaskToReadyList( pxTCB ); 01162 01163 /* We may have just resumed a higher priority task. */ 01164 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) 01165 { 01166 /* This yield may not cause the task just resumed to run, 01167 but will leave the lists in the correct state for the 01168 next yield. */ 01169 taskYIELD_IF_USING_PREEMPTION(); 01170 } 01171 } 01172 } 01173 taskEXIT_CRITICAL(); 01174 } 01175 } 01176 01177 #endif /* INCLUDE_vTaskSuspend */ 01178 01179 /*-----------------------------------------------------------*/ 01180 01181 #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) 01182 01183 portBASE_TYPE xTaskResumeFromISR( xTaskHandle xTaskToResume ) 01184 { 01185 portBASE_TYPE xYieldRequired = pdFALSE; 01186 tskTCB * const pxTCB = ( tskTCB * ) xTaskToResume; 01187 unsigned portBASE_TYPE uxSavedInterruptStatus; 01188 01189 configASSERT( xTaskToResume ); 01190 01191 /* RTOS ports that support interrupt nesting have the concept of a 01192 maximum system call (or maximum API call) interrupt priority. 01193 Interrupts that are above the maximum system call priority are keep 01194 permanently enabled, even when the RTOS kernel is in a critical section, 01195 but cannot make any calls to FreeRTOS API functions. If configASSERT() 01196 is defined in FreeRTOSConfig.h then 01197 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion 01198 failure if a FreeRTOS API function is called from an interrupt that has 01199 been assigned a priority above the configured maximum system call 01200 priority. Only FreeRTOS functions that end in FromISR can be called 01201 from interrupts that have been assigned a priority at or (logically) 01202 below the maximum system call interrupt priority. FreeRTOS maintains a 01203 separate interrupt safe API to ensure interrupt entry is as fast and as 01204 simple as possible. More information (albeit Cortex-M specific) is 01205 provided on the following link: 01206 http://www.freertos.org/RTOS-Cortex-M3-M4.html */ 01207 portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); 01208 01209 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); 01210 { 01211 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE ) 01212 { 01213 traceTASK_RESUME_FROM_ISR( pxTCB ); 01214 01215 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) 01216 { 01217 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) 01218 { 01219 xYieldRequired = pdTRUE; 01220 } 01221 01222 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 01223 prvAddTaskToReadyList( pxTCB ); 01224 } 01225 else 01226 { 01227 /* We cannot access the delayed or ready lists, so will hold this 01228 task pending until the scheduler is resumed, at which point a 01229 yield will be performed if necessary. */ 01230 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); 01231 } 01232 } 01233 } 01234 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 01235 01236 return xYieldRequired; 01237 } 01238 01239 #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */ 01240 /*-----------------------------------------------------------*/ 01241 01242 void vTaskStartScheduler( void ) 01243 { 01244 portBASE_TYPE xReturn; 01245 01246 /* Add the idle task at the lowest priority. */ 01247 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) 01248 { 01249 /* Create the idle task, storing its handle in xIdleTaskHandle so it can 01250 be returned by the xTaskGetIdleTaskHandle() function. */ 01251 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. */ 01252 } 01253 #else 01254 { 01255 /* Create the idle task without storing its handle. */ 01256 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. */ 01257 } 01258 #endif /* INCLUDE_xTaskGetIdleTaskHandle */ 01259 01260 #if ( configUSE_TIMERS == 1 ) 01261 { 01262 if( xReturn == pdPASS ) 01263 { 01264 xReturn = xTimerCreateTimerTask(); 01265 } 01266 } 01267 #endif /* configUSE_TIMERS */ 01268 01269 if( xReturn == pdPASS ) 01270 { 01271 /* Interrupts are turned off here, to ensure a tick does not occur 01272 before or during the call to xPortStartScheduler(). The stacks of 01273 the created tasks contain a status word with interrupts switched on 01274 so interrupts will automatically get re-enabled when the first task 01275 starts to run. */ 01276 portDISABLE_INTERRUPTS(); 01277 01278 #if ( configUSE_NEWLIB_REENTRANT == 1 ) 01279 { 01280 /* Switch Newlib's _impure_ptr variable to point to the _reent 01281 structure specific to the task that will run first. */ 01282 _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); 01283 } 01284 #endif /* configUSE_NEWLIB_REENTRANT */ 01285 01286 xSchedulerRunning = pdTRUE; 01287 xTickCount = ( portTickType ) 0U; 01288 01289 /* If configGENERATE_RUN_TIME_STATS is defined then the following 01290 macro must be defined to configure the timer/counter used to generate 01291 the run time counter time base. */ 01292 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); 01293 01294 /* Setting up the timer tick is hardware specific and thus in the 01295 portable interface. */ 01296 if( xPortStartScheduler() != pdFALSE ) 01297 { 01298 /* Should not reach here as if the scheduler is running the 01299 function will not return. */ 01300 } 01301 else 01302 { 01303 /* Should only reach here if a task calls xTaskEndScheduler(). */ 01304 } 01305 } 01306 else 01307 { 01308 /* This line will only be reached if the kernel could not be started, 01309 because there was not enough FreeRTOS heap to create the idle task 01310 or the timer task. */ 01311 configASSERT( xReturn ); 01312 } 01313 } 01314 /*-----------------------------------------------------------*/ 01315 01316 void vTaskEndScheduler( void ) 01317 { 01318 /* Stop the scheduler interrupts and call the portable scheduler end 01319 routine so the original ISRs can be restored if necessary. The port 01320 layer must ensure interrupts enable bit is left in the correct state. */ 01321 portDISABLE_INTERRUPTS(); 01322 xSchedulerRunning = pdFALSE; 01323 vPortEndScheduler(); 01324 } 01325 /*----------------------------------------------------------*/ 01326 01327 void vTaskSuspendAll( void ) 01328 { 01329 /* A critical section is not required as the variable is of type 01330 portBASE_TYPE. */ 01331 ++uxSchedulerSuspended; 01332 } 01333 /*----------------------------------------------------------*/ 01334 01335 #if ( configUSE_TICKLESS_IDLE != 0 ) 01336 01337 static portTickType prvGetExpectedIdleTime( void ) 01338 { 01339 portTickType xReturn; 01340 01341 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY ) 01342 { 01343 xReturn = 0; 01344 } 01345 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 ) 01346 { 01347 /* There are other idle priority tasks in the ready state. If 01348 time slicing is used then the very next tick interrupt must be 01349 processed. */ 01350 xReturn = 0; 01351 } 01352 else 01353 { 01354 xReturn = xNextTaskUnblockTime - xTickCount; 01355 } 01356 01357 return xReturn; 01358 } 01359 01360 #endif /* configUSE_TICKLESS_IDLE */ 01361 /*----------------------------------------------------------*/ 01362 01363 signed portBASE_TYPE xTaskResumeAll( void ) 01364 { 01365 tskTCB *pxTCB; 01366 portBASE_TYPE xAlreadyYielded = pdFALSE; 01367 01368 /* If uxSchedulerSuspended is zero then this function does not match a 01369 previous call to vTaskSuspendAll(). */ 01370 configASSERT( uxSchedulerSuspended ); 01371 01372 /* It is possible that an ISR caused a task to be removed from an event 01373 list while the scheduler was suspended. If this was the case then the 01374 removed task will have been added to the xPendingReadyList. Once the 01375 scheduler has been resumed it is safe to move all the pending ready 01376 tasks from this list into their appropriate ready list. */ 01377 taskENTER_CRITICAL(); 01378 { 01379 --uxSchedulerSuspended; 01380 01381 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) 01382 { 01383 if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0U ) 01384 { 01385 /* Move any readied tasks from the pending list into the 01386 appropriate ready list. */ 01387 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ) 01388 { 01389 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); 01390 ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); 01391 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 01392 prvAddTaskToReadyList( pxTCB ); 01393 01394 /* If we have moved a task that has a priority higher than 01395 the current task then we should yield. */ 01396 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) 01397 { 01398 xYieldPending = pdTRUE; 01399 } 01400 } 01401 01402 /* If any ticks occurred while the scheduler was suspended then 01403 they should be processed now. This ensures the tick count does not 01404 slip, and that any delayed tasks are resumed at the correct time. */ 01405 if( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U ) 01406 { 01407 while( uxPendedTicks > ( unsigned portBASE_TYPE ) 0U ) 01408 { 01409 if( xTaskIncrementTick() != pdFALSE ) 01410 { 01411 xYieldPending = pdTRUE; 01412 } 01413 --uxPendedTicks; 01414 } 01415 } 01416 01417 if( xYieldPending == pdTRUE ) 01418 { 01419 #if( configUSE_PREEMPTION != 0 ) 01420 { 01421 xAlreadyYielded = pdTRUE; 01422 } 01423 #endif 01424 taskYIELD_IF_USING_PREEMPTION(); 01425 } 01426 } 01427 } 01428 } 01429 taskEXIT_CRITICAL(); 01430 01431 return xAlreadyYielded; 01432 } 01433 /*-----------------------------------------------------------*/ 01434 01435 portTickType xTaskGetTickCount( void ) 01436 { 01437 portTickType xTicks; 01438 01439 /* Critical section required if running on a 16 bit processor. */ 01440 taskENTER_CRITICAL(); 01441 { 01442 xTicks = xTickCount; 01443 } 01444 taskEXIT_CRITICAL(); 01445 01446 return xTicks; 01447 } 01448 /*-----------------------------------------------------------*/ 01449 01450 portTickType xTaskGetTickCountFromISR( void ) 01451 { 01452 portTickType xReturn; 01453 unsigned portBASE_TYPE uxSavedInterruptStatus; 01454 01455 /* RTOS ports that support interrupt nesting have the concept of a maximum 01456 system call (or maximum API call) interrupt priority. Interrupts that are 01457 above the maximum system call priority are keep permanently enabled, even 01458 when the RTOS kernel is in a critical section, but cannot make any calls to 01459 FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h 01460 then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion 01461 failure if a FreeRTOS API function is called from an interrupt that has been 01462 assigned a priority above the configured maximum system call priority. 01463 Only FreeRTOS functions that end in FromISR can be called from interrupts 01464 that have been assigned a priority at or (logically) below the maximum 01465 system call interrupt priority. FreeRTOS maintains a separate interrupt 01466 safe API to ensure interrupt entry is as fast and as simple as possible. 01467 More information (albeit Cortex-M specific) is provided on the following 01468 link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ 01469 portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); 01470 01471 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); 01472 xReturn = xTickCount; 01473 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 01474 01475 return xReturn; 01476 } 01477 /*-----------------------------------------------------------*/ 01478 01479 unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) 01480 { 01481 /* A critical section is not required because the variables are of type 01482 portBASE_TYPE. */ 01483 return uxCurrentNumberOfTasks; 01484 } 01485 /*-----------------------------------------------------------*/ 01486 01487 #if ( INCLUDE_pcTaskGetTaskName == 1 ) 01488 01489 signed char *pcTaskGetTaskName( xTaskHandle xTaskToQuery ) 01490 { 01491 tskTCB *pxTCB; 01492 01493 /* If null is passed in here then the name of the calling task is being queried. */ 01494 pxTCB = prvGetTCBFromHandle( xTaskToQuery ); 01495 configASSERT( pxTCB ); 01496 return &( pxTCB->pcTaskName[ 0 ] ); 01497 } 01498 01499 #endif /* INCLUDE_pcTaskGetTaskName */ 01500 /*-----------------------------------------------------------*/ 01501 01502 #if ( configUSE_TRACE_FACILITY == 1 ) 01503 01504 unsigned portBASE_TYPE uxTaskGetSystemState( xTaskStatusType *pxTaskStatusArray, unsigned portBASE_TYPE uxArraySize, unsigned long *pulTotalRunTime ) 01505 { 01506 unsigned portBASE_TYPE uxTask = 0, uxQueue = configMAX_PRIORITIES; 01507 01508 vTaskSuspendAll(); 01509 { 01510 /* Is there a space in the array for each task in the system? */ 01511 if( uxArraySize >= uxCurrentNumberOfTasks ) 01512 { 01513 /* Fill in an xTaskStatusType structure with information on each 01514 task in the Ready state. */ 01515 do 01516 { 01517 uxQueue--; 01518 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady ); 01519 01520 } while( uxQueue > ( unsigned portBASE_TYPE ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 01521 01522 /* Fill in an xTaskStatusType structure with information on each 01523 task in the Blocked state. */ 01524 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) pxDelayedTaskList, eBlocked ); 01525 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( xList * ) pxOverflowDelayedTaskList, eBlocked ); 01526 01527 #if( INCLUDE_vTaskDelete == 1 ) 01528 { 01529 /* Fill in an xTaskStatusType structure with information on 01530 each task that has been deleted but not yet cleaned up. */ 01531 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ); 01532 } 01533 #endif 01534 01535 #if ( INCLUDE_vTaskSuspend == 1 ) 01536 { 01537 /* Fill in an xTaskStatusType structure with information on 01538 each task in the Suspended state. */ 01539 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ); 01540 } 01541 #endif 01542 01543 #if ( configGENERATE_RUN_TIME_STATS == 1) 01544 { 01545 if( pulTotalRunTime != NULL ) 01546 { 01547 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE 01548 portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) ); 01549 #else 01550 *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); 01551 #endif 01552 } 01553 } 01554 #else 01555 { 01556 if( pulTotalRunTime != NULL ) 01557 { 01558 *pulTotalRunTime = 0; 01559 } 01560 } 01561 #endif 01562 } 01563 } 01564 ( void ) xTaskResumeAll(); 01565 01566 return uxTask; 01567 } 01568 01569 #endif /* configUSE_TRACE_FACILITY */ 01570 /*----------------------------------------------------------*/ 01571 01572 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) 01573 01574 xTaskHandle xTaskGetIdleTaskHandle( void ) 01575 { 01576 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been 01577 started, then xIdleTaskHandle will be NULL. */ 01578 configASSERT( ( xIdleTaskHandle != NULL ) ); 01579 return xIdleTaskHandle; 01580 } 01581 01582 #endif /* INCLUDE_xTaskGetIdleTaskHandle */ 01583 /*----------------------------------------------------------*/ 01584 01585 /* This conditional compilation should use inequality to 0, not equality to 1. 01586 This is to ensure vTaskStepTick() is available when user defined low power mode 01587 implementations require configUSE_TICKLESS_IDLE to be set to a value other than 01588 1. */ 01589 #if ( configUSE_TICKLESS_IDLE != 0 ) 01590 01591 void vTaskStepTick( portTickType xTicksToJump ) 01592 { 01593 /* Correct the tick count value after a period during which the tick 01594 was suppressed. Note this does *not* call the tick hook function for 01595 each stepped tick. */ 01596 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime ); 01597 xTickCount += xTicksToJump; 01598 traceINCREASE_TICK_COUNT( xTicksToJump ); 01599 } 01600 01601 #endif /* configUSE_TICKLESS_IDLE */ 01602 /*----------------------------------------------------------*/ 01603 01604 portBASE_TYPE xTaskIncrementTick( void ) 01605 { 01606 tskTCB * pxTCB; 01607 portTickType xItemValue; 01608 portBASE_TYPE xSwitchRequired = pdFALSE; 01609 01610 /* Called by the portable layer each time a tick interrupt occurs. 01611 Increments the tick then checks to see if the new tick value will cause any 01612 tasks to be unblocked. */ 01613 traceTASK_INCREMENT_TICK( xTickCount ); 01614 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) 01615 { 01616 /* Increment the RTOS tick, switching the delayed and overflowed 01617 delayed lists if it wraps to 0. */ 01618 ++xTickCount; 01619 01620 { 01621 /* Minor optimisation. The tick count cannot change in this 01622 block. */ 01623 const portTickType xConstTickCount = xTickCount; 01624 01625 if( xConstTickCount == ( portTickType ) 0U ) 01626 { 01627 taskSWITCH_DELAYED_LISTS(); 01628 } 01629 01630 /* See if this tick has made a timeout expire. Tasks are stored in the 01631 queue in the order of their wake time - meaning once one tasks has been 01632 found whose block time has not expired there is no need not look any 01633 further down the list. */ 01634 if( xConstTickCount >= xNextTaskUnblockTime ) 01635 { 01636 for( ;; ) 01637 { 01638 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) 01639 { 01640 /* The delayed list is empty. Set xNextTaskUnblockTime to 01641 the maximum possible value so it is extremely unlikely that 01642 the if( xTickCount >= xNextTaskUnblockTime ) test will pass 01643 next time through. */ 01644 xNextTaskUnblockTime = portMAX_DELAY; 01645 break; 01646 } 01647 else 01648 { 01649 /* The delayed list is not empty, get the value of the item 01650 at the head of the delayed list. This is the time at which 01651 the task at the head of the delayed list must be removed 01652 from the Blocked state. */ 01653 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); 01654 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); 01655 01656 if( xConstTickCount < xItemValue ) 01657 { 01658 /* It is not time to unblock this item yet, but the item 01659 value is the time at which the task at the head of the 01660 blocked list must be removed from the Blocked state - 01661 so record the item value in xNextTaskUnblockTime. */ 01662 xNextTaskUnblockTime = xItemValue; 01663 break; 01664 } 01665 01666 /* It is time to remove the item from the Blocked state. */ 01667 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 01668 01669 /* Is the task waiting on an event also? If so remove it 01670 from the event list. */ 01671 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) 01672 { 01673 ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); 01674 } 01675 01676 /* Place the unblocked task into the appropriate ready 01677 list. */ 01678 prvAddTaskToReadyList( pxTCB ); 01679 01680 /* A task being unblocked cannot cause an immediate context 01681 switch if preemption is turned off. */ 01682 #if ( configUSE_PREEMPTION == 1 ) 01683 { 01684 /* Preemption is on, but a context switch should only 01685 be performed if the unblocked task has a priority that 01686 is equal to or higher than the currently executing 01687 task. */ 01688 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) 01689 { 01690 xSwitchRequired = pdTRUE; 01691 } 01692 } 01693 #endif /* configUSE_PREEMPTION */ 01694 } 01695 } 01696 } 01697 } 01698 01699 /* Tasks of equal priority to the currently running task will share 01700 processing time (time slice) if preemption is on, and the application 01701 writer has not explicitly turned time slicing off. */ 01702 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) 01703 { 01704 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( unsigned portBASE_TYPE ) 1 ) 01705 { 01706 xSwitchRequired = pdTRUE; 01707 } 01708 } 01709 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ 01710 01711 #if ( configUSE_TICK_HOOK == 1 ) 01712 { 01713 /* Guard against the tick hook being called when the pended tick 01714 count is being unwound (when the scheduler is being unlocked). */ 01715 if( uxPendedTicks == ( unsigned portBASE_TYPE ) 0U ) 01716 { 01717 vApplicationTickHook(); 01718 } 01719 } 01720 #endif /* configUSE_TICK_HOOK */ 01721 } 01722 else 01723 { 01724 ++uxPendedTicks; 01725 01726 /* The tick hook gets called at regular intervals, even if the 01727 scheduler is locked. */ 01728 #if ( configUSE_TICK_HOOK == 1 ) 01729 { 01730 vApplicationTickHook(); 01731 } 01732 #endif 01733 } 01734 01735 #if ( configUSE_PREEMPTION == 1 ) 01736 { 01737 if( xYieldPending != pdFALSE ) 01738 { 01739 xSwitchRequired = pdTRUE; 01740 } 01741 } 01742 #endif /* configUSE_PREEMPTION */ 01743 01744 return xSwitchRequired; 01745 } 01746 /*-----------------------------------------------------------*/ 01747 01748 #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 01749 01750 void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxHookFunction ) 01751 { 01752 tskTCB *xTCB; 01753 01754 /* If xTask is NULL then we are setting our own task hook. */ 01755 if( xTask == NULL ) 01756 { 01757 xTCB = ( tskTCB * ) pxCurrentTCB; 01758 } 01759 else 01760 { 01761 xTCB = ( tskTCB * ) xTask; 01762 } 01763 01764 /* Save the hook function in the TCB. A critical section is required as 01765 the value can be accessed from an interrupt. */ 01766 taskENTER_CRITICAL(); 01767 xTCB->pxTaskTag = pxHookFunction; 01768 taskEXIT_CRITICAL(); 01769 } 01770 01771 #endif /* configUSE_APPLICATION_TASK_TAG */ 01772 /*-----------------------------------------------------------*/ 01773 01774 #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 01775 01776 pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask ) 01777 { 01778 tskTCB *xTCB; 01779 pdTASK_HOOK_CODE xReturn; 01780 01781 /* If xTask is NULL then we are setting our own task hook. */ 01782 if( xTask == NULL ) 01783 { 01784 xTCB = ( tskTCB * ) pxCurrentTCB; 01785 } 01786 else 01787 { 01788 xTCB = ( tskTCB * ) xTask; 01789 } 01790 01791 /* Save the hook function in the TCB. A critical section is required as 01792 the value can be accessed from an interrupt. */ 01793 taskENTER_CRITICAL(); 01794 xReturn = xTCB->pxTaskTag; 01795 taskEXIT_CRITICAL(); 01796 01797 return xReturn; 01798 } 01799 01800 #endif /* configUSE_APPLICATION_TASK_TAG */ 01801 /*-----------------------------------------------------------*/ 01802 01803 #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 01804 01805 portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter ) 01806 { 01807 tskTCB *xTCB; 01808 portBASE_TYPE xReturn; 01809 01810 /* If xTask is NULL then we are calling our own task hook. */ 01811 if( xTask == NULL ) 01812 { 01813 xTCB = ( tskTCB * ) pxCurrentTCB; 01814 } 01815 else 01816 { 01817 xTCB = ( tskTCB * ) xTask; 01818 } 01819 01820 if( xTCB->pxTaskTag != NULL ) 01821 { 01822 xReturn = xTCB->pxTaskTag( pvParameter ); 01823 } 01824 else 01825 { 01826 xReturn = pdFAIL; 01827 } 01828 01829 return xReturn; 01830 } 01831 01832 #endif /* configUSE_APPLICATION_TASK_TAG */ 01833 /*-----------------------------------------------------------*/ 01834 01835 void vTaskSwitchContext( void ) 01836 { 01837 if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE ) 01838 { 01839 /* The scheduler is currently suspended - do not allow a context 01840 switch. */ 01841 xYieldPending = pdTRUE; 01842 } 01843 else 01844 { 01845 xYieldPending = pdFALSE; 01846 traceTASK_SWITCHED_OUT(); 01847 01848 #if ( configGENERATE_RUN_TIME_STATS == 1 ) 01849 { 01850 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE 01851 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime ); 01852 #else 01853 ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); 01854 #endif 01855 01856 /* Add the amount of time the task has been running to the 01857 accumulated time so far. The time the task started running was 01858 stored in ulTaskSwitchedInTime. Note that there is no overflow 01859 protection here so count values are only valid until the timer 01860 overflows. The guard against negative values is to protect 01861 against suspect run time stat counter implementations - which 01862 are provided by the application, not the kernel. */ 01863 if( ulTotalRunTime > ulTaskSwitchedInTime ) 01864 { 01865 pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); 01866 } 01867 ulTaskSwitchedInTime = ulTotalRunTime; 01868 } 01869 #endif /* configGENERATE_RUN_TIME_STATS */ 01870 01871 taskFIRST_CHECK_FOR_STACK_OVERFLOW(); 01872 taskSECOND_CHECK_FOR_STACK_OVERFLOW(); 01873 01874 taskSELECT_HIGHEST_PRIORITY_TASK(); 01875 01876 traceTASK_SWITCHED_IN(); 01877 01878 #if ( configUSE_NEWLIB_REENTRANT == 1 ) 01879 { 01880 /* Switch Newlib's _impure_ptr variable to point to the _reent 01881 structure specific to this task. */ 01882 _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); 01883 } 01884 #endif /* configUSE_NEWLIB_REENTRANT */ 01885 } 01886 } 01887 /*-----------------------------------------------------------*/ 01888 01889 void vTaskPlaceOnEventList( xList * const pxEventList, portTickType xTicksToWait ) 01890 { 01891 portTickType xTimeToWake; 01892 01893 configASSERT( pxEventList ); 01894 01895 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE 01896 SCHEDULER SUSPENDED. */ 01897 01898 /* Place the event list item of the TCB in the appropriate event list. 01899 This is placed in the list in priority order so the highest priority task 01900 is the first to be woken by the event. */ 01901 vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) ); 01902 01903 /* We must remove ourselves from the ready list before adding ourselves 01904 to the blocked list as the same list item is used for both lists. We have 01905 exclusive access to the ready lists as the scheduler is locked. */ 01906 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) 01907 { 01908 /* The current task must be in a ready list, so there is no need to 01909 check, and the port reset macro can be called directly. */ 01910 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 01911 } 01912 01913 #if ( INCLUDE_vTaskSuspend == 1 ) 01914 { 01915 if( xTicksToWait == portMAX_DELAY ) 01916 { 01917 /* Add ourselves to the suspended task list instead of a delayed task 01918 list to ensure we are not woken by a timing event. We will block 01919 indefinitely. */ 01920 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); 01921 } 01922 else 01923 { 01924 /* Calculate the time at which the task should be woken if the event does 01925 not occur. This may overflow but this doesn't matter. */ 01926 xTimeToWake = xTickCount + xTicksToWait; 01927 prvAddCurrentTaskToDelayedList( xTimeToWake ); 01928 } 01929 } 01930 #else /* INCLUDE_vTaskSuspend */ 01931 { 01932 /* Calculate the time at which the task should be woken if the event does 01933 not occur. This may overflow but this doesn't matter. */ 01934 xTimeToWake = xTickCount + xTicksToWait; 01935 prvAddCurrentTaskToDelayedList( xTimeToWake ); 01936 } 01937 #endif /* INCLUDE_vTaskSuspend */ 01938 } 01939 /*-----------------------------------------------------------*/ 01940 01941 #if configUSE_TIMERS == 1 01942 01943 void vTaskPlaceOnEventListRestricted( xList * const pxEventList, portTickType xTicksToWait ) 01944 { 01945 portTickType xTimeToWake; 01946 01947 configASSERT( pxEventList ); 01948 01949 /* This function should not be called by application code hence the 01950 'Restricted' in its name. It is not part of the public API. It is 01951 designed for use by kernel code, and has special calling requirements - 01952 it should be called from a critical section. */ 01953 01954 01955 /* Place the event list item of the TCB in the appropriate event list. 01956 In this case it is assume that this is the only task that is going to 01957 be waiting on this event list, so the faster vListInsertEnd() function 01958 can be used in place of vListInsert. */ 01959 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); 01960 01961 /* We must remove this task from the ready list before adding it to the 01962 blocked list as the same list item is used for both lists. This 01963 function is called form a critical section. */ 01964 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) 01965 { 01966 /* The current task must be in a ready list, so there is no need to 01967 check, and the port reset macro can be called directly. */ 01968 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 01969 } 01970 01971 /* Calculate the time at which the task should be woken if the event does 01972 not occur. This may overflow but this doesn't matter. */ 01973 xTimeToWake = xTickCount + xTicksToWait; 01974 01975 traceTASK_DELAY_UNTIL(); 01976 prvAddCurrentTaskToDelayedList( xTimeToWake ); 01977 } 01978 01979 #endif /* configUSE_TIMERS */ 01980 /*-----------------------------------------------------------*/ 01981 01982 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) 01983 { 01984 tskTCB *pxUnblockedTCB; 01985 portBASE_TYPE xReturn; 01986 01987 /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE 01988 SCHEDULER SUSPENDED. It can also be called from within an ISR. */ 01989 01990 /* The event list is sorted in priority order, so we can remove the 01991 first in the list, remove the TCB from the delayed list, and add 01992 it to the ready list. 01993 01994 If an event is for a queue that is locked then this function will never 01995 get called - the lock count on the queue will get modified instead. This 01996 means we can always expect exclusive access to the event list here. 01997 01998 This function assumes that a check has already been made to ensure that 01999 pxEventList is not empty. */ 02000 pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); 02001 configASSERT( pxUnblockedTCB ); 02002 ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) ); 02003 02004 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) 02005 { 02006 ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); 02007 prvAddTaskToReadyList( pxUnblockedTCB ); 02008 } 02009 else 02010 { 02011 /* We cannot access the delayed or ready lists, so will hold this 02012 task pending until the scheduler is resumed. */ 02013 vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) ); 02014 } 02015 02016 if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority ) 02017 { 02018 /* Return true if the task removed from the event list has 02019 a higher priority than the calling task. This allows 02020 the calling task to know if it should force a context 02021 switch now. */ 02022 xReturn = pdTRUE; 02023 02024 /* Mark that a yield is pending in case the user is not using the 02025 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ 02026 xYieldPending = pdTRUE; 02027 } 02028 else 02029 { 02030 xReturn = pdFALSE; 02031 } 02032 02033 return xReturn; 02034 } 02035 /*-----------------------------------------------------------*/ 02036 02037 void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) 02038 { 02039 configASSERT( pxTimeOut ); 02040 pxTimeOut->xOverflowCount = xNumOfOverflows; 02041 pxTimeOut->xTimeOnEntering = xTickCount; 02042 } 02043 /*-----------------------------------------------------------*/ 02044 02045 portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait ) 02046 { 02047 portBASE_TYPE xReturn; 02048 02049 configASSERT( pxTimeOut ); 02050 configASSERT( pxTicksToWait ); 02051 02052 taskENTER_CRITICAL(); 02053 { 02054 /* Minor optimisation. The tick count cannot change in this block. */ 02055 const portTickType xConstTickCount = xTickCount; 02056 02057 #if ( INCLUDE_vTaskSuspend == 1 ) 02058 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is 02059 the maximum block time then the task should block indefinitely, and 02060 therefore never time out. */ 02061 if( *pxTicksToWait == portMAX_DELAY ) 02062 { 02063 xReturn = pdFALSE; 02064 } 02065 else /* We are not blocking indefinitely, perform the checks below. */ 02066 #endif 02067 02068 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */ 02069 { 02070 /* The tick count is greater than the time at which vTaskSetTimeout() 02071 was called, but has also overflowed since vTaskSetTimeOut() was called. 02072 It must have wrapped all the way around and gone past us again. This 02073 passed since vTaskSetTimeout() was called. */ 02074 xReturn = pdTRUE; 02075 } 02076 else if( ( xConstTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait ) 02077 { 02078 /* Not a genuine timeout. Adjust parameters for time remaining. */ 02079 *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering ); 02080 vTaskSetTimeOutState( pxTimeOut ); 02081 xReturn = pdFALSE; 02082 } 02083 else 02084 { 02085 xReturn = pdTRUE; 02086 } 02087 } 02088 taskEXIT_CRITICAL(); 02089 02090 return xReturn; 02091 } 02092 /*-----------------------------------------------------------*/ 02093 02094 void vTaskMissedYield( void ) 02095 { 02096 xYieldPending = pdTRUE; 02097 } 02098 /*-----------------------------------------------------------*/ 02099 02100 #if ( configUSE_TRACE_FACILITY == 1 ) 02101 02102 unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask ) 02103 { 02104 unsigned portBASE_TYPE uxReturn; 02105 tskTCB *pxTCB; 02106 02107 if( xTask != NULL ) 02108 { 02109 pxTCB = ( tskTCB * ) xTask; 02110 uxReturn = pxTCB->uxTaskNumber; 02111 } 02112 else 02113 { 02114 uxReturn = 0U; 02115 } 02116 02117 return uxReturn; 02118 } 02119 02120 #endif /* configUSE_TRACE_FACILITY */ 02121 /*-----------------------------------------------------------*/ 02122 02123 #if ( configUSE_TRACE_FACILITY == 1 ) 02124 02125 void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ) 02126 { 02127 tskTCB *pxTCB; 02128 02129 if( xTask != NULL ) 02130 { 02131 pxTCB = ( tskTCB * ) xTask; 02132 pxTCB->uxTaskNumber = uxHandle; 02133 } 02134 } 02135 02136 #endif /* configUSE_TRACE_FACILITY */ 02137 02138 /* 02139 * ----------------------------------------------------------- 02140 * The Idle task. 02141 * ---------------------------------------------------------- 02142 * 02143 * The portTASK_FUNCTION() macro is used to allow port/compiler specific 02144 * language extensions. The equivalent prototype for this function is: 02145 * 02146 * void prvIdleTask( void *pvParameters ); 02147 * 02148 */ 02149 static portTASK_FUNCTION( prvIdleTask, pvParameters ) 02150 { 02151 /* Stop warnings. */ 02152 ( void ) pvParameters; 02153 02154 for( ;; ) 02155 { 02156 /* See if any tasks have been deleted. */ 02157 prvCheckTasksWaitingTermination(); 02158 02159 #if ( configUSE_PREEMPTION == 0 ) 02160 { 02161 /* If we are not using preemption we keep forcing a task switch to 02162 see if any other task has become available. If we are using 02163 preemption we don't need to do this as any task becoming available 02164 will automatically get the processor anyway. */ 02165 taskYIELD(); 02166 } 02167 #endif /* configUSE_PREEMPTION */ 02168 02169 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) 02170 { 02171 /* When using preemption tasks of equal priority will be 02172 timesliced. If a task that is sharing the idle priority is ready 02173 to run then the idle task should yield before the end of the 02174 timeslice. 02175 02176 A critical region is not required here as we are just reading from 02177 the list, and an occasional incorrect value will not matter. If 02178 the ready list at the idle priority contains more than one task 02179 then a task other than the idle task is ready to execute. */ 02180 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 ) 02181 { 02182 taskYIELD(); 02183 } 02184 } 02185 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */ 02186 02187 #if ( configUSE_IDLE_HOOK == 1 ) 02188 { 02189 extern void vApplicationIdleHook( void ); 02190 02191 /* Call the user defined function from within the idle task. This 02192 allows the application designer to add background functionality 02193 without the overhead of a separate task. 02194 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, 02195 CALL A FUNCTION THAT MIGHT BLOCK. */ 02196 vApplicationIdleHook(); 02197 } 02198 #endif /* configUSE_IDLE_HOOK */ 02199 02200 /* This conditional compilation should use inequality to 0, not equality 02201 to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when 02202 user defined low power mode implementations require 02203 configUSE_TICKLESS_IDLE to be set to a value other than 1. */ 02204 #if ( configUSE_TICKLESS_IDLE != 0 ) 02205 { 02206 portTickType xExpectedIdleTime; 02207 02208 /* It is not desirable to suspend then resume the scheduler on 02209 each iteration of the idle task. Therefore, a preliminary 02210 test of the expected idle time is performed without the 02211 scheduler suspended. The result here is not necessarily 02212 valid. */ 02213 xExpectedIdleTime = prvGetExpectedIdleTime(); 02214 02215 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) 02216 { 02217 vTaskSuspendAll(); 02218 { 02219 /* Now the scheduler is suspended, the expected idle 02220 time can be sampled again, and this time its value can 02221 be used. */ 02222 configASSERT( xNextTaskUnblockTime >= xTickCount ); 02223 xExpectedIdleTime = prvGetExpectedIdleTime(); 02224 02225 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) 02226 { 02227 traceLOW_POWER_IDLE_BEGIN(); 02228 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); 02229 traceLOW_POWER_IDLE_END(); 02230 } 02231 } 02232 ( void ) xTaskResumeAll(); 02233 } 02234 } 02235 #endif /* configUSE_TICKLESS_IDLE */ 02236 } 02237 } 02238 /*-----------------------------------------------------------*/ 02239 02240 #if configUSE_TICKLESS_IDLE != 0 02241 02242 eSleepModeStatus eTaskConfirmSleepModeStatus( void ) 02243 { 02244 eSleepModeStatus eReturn = eStandardSleep; 02245 02246 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 ) 02247 { 02248 /* A task was made ready while the scheduler was suspended. */ 02249 eReturn = eAbortSleep; 02250 } 02251 else if( xYieldPending != pdFALSE ) 02252 { 02253 /* A yield was pended while the scheduler was suspended. */ 02254 eReturn = eAbortSleep; 02255 } 02256 else 02257 { 02258 #if configUSE_TIMERS == 0 02259 { 02260 /* The idle task exists in addition to the application tasks. */ 02261 const unsigned portBASE_TYPE uxNonApplicationTasks = 1; 02262 02263 /* If timers are not being used and all the tasks are in the 02264 suspended list (which might mean they have an infinite block 02265 time rather than actually being suspended) then it is safe to 02266 turn all clocks off and just wait for external interrupts. */ 02267 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) ) 02268 { 02269 eReturn = eNoTasksWaitingTimeout; 02270 } 02271 } 02272 #endif /* configUSE_TIMERS */ 02273 } 02274 02275 return eReturn; 02276 } 02277 #endif /* configUSE_TICKLESS_IDLE */ 02278 /*-----------------------------------------------------------*/ 02279 02280 static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) 02281 { 02282 unsigned portBASE_TYPE x; 02283 02284 /* Store the task name in the TCB. */ 02285 for( x = ( unsigned portBASE_TYPE ) 0; x < ( unsigned portBASE_TYPE ) configMAX_TASK_NAME_LEN; x++ ) 02286 { 02287 pxTCB->pcTaskName[ x ] = pcName[ x ]; 02288 02289 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than 02290 configMAX_TASK_NAME_LEN characters just in case the memory after the 02291 string is not accessible (extremely unlikely). */ 02292 if( pcName[ x ] == 0x00 ) 02293 { 02294 break; 02295 } 02296 } 02297 02298 /* Ensure the name string is terminated in the case that the string length 02299 was greater or equal to configMAX_TASK_NAME_LEN. */ 02300 pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = ( signed char ) '\0'; 02301 02302 /* This is used as an array index so must ensure it's not too large. First 02303 remove the privilege bit if one is present. */ 02304 if( uxPriority >= ( unsigned portBASE_TYPE ) configMAX_PRIORITIES ) 02305 { 02306 uxPriority = ( unsigned portBASE_TYPE ) configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U; 02307 } 02308 02309 pxTCB->uxPriority = uxPriority; 02310 #if ( configUSE_MUTEXES == 1 ) 02311 { 02312 pxTCB->uxBasePriority = uxPriority; 02313 } 02314 #endif /* configUSE_MUTEXES */ 02315 02316 vListInitialiseItem( &( pxTCB->xGenericListItem ) ); 02317 vListInitialiseItem( &( pxTCB->xEventListItem ) ); 02318 02319 /* Set the pxTCB as a link back from the xListItem. This is so we can get 02320 back to the containing TCB from a generic item in a list. */ 02321 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB ); 02322 02323 /* Event lists are always in priority order. */ 02324 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( portTickType ) configMAX_PRIORITIES - ( portTickType ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 02325 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB ); 02326 02327 #if ( portCRITICAL_NESTING_IN_TCB == 1 ) 02328 { 02329 pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0U; 02330 } 02331 #endif /* portCRITICAL_NESTING_IN_TCB */ 02332 02333 #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 02334 { 02335 pxTCB->pxTaskTag = NULL; 02336 } 02337 #endif /* configUSE_APPLICATION_TASK_TAG */ 02338 02339 #if ( configGENERATE_RUN_TIME_STATS == 1 ) 02340 { 02341 pxTCB->ulRunTimeCounter = 0UL; 02342 } 02343 #endif /* configGENERATE_RUN_TIME_STATS */ 02344 02345 #if ( portUSING_MPU_WRAPPERS == 1 ) 02346 { 02347 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth ); 02348 } 02349 #else /* portUSING_MPU_WRAPPERS */ 02350 { 02351 ( void ) xRegions; 02352 ( void ) usStackDepth; 02353 } 02354 #endif /* portUSING_MPU_WRAPPERS */ 02355 02356 #if ( configUSE_NEWLIB_REENTRANT == 1 ) 02357 { 02358 /* Initialise this task's Newlib reent structure. */ 02359 _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) ); 02360 } 02361 #endif /* configUSE_NEWLIB_REENTRANT */ 02362 } 02363 /*-----------------------------------------------------------*/ 02364 02365 #if ( portUSING_MPU_WRAPPERS == 1 ) 02366 02367 void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions ) 02368 { 02369 tskTCB *pxTCB; 02370 02371 /* If null is passed in here then we are deleting ourselves. */ 02372 pxTCB = prvGetTCBFromHandle( xTaskToModify ); 02373 02374 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 ); 02375 } 02376 02377 #endif /* portUSING_MPU_WRAPPERS */ 02378 /*-----------------------------------------------------------*/ 02379 02380 static void prvInitialiseTaskLists( void ) 02381 { 02382 unsigned portBASE_TYPE uxPriority; 02383 02384 for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < ( unsigned portBASE_TYPE ) configMAX_PRIORITIES; uxPriority++ ) 02385 { 02386 vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) ); 02387 } 02388 02389 vListInitialise( &xDelayedTaskList1 ); 02390 vListInitialise( &xDelayedTaskList2 ); 02391 vListInitialise( &xPendingReadyList ); 02392 02393 #if ( INCLUDE_vTaskDelete == 1 ) 02394 { 02395 vListInitialise( &xTasksWaitingTermination ); 02396 } 02397 #endif /* INCLUDE_vTaskDelete */ 02398 02399 #if ( INCLUDE_vTaskSuspend == 1 ) 02400 { 02401 vListInitialise( &xSuspendedTaskList ); 02402 } 02403 #endif /* INCLUDE_vTaskSuspend */ 02404 02405 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList 02406 using list2. */ 02407 pxDelayedTaskList = &xDelayedTaskList1; 02408 pxOverflowDelayedTaskList = &xDelayedTaskList2; 02409 } 02410 /*-----------------------------------------------------------*/ 02411 02412 static void prvCheckTasksWaitingTermination( void ) 02413 { 02414 #if ( INCLUDE_vTaskDelete == 1 ) 02415 { 02416 portBASE_TYPE xListIsEmpty; 02417 02418 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called 02419 too often in the idle task. */ 02420 while( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0U ) 02421 { 02422 vTaskSuspendAll(); 02423 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); 02424 ( void ) xTaskResumeAll(); 02425 02426 if( xListIsEmpty == pdFALSE ) 02427 { 02428 tskTCB *pxTCB; 02429 02430 taskENTER_CRITICAL(); 02431 { 02432 pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); 02433 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 02434 --uxCurrentNumberOfTasks; 02435 --uxTasksDeleted; 02436 } 02437 taskEXIT_CRITICAL(); 02438 02439 prvDeleteTCB( pxTCB ); 02440 } 02441 } 02442 } 02443 #endif /* vTaskDelete */ 02444 } 02445 /*-----------------------------------------------------------*/ 02446 02447 static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) 02448 { 02449 /* The list item will be inserted in wake time order. */ 02450 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); 02451 02452 if( xTimeToWake < xTickCount ) 02453 { 02454 /* Wake time has overflowed. Place this item in the overflow list. */ 02455 vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) ); 02456 } 02457 else 02458 { 02459 /* The wake time has not overflowed, so we can use the current block list. */ 02460 vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) ); 02461 02462 /* If the task entering the blocked state was placed at the head of the 02463 list of blocked tasks then xNextTaskUnblockTime needs to be updated 02464 too. */ 02465 if( xTimeToWake < xNextTaskUnblockTime ) 02466 { 02467 xNextTaskUnblockTime = xTimeToWake; 02468 } 02469 } 02470 } 02471 /*-----------------------------------------------------------*/ 02472 02473 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) 02474 { 02475 tskTCB *pxNewTCB; 02476 02477 /* Allocate space for the TCB. Where the memory comes from depends on 02478 the implementation of the port malloc function. */ 02479 pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) ); 02480 02481 if( pxNewTCB != NULL ) 02482 { 02483 /* Allocate space for the stack used by the task being created. 02484 The base of the stack memory stored in the TCB so the task can 02485 be deleted later if required. */ 02486 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. */ 02487 02488 if( pxNewTCB->pxStack == NULL ) 02489 { 02490 /* Could not allocate the stack. Delete the allocated TCB. */ 02491 vPortFree( pxNewTCB ); 02492 pxNewTCB = NULL; 02493 } 02494 else 02495 { 02496 /* Just to help debugging. */ 02497 ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( portSTACK_TYPE ) ); 02498 } 02499 } 02500 02501 return pxNewTCB; 02502 } 02503 /*-----------------------------------------------------------*/ 02504 02505 #if ( configUSE_TRACE_FACILITY == 1 ) 02506 02507 static unsigned portBASE_TYPE prvListTaskWithinSingleList( xTaskStatusType *pxTaskStatusArray, xList *pxList, eTaskState eState ) 02508 { 02509 volatile tskTCB *pxNextTCB, *pxFirstTCB; 02510 unsigned portBASE_TYPE uxTask = 0; 02511 02512 if( listCURRENT_LIST_LENGTH( pxList ) > ( unsigned portBASE_TYPE ) 0 ) 02513 { 02514 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); 02515 02516 /* Populate an xTaskStatusType structure within the 02517 pxTaskStatusArray array for each task that is referenced from 02518 pxList. See the definition of xTaskStatusType in task.h for the 02519 meaning of each xTaskStatusType structure member. */ 02520 do 02521 { 02522 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); 02523 02524 pxTaskStatusArray[ uxTask ].xHandle = ( xTaskHandle ) pxNextTCB; 02525 pxTaskStatusArray[ uxTask ].pcTaskName = ( const signed char * ) &( pxNextTCB->pcTaskName [ 0 ] ); 02526 pxTaskStatusArray[ uxTask ].xTaskNumber = pxNextTCB->uxTCBNumber; 02527 pxTaskStatusArray[ uxTask ].eCurrentState = eState; 02528 pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority; 02529 02530 #if ( configUSE_MUTEXES == 1 ) 02531 { 02532 pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority; 02533 } 02534 #else 02535 { 02536 pxTaskStatusArray[ uxTask ].uxBasePriority = 0; 02537 } 02538 #endif 02539 02540 #if ( configGENERATE_RUN_TIME_STATS == 1 ) 02541 { 02542 pxTaskStatusArray[ uxTask ].ulRunTimeCounter = pxNextTCB->ulRunTimeCounter; 02543 } 02544 #else 02545 { 02546 pxTaskStatusArray[ uxTask ].ulRunTimeCounter = 0; 02547 } 02548 #endif 02549 02550 #if ( portSTACK_GROWTH > 0 ) 02551 { 02552 pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack ); 02553 } 02554 #else 02555 { 02556 pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack ); 02557 } 02558 #endif 02559 02560 uxTask++; 02561 02562 } while( pxNextTCB != pxFirstTCB ); 02563 } 02564 02565 return uxTask; 02566 } 02567 02568 #endif /* configUSE_TRACE_FACILITY */ 02569 /*-----------------------------------------------------------*/ 02570 02571 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) 02572 02573 static unsigned short prvTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) 02574 { 02575 unsigned short usCount = 0U; 02576 02577 while( *pucStackByte == tskSTACK_FILL_BYTE ) 02578 { 02579 pucStackByte -= portSTACK_GROWTH; 02580 usCount++; 02581 } 02582 02583 usCount /= sizeof( portSTACK_TYPE ); 02584 02585 return usCount; 02586 } 02587 02588 #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */ 02589 /*-----------------------------------------------------------*/ 02590 02591 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) 02592 02593 unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask ) 02594 { 02595 tskTCB *pxTCB; 02596 unsigned char *pcEndOfStack; 02597 unsigned portBASE_TYPE uxReturn; 02598 02599 pxTCB = prvGetTCBFromHandle( xTask ); 02600 02601 #if portSTACK_GROWTH < 0 02602 { 02603 pcEndOfStack = ( unsigned char * ) pxTCB->pxStack; 02604 } 02605 #else 02606 { 02607 pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack; 02608 } 02609 #endif 02610 02611 uxReturn = ( unsigned portBASE_TYPE ) prvTaskCheckFreeStackSpace( pcEndOfStack ); 02612 02613 return uxReturn; 02614 } 02615 02616 #endif /* INCLUDE_uxTaskGetStackHighWaterMark */ 02617 /*-----------------------------------------------------------*/ 02618 02619 #if ( INCLUDE_vTaskDelete == 1 ) 02620 02621 static void prvDeleteTCB( tskTCB *pxTCB ) 02622 { 02623 /* This call is required specifically for the TriCore port. It must be 02624 above the vPortFree() calls. The call is also used by ports/demos that 02625 want to allocate and clean RAM statically. */ 02626 portCLEAN_UP_TCB( pxTCB ); 02627 02628 /* Free up the memory allocated by the scheduler for the task. It is up to 02629 the task to free any memory allocated at the application level. */ 02630 vPortFreeAligned( pxTCB->pxStack ); 02631 vPortFree( pxTCB ); 02632 } 02633 02634 #endif /* INCLUDE_vTaskDelete */ 02635 /*-----------------------------------------------------------*/ 02636 02637 #if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) 02638 02639 xTaskHandle xTaskGetCurrentTaskHandle( void ) 02640 { 02641 xTaskHandle xReturn; 02642 02643 /* A critical section is not required as this is not called from 02644 an interrupt and the current TCB will always be the same for any 02645 individual execution thread. */ 02646 xReturn = pxCurrentTCB; 02647 02648 return xReturn; 02649 } 02650 02651 #endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ 02652 /*-----------------------------------------------------------*/ 02653 02654 #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) 02655 02656 portBASE_TYPE xTaskGetSchedulerState( void ) 02657 { 02658 portBASE_TYPE xReturn; 02659 02660 if( xSchedulerRunning == pdFALSE ) 02661 { 02662 xReturn = taskSCHEDULER_NOT_STARTED; 02663 } 02664 else 02665 { 02666 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) 02667 { 02668 xReturn = taskSCHEDULER_RUNNING; 02669 } 02670 else 02671 { 02672 xReturn = taskSCHEDULER_SUSPENDED; 02673 } 02674 } 02675 02676 return xReturn; 02677 } 02678 02679 #endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */ 02680 /*-----------------------------------------------------------*/ 02681 02682 #if ( configUSE_MUTEXES == 1 ) 02683 02684 void vTaskPriorityInherit( xTaskHandle const pxMutexHolder ) 02685 { 02686 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder; 02687 02688 /* If the mutex was given back by an interrupt while the queue was 02689 locked then the mutex holder might now be NULL. */ 02690 if( pxMutexHolder != NULL ) 02691 { 02692 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority ) 02693 { 02694 /* Adjust the mutex holder state to account for its new priority. */ 02695 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. */ 02696 02697 /* If the task being modified is in the ready state it will need to 02698 be moved into a new list. */ 02699 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE ) 02700 { 02701 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) 02702 { 02703 taskRESET_READY_PRIORITY( pxTCB->uxPriority ); 02704 } 02705 02706 /* Inherit the priority before being moved into the new list. */ 02707 pxTCB->uxPriority = pxCurrentTCB->uxPriority; 02708 prvAddTaskToReadyList( pxTCB ); 02709 } 02710 else 02711 { 02712 /* Just inherit the priority. */ 02713 pxTCB->uxPriority = pxCurrentTCB->uxPriority; 02714 } 02715 02716 traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority ); 02717 } 02718 } 02719 } 02720 02721 #endif /* configUSE_MUTEXES */ 02722 /*-----------------------------------------------------------*/ 02723 02724 #if ( configUSE_MUTEXES == 1 ) 02725 02726 void vTaskPriorityDisinherit( xTaskHandle const pxMutexHolder ) 02727 { 02728 tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder; 02729 02730 if( pxMutexHolder != NULL ) 02731 { 02732 if( pxTCB->uxPriority != pxTCB->uxBasePriority ) 02733 { 02734 /* We must be the running task to be able to give the mutex back. 02735 Remove ourselves from the ready list we currently appear in. */ 02736 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) 02737 { 02738 taskRESET_READY_PRIORITY( pxTCB->uxPriority ); 02739 } 02740 02741 /* Disinherit the priority before adding the task into the new 02742 ready list. */ 02743 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); 02744 pxTCB->uxPriority = pxTCB->uxBasePriority; 02745 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. */ 02746 prvAddTaskToReadyList( pxTCB ); 02747 } 02748 } 02749 } 02750 02751 #endif /* configUSE_MUTEXES */ 02752 /*-----------------------------------------------------------*/ 02753 02754 #if ( portCRITICAL_NESTING_IN_TCB == 1 ) 02755 02756 void vTaskEnterCritical( void ) 02757 { 02758 portDISABLE_INTERRUPTS(); 02759 02760 if( xSchedulerRunning != pdFALSE ) 02761 { 02762 ( pxCurrentTCB->uxCriticalNesting )++; 02763 } 02764 } 02765 02766 #endif /* portCRITICAL_NESTING_IN_TCB */ 02767 /*-----------------------------------------------------------*/ 02768 02769 #if ( portCRITICAL_NESTING_IN_TCB == 1 ) 02770 02771 void vTaskExitCritical( void ) 02772 { 02773 if( xSchedulerRunning != pdFALSE ) 02774 { 02775 if( pxCurrentTCB->uxCriticalNesting > 0U ) 02776 { 02777 ( pxCurrentTCB->uxCriticalNesting )--; 02778 02779 if( pxCurrentTCB->uxCriticalNesting == 0U ) 02780 { 02781 portENABLE_INTERRUPTS(); 02782 } 02783 } 02784 } 02785 } 02786 02787 #endif /* portCRITICAL_NESTING_IN_TCB */ 02788 /*-----------------------------------------------------------*/ 02789 02790 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) ) 02791 02792 void vTaskList( signed char *pcWriteBuffer ) 02793 { 02794 xTaskStatusType *pxTaskStatusArray; 02795 volatile unsigned portBASE_TYPE uxArraySize, x; 02796 char cStatus; 02797 02798 /* 02799 * PLEASE NOTE: 02800 * 02801 * This function is provided for convenience only, and is used by many 02802 * of the demo applications. Do not consider it to be part of the 02803 * scheduler. 02804 * 02805 * vTaskList() calls uxTaskGetSystemState(), then formats part of the 02806 * uxTaskGetSystemState() output into a human readable table that 02807 * displays task names, states and stack usage. 02808 * 02809 * vTaskList() has a dependency on the sprintf() C library function that 02810 * might bloat the code size, use a lot of stack, and provide different 02811 * results on different platforms. An alternative, tiny, third party, 02812 * and limited functionality implementation of sprintf() is provided in 02813 * many of the FreeRTOS/Demo sub-directories in a file called 02814 * printf-stdarg.c (note printf-stdarg.c does not provide a full 02815 * snprintf() implementation!). 02816 * 02817 * It is recommended that production systems call uxTaskGetSystemState() 02818 * directly to get access to raw stats data, rather than indirectly 02819 * through a call to vTaskList(). 02820 */ 02821 02822 02823 /* Make sure the write buffer does not contain a string. */ 02824 *pcWriteBuffer = 0x00; 02825 02826 /* Take a snapshot of the number of tasks in case it changes while this 02827 function is executing. */ 02828 uxArraySize = uxCurrentNumberOfTasks; 02829 02830 /* Allocate an array index for each task. */ 02831 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) ); 02832 02833 if( pxTaskStatusArray != NULL ) 02834 { 02835 /* Generate the (binary) data. */ 02836 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL ); 02837 02838 /* Create a human readable table from the binary data. */ 02839 for( x = 0; x < uxArraySize; x++ ) 02840 { 02841 switch( pxTaskStatusArray[ x ].eCurrentState ) 02842 { 02843 case eReady: cStatus = tskREADY_CHAR; 02844 break; 02845 02846 case eBlocked: cStatus = tskBLOCKED_CHAR; 02847 break; 02848 02849 case eSuspended: cStatus = tskSUSPENDED_CHAR; 02850 break; 02851 02852 case eDeleted: cStatus = tskDELETED_CHAR; 02853 break; 02854 02855 default: /* Should not get here, but it is included 02856 to prevent static checking errors. */ 02857 cStatus = 0x00; 02858 break; 02859 } 02860 02861 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 ); 02862 pcWriteBuffer += strlen( ( char * ) pcWriteBuffer ); 02863 } 02864 02865 /* Free the array again. */ 02866 vPortFree( pxTaskStatusArray ); 02867 } 02868 } 02869 02870 #endif /* configUSE_TRACE_FACILITY */ 02871 /*----------------------------------------------------------*/ 02872 02873 #if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) ) 02874 02875 void vTaskGetRunTimeStats( signed char *pcWriteBuffer ) 02876 { 02877 xTaskStatusType *pxTaskStatusArray; 02878 volatile unsigned portBASE_TYPE uxArraySize, x; 02879 unsigned long ulTotalTime, ulStatsAsPercentage; 02880 02881 /* 02882 * PLEASE NOTE: 02883 * 02884 * This function is provided for convenience only, and is used by many 02885 * of the demo applications. Do not consider it to be part of the 02886 * scheduler. 02887 * 02888 * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part 02889 * of the uxTaskGetSystemState() output into a human readable table that 02890 * displays the amount of time each task has spent in the Running state 02891 * in both absolute and percentage terms. 02892 * 02893 * vTaskGetRunTimeStats() has a dependency on the sprintf() C library 02894 * function that might bloat the code size, use a lot of stack, and 02895 * provide different results on different platforms. An alternative, 02896 * tiny, third party, and limited functionality implementation of 02897 * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in 02898 * a file called printf-stdarg.c (note printf-stdarg.c does not provide 02899 * a full snprintf() implementation!). 02900 * 02901 * It is recommended that production systems call uxTaskGetSystemState() 02902 * directly to get access to raw stats data, rather than indirectly 02903 * through a call to vTaskGetRunTimeStats(). 02904 */ 02905 02906 /* Make sure the write buffer does not contain a string. */ 02907 *pcWriteBuffer = 0x00; 02908 02909 /* Take a snapshot of the number of tasks in case it changes while this 02910 function is executing. */ 02911 uxArraySize = uxCurrentNumberOfTasks; 02912 02913 /* Allocate an array index for each task. */ 02914 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( xTaskStatusType ) ); 02915 02916 if( pxTaskStatusArray != NULL ) 02917 { 02918 /* Generate the (binary) data. */ 02919 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime ); 02920 02921 /* For percentage calculations. */ 02922 ulTotalTime /= 100UL; 02923 02924 /* Avoid divide by zero errors. */ 02925 if( ulTotalTime > 0 ) 02926 { 02927 /* Create a human readable table from the binary data. */ 02928 for( x = 0; x < uxArraySize; x++ ) 02929 { 02930 /* What percentage of the total run time has the task used? 02931 This will always be rounded down to the nearest integer. 02932 ulTotalRunTimeDiv100 has already been divided by 100. */ 02933 ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime; 02934 02935 if( ulStatsAsPercentage > 0UL ) 02936 { 02937 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED 02938 { 02939 sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); 02940 } 02941 #else 02942 { 02943 /* sizeof( int ) == sizeof( long ) so a smaller 02944 printf() library can be used. */ 02945 sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); 02946 } 02947 #endif 02948 } 02949 else 02950 { 02951 /* If the percentage is zero here then the task has 02952 consumed less than 1% of the total run time. */ 02953 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED 02954 { 02955 sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter ); 02956 } 02957 #else 02958 { 02959 /* sizeof( int ) == sizeof( long ) so a smaller 02960 printf() library can be used. */ 02961 sprintf( ( char * ) pcWriteBuffer, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); 02962 } 02963 #endif 02964 } 02965 02966 pcWriteBuffer += strlen( ( char * ) pcWriteBuffer ); 02967 } 02968 } 02969 02970 /* Free the array again. */ 02971 vPortFree( pxTaskStatusArray ); 02972 } 02973 } 02974 02975 #endif /* configGENERATE_RUN_TIME_STATS */ 02976 02977 02978
Generated on Tue Jul 12 2022 11:36:40 by
1.7.2