Update revision to use TI's mqtt and Freertos.
Dependencies: mbed client server
Fork of cc3100_Test_mqtt_CM3 by
tasks.c
00001 /* 00002 FreeRTOS V8.2.1 - Copyright (C) 2015 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 This file is part of the FreeRTOS distribution. 00008 00009 FreeRTOS is free software; you can redistribute it and/or modify it under 00010 the terms of the GNU General Public License (version 2) as published by the 00011 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. 00012 00013 *************************************************************************** 00014 >>! NOTE: The modification to the GPL is included to allow you to !<< 00015 >>! distribute a combined work that includes FreeRTOS without being !<< 00016 >>! obliged to provide the source code for proprietary components !<< 00017 >>! outside of the FreeRTOS kernel. !<< 00018 *************************************************************************** 00019 00020 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY 00021 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00022 FOR A PARTICULAR PURPOSE. Full license text is available on the following 00023 link: http://www.freertos.org/a00114.html 00024 00025 *************************************************************************** 00026 * * 00027 * FreeRTOS provides completely free yet professionally developed, * 00028 * robust, strictly quality controlled, supported, and cross * 00029 * platform software that is more than just the market leader, it * 00030 * is the industry's de facto standard. * 00031 * * 00032 * Help yourself get started quickly while simultaneously helping * 00033 * to support the FreeRTOS project by purchasing a FreeRTOS * 00034 * tutorial book, reference manual, or both: * 00035 * http://www.FreeRTOS.org/Documentation * 00036 * * 00037 *************************************************************************** 00038 00039 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading 00040 the FAQ page "My application does not run, what could be wrong?". Have you 00041 defined configASSERT()? 00042 00043 http://www.FreeRTOS.org/support - In return for receiving this top quality 00044 embedded software for free we request you assist our global community by 00045 participating in the support forum. 00046 00047 http://www.FreeRTOS.org/training - Investing in training allows your team to 00048 be as productive as possible as early as possible. Now you can receive 00049 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers 00050 Ltd, and the world's leading authority on the world's leading RTOS. 00051 00052 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, 00053 including FreeRTOS+Trace - an indispensable productivity tool, a DOS 00054 compatible FAT file system, and our tiny thread aware UDP/IP stack. 00055 00056 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. 00057 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. 00058 00059 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High 00060 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS 00061 licenses offer ticketed support, indemnification and commercial middleware. 00062 00063 http://www.SafeRTOS.com - High Integrity Systems also provide a safety 00064 engineered and independently SIL3 certified version for use in safety and 00065 mission critical applications that require provable dependability. 00066 00067 1 tab == 4 spaces! 00068 */ 00069 00070 /* Standard includes. */ 00071 #include <stdlib.h> 00072 #include <string.h> 00073 00074 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining 00075 all the API functions to use the MPU wrappers. That should only be done when 00076 task.h is included from an application file. */ 00077 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE 00078 00079 /* FreeRTOS includes. */ 00080 #include "FreeRTOS.h" 00081 #include "task.h" 00082 #include "timers.h" 00083 #include "StackMacros.h" 00084 00085 /* Lint e961 and e750 are suppressed as a MISRA exception justified because the 00086 MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the 00087 header files above, but not in this file, in order to generate the correct 00088 privileged Vs unprivileged linkage and placement. */ 00089 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ 00090 00091 /* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting 00092 functions but without including stdio.h here. */ 00093 #if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) 00094 /* At the bottom of this file are two optional functions that can be used 00095 to generate human readable text from the raw data generated by the 00096 uxTaskGetSystemState() function. Note the formatting functions are provided 00097 for convenience only, and are NOT considered part of the kernel. */ 00098 #include <stdio.h> 00099 #endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */ 00100 00101 /* Sanity check the configuration. */ 00102 #if configUSE_TICKLESS_IDLE != 0 00103 #if INCLUDE_vTaskSuspend != 1 00104 #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0 00105 #endif /* INCLUDE_vTaskSuspend */ 00106 #endif /* configUSE_TICKLESS_IDLE */ 00107 00108 /* 00109 * Defines the size, in words, of the stack allocated to the idle task. 00110 */ 00111 #define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE 00112 00113 #if( configUSE_PREEMPTION == 0 ) 00114 /* If the cooperative scheduler is being used then a yield should not be 00115 performed just because a higher priority task has been woken. */ 00116 #define taskYIELD_IF_USING_PREEMPTION() 00117 #else 00118 #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() 00119 #endif 00120 00121 /* Value that can be assigned to the eNotifyState member of the TCB. */ 00122 typedef enum 00123 { 00124 eNotWaitingNotification = 0, 00125 eWaitingNotification, 00126 eNotified 00127 } eNotifyValue; 00128 00129 /* 00130 * Task control block. A task control block (TCB) is allocated for each task, 00131 * and stores task state information, including a pointer to the task's context 00132 * (the task's run time environment, including register values) 00133 */ 00134 typedef struct tskTaskControlBlock 00135 { 00136 volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ 00137 00138 #if ( portUSING_MPU_WRAPPERS == 1 ) 00139 xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ 00140 BaseType_t xUsingStaticallyAllocatedStack; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */ 00141 #endif 00142 00143 ListItem_t xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ 00144 ListItem_t xEventListItem; /*< Used to reference a task from an event list. */ 00145 UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */ 00146 StackType_t *pxStack; /*< Points to the start of the stack. */ 00147 char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 00148 00149 #if ( portSTACK_GROWTH > 0 ) 00150 StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ 00151 #endif 00152 00153 #if ( portCRITICAL_NESTING_IN_TCB == 1 ) 00154 UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ 00155 #endif 00156 00157 #if ( configUSE_TRACE_FACILITY == 1 ) 00158 UBaseType_t 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. */ 00159 UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ 00160 #endif 00161 00162 #if ( configUSE_MUTEXES == 1 ) 00163 UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ 00164 UBaseType_t uxMutexesHeld; 00165 #endif 00166 00167 #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 00168 TaskHookFunction_t pxTaskTag; 00169 #endif 00170 00171 #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) 00172 void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; 00173 #endif 00174 00175 #if ( configGENERATE_RUN_TIME_STATS == 1 ) 00176 uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ 00177 #endif 00178 00179 #if ( configUSE_NEWLIB_REENTRANT == 1 ) 00180 /* Allocate a Newlib reent structure that is specific to this task. 00181 Note Newlib support has been included by popular demand, but is not 00182 used by the FreeRTOS maintainers themselves. FreeRTOS is not 00183 responsible for resulting newlib operation. User must be familiar with 00184 newlib and must provide system-wide implementations of the necessary 00185 stubs. Be warned that (at the time of writing) the current newlib design 00186 implements a system-wide malloc() that must be provided with locks. */ 00187 struct _reent xNewLib_reent; 00188 #endif 00189 00190 #if ( configUSE_TASK_NOTIFICATIONS == 1 ) 00191 volatile uint32_t ulNotifiedValue; 00192 volatile eNotifyValue eNotifyState; 00193 #endif 00194 00195 } tskTCB; 00196 00197 /* The old tskTCB name is maintained above then typedefed to the new TCB_t name 00198 below to enable the use of older kernel aware debuggers. */ 00199 typedef tskTCB TCB_t; 00200 00201 /* 00202 * Some kernel aware debuggers require the data the debugger needs access to to 00203 * be global, rather than file scope. 00204 */ 00205 #ifdef portREMOVE_STATIC_QUALIFIER 00206 #define static 00207 #endif 00208 00209 /*lint -e956 A manual analysis and inspection has been used to determine which 00210 static variables must be declared volatile. */ 00211 00212 PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL; 00213 00214 /* Lists for ready and blocked tasks. --------------------*/ 00215 PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */ 00216 PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */ 00217 PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ 00218 PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */ 00219 PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ 00220 PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ 00221 00222 #if ( INCLUDE_vTaskDelete == 1 ) 00223 00224 PRIVILEGED_DATA static List_t xTasksWaitingTermination; /*< Tasks that have been deleted - but their memory not yet freed. */ 00225 PRIVILEGED_DATA static volatile UBaseType_t uxTasksDeleted = ( UBaseType_t ) 0U; 00226 00227 #endif 00228 00229 #if ( INCLUDE_vTaskSuspend == 1 ) 00230 00231 PRIVILEGED_DATA static List_t xSuspendedTaskList; /*< Tasks that are currently suspended. */ 00232 00233 #endif 00234 00235 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) 00236 00237 PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ 00238 00239 #endif 00240 00241 /* Other file private variables. --------------------------------*/ 00242 PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; 00243 PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U; 00244 PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; 00245 PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; 00246 PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U; 00247 PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE; 00248 PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; 00249 PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; 00250 PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = portMAX_DELAY; 00251 00252 /* Context switches are held pending while the scheduler is suspended. Also, 00253 interrupts must not manipulate the xGenericListItem of a TCB, or any of the 00254 lists the xGenericListItem can be referenced from, if the scheduler is suspended. 00255 If an interrupt needs to unblock a task while the scheduler is suspended then it 00256 moves the task's event list item into the xPendingReadyList, ready for the 00257 kernel to move the task from the pending ready list into the real ready list 00258 when the scheduler is unsuspended. The pending ready list itself can only be 00259 accessed from a critical section. */ 00260 PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE; 00261 00262 #if ( configGENERATE_RUN_TIME_STATS == 1 ) 00263 00264 PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ 00265 PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ 00266 00267 #endif 00268 00269 /*lint +e956 */ 00270 00271 /* Debugging and trace facilities private variables and macros. ------------*/ 00272 00273 /* 00274 * The value used to fill the stack of a task when the task is created. This 00275 * is used purely for checking the high water mark for tasks. 00276 */ 00277 #define tskSTACK_FILL_BYTE ( 0xa5U ) 00278 00279 /* 00280 * Macros used by vListTask to indicate which state a task is in. 00281 */ 00282 #define tskBLOCKED_CHAR ( 'B' ) 00283 #define tskREADY_CHAR ( 'R' ) 00284 #define tskDELETED_CHAR ( 'D' ) 00285 #define tskSUSPENDED_CHAR ( 'S' ) 00286 00287 /*-----------------------------------------------------------*/ 00288 00289 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) 00290 00291 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is 00292 performed in a generic way that is not optimised to any particular 00293 microcontroller architecture. */ 00294 00295 /* uxTopReadyPriority holds the priority of the highest priority ready 00296 state task. */ 00297 #define taskRECORD_READY_PRIORITY( uxPriority ) \ 00298 { \ 00299 if( ( uxPriority ) > uxTopReadyPriority ) \ 00300 { \ 00301 uxTopReadyPriority = ( uxPriority ); \ 00302 } \ 00303 } /* taskRECORD_READY_PRIORITY */ 00304 00305 /*-----------------------------------------------------------*/ 00306 00307 #define taskSELECT_HIGHEST_PRIORITY_TASK() \ 00308 { \ 00309 /* Find the highest priority queue that contains ready tasks. */ \ 00310 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) \ 00311 { \ 00312 configASSERT( uxTopReadyPriority ); \ 00313 --uxTopReadyPriority; \ 00314 } \ 00315 \ 00316 /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ 00317 the same priority get an equal share of the processor time. */ \ 00318 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \ 00319 } /* taskSELECT_HIGHEST_PRIORITY_TASK */ 00320 00321 /*-----------------------------------------------------------*/ 00322 00323 /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as 00324 they are only required when a port optimised method of task selection is 00325 being used. */ 00326 #define taskRESET_READY_PRIORITY( uxPriority ) 00327 #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority ) 00328 00329 #else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ 00330 00331 /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is 00332 performed in a way that is tailored to the particular microcontroller 00333 architecture being used. */ 00334 00335 /* A port optimised version is provided. Call the port defined macros. */ 00336 #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority ) 00337 00338 /*-----------------------------------------------------------*/ 00339 00340 #define taskSELECT_HIGHEST_PRIORITY_TASK() \ 00341 { \ 00342 UBaseType_t uxTopPriority; \ 00343 \ 00344 /* Find the highest priority queue that contains ready tasks. */ \ 00345 portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ 00346 configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ 00347 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ 00348 } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ 00349 00350 /*-----------------------------------------------------------*/ 00351 00352 /* A port optimised version is provided, call it only if the TCB being reset 00353 is being referenced from a ready list. If it is referenced from a delayed 00354 or suspended list then it won't be in a ready list. */ 00355 #define taskRESET_READY_PRIORITY( uxPriority ) \ 00356 { \ 00357 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) \ 00358 { \ 00359 portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \ 00360 } \ 00361 } 00362 00363 #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ 00364 00365 /*-----------------------------------------------------------*/ 00366 00367 /* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick 00368 count overflows. */ 00369 #define taskSWITCH_DELAYED_LISTS() \ 00370 { \ 00371 List_t *pxTemp; \ 00372 \ 00373 /* The delayed tasks list should be empty when the lists are switched. */ \ 00374 configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \ 00375 \ 00376 pxTemp = pxDelayedTaskList; \ 00377 pxDelayedTaskList = pxOverflowDelayedTaskList; \ 00378 pxOverflowDelayedTaskList = pxTemp; \ 00379 xNumOfOverflows++; \ 00380 prvResetNextTaskUnblockTime(); \ 00381 } 00382 00383 /*-----------------------------------------------------------*/ 00384 00385 /* 00386 * Place the task represented by pxTCB into the appropriate ready list for 00387 * the task. It is inserted at the end of the list. 00388 */ 00389 #define prvAddTaskToReadyList( pxTCB ) \ 00390 traceMOVED_TASK_TO_READY_STATE( pxTCB ); \ 00391 taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \ 00392 vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) ) 00393 /*-----------------------------------------------------------*/ 00394 00395 /* 00396 * Several functions take an TaskHandle_t parameter that can optionally be NULL, 00397 * where NULL is used to indicate that the handle of the currently executing 00398 * task should be used in place of the parameter. This macro simply checks to 00399 * see if the parameter is NULL and returns a pointer to the appropriate TCB. 00400 */ 00401 #define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) ) 00402 00403 /* The item value of the event list item is normally used to hold the priority 00404 of the task to which it belongs (coded to allow it to be held in reverse 00405 priority order). However, it is occasionally borrowed for other purposes. It 00406 is important its value is not updated due to a task priority change while it is 00407 being used for another purpose. The following bit definition is used to inform 00408 the scheduler that the value should not be changed - in which case it is the 00409 responsibility of whichever module is using the value to ensure it gets set back 00410 to its original value when it is released. */ 00411 #if configUSE_16_BIT_TICKS == 1 00412 #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U 00413 #else 00414 #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL 00415 #endif 00416 00417 /* Callback function prototypes. --------------------------*/ 00418 #if configCHECK_FOR_STACK_OVERFLOW > 0 00419 extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ); 00420 #endif 00421 00422 #if configUSE_TICK_HOOK > 0 00423 extern void vApplicationTickHook( void ); 00424 #endif 00425 00426 /* File private functions. --------------------------------*/ 00427 00428 /* 00429 * Utility to ready a TCB for a given task. Mainly just copies the parameters 00430 * into the TCB structure. 00431 */ 00432 static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 00433 00434 /** 00435 * Utility task that simply returns pdTRUE if the task referenced by xTask is 00436 * currently in the Suspended state, or pdFALSE if the task referenced by xTask 00437 * is in any other state. 00438 */ 00439 #if ( INCLUDE_vTaskSuspend == 1 ) 00440 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; 00441 #endif /* INCLUDE_vTaskSuspend */ 00442 00443 /* 00444 * Utility to ready all the lists used by the scheduler. This is called 00445 * automatically upon the creation of the first task. 00446 */ 00447 static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; 00448 00449 /* 00450 * The idle task, which as all tasks is implemented as a never ending loop. 00451 * The idle task is automatically created and added to the ready lists upon 00452 * creation of the first user task. 00453 * 00454 * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific 00455 * language extensions. The equivalent prototype for this function is: 00456 * 00457 * void prvIdleTask( void *pvParameters ); 00458 * 00459 */ 00460 static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ); 00461 00462 /* 00463 * Utility to free all memory allocated by the scheduler to hold a TCB, 00464 * including the stack pointed to by the TCB. 00465 * 00466 * This does not free memory allocated by the task itself (i.e. memory 00467 * allocated by calls to pvPortMalloc from within the tasks application code). 00468 */ 00469 #if ( INCLUDE_vTaskDelete == 1 ) 00470 00471 static void prvDeleteTCB( TCB_t *pxTCB ) PRIVILEGED_FUNCTION; 00472 00473 #endif 00474 00475 /* 00476 * Used only by the idle task. This checks to see if anything has been placed 00477 * in the list of tasks waiting to be deleted. If so the task is cleaned up 00478 * and its TCB deleted. 00479 */ 00480 static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; 00481 00482 /* 00483 * The currently executing task is entering the Blocked state. Add the task to 00484 * either the current or the overflow delayed task list. 00485 */ 00486 static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake ) PRIVILEGED_FUNCTION; 00487 00488 /* 00489 * Allocates memory from the heap for a TCB and associated stack. Checks the 00490 * allocation was successful. 00491 */ 00492 static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) PRIVILEGED_FUNCTION; 00493 00494 /* 00495 * Fills an TaskStatus_t structure with information on each task that is 00496 * referenced from the pxList list (which may be a ready list, a delayed list, 00497 * a suspended list, etc.). 00498 * 00499 * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM 00500 * NORMAL APPLICATION CODE. 00501 */ 00502 #if ( configUSE_TRACE_FACILITY == 1 ) 00503 00504 static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION; 00505 00506 #endif 00507 00508 /* 00509 * When a task is created, the stack of the task is filled with a known value. 00510 * This function determines the 'high water mark' of the task stack by 00511 * determining how much of the stack remains at the original preset value. 00512 */ 00513 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) 00514 00515 static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION; 00516 00517 #endif 00518 00519 /* 00520 * Return the amount of time, in ticks, that will pass before the kernel will 00521 * next move a task from the Blocked state to the Running state. 00522 * 00523 * This conditional compilation should use inequality to 0, not equality to 1. 00524 * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user 00525 * defined low power mode implementations require configUSE_TICKLESS_IDLE to be 00526 * set to a value other than 1. 00527 */ 00528 #if ( configUSE_TICKLESS_IDLE != 0 ) 00529 00530 static TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION; 00531 00532 #endif 00533 00534 /* 00535 * Set xNextTaskUnblockTime to the time at which the next Blocked state task 00536 * will exit the Blocked state. 00537 */ 00538 static void prvResetNextTaskUnblockTime( void ); 00539 00540 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) 00541 00542 /* 00543 * Helper function used to pad task names with spaces when printing out 00544 * human readable tables of task information. 00545 */ 00546 static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ); 00547 00548 #endif 00549 /*-----------------------------------------------------------*/ 00550 00551 BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 00552 { 00553 BaseType_t xReturn; 00554 TCB_t * pxNewTCB; 00555 StackType_t *pxTopOfStack; 00556 00557 configASSERT( pxTaskCode ); 00558 configASSERT( ( ( uxPriority & ( UBaseType_t ) ( ~portPRIVILEGE_BIT ) ) < ( UBaseType_t ) configMAX_PRIORITIES ) ); 00559 00560 /* Allocate the memory required by the TCB and stack for the new task, 00561 checking that the allocation was successful. */ 00562 pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer ); 00563 00564 if( pxNewTCB != NULL ) 00565 { 00566 #if( portUSING_MPU_WRAPPERS == 1 ) 00567 /* Should the task be created in privileged mode? */ 00568 BaseType_t xRunPrivileged; 00569 if( ( uxPriority & portPRIVILEGE_BIT ) != 0U ) 00570 { 00571 xRunPrivileged = pdTRUE; 00572 } 00573 else 00574 { 00575 xRunPrivileged = pdFALSE; 00576 } 00577 uxPriority &= ~portPRIVILEGE_BIT; 00578 00579 if( puxStackBuffer != NULL ) 00580 { 00581 /* The application provided its own stack. Note this so no 00582 attempt is made to delete the stack should that task be 00583 deleted. */ 00584 pxNewTCB->xUsingStaticallyAllocatedStack = pdTRUE; 00585 } 00586 else 00587 { 00588 /* The stack was allocated dynamically. Note this so it can be 00589 deleted again if the task is deleted. */ 00590 pxNewTCB->xUsingStaticallyAllocatedStack = pdFALSE; 00591 } 00592 #endif /* portUSING_MPU_WRAPPERS == 1 */ 00593 00594 /* Calculate the top of stack address. This depends on whether the 00595 stack grows from high memory to low (as per the 80x86) or vice versa. 00596 portSTACK_GROWTH is used to make the result positive or negative as 00597 required by the port. */ 00598 #if( portSTACK_GROWTH < 0 ) 00599 { 00600 pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( uint16_t ) 1 ); 00601 pxTopOfStack = ( StackType_t * ) ( ( ( 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. */ 00602 00603 /* Check the alignment of the calculated top of stack is correct. */ 00604 configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); 00605 } 00606 #else /* portSTACK_GROWTH */ 00607 { 00608 pxTopOfStack = pxNewTCB->pxStack; 00609 00610 /* Check the alignment of the stack buffer is correct. */ 00611 configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); 00612 00613 /* If we want to use stack checking on architectures that use 00614 a positive stack growth direction then we also need to store the 00615 other extreme of the stack space. */ 00616 pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ); 00617 } 00618 #endif /* portSTACK_GROWTH */ 00619 00620 /* Setup the newly allocated TCB with the initial state of the task. */ 00621 prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth ); 00622 00623 /* Initialize the TCB stack to look as if the task was already running, 00624 but had been interrupted by the scheduler. The return address is set 00625 to the start of the task function. Once the stack has been initialised 00626 the top of stack variable is updated. */ 00627 #if( portUSING_MPU_WRAPPERS == 1 ) 00628 { 00629 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); 00630 } 00631 #else /* portUSING_MPU_WRAPPERS */ 00632 { 00633 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); 00634 } 00635 #endif /* portUSING_MPU_WRAPPERS */ 00636 00637 if( ( void * ) pxCreatedTask != NULL ) 00638 { 00639 /* Pass the TCB out - in an anonymous way. The calling function/ 00640 task can use this as a handle to delete the task later if 00641 required.*/ 00642 *pxCreatedTask = ( TaskHandle_t ) pxNewTCB; 00643 } 00644 else 00645 { 00646 mtCOVERAGE_TEST_MARKER(); 00647 } 00648 00649 /* Ensure interrupts don't access the task lists while they are being 00650 updated. */ 00651 taskENTER_CRITICAL(); 00652 { 00653 uxCurrentNumberOfTasks++; 00654 if( pxCurrentTCB == NULL ) 00655 { 00656 /* There are no other tasks, or all the other tasks are in 00657 the suspended state - make this the current task. */ 00658 pxCurrentTCB = pxNewTCB; 00659 00660 if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) 00661 { 00662 /* This is the first task to be created so do the preliminary 00663 initialisation required. We will not recover if this call 00664 fails, but we will report the failure. */ 00665 prvInitialiseTaskLists(); 00666 } 00667 else 00668 { 00669 mtCOVERAGE_TEST_MARKER(); 00670 } 00671 } 00672 else 00673 { 00674 /* If the scheduler is not already running, make this task the 00675 current task if it is the highest priority task to be created 00676 so far. */ 00677 if( xSchedulerRunning == pdFALSE ) 00678 { 00679 if( pxCurrentTCB->uxPriority <= uxPriority ) 00680 { 00681 pxCurrentTCB = pxNewTCB; 00682 } 00683 else 00684 { 00685 mtCOVERAGE_TEST_MARKER(); 00686 } 00687 } 00688 else 00689 { 00690 mtCOVERAGE_TEST_MARKER(); 00691 } 00692 } 00693 00694 uxTaskNumber++; 00695 00696 #if ( configUSE_TRACE_FACILITY == 1 ) 00697 { 00698 /* Add a counter into the TCB for tracing only. */ 00699 pxNewTCB->uxTCBNumber = uxTaskNumber; 00700 } 00701 #endif /* configUSE_TRACE_FACILITY */ 00702 traceTASK_CREATE( pxNewTCB ); 00703 00704 prvAddTaskToReadyList( pxNewTCB ); 00705 00706 xReturn = pdPASS; 00707 portSETUP_TCB( pxNewTCB ); 00708 } 00709 taskEXIT_CRITICAL(); 00710 } 00711 else 00712 { 00713 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; 00714 traceTASK_CREATE_FAILED(); 00715 } 00716 00717 if( xReturn == pdPASS ) 00718 { 00719 if( xSchedulerRunning != pdFALSE ) 00720 { 00721 /* If the created task is of a higher priority than the current task 00722 then it should run now. */ 00723 if( pxCurrentTCB->uxPriority < uxPriority ) 00724 { 00725 taskYIELD_IF_USING_PREEMPTION(); 00726 } 00727 else 00728 { 00729 mtCOVERAGE_TEST_MARKER(); 00730 } 00731 } 00732 else 00733 { 00734 mtCOVERAGE_TEST_MARKER(); 00735 } 00736 } 00737 00738 return xReturn; 00739 } 00740 /*-----------------------------------------------------------*/ 00741 00742 #if ( INCLUDE_vTaskDelete == 1 ) 00743 00744 void vTaskDelete( TaskHandle_t xTaskToDelete ) 00745 { 00746 TCB_t *pxTCB; 00747 00748 taskENTER_CRITICAL(); 00749 { 00750 /* If null is passed in here then it is the calling task that is 00751 being deleted. */ 00752 pxTCB = prvGetTCBFromHandle( xTaskToDelete ); 00753 00754 /* Remove task from the ready list and place in the termination list. 00755 This will stop the task from be scheduled. The idle task will check 00756 the termination list and free up any memory allocated by the 00757 scheduler for the TCB and stack. */ 00758 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 00759 { 00760 taskRESET_READY_PRIORITY( pxTCB->uxPriority ); 00761 } 00762 else 00763 { 00764 mtCOVERAGE_TEST_MARKER(); 00765 } 00766 00767 /* Is the task waiting on an event also? */ 00768 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) 00769 { 00770 ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); 00771 } 00772 else 00773 { 00774 mtCOVERAGE_TEST_MARKER(); 00775 } 00776 00777 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) ); 00778 00779 /* Increment the ucTasksDeleted variable so the idle task knows 00780 there is a task that has been deleted and that it should therefore 00781 check the xTasksWaitingTermination list. */ 00782 ++uxTasksDeleted; 00783 00784 /* Increment the uxTaskNumberVariable also so kernel aware debuggers 00785 can detect that the task lists need re-generating. */ 00786 uxTaskNumber++; 00787 00788 traceTASK_DELETE( pxTCB ); 00789 } 00790 taskEXIT_CRITICAL(); 00791 00792 /* Force a reschedule if it is the currently running task that has just 00793 been deleted. */ 00794 if( xSchedulerRunning != pdFALSE ) 00795 { 00796 if( pxTCB == pxCurrentTCB ) 00797 { 00798 configASSERT( uxSchedulerSuspended == 0 ); 00799 00800 /* The pre-delete hook is primarily for the Windows simulator, 00801 in which Windows specific clean up operations are performed, 00802 after which it is not possible to yield away from this task - 00803 hence xYieldPending is used to latch that a context switch is 00804 required. */ 00805 portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending ); 00806 portYIELD_WITHIN_API(); 00807 } 00808 else 00809 { 00810 /* Reset the next expected unblock time in case it referred to 00811 the task that has just been deleted. */ 00812 taskENTER_CRITICAL(); 00813 { 00814 prvResetNextTaskUnblockTime(); 00815 } 00816 taskEXIT_CRITICAL(); 00817 } 00818 } 00819 } 00820 00821 #endif /* INCLUDE_vTaskDelete */ 00822 /*-----------------------------------------------------------*/ 00823 00824 #if ( INCLUDE_vTaskDelayUntil == 1 ) 00825 00826 void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) 00827 { 00828 TickType_t xTimeToWake; 00829 BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE; 00830 00831 configASSERT( pxPreviousWakeTime ); 00832 configASSERT( ( xTimeIncrement > 0U ) ); 00833 configASSERT( uxSchedulerSuspended == 0 ); 00834 00835 vTaskSuspendAll(); 00836 { 00837 /* Minor optimisation. The tick count cannot change in this 00838 block. */ 00839 const TickType_t xConstTickCount = xTickCount; 00840 00841 /* Generate the tick time at which the task wants to wake. */ 00842 xTimeToWake = *pxPreviousWakeTime + xTimeIncrement; 00843 00844 if( xConstTickCount < *pxPreviousWakeTime ) 00845 { 00846 /* The tick count has overflowed since this function was 00847 lasted called. In this case the only time we should ever 00848 actually delay is if the wake time has also overflowed, 00849 and the wake time is greater than the tick time. When this 00850 is the case it is as if neither time had overflowed. */ 00851 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) ) 00852 { 00853 xShouldDelay = pdTRUE; 00854 } 00855 else 00856 { 00857 mtCOVERAGE_TEST_MARKER(); 00858 } 00859 } 00860 else 00861 { 00862 /* The tick time has not overflowed. In this case we will 00863 delay if either the wake time has overflowed, and/or the 00864 tick time is less than the wake time. */ 00865 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) ) 00866 { 00867 xShouldDelay = pdTRUE; 00868 } 00869 else 00870 { 00871 mtCOVERAGE_TEST_MARKER(); 00872 } 00873 } 00874 00875 /* Update the wake time ready for the next call. */ 00876 *pxPreviousWakeTime = xTimeToWake; 00877 00878 if( xShouldDelay != pdFALSE ) 00879 { 00880 traceTASK_DELAY_UNTIL(); 00881 00882 /* Remove the task from the ready list before adding it to the 00883 blocked list as the same list item is used for both lists. */ 00884 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 00885 { 00886 /* The current task must be in a ready list, so there is 00887 no need to check, and the port reset macro can be called 00888 directly. */ 00889 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 00890 } 00891 else 00892 { 00893 mtCOVERAGE_TEST_MARKER(); 00894 } 00895 00896 prvAddCurrentTaskToDelayedList( xTimeToWake ); 00897 } 00898 else 00899 { 00900 mtCOVERAGE_TEST_MARKER(); 00901 } 00902 } 00903 xAlreadyYielded = xTaskResumeAll(); 00904 00905 /* Force a reschedule if xTaskResumeAll has not already done so, we may 00906 have put ourselves to sleep. */ 00907 if( xAlreadyYielded == pdFALSE ) 00908 { 00909 portYIELD_WITHIN_API(); 00910 } 00911 else 00912 { 00913 mtCOVERAGE_TEST_MARKER(); 00914 } 00915 } 00916 00917 #endif /* INCLUDE_vTaskDelayUntil */ 00918 /*-----------------------------------------------------------*/ 00919 00920 #if ( INCLUDE_vTaskDelay == 1 ) 00921 00922 void vTaskDelay( const TickType_t xTicksToDelay ) 00923 { 00924 TickType_t xTimeToWake; 00925 BaseType_t xAlreadyYielded = pdFALSE; 00926 00927 00928 /* A delay time of zero just forces a reschedule. */ 00929 if( xTicksToDelay > ( TickType_t ) 0U ) 00930 { 00931 configASSERT( uxSchedulerSuspended == 0 ); 00932 vTaskSuspendAll(); 00933 { 00934 traceTASK_DELAY(); 00935 00936 /* A task that is removed from the event list while the 00937 scheduler is suspended will not get placed in the ready 00938 list or removed from the blocked list until the scheduler 00939 is resumed. 00940 00941 This task cannot be in an event list as it is the currently 00942 executing task. */ 00943 00944 /* Calculate the time to wake - this may overflow but this is 00945 not a problem. */ 00946 xTimeToWake = xTickCount + xTicksToDelay; 00947 00948 /* We must remove ourselves from the ready list before adding 00949 ourselves to the blocked list as the same list item is used for 00950 both lists. */ 00951 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 00952 { 00953 /* The current task must be in a ready list, so there is 00954 no need to check, and the port reset macro can be called 00955 directly. */ 00956 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 00957 } 00958 else 00959 { 00960 mtCOVERAGE_TEST_MARKER(); 00961 } 00962 prvAddCurrentTaskToDelayedList( xTimeToWake ); 00963 } 00964 xAlreadyYielded = xTaskResumeAll(); 00965 } 00966 else 00967 { 00968 mtCOVERAGE_TEST_MARKER(); 00969 } 00970 00971 /* Force a reschedule if xTaskResumeAll has not already done so, we may 00972 have put ourselves to sleep. */ 00973 if( xAlreadyYielded == pdFALSE ) 00974 { 00975 portYIELD_WITHIN_API(); 00976 } 00977 else 00978 { 00979 mtCOVERAGE_TEST_MARKER(); 00980 } 00981 } 00982 00983 #endif /* INCLUDE_vTaskDelay */ 00984 /*-----------------------------------------------------------*/ 00985 00986 #if ( INCLUDE_eTaskGetState == 1 ) 00987 00988 eTaskState eTaskGetState( TaskHandle_t xTask ) 00989 { 00990 eTaskState eReturn; 00991 List_t *pxStateList; 00992 const TCB_t * const pxTCB = ( TCB_t * ) xTask; 00993 00994 configASSERT( pxTCB ); 00995 00996 if( pxTCB == pxCurrentTCB ) 00997 { 00998 /* The task calling this function is querying its own state. */ 00999 eReturn = eRunning; 01000 } 01001 else 01002 { 01003 taskENTER_CRITICAL(); 01004 { 01005 pxStateList = ( List_t * ) listLIST_ITEM_CONTAINER( &( pxTCB->xGenericListItem ) ); 01006 } 01007 taskEXIT_CRITICAL(); 01008 01009 if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) ) 01010 { 01011 /* The task being queried is referenced from one of the Blocked 01012 lists. */ 01013 eReturn = eBlocked; 01014 } 01015 01016 #if ( INCLUDE_vTaskSuspend == 1 ) 01017 else if( pxStateList == &xSuspendedTaskList ) 01018 { 01019 /* The task being queried is referenced from the suspended 01020 list. Is it genuinely suspended or is it block 01021 indefinitely? */ 01022 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ) 01023 { 01024 eReturn = eSuspended; 01025 } 01026 else 01027 { 01028 eReturn = eBlocked; 01029 } 01030 } 01031 #endif 01032 01033 #if ( INCLUDE_vTaskDelete == 1 ) 01034 else if( pxStateList == &xTasksWaitingTermination ) 01035 { 01036 /* The task being queried is referenced from the deleted 01037 tasks list. */ 01038 eReturn = eDeleted; 01039 } 01040 #endif 01041 01042 else /*lint !e525 Negative indentation is intended to make use of pre-processor clearer. */ 01043 { 01044 /* If the task is not in any other state, it must be in the 01045 Ready (including pending ready) state. */ 01046 eReturn = eReady; 01047 } 01048 } 01049 01050 return eReturn; 01051 } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ 01052 01053 #endif /* INCLUDE_eTaskGetState */ 01054 /*-----------------------------------------------------------*/ 01055 01056 #if ( INCLUDE_uxTaskPriorityGet == 1 ) 01057 01058 UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ) 01059 { 01060 TCB_t *pxTCB; 01061 UBaseType_t uxReturn; 01062 01063 taskENTER_CRITICAL(); 01064 { 01065 /* If null is passed in here then we are changing the 01066 priority of the calling function. */ 01067 pxTCB = prvGetTCBFromHandle( xTask ); 01068 uxReturn = pxTCB->uxPriority; 01069 } 01070 taskEXIT_CRITICAL(); 01071 01072 return uxReturn; 01073 } 01074 01075 #endif /* INCLUDE_uxTaskPriorityGet */ 01076 /*-----------------------------------------------------------*/ 01077 01078 #if ( INCLUDE_uxTaskPriorityGet == 1 ) 01079 01080 UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) 01081 { 01082 TCB_t *pxTCB; 01083 UBaseType_t uxReturn, uxSavedInterruptState; 01084 01085 /* RTOS ports that support interrupt nesting have the concept of a 01086 maximum system call (or maximum API call) interrupt priority. 01087 Interrupts that are above the maximum system call priority are keep 01088 permanently enabled, even when the RTOS kernel is in a critical section, 01089 but cannot make any calls to FreeRTOS API functions. If configASSERT() 01090 is defined in FreeRTOSConfig.h then 01091 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion 01092 failure if a FreeRTOS API function is called from an interrupt that has 01093 been assigned a priority above the configured maximum system call 01094 priority. Only FreeRTOS functions that end in FromISR can be called 01095 from interrupts that have been assigned a priority at or (logically) 01096 below the maximum system call interrupt priority. FreeRTOS maintains a 01097 separate interrupt safe API to ensure interrupt entry is as fast and as 01098 simple as possible. More information (albeit Cortex-M specific) is 01099 provided on the following link: 01100 http://www.freertos.org/RTOS-Cortex-M3-M4.html */ 01101 portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); 01102 01103 uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR(); 01104 { 01105 /* If null is passed in here then it is the priority of the calling 01106 task that is being queried. */ 01107 pxTCB = prvGetTCBFromHandle( xTask ); 01108 uxReturn = pxTCB->uxPriority; 01109 } 01110 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptState ); 01111 01112 return uxReturn; 01113 } 01114 01115 #endif /* INCLUDE_uxTaskPriorityGet */ 01116 /*-----------------------------------------------------------*/ 01117 01118 #if ( INCLUDE_vTaskPrioritySet == 1 ) 01119 01120 void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) 01121 { 01122 TCB_t *pxTCB; 01123 UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry; 01124 BaseType_t xYieldRequired = pdFALSE; 01125 01126 configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); 01127 01128 /* Ensure the new priority is valid. */ 01129 if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) 01130 { 01131 uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; 01132 } 01133 else 01134 { 01135 mtCOVERAGE_TEST_MARKER(); 01136 } 01137 01138 taskENTER_CRITICAL(); 01139 { 01140 /* If null is passed in here then it is the priority of the calling 01141 task that is being changed. */ 01142 pxTCB = prvGetTCBFromHandle( xTask ); 01143 01144 traceTASK_PRIORITY_SET( pxTCB, uxNewPriority ); 01145 01146 #if ( configUSE_MUTEXES == 1 ) 01147 { 01148 uxCurrentBasePriority = pxTCB->uxBasePriority; 01149 } 01150 #else 01151 { 01152 uxCurrentBasePriority = pxTCB->uxPriority; 01153 } 01154 #endif 01155 01156 if( uxCurrentBasePriority != uxNewPriority ) 01157 { 01158 /* The priority change may have readied a task of higher 01159 priority than the calling task. */ 01160 if( uxNewPriority > uxCurrentBasePriority ) 01161 { 01162 if( pxTCB != pxCurrentTCB ) 01163 { 01164 /* The priority of a task other than the currently 01165 running task is being raised. Is the priority being 01166 raised above that of the running task? */ 01167 if( uxNewPriority >= pxCurrentTCB->uxPriority ) 01168 { 01169 xYieldRequired = pdTRUE; 01170 } 01171 else 01172 { 01173 mtCOVERAGE_TEST_MARKER(); 01174 } 01175 } 01176 else 01177 { 01178 /* The priority of the running task is being raised, 01179 but the running task must already be the highest 01180 priority task able to run so no yield is required. */ 01181 } 01182 } 01183 else if( pxTCB == pxCurrentTCB ) 01184 { 01185 /* Setting the priority of the running task down means 01186 there may now be another task of higher priority that 01187 is ready to execute. */ 01188 xYieldRequired = pdTRUE; 01189 } 01190 else 01191 { 01192 /* Setting the priority of any other task down does not 01193 require a yield as the running task must be above the 01194 new priority of the task being modified. */ 01195 } 01196 01197 /* Remember the ready list the task might be referenced from 01198 before its uxPriority member is changed so the 01199 taskRESET_READY_PRIORITY() macro can function correctly. */ 01200 uxPriorityUsedOnEntry = pxTCB->uxPriority; 01201 01202 #if ( configUSE_MUTEXES == 1 ) 01203 { 01204 /* Only change the priority being used if the task is not 01205 currently using an inherited priority. */ 01206 if( pxTCB->uxBasePriority == pxTCB->uxPriority ) 01207 { 01208 pxTCB->uxPriority = uxNewPriority; 01209 } 01210 else 01211 { 01212 mtCOVERAGE_TEST_MARKER(); 01213 } 01214 01215 /* The base priority gets set whatever. */ 01216 pxTCB->uxBasePriority = uxNewPriority; 01217 } 01218 #else 01219 { 01220 pxTCB->uxPriority = uxNewPriority; 01221 } 01222 #endif 01223 01224 /* Only reset the event list item value if the value is not 01225 being used for anything else. */ 01226 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) 01227 { 01228 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 01229 } 01230 else 01231 { 01232 mtCOVERAGE_TEST_MARKER(); 01233 } 01234 01235 /* If the task is in the blocked or suspended list we need do 01236 nothing more than change it's priority variable. However, if 01237 the task is in a ready list it needs to be removed and placed 01238 in the list appropriate to its new priority. */ 01239 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE ) 01240 { 01241 /* The task is currently in its ready list - remove before adding 01242 it to it's new ready list. As we are in a critical section we 01243 can do this even if the scheduler is suspended. */ 01244 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 01245 { 01246 /* It is known that the task is in its ready list so 01247 there is no need to check again and the port level 01248 reset macro can be called directly. */ 01249 portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); 01250 } 01251 else 01252 { 01253 mtCOVERAGE_TEST_MARKER(); 01254 } 01255 prvAddTaskToReadyList( pxTCB ); 01256 } 01257 else 01258 { 01259 mtCOVERAGE_TEST_MARKER(); 01260 } 01261 01262 if( xYieldRequired == pdTRUE ) 01263 { 01264 taskYIELD_IF_USING_PREEMPTION(); 01265 } 01266 else 01267 { 01268 mtCOVERAGE_TEST_MARKER(); 01269 } 01270 01271 /* Remove compiler warning about unused variables when the port 01272 optimised task selection is not being used. */ 01273 ( void ) uxPriorityUsedOnEntry; 01274 } 01275 } 01276 taskEXIT_CRITICAL(); 01277 } 01278 01279 #endif /* INCLUDE_vTaskPrioritySet */ 01280 /*-----------------------------------------------------------*/ 01281 01282 #if ( INCLUDE_vTaskSuspend == 1 ) 01283 01284 void vTaskSuspend( TaskHandle_t xTaskToSuspend ) 01285 { 01286 TCB_t *pxTCB; 01287 01288 taskENTER_CRITICAL(); 01289 { 01290 /* If null is passed in here then it is the running task that is 01291 being suspended. */ 01292 pxTCB = prvGetTCBFromHandle( xTaskToSuspend ); 01293 01294 traceTASK_SUSPEND( pxTCB ); 01295 01296 /* Remove task from the ready/delayed list and place in the 01297 suspended list. */ 01298 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 01299 { 01300 taskRESET_READY_PRIORITY( pxTCB->uxPriority ); 01301 } 01302 else 01303 { 01304 mtCOVERAGE_TEST_MARKER(); 01305 } 01306 01307 /* Is the task waiting on an event also? */ 01308 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) 01309 { 01310 ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); 01311 } 01312 else 01313 { 01314 mtCOVERAGE_TEST_MARKER(); 01315 } 01316 01317 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ); 01318 } 01319 taskEXIT_CRITICAL(); 01320 01321 if( pxTCB == pxCurrentTCB ) 01322 { 01323 if( xSchedulerRunning != pdFALSE ) 01324 { 01325 /* The current task has just been suspended. */ 01326 configASSERT( uxSchedulerSuspended == 0 ); 01327 portYIELD_WITHIN_API(); 01328 } 01329 else 01330 { 01331 /* The scheduler is not running, but the task that was pointed 01332 to by pxCurrentTCB has just been suspended and pxCurrentTCB 01333 must be adjusted to point to a different task. */ 01334 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) 01335 { 01336 /* No other tasks are ready, so set pxCurrentTCB back to 01337 NULL so when the next task is created pxCurrentTCB will 01338 be set to point to it no matter what its relative priority 01339 is. */ 01340 pxCurrentTCB = NULL; 01341 } 01342 else 01343 { 01344 vTaskSwitchContext(); 01345 } 01346 } 01347 } 01348 else 01349 { 01350 if( xSchedulerRunning != pdFALSE ) 01351 { 01352 /* A task other than the currently running task was suspended, 01353 reset the next expected unblock time in case it referred to the 01354 task that is now in the Suspended state. */ 01355 taskENTER_CRITICAL(); 01356 { 01357 prvResetNextTaskUnblockTime(); 01358 } 01359 taskEXIT_CRITICAL(); 01360 } 01361 else 01362 { 01363 mtCOVERAGE_TEST_MARKER(); 01364 } 01365 } 01366 } 01367 01368 #endif /* INCLUDE_vTaskSuspend */ 01369 /*-----------------------------------------------------------*/ 01370 01371 #if ( INCLUDE_vTaskSuspend == 1 ) 01372 01373 static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) 01374 { 01375 BaseType_t xReturn = pdFALSE; 01376 const TCB_t * const pxTCB = ( TCB_t * ) xTask; 01377 01378 /* Accesses xPendingReadyList so must be called from a critical 01379 section. */ 01380 01381 /* It does not make sense to check if the calling task is suspended. */ 01382 configASSERT( xTask ); 01383 01384 /* Is the task being resumed actually in the suspended list? */ 01385 if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE ) 01386 { 01387 /* Has the task already been resumed from within an ISR? */ 01388 if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) 01389 { 01390 /* Is it in the suspended list because it is in the Suspended 01391 state, or because is is blocked with no timeout? */ 01392 if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) 01393 { 01394 xReturn = pdTRUE; 01395 } 01396 else 01397 { 01398 mtCOVERAGE_TEST_MARKER(); 01399 } 01400 } 01401 else 01402 { 01403 mtCOVERAGE_TEST_MARKER(); 01404 } 01405 } 01406 else 01407 { 01408 mtCOVERAGE_TEST_MARKER(); 01409 } 01410 01411 return xReturn; 01412 } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ 01413 01414 #endif /* INCLUDE_vTaskSuspend */ 01415 /*-----------------------------------------------------------*/ 01416 01417 #if ( INCLUDE_vTaskSuspend == 1 ) 01418 01419 void vTaskResume( TaskHandle_t xTaskToResume ) 01420 { 01421 TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume; 01422 01423 /* It does not make sense to resume the calling task. */ 01424 configASSERT( xTaskToResume ); 01425 01426 /* The parameter cannot be NULL as it is impossible to resume the 01427 currently executing task. */ 01428 if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ) 01429 { 01430 taskENTER_CRITICAL(); 01431 { 01432 if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE ) 01433 { 01434 traceTASK_RESUME( pxTCB ); 01435 01436 /* As we are in a critical section we can access the ready 01437 lists even if the scheduler is suspended. */ 01438 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 01439 prvAddTaskToReadyList( pxTCB ); 01440 01441 /* We may have just resumed a higher priority task. */ 01442 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) 01443 { 01444 /* This yield may not cause the task just resumed to run, 01445 but will leave the lists in the correct state for the 01446 next yield. */ 01447 taskYIELD_IF_USING_PREEMPTION(); 01448 } 01449 else 01450 { 01451 mtCOVERAGE_TEST_MARKER(); 01452 } 01453 } 01454 else 01455 { 01456 mtCOVERAGE_TEST_MARKER(); 01457 } 01458 } 01459 taskEXIT_CRITICAL(); 01460 } 01461 else 01462 { 01463 mtCOVERAGE_TEST_MARKER(); 01464 } 01465 } 01466 01467 #endif /* INCLUDE_vTaskSuspend */ 01468 01469 /*-----------------------------------------------------------*/ 01470 01471 #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) 01472 01473 BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) 01474 { 01475 BaseType_t xYieldRequired = pdFALSE; 01476 TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume; 01477 UBaseType_t uxSavedInterruptStatus; 01478 01479 configASSERT( xTaskToResume ); 01480 01481 /* RTOS ports that support interrupt nesting have the concept of a 01482 maximum system call (or maximum API call) interrupt priority. 01483 Interrupts that are above the maximum system call priority are keep 01484 permanently enabled, even when the RTOS kernel is in a critical section, 01485 but cannot make any calls to FreeRTOS API functions. If configASSERT() 01486 is defined in FreeRTOSConfig.h then 01487 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion 01488 failure if a FreeRTOS API function is called from an interrupt that has 01489 been assigned a priority above the configured maximum system call 01490 priority. Only FreeRTOS functions that end in FromISR can be called 01491 from interrupts that have been assigned a priority at or (logically) 01492 below the maximum system call interrupt priority. FreeRTOS maintains a 01493 separate interrupt safe API to ensure interrupt entry is as fast and as 01494 simple as possible. More information (albeit Cortex-M specific) is 01495 provided on the following link: 01496 http://www.freertos.org/RTOS-Cortex-M3-M4.html */ 01497 portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); 01498 01499 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); 01500 { 01501 if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE ) 01502 { 01503 traceTASK_RESUME_FROM_ISR( pxTCB ); 01504 01505 /* Check the ready lists can be accessed. */ 01506 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) 01507 { 01508 /* Ready lists can be accessed so move the task from the 01509 suspended list to the ready list directly. */ 01510 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) 01511 { 01512 xYieldRequired = pdTRUE; 01513 } 01514 else 01515 { 01516 mtCOVERAGE_TEST_MARKER(); 01517 } 01518 01519 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 01520 prvAddTaskToReadyList( pxTCB ); 01521 } 01522 else 01523 { 01524 /* The delayed or ready lists cannot be accessed so the task 01525 is held in the pending ready list until the scheduler is 01526 unsuspended. */ 01527 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); 01528 } 01529 } 01530 else 01531 { 01532 mtCOVERAGE_TEST_MARKER(); 01533 } 01534 } 01535 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 01536 01537 return xYieldRequired; 01538 } 01539 01540 #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */ 01541 /*-----------------------------------------------------------*/ 01542 01543 void vTaskStartScheduler( void ) 01544 { 01545 BaseType_t xReturn; 01546 01547 /* Add the idle task at the lowest priority. */ 01548 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) 01549 { 01550 /* Create the idle task, storing its handle in xIdleTaskHandle so it can 01551 be returned by the xTaskGetIdleTaskHandle() function. */ 01552 xReturn = xTaskCreate( prvIdleTask, "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. */ 01553 } 01554 #else 01555 { 01556 /* Create the idle task without storing its handle. */ 01557 xReturn = xTaskCreate( prvIdleTask, "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. */ 01558 } 01559 #endif /* INCLUDE_xTaskGetIdleTaskHandle */ 01560 01561 #if ( configUSE_TIMERS == 1 ) 01562 { 01563 if( xReturn == pdPASS ) 01564 { 01565 xReturn = xTimerCreateTimerTask(); 01566 } 01567 else 01568 { 01569 mtCOVERAGE_TEST_MARKER(); 01570 } 01571 } 01572 #endif /* configUSE_TIMERS */ 01573 01574 if( xReturn == pdPASS ) 01575 { 01576 /* Interrupts are turned off here, to ensure a tick does not occur 01577 before or during the call to xPortStartScheduler(). The stacks of 01578 the created tasks contain a status word with interrupts switched on 01579 so interrupts will automatically get re-enabled when the first task 01580 starts to run. */ 01581 portDISABLE_INTERRUPTS(); 01582 01583 #if ( configUSE_NEWLIB_REENTRANT == 1 ) 01584 { 01585 /* Switch Newlib's _impure_ptr variable to point to the _reent 01586 structure specific to the task that will run first. */ 01587 _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); 01588 } 01589 #endif /* configUSE_NEWLIB_REENTRANT */ 01590 01591 xSchedulerRunning = pdTRUE; 01592 xTickCount = ( TickType_t ) 0U; 01593 01594 /* If configGENERATE_RUN_TIME_STATS is defined then the following 01595 macro must be defined to configure the timer/counter used to generate 01596 the run time counter time base. */ 01597 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); 01598 01599 /* Setting up the timer tick is hardware specific and thus in the 01600 portable interface. */ 01601 if( xPortStartScheduler() != pdFALSE ) 01602 { 01603 /* Should not reach here as if the scheduler is running the 01604 function will not return. */ 01605 } 01606 else 01607 { 01608 /* Should only reach here if a task calls xTaskEndScheduler(). */ 01609 } 01610 } 01611 else 01612 { 01613 /* This line will only be reached if the kernel could not be started, 01614 because there was not enough FreeRTOS heap to create the idle task 01615 or the timer task. */ 01616 configASSERT( xReturn ); 01617 } 01618 } 01619 /*-----------------------------------------------------------*/ 01620 01621 void vTaskEndScheduler( void ) 01622 { 01623 /* Stop the scheduler interrupts and call the portable scheduler end 01624 routine so the original ISRs can be restored if necessary. The port 01625 layer must ensure interrupts enable bit is left in the correct state. */ 01626 portDISABLE_INTERRUPTS(); 01627 xSchedulerRunning = pdFALSE; 01628 vPortEndScheduler(); 01629 } 01630 /*----------------------------------------------------------*/ 01631 01632 void vTaskSuspendAll( void ) 01633 { 01634 /* A critical section is not required as the variable is of type 01635 BaseType_t. Please read Richard Barry's reply in the following link to a 01636 post in the FreeRTOS support forum before reporting this as a bug! - 01637 http://goo.gl/wu4acr */ 01638 ++uxSchedulerSuspended; 01639 } 01640 /*----------------------------------------------------------*/ 01641 01642 #if ( configUSE_TICKLESS_IDLE != 0 ) 01643 01644 static TickType_t prvGetExpectedIdleTime( void ) 01645 { 01646 TickType_t xReturn; 01647 01648 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY ) 01649 { 01650 xReturn = 0; 01651 } 01652 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 ) 01653 { 01654 /* There are other idle priority tasks in the ready state. If 01655 time slicing is used then the very next tick interrupt must be 01656 processed. */ 01657 xReturn = 0; 01658 } 01659 else 01660 { 01661 xReturn = xNextTaskUnblockTime - xTickCount; 01662 } 01663 01664 return xReturn; 01665 } 01666 01667 #endif /* configUSE_TICKLESS_IDLE */ 01668 /*----------------------------------------------------------*/ 01669 01670 BaseType_t xTaskResumeAll( void ) 01671 { 01672 TCB_t *pxTCB; 01673 BaseType_t xAlreadyYielded = pdFALSE; 01674 01675 /* If uxSchedulerSuspended is zero then this function does not match a 01676 previous call to vTaskSuspendAll(). */ 01677 configASSERT( uxSchedulerSuspended ); 01678 01679 /* It is possible that an ISR caused a task to be removed from an event 01680 list while the scheduler was suspended. If this was the case then the 01681 removed task will have been added to the xPendingReadyList. Once the 01682 scheduler has been resumed it is safe to move all the pending ready 01683 tasks from this list into their appropriate ready list. */ 01684 taskENTER_CRITICAL(); 01685 { 01686 --uxSchedulerSuspended; 01687 01688 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) 01689 { 01690 if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ) 01691 { 01692 /* Move any readied tasks from the pending list into the 01693 appropriate ready list. */ 01694 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ) 01695 { 01696 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); 01697 ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); 01698 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 01699 prvAddTaskToReadyList( pxTCB ); 01700 01701 /* If the moved task has a priority higher than the current 01702 task then a yield must be performed. */ 01703 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) 01704 { 01705 xYieldPending = pdTRUE; 01706 } 01707 else 01708 { 01709 mtCOVERAGE_TEST_MARKER(); 01710 } 01711 } 01712 01713 /* If any ticks occurred while the scheduler was suspended then 01714 they should be processed now. This ensures the tick count does 01715 not slip, and that any delayed tasks are resumed at the correct 01716 time. */ 01717 if( uxPendedTicks > ( UBaseType_t ) 0U ) 01718 { 01719 while( uxPendedTicks > ( UBaseType_t ) 0U ) 01720 { 01721 if( xTaskIncrementTick() != pdFALSE ) 01722 { 01723 xYieldPending = pdTRUE; 01724 } 01725 else 01726 { 01727 mtCOVERAGE_TEST_MARKER(); 01728 } 01729 --uxPendedTicks; 01730 } 01731 } 01732 else 01733 { 01734 mtCOVERAGE_TEST_MARKER(); 01735 } 01736 01737 if( xYieldPending == pdTRUE ) 01738 { 01739 #if( configUSE_PREEMPTION != 0 ) 01740 { 01741 xAlreadyYielded = pdTRUE; 01742 } 01743 #endif 01744 taskYIELD_IF_USING_PREEMPTION(); 01745 } 01746 else 01747 { 01748 mtCOVERAGE_TEST_MARKER(); 01749 } 01750 } 01751 } 01752 else 01753 { 01754 mtCOVERAGE_TEST_MARKER(); 01755 } 01756 } 01757 taskEXIT_CRITICAL(); 01758 01759 return xAlreadyYielded; 01760 } 01761 /*-----------------------------------------------------------*/ 01762 01763 TickType_t xTaskGetTickCount( void ) 01764 { 01765 TickType_t xTicks; 01766 01767 /* Critical section required if running on a 16 bit processor. */ 01768 portTICK_TYPE_ENTER_CRITICAL(); 01769 { 01770 xTicks = xTickCount; 01771 } 01772 portTICK_TYPE_EXIT_CRITICAL(); 01773 01774 return xTicks; 01775 } 01776 /*-----------------------------------------------------------*/ 01777 01778 TickType_t xTaskGetTickCountFromISR( void ) 01779 { 01780 TickType_t xReturn; 01781 UBaseType_t uxSavedInterruptStatus; 01782 01783 /* RTOS ports that support interrupt nesting have the concept of a maximum 01784 system call (or maximum API call) interrupt priority. Interrupts that are 01785 above the maximum system call priority are kept permanently enabled, even 01786 when the RTOS kernel is in a critical section, but cannot make any calls to 01787 FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h 01788 then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion 01789 failure if a FreeRTOS API function is called from an interrupt that has been 01790 assigned a priority above the configured maximum system call priority. 01791 Only FreeRTOS functions that end in FromISR can be called from interrupts 01792 that have been assigned a priority at or (logically) below the maximum 01793 system call interrupt priority. FreeRTOS maintains a separate interrupt 01794 safe API to ensure interrupt entry is as fast and as simple as possible. 01795 More information (albeit Cortex-M specific) is provided on the following 01796 link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ 01797 portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); 01798 01799 uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR(); 01800 { 01801 xReturn = xTickCount; 01802 } 01803 portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 01804 01805 return xReturn; 01806 } 01807 /*-----------------------------------------------------------*/ 01808 01809 UBaseType_t uxTaskGetNumberOfTasks( void ) 01810 { 01811 /* A critical section is not required because the variables are of type 01812 BaseType_t. */ 01813 return uxCurrentNumberOfTasks; 01814 } 01815 /*-----------------------------------------------------------*/ 01816 01817 #if ( INCLUDE_pcTaskGetTaskName == 1 ) 01818 01819 char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 01820 { 01821 TCB_t *pxTCB; 01822 01823 /* If null is passed in here then the name of the calling task is being queried. */ 01824 pxTCB = prvGetTCBFromHandle( xTaskToQuery ); 01825 configASSERT( pxTCB ); 01826 return &( pxTCB->pcTaskName[ 0 ] ); 01827 } 01828 01829 #endif /* INCLUDE_pcTaskGetTaskName */ 01830 /*-----------------------------------------------------------*/ 01831 01832 #if ( configUSE_TRACE_FACILITY == 1 ) 01833 01834 UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) 01835 { 01836 UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES; 01837 01838 vTaskSuspendAll(); 01839 { 01840 /* Is there a space in the array for each task in the system? */ 01841 if( uxArraySize >= uxCurrentNumberOfTasks ) 01842 { 01843 /* Fill in an TaskStatus_t structure with information on each 01844 task in the Ready state. */ 01845 do 01846 { 01847 uxQueue--; 01848 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady ); 01849 01850 } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 01851 01852 /* Fill in an TaskStatus_t structure with information on each 01853 task in the Blocked state. */ 01854 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked ); 01855 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked ); 01856 01857 #if( INCLUDE_vTaskDelete == 1 ) 01858 { 01859 /* Fill in an TaskStatus_t structure with information on 01860 each task that has been deleted but not yet cleaned up. */ 01861 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ); 01862 } 01863 #endif 01864 01865 #if ( INCLUDE_vTaskSuspend == 1 ) 01866 { 01867 /* Fill in an TaskStatus_t structure with information on 01868 each task in the Suspended state. */ 01869 uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ); 01870 } 01871 #endif 01872 01873 #if ( configGENERATE_RUN_TIME_STATS == 1) 01874 { 01875 if( pulTotalRunTime != NULL ) 01876 { 01877 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE 01878 portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) ); 01879 #else 01880 *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); 01881 #endif 01882 } 01883 } 01884 #else 01885 { 01886 if( pulTotalRunTime != NULL ) 01887 { 01888 *pulTotalRunTime = 0; 01889 } 01890 } 01891 #endif 01892 } 01893 else 01894 { 01895 mtCOVERAGE_TEST_MARKER(); 01896 } 01897 } 01898 ( void ) xTaskResumeAll(); 01899 01900 return uxTask; 01901 } 01902 01903 #endif /* configUSE_TRACE_FACILITY */ 01904 /*----------------------------------------------------------*/ 01905 01906 #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) 01907 01908 TaskHandle_t xTaskGetIdleTaskHandle( void ) 01909 { 01910 /* If xTaskGetIdleTaskHandle() is called before the scheduler has been 01911 started, then xIdleTaskHandle will be NULL. */ 01912 configASSERT( ( xIdleTaskHandle != NULL ) ); 01913 return xIdleTaskHandle; 01914 } 01915 01916 #endif /* INCLUDE_xTaskGetIdleTaskHandle */ 01917 /*----------------------------------------------------------*/ 01918 01919 /* This conditional compilation should use inequality to 0, not equality to 1. 01920 This is to ensure vTaskStepTick() is available when user defined low power mode 01921 implementations require configUSE_TICKLESS_IDLE to be set to a value other than 01922 1. */ 01923 #if ( configUSE_TICKLESS_IDLE != 0 ) 01924 01925 void vTaskStepTick( const TickType_t xTicksToJump ) 01926 { 01927 /* Correct the tick count value after a period during which the tick 01928 was suppressed. Note this does *not* call the tick hook function for 01929 each stepped tick. */ 01930 configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime ); 01931 xTickCount += xTicksToJump; 01932 traceINCREASE_TICK_COUNT( xTicksToJump ); 01933 } 01934 01935 #endif /* configUSE_TICKLESS_IDLE */ 01936 /*----------------------------------------------------------*/ 01937 01938 BaseType_t xTaskIncrementTick( void ) 01939 { 01940 TCB_t * pxTCB; 01941 TickType_t xItemValue; 01942 BaseType_t xSwitchRequired = pdFALSE; 01943 01944 /* Called by the portable layer each time a tick interrupt occurs. 01945 Increments the tick then checks to see if the new tick value will cause any 01946 tasks to be unblocked. */ 01947 traceTASK_INCREMENT_TICK( xTickCount ); 01948 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) 01949 { 01950 /* Increment the RTOS tick, switching the delayed and overflowed 01951 delayed lists if it wraps to 0. */ 01952 ++xTickCount; 01953 01954 { 01955 /* Minor optimisation. The tick count cannot change in this 01956 block. */ 01957 const TickType_t xConstTickCount = xTickCount; 01958 01959 if( xConstTickCount == ( TickType_t ) 0U ) 01960 { 01961 taskSWITCH_DELAYED_LISTS(); 01962 } 01963 else 01964 { 01965 mtCOVERAGE_TEST_MARKER(); 01966 } 01967 01968 /* See if this tick has made a timeout expire. Tasks are stored in 01969 the queue in the order of their wake time - meaning once one task 01970 has been found whose block time has not expired there is no need to 01971 look any further down the list. */ 01972 if( xConstTickCount >= xNextTaskUnblockTime ) 01973 { 01974 for( ;; ) 01975 { 01976 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) 01977 { 01978 /* The delayed list is empty. Set xNextTaskUnblockTime 01979 to the maximum possible value so it is extremely 01980 unlikely that the 01981 if( xTickCount >= xNextTaskUnblockTime ) test will pass 01982 next time through. */ 01983 xNextTaskUnblockTime = portMAX_DELAY; 01984 break; 01985 } 01986 else 01987 { 01988 /* The delayed list is not empty, get the value of the 01989 item at the head of the delayed list. This is the time 01990 at which the task at the head of the delayed list must 01991 be removed from the Blocked state. */ 01992 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); 01993 xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); 01994 01995 if( xConstTickCount < xItemValue ) 01996 { 01997 /* It is not time to unblock this item yet, but the 01998 item value is the time at which the task at the head 01999 of the blocked list must be removed from the Blocked 02000 state - so record the item value in 02001 xNextTaskUnblockTime. */ 02002 xNextTaskUnblockTime = xItemValue; 02003 break; 02004 } 02005 else 02006 { 02007 mtCOVERAGE_TEST_MARKER(); 02008 } 02009 02010 /* It is time to remove the item from the Blocked state. */ 02011 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 02012 02013 /* Is the task waiting on an event also? If so remove 02014 it from the event list. */ 02015 if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) 02016 { 02017 ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); 02018 } 02019 else 02020 { 02021 mtCOVERAGE_TEST_MARKER(); 02022 } 02023 02024 /* Place the unblocked task into the appropriate ready 02025 list. */ 02026 prvAddTaskToReadyList( pxTCB ); 02027 02028 /* A task being unblocked cannot cause an immediate 02029 context switch if preemption is turned off. */ 02030 #if ( configUSE_PREEMPTION == 1 ) 02031 { 02032 /* Preemption is on, but a context switch should 02033 only be performed if the unblocked task has a 02034 priority that is equal to or higher than the 02035 currently executing task. */ 02036 if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) 02037 { 02038 xSwitchRequired = pdTRUE; 02039 } 02040 else 02041 { 02042 mtCOVERAGE_TEST_MARKER(); 02043 } 02044 } 02045 #endif /* configUSE_PREEMPTION */ 02046 } 02047 } 02048 } 02049 } 02050 02051 /* Tasks of equal priority to the currently running task will share 02052 processing time (time slice) if preemption is on, and the application 02053 writer has not explicitly turned time slicing off. */ 02054 #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) 02055 { 02056 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 ) 02057 { 02058 xSwitchRequired = pdTRUE; 02059 } 02060 else 02061 { 02062 mtCOVERAGE_TEST_MARKER(); 02063 } 02064 } 02065 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ 02066 02067 #if ( configUSE_TICK_HOOK == 1 ) 02068 { 02069 /* Guard against the tick hook being called when the pended tick 02070 count is being unwound (when the scheduler is being unlocked). */ 02071 if( uxPendedTicks == ( UBaseType_t ) 0U ) 02072 { 02073 vApplicationTickHook(); 02074 } 02075 else 02076 { 02077 mtCOVERAGE_TEST_MARKER(); 02078 } 02079 } 02080 #endif /* configUSE_TICK_HOOK */ 02081 } 02082 else 02083 { 02084 ++uxPendedTicks; 02085 02086 /* The tick hook gets called at regular intervals, even if the 02087 scheduler is locked. */ 02088 #if ( configUSE_TICK_HOOK == 1 ) 02089 { 02090 vApplicationTickHook(); 02091 } 02092 #endif 02093 } 02094 02095 #if ( configUSE_PREEMPTION == 1 ) 02096 { 02097 if( xYieldPending != pdFALSE ) 02098 { 02099 xSwitchRequired = pdTRUE; 02100 } 02101 else 02102 { 02103 mtCOVERAGE_TEST_MARKER(); 02104 } 02105 } 02106 #endif /* configUSE_PREEMPTION */ 02107 02108 return xSwitchRequired; 02109 } 02110 /*-----------------------------------------------------------*/ 02111 02112 #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 02113 02114 void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ) 02115 { 02116 TCB_t *xTCB; 02117 02118 /* If xTask is NULL then it is the task hook of the calling task that is 02119 getting set. */ 02120 if( xTask == NULL ) 02121 { 02122 xTCB = ( TCB_t * ) pxCurrentTCB; 02123 } 02124 else 02125 { 02126 xTCB = ( TCB_t * ) xTask; 02127 } 02128 02129 /* Save the hook function in the TCB. A critical section is required as 02130 the value can be accessed from an interrupt. */ 02131 taskENTER_CRITICAL(); 02132 xTCB->pxTaskTag = pxHookFunction; 02133 taskEXIT_CRITICAL(); 02134 } 02135 02136 #endif /* configUSE_APPLICATION_TASK_TAG */ 02137 /*-----------------------------------------------------------*/ 02138 02139 #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 02140 02141 TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ) 02142 { 02143 TCB_t *xTCB; 02144 TaskHookFunction_t xReturn; 02145 02146 /* If xTask is NULL then we are setting our own task hook. */ 02147 if( xTask == NULL ) 02148 { 02149 xTCB = ( TCB_t * ) pxCurrentTCB; 02150 } 02151 else 02152 { 02153 xTCB = ( TCB_t * ) xTask; 02154 } 02155 02156 /* Save the hook function in the TCB. A critical section is required as 02157 the value can be accessed from an interrupt. */ 02158 taskENTER_CRITICAL(); 02159 { 02160 xReturn = xTCB->pxTaskTag; 02161 } 02162 taskEXIT_CRITICAL(); 02163 02164 return xReturn; 02165 } 02166 02167 #endif /* configUSE_APPLICATION_TASK_TAG */ 02168 /*-----------------------------------------------------------*/ 02169 02170 #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 02171 02172 BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) 02173 { 02174 TCB_t *xTCB; 02175 BaseType_t xReturn; 02176 02177 /* If xTask is NULL then we are calling our own task hook. */ 02178 if( xTask == NULL ) 02179 { 02180 xTCB = ( TCB_t * ) pxCurrentTCB; 02181 } 02182 else 02183 { 02184 xTCB = ( TCB_t * ) xTask; 02185 } 02186 02187 if( xTCB->pxTaskTag != NULL ) 02188 { 02189 xReturn = xTCB->pxTaskTag( pvParameter ); 02190 } 02191 else 02192 { 02193 xReturn = pdFAIL; 02194 } 02195 02196 return xReturn; 02197 } 02198 02199 #endif /* configUSE_APPLICATION_TASK_TAG */ 02200 /*-----------------------------------------------------------*/ 02201 02202 void vTaskSwitchContext( void ) 02203 { 02204 if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE ) 02205 { 02206 /* The scheduler is currently suspended - do not allow a context 02207 switch. */ 02208 xYieldPending = pdTRUE; 02209 } 02210 else 02211 { 02212 xYieldPending = pdFALSE; 02213 traceTASK_SWITCHED_OUT(); 02214 02215 #if ( configGENERATE_RUN_TIME_STATS == 1 ) 02216 { 02217 #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE 02218 portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime ); 02219 #else 02220 ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); 02221 #endif 02222 02223 /* Add the amount of time the task has been running to the 02224 accumulated time so far. The time the task started running was 02225 stored in ulTaskSwitchedInTime. Note that there is no overflow 02226 protection here so count values are only valid until the timer 02227 overflows. The guard against negative values is to protect 02228 against suspect run time stat counter implementations - which 02229 are provided by the application, not the kernel. */ 02230 if( ulTotalRunTime > ulTaskSwitchedInTime ) 02231 { 02232 pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); 02233 } 02234 else 02235 { 02236 mtCOVERAGE_TEST_MARKER(); 02237 } 02238 ulTaskSwitchedInTime = ulTotalRunTime; 02239 } 02240 #endif /* configGENERATE_RUN_TIME_STATS */ 02241 02242 /* Check for stack overflow, if configured. */ 02243 taskFIRST_CHECK_FOR_STACK_OVERFLOW(); 02244 taskSECOND_CHECK_FOR_STACK_OVERFLOW(); 02245 02246 /* Select a new task to run using either the generic C or port 02247 optimised asm code. */ 02248 taskSELECT_HIGHEST_PRIORITY_TASK(); 02249 traceTASK_SWITCHED_IN(); 02250 02251 #if ( configUSE_NEWLIB_REENTRANT == 1 ) 02252 { 02253 /* Switch Newlib's _impure_ptr variable to point to the _reent 02254 structure specific to this task. */ 02255 _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); 02256 } 02257 #endif /* configUSE_NEWLIB_REENTRANT */ 02258 } 02259 } 02260 /*-----------------------------------------------------------*/ 02261 02262 void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait ) 02263 { 02264 TickType_t xTimeToWake; 02265 02266 configASSERT( pxEventList ); 02267 02268 /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE 02269 SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */ 02270 02271 /* Place the event list item of the TCB in the appropriate event list. 02272 This is placed in the list in priority order so the highest priority task 02273 is the first to be woken by the event. The queue that contains the event 02274 list is locked, preventing simultaneous access from interrupts. */ 02275 vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) ); 02276 02277 /* The task must be removed from from the ready list before it is added to 02278 the blocked list as the same list item is used for both lists. Exclusive 02279 access to the ready lists guaranteed because the scheduler is locked. */ 02280 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 02281 { 02282 /* The current task must be in a ready list, so there is no need to 02283 check, and the port reset macro can be called directly. */ 02284 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 02285 } 02286 else 02287 { 02288 mtCOVERAGE_TEST_MARKER(); 02289 } 02290 02291 #if ( INCLUDE_vTaskSuspend == 1 ) 02292 { 02293 if( xTicksToWait == portMAX_DELAY ) 02294 { 02295 /* Add the task to the suspended task list instead of a delayed task 02296 list to ensure the task is not woken by a timing event. It will 02297 block indefinitely. */ 02298 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); 02299 } 02300 else 02301 { 02302 /* Calculate the time at which the task should be woken if the event 02303 does not occur. This may overflow but this doesn't matter, the 02304 scheduler will handle it. */ 02305 xTimeToWake = xTickCount + xTicksToWait; 02306 prvAddCurrentTaskToDelayedList( xTimeToWake ); 02307 } 02308 } 02309 #else /* INCLUDE_vTaskSuspend */ 02310 { 02311 /* Calculate the time at which the task should be woken if the event does 02312 not occur. This may overflow but this doesn't matter, the scheduler 02313 will handle it. */ 02314 xTimeToWake = xTickCount + xTicksToWait; 02315 prvAddCurrentTaskToDelayedList( xTimeToWake ); 02316 } 02317 #endif /* INCLUDE_vTaskSuspend */ 02318 } 02319 /*-----------------------------------------------------------*/ 02320 02321 void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait ) 02322 { 02323 TickType_t xTimeToWake; 02324 02325 configASSERT( pxEventList ); 02326 02327 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by 02328 the event groups implementation. */ 02329 configASSERT( uxSchedulerSuspended != 0 ); 02330 02331 /* Store the item value in the event list item. It is safe to access the 02332 event list item here as interrupts won't access the event list item of a 02333 task that is not in the Blocked state. */ 02334 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); 02335 02336 /* Place the event list item of the TCB at the end of the appropriate event 02337 list. It is safe to access the event list here because it is part of an 02338 event group implementation - and interrupts don't access event groups 02339 directly (instead they access them indirectly by pending function calls to 02340 the task level). */ 02341 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); 02342 02343 /* The task must be removed from the ready list before it is added to the 02344 blocked list. Exclusive access can be assured to the ready list as the 02345 scheduler is locked. */ 02346 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 02347 { 02348 /* The current task must be in a ready list, so there is no need to 02349 check, and the port reset macro can be called directly. */ 02350 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 02351 } 02352 else 02353 { 02354 mtCOVERAGE_TEST_MARKER(); 02355 } 02356 02357 #if ( INCLUDE_vTaskSuspend == 1 ) 02358 { 02359 if( xTicksToWait == portMAX_DELAY ) 02360 { 02361 /* Add the task to the suspended task list instead of a delayed task 02362 list to ensure it is not woken by a timing event. It will block 02363 indefinitely. */ 02364 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); 02365 } 02366 else 02367 { 02368 /* Calculate the time at which the task should be woken if the event 02369 does not occur. This may overflow but this doesn't matter, the 02370 kernel will manage it correctly. */ 02371 xTimeToWake = xTickCount + xTicksToWait; 02372 prvAddCurrentTaskToDelayedList( xTimeToWake ); 02373 } 02374 } 02375 #else /* INCLUDE_vTaskSuspend */ 02376 { 02377 /* Calculate the time at which the task should be woken if the event does 02378 not occur. This may overflow but this doesn't matter, the kernel 02379 will manage it correctly. */ 02380 xTimeToWake = xTickCount + xTicksToWait; 02381 prvAddCurrentTaskToDelayedList( xTimeToWake ); 02382 } 02383 #endif /* INCLUDE_vTaskSuspend */ 02384 } 02385 /*-----------------------------------------------------------*/ 02386 02387 #if configUSE_TIMERS == 1 02388 02389 void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait ) 02390 { 02391 TickType_t xTimeToWake; 02392 02393 configASSERT( pxEventList ); 02394 02395 /* This function should not be called by application code hence the 02396 'Restricted' in its name. It is not part of the public API. It is 02397 designed for use by kernel code, and has special calling requirements - 02398 it should be called with the scheduler suspended. */ 02399 02400 02401 /* Place the event list item of the TCB in the appropriate event list. 02402 In this case it is assume that this is the only task that is going to 02403 be waiting on this event list, so the faster vListInsertEnd() function 02404 can be used in place of vListInsert. */ 02405 vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); 02406 02407 /* We must remove this task from the ready list before adding it to the 02408 blocked list as the same list item is used for both lists. This 02409 function is called with the scheduler locked so interrupts will not 02410 access the lists at the same time. */ 02411 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 02412 { 02413 /* The current task must be in a ready list, so there is no need to 02414 check, and the port reset macro can be called directly. */ 02415 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 02416 } 02417 else 02418 { 02419 mtCOVERAGE_TEST_MARKER(); 02420 } 02421 02422 /* Calculate the time at which the task should be woken if the event does 02423 not occur. This may overflow but this doesn't matter. */ 02424 xTimeToWake = xTickCount + xTicksToWait; 02425 02426 traceTASK_DELAY_UNTIL(); 02427 prvAddCurrentTaskToDelayedList( xTimeToWake ); 02428 } 02429 02430 #endif /* configUSE_TIMERS */ 02431 /*-----------------------------------------------------------*/ 02432 02433 BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) 02434 { 02435 TCB_t *pxUnblockedTCB; 02436 BaseType_t xReturn; 02437 02438 /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be 02439 called from a critical section within an ISR. */ 02440 02441 /* The event list is sorted in priority order, so the first in the list can 02442 be removed as it is known to be the highest priority. Remove the TCB from 02443 the delayed list, and add it to the ready list. 02444 02445 If an event is for a queue that is locked then this function will never 02446 get called - the lock count on the queue will get modified instead. This 02447 means exclusive access to the event list is guaranteed here. 02448 02449 This function assumes that a check has already been made to ensure that 02450 pxEventList is not empty. */ 02451 pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); 02452 configASSERT( pxUnblockedTCB ); 02453 ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) ); 02454 02455 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) 02456 { 02457 ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); 02458 prvAddTaskToReadyList( pxUnblockedTCB ); 02459 } 02460 else 02461 { 02462 /* The delayed and ready lists cannot be accessed, so hold this task 02463 pending until the scheduler is resumed. */ 02464 vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) ); 02465 } 02466 02467 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) 02468 { 02469 /* Return true if the task removed from the event list has a higher 02470 priority than the calling task. This allows the calling task to know if 02471 it should force a context switch now. */ 02472 xReturn = pdTRUE; 02473 02474 /* Mark that a yield is pending in case the user is not using the 02475 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ 02476 xYieldPending = pdTRUE; 02477 } 02478 else 02479 { 02480 xReturn = pdFALSE; 02481 } 02482 02483 #if( configUSE_TICKLESS_IDLE == 1 ) 02484 { 02485 /* If a task is blocked on a kernel object then xNextTaskUnblockTime 02486 might be set to the blocked task's time out time. If the task is 02487 unblocked for a reason other than a timeout xNextTaskUnblockTime is 02488 normally left unchanged, because it is automatically get reset to a new 02489 value when the tick count equals xNextTaskUnblockTime. However if 02490 tickless idling is used it might be more important to enter sleep mode 02491 at the earliest possible time - so reset xNextTaskUnblockTime here to 02492 ensure it is updated at the earliest possible time. */ 02493 prvResetNextTaskUnblockTime(); 02494 } 02495 #endif 02496 02497 return xReturn; 02498 } 02499 /*-----------------------------------------------------------*/ 02500 02501 BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) 02502 { 02503 TCB_t *pxUnblockedTCB; 02504 BaseType_t xReturn; 02505 02506 /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by 02507 the event flags implementation. */ 02508 configASSERT( uxSchedulerSuspended != pdFALSE ); 02509 02510 /* Store the new item value in the event list. */ 02511 listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); 02512 02513 /* Remove the event list form the event flag. Interrupts do not access 02514 event flags. */ 02515 pxUnblockedTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxEventListItem ); 02516 configASSERT( pxUnblockedTCB ); 02517 ( void ) uxListRemove( pxEventListItem ); 02518 02519 /* Remove the task from the delayed list and add it to the ready list. The 02520 scheduler is suspended so interrupts will not be accessing the ready 02521 lists. */ 02522 ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); 02523 prvAddTaskToReadyList( pxUnblockedTCB ); 02524 02525 if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) 02526 { 02527 /* Return true if the task removed from the event list has 02528 a higher priority than the calling task. This allows 02529 the calling task to know if it should force a context 02530 switch now. */ 02531 xReturn = pdTRUE; 02532 02533 /* Mark that a yield is pending in case the user is not using the 02534 "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ 02535 xYieldPending = pdTRUE; 02536 } 02537 else 02538 { 02539 xReturn = pdFALSE; 02540 } 02541 02542 return xReturn; 02543 } 02544 /*-----------------------------------------------------------*/ 02545 02546 void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) 02547 { 02548 configASSERT( pxTimeOut ); 02549 pxTimeOut->xOverflowCount = xNumOfOverflows; 02550 pxTimeOut->xTimeOnEntering = xTickCount; 02551 } 02552 /*-----------------------------------------------------------*/ 02553 02554 BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) 02555 { 02556 BaseType_t xReturn; 02557 02558 configASSERT( pxTimeOut ); 02559 configASSERT( pxTicksToWait ); 02560 02561 taskENTER_CRITICAL(); 02562 { 02563 /* Minor optimisation. The tick count cannot change in this block. */ 02564 const TickType_t xConstTickCount = xTickCount; 02565 02566 #if ( INCLUDE_vTaskSuspend == 1 ) 02567 /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is 02568 the maximum block time then the task should block indefinitely, and 02569 therefore never time out. */ 02570 if( *pxTicksToWait == portMAX_DELAY ) 02571 { 02572 xReturn = pdFALSE; 02573 } 02574 else /* We are not blocking indefinitely, perform the checks below. */ 02575 #endif 02576 02577 if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */ 02578 { 02579 /* The tick count is greater than the time at which vTaskSetTimeout() 02580 was called, but has also overflowed since vTaskSetTimeOut() was called. 02581 It must have wrapped all the way around and gone past us again. This 02582 passed since vTaskSetTimeout() was called. */ 02583 xReturn = pdTRUE; 02584 } 02585 else if( ( xConstTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait ) 02586 { 02587 /* Not a genuine timeout. Adjust parameters for time remaining. */ 02588 *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering ); 02589 vTaskSetTimeOutState( pxTimeOut ); 02590 xReturn = pdFALSE; 02591 } 02592 else 02593 { 02594 xReturn = pdTRUE; 02595 } 02596 } 02597 taskEXIT_CRITICAL(); 02598 02599 return xReturn; 02600 } 02601 /*-----------------------------------------------------------*/ 02602 02603 void vTaskMissedYield( void ) 02604 { 02605 xYieldPending = pdTRUE; 02606 } 02607 /*-----------------------------------------------------------*/ 02608 02609 #if ( configUSE_TRACE_FACILITY == 1 ) 02610 02611 UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) 02612 { 02613 UBaseType_t uxReturn; 02614 TCB_t *pxTCB; 02615 02616 if( xTask != NULL ) 02617 { 02618 pxTCB = ( TCB_t * ) xTask; 02619 uxReturn = pxTCB->uxTaskNumber; 02620 } 02621 else 02622 { 02623 uxReturn = 0U; 02624 } 02625 02626 return uxReturn; 02627 } 02628 02629 #endif /* configUSE_TRACE_FACILITY */ 02630 /*-----------------------------------------------------------*/ 02631 02632 #if ( configUSE_TRACE_FACILITY == 1 ) 02633 02634 void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle ) 02635 { 02636 TCB_t *pxTCB; 02637 02638 if( xTask != NULL ) 02639 { 02640 pxTCB = ( TCB_t * ) xTask; 02641 pxTCB->uxTaskNumber = uxHandle; 02642 } 02643 } 02644 02645 #endif /* configUSE_TRACE_FACILITY */ 02646 02647 /* 02648 * ----------------------------------------------------------- 02649 * The Idle task. 02650 * ---------------------------------------------------------- 02651 * 02652 * The portTASK_FUNCTION() macro is used to allow port/compiler specific 02653 * language extensions. The equivalent prototype for this function is: 02654 * 02655 * void prvIdleTask( void *pvParameters ); 02656 * 02657 */ 02658 static portTASK_FUNCTION( prvIdleTask, pvParameters ) 02659 { 02660 /* Stop warnings. */ 02661 ( void ) pvParameters; 02662 02663 for( ;; ) 02664 { 02665 /* See if any tasks have been deleted. */ 02666 prvCheckTasksWaitingTermination(); 02667 02668 #if ( configUSE_PREEMPTION == 0 ) 02669 { 02670 /* If we are not using preemption we keep forcing a task switch to 02671 see if any other task has become available. If we are using 02672 preemption we don't need to do this as any task becoming available 02673 will automatically get the processor anyway. */ 02674 taskYIELD(); 02675 } 02676 #endif /* configUSE_PREEMPTION */ 02677 02678 #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) 02679 { 02680 /* When using preemption tasks of equal priority will be 02681 timesliced. If a task that is sharing the idle priority is ready 02682 to run then the idle task should yield before the end of the 02683 timeslice. 02684 02685 A critical region is not required here as we are just reading from 02686 the list, and an occasional incorrect value will not matter. If 02687 the ready list at the idle priority contains more than one task 02688 then a task other than the idle task is ready to execute. */ 02689 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 ) 02690 { 02691 taskYIELD(); 02692 } 02693 else 02694 { 02695 mtCOVERAGE_TEST_MARKER(); 02696 } 02697 } 02698 #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */ 02699 02700 #if ( configUSE_IDLE_HOOK == 1 ) 02701 { 02702 extern void vApplicationIdleHook( void ); 02703 02704 /* Call the user defined function from within the idle task. This 02705 allows the application designer to add background functionality 02706 without the overhead of a separate task. 02707 NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, 02708 CALL A FUNCTION THAT MIGHT BLOCK. */ 02709 vApplicationIdleHook(); 02710 } 02711 #endif /* configUSE_IDLE_HOOK */ 02712 02713 /* This conditional compilation should use inequality to 0, not equality 02714 to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when 02715 user defined low power mode implementations require 02716 configUSE_TICKLESS_IDLE to be set to a value other than 1. */ 02717 #if ( configUSE_TICKLESS_IDLE != 0 ) 02718 { 02719 TickType_t xExpectedIdleTime; 02720 02721 /* It is not desirable to suspend then resume the scheduler on 02722 each iteration of the idle task. Therefore, a preliminary 02723 test of the expected idle time is performed without the 02724 scheduler suspended. The result here is not necessarily 02725 valid. */ 02726 xExpectedIdleTime = prvGetExpectedIdleTime(); 02727 02728 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) 02729 { 02730 vTaskSuspendAll(); 02731 { 02732 /* Now the scheduler is suspended, the expected idle 02733 time can be sampled again, and this time its value can 02734 be used. */ 02735 configASSERT( xNextTaskUnblockTime >= xTickCount ); 02736 xExpectedIdleTime = prvGetExpectedIdleTime(); 02737 02738 if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) 02739 { 02740 traceLOW_POWER_IDLE_BEGIN(); 02741 portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); 02742 traceLOW_POWER_IDLE_END(); 02743 } 02744 else 02745 { 02746 mtCOVERAGE_TEST_MARKER(); 02747 } 02748 } 02749 ( void ) xTaskResumeAll(); 02750 } 02751 else 02752 { 02753 mtCOVERAGE_TEST_MARKER(); 02754 } 02755 } 02756 #endif /* configUSE_TICKLESS_IDLE */ 02757 } 02758 } 02759 /*-----------------------------------------------------------*/ 02760 02761 #if configUSE_TICKLESS_IDLE != 0 02762 02763 eSleepModeStatus eTaskConfirmSleepModeStatus( void ) 02764 { 02765 eSleepModeStatus eReturn = eStandardSleep; 02766 02767 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 ) 02768 { 02769 /* A task was made ready while the scheduler was suspended. */ 02770 eReturn = eAbortSleep; 02771 } 02772 else if( xYieldPending != pdFALSE ) 02773 { 02774 /* A yield was pended while the scheduler was suspended. */ 02775 eReturn = eAbortSleep; 02776 } 02777 else 02778 { 02779 #if configUSE_TIMERS == 0 02780 { 02781 /* The idle task exists in addition to the application tasks. */ 02782 const UBaseType_t uxNonApplicationTasks = 1; 02783 02784 /* If timers are not being used and all the tasks are in the 02785 suspended list (which might mean they have an infinite block 02786 time rather than actually being suspended) then it is safe to 02787 turn all clocks off and just wait for external interrupts. */ 02788 if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) ) 02789 { 02790 eReturn = eNoTasksWaitingTimeout; 02791 } 02792 else 02793 { 02794 mtCOVERAGE_TEST_MARKER(); 02795 } 02796 } 02797 #endif /* configUSE_TIMERS */ 02798 } 02799 02800 return eReturn; 02801 } 02802 #endif /* configUSE_TICKLESS_IDLE */ 02803 /*-----------------------------------------------------------*/ 02804 02805 static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 02806 { 02807 UBaseType_t x; 02808 02809 /* Store the task name in the TCB. */ 02810 for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) 02811 { 02812 pxTCB->pcTaskName[ x ] = pcName[ x ]; 02813 02814 /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than 02815 configMAX_TASK_NAME_LEN characters just in case the memory after the 02816 string is not accessible (extremely unlikely). */ 02817 if( pcName[ x ] == 0x00 ) 02818 { 02819 break; 02820 } 02821 else 02822 { 02823 mtCOVERAGE_TEST_MARKER(); 02824 } 02825 } 02826 02827 /* Ensure the name string is terminated in the case that the string length 02828 was greater or equal to configMAX_TASK_NAME_LEN. */ 02829 pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0'; 02830 02831 /* This is used as an array index so must ensure it's not too large. First 02832 remove the privilege bit if one is present. */ 02833 if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) 02834 { 02835 uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; 02836 } 02837 else 02838 { 02839 mtCOVERAGE_TEST_MARKER(); 02840 } 02841 02842 pxTCB->uxPriority = uxPriority; 02843 #if ( configUSE_MUTEXES == 1 ) 02844 { 02845 pxTCB->uxBasePriority = uxPriority; 02846 pxTCB->uxMutexesHeld = 0; 02847 } 02848 #endif /* configUSE_MUTEXES */ 02849 02850 vListInitialiseItem( &( pxTCB->xGenericListItem ) ); 02851 vListInitialiseItem( &( pxTCB->xEventListItem ) ); 02852 02853 /* Set the pxTCB as a link back from the ListItem_t. This is so we can get 02854 back to the containing TCB from a generic item in a list. */ 02855 listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB ); 02856 02857 /* Event lists are always in priority order. */ 02858 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 02859 listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB ); 02860 02861 #if ( portCRITICAL_NESTING_IN_TCB == 1 ) 02862 { 02863 pxTCB->uxCriticalNesting = ( UBaseType_t ) 0U; 02864 } 02865 #endif /* portCRITICAL_NESTING_IN_TCB */ 02866 02867 #if ( configUSE_APPLICATION_TASK_TAG == 1 ) 02868 { 02869 pxTCB->pxTaskTag = NULL; 02870 } 02871 #endif /* configUSE_APPLICATION_TASK_TAG */ 02872 02873 #if ( configGENERATE_RUN_TIME_STATS == 1 ) 02874 { 02875 pxTCB->ulRunTimeCounter = 0UL; 02876 } 02877 #endif /* configGENERATE_RUN_TIME_STATS */ 02878 02879 #if ( portUSING_MPU_WRAPPERS == 1 ) 02880 { 02881 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth ); 02882 } 02883 #else /* portUSING_MPU_WRAPPERS */ 02884 { 02885 ( void ) xRegions; 02886 ( void ) usStackDepth; 02887 } 02888 #endif /* portUSING_MPU_WRAPPERS */ 02889 02890 #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) 02891 { 02892 for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ ) 02893 { 02894 pxTCB->pvThreadLocalStoragePointers[ x ] = NULL; 02895 } 02896 } 02897 #endif 02898 02899 #if ( configUSE_TASK_NOTIFICATIONS == 1 ) 02900 { 02901 pxTCB->ulNotifiedValue = 0; 02902 pxTCB->eNotifyState = eNotWaitingNotification; 02903 } 02904 #endif 02905 02906 #if ( configUSE_NEWLIB_REENTRANT == 1 ) 02907 { 02908 /* Initialise this task's Newlib reent structure. */ 02909 _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) ); 02910 } 02911 #endif /* configUSE_NEWLIB_REENTRANT */ 02912 } 02913 /*-----------------------------------------------------------*/ 02914 02915 #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) 02916 02917 void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) 02918 { 02919 TCB_t *pxTCB; 02920 02921 if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) 02922 { 02923 pxTCB = prvGetTCBFromHandle( xTaskToSet ); 02924 pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; 02925 } 02926 } 02927 02928 #endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ 02929 /*-----------------------------------------------------------*/ 02930 02931 #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) 02932 02933 void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) 02934 { 02935 void *pvReturn = NULL; 02936 TCB_t *pxTCB; 02937 02938 if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) 02939 { 02940 pxTCB = prvGetTCBFromHandle( xTaskToQuery ); 02941 pvReturn = pxTCB->pvThreadLocalStoragePointers[ xIndex ]; 02942 } 02943 else 02944 { 02945 pvReturn = NULL; 02946 } 02947 02948 return pvReturn; 02949 } 02950 02951 #endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ 02952 /*-----------------------------------------------------------*/ 02953 02954 #if ( portUSING_MPU_WRAPPERS == 1 ) 02955 02956 void vTaskAllocateMPURegions( TaskHandle_t xTaskToModify, const MemoryRegion_t * const xRegions ) 02957 { 02958 TCB_t *pxTCB; 02959 02960 /* If null is passed in here then we are deleting ourselves. */ 02961 pxTCB = prvGetTCBFromHandle( xTaskToModify ); 02962 02963 vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 ); 02964 } 02965 02966 #endif /* portUSING_MPU_WRAPPERS */ 02967 /*-----------------------------------------------------------*/ 02968 02969 static void prvInitialiseTaskLists( void ) 02970 { 02971 UBaseType_t uxPriority; 02972 02973 for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ ) 02974 { 02975 vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) ); 02976 } 02977 02978 vListInitialise( &xDelayedTaskList1 ); 02979 vListInitialise( &xDelayedTaskList2 ); 02980 vListInitialise( &xPendingReadyList ); 02981 02982 #if ( INCLUDE_vTaskDelete == 1 ) 02983 { 02984 vListInitialise( &xTasksWaitingTermination ); 02985 } 02986 #endif /* INCLUDE_vTaskDelete */ 02987 02988 #if ( INCLUDE_vTaskSuspend == 1 ) 02989 { 02990 vListInitialise( &xSuspendedTaskList ); 02991 } 02992 #endif /* INCLUDE_vTaskSuspend */ 02993 02994 /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList 02995 using list2. */ 02996 pxDelayedTaskList = &xDelayedTaskList1; 02997 pxOverflowDelayedTaskList = &xDelayedTaskList2; 02998 } 02999 /*-----------------------------------------------------------*/ 03000 03001 static void prvCheckTasksWaitingTermination( void ) 03002 { 03003 #if ( INCLUDE_vTaskDelete == 1 ) 03004 { 03005 BaseType_t xListIsEmpty; 03006 03007 /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called 03008 too often in the idle task. */ 03009 while( uxTasksDeleted > ( UBaseType_t ) 0U ) 03010 { 03011 vTaskSuspendAll(); 03012 { 03013 xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); 03014 } 03015 ( void ) xTaskResumeAll(); 03016 03017 if( xListIsEmpty == pdFALSE ) 03018 { 03019 TCB_t *pxTCB; 03020 03021 taskENTER_CRITICAL(); 03022 { 03023 pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); 03024 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 03025 --uxCurrentNumberOfTasks; 03026 --uxTasksDeleted; 03027 } 03028 taskEXIT_CRITICAL(); 03029 03030 prvDeleteTCB( pxTCB ); 03031 } 03032 else 03033 { 03034 mtCOVERAGE_TEST_MARKER(); 03035 } 03036 } 03037 } 03038 #endif /* vTaskDelete */ 03039 } 03040 /*-----------------------------------------------------------*/ 03041 03042 static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake ) 03043 { 03044 /* The list item will be inserted in wake time order. */ 03045 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); 03046 03047 if( xTimeToWake < xTickCount ) 03048 { 03049 /* Wake time has overflowed. Place this item in the overflow list. */ 03050 vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) ); 03051 } 03052 else 03053 { 03054 /* The wake time has not overflowed, so the current block list is used. */ 03055 vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xGenericListItem ) ); 03056 03057 /* If the task entering the blocked state was placed at the head of the 03058 list of blocked tasks then xNextTaskUnblockTime needs to be updated 03059 too. */ 03060 if( xTimeToWake < xNextTaskUnblockTime ) 03061 { 03062 xNextTaskUnblockTime = xTimeToWake; 03063 } 03064 else 03065 { 03066 mtCOVERAGE_TEST_MARKER(); 03067 } 03068 } 03069 } 03070 /*-----------------------------------------------------------*/ 03071 03072 static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) 03073 { 03074 TCB_t *pxNewTCB; 03075 03076 /* If the stack grows down then allocate the stack then the TCB so the stack 03077 does not grow into the TCB. Likewise if the stack grows up then allocate 03078 the TCB then the stack. */ 03079 #if( portSTACK_GROWTH > 0 ) 03080 { 03081 /* Allocate space for the TCB. Where the memory comes from depends on 03082 the implementation of the port malloc function. */ 03083 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); 03084 03085 if( pxNewTCB != NULL ) 03086 { 03087 /* Allocate space for the stack used by the task being created. 03088 The base of the stack memory stored in the TCB so the task can 03089 be deleted later if required. */ 03090 pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 03091 03092 if( pxNewTCB->pxStack == NULL ) 03093 { 03094 /* Could not allocate the stack. Delete the allocated TCB. */ 03095 vPortFree( pxNewTCB ); 03096 pxNewTCB = NULL; 03097 } 03098 } 03099 } 03100 #else /* portSTACK_GROWTH */ 03101 { 03102 StackType_t *pxStack; 03103 03104 /* Allocate space for the stack used by the task being created. */ 03105 pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 03106 03107 if( pxStack != NULL ) 03108 { 03109 /* Allocate space for the TCB. Where the memory comes from depends 03110 on the implementation of the port malloc function. */ 03111 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); 03112 03113 if( pxNewTCB != NULL ) 03114 { 03115 /* Store the stack location in the TCB. */ 03116 pxNewTCB->pxStack = pxStack; 03117 } 03118 else 03119 { 03120 /* The stack cannot be used as the TCB was not created. Free it 03121 again. */ 03122 vPortFree( pxStack ); 03123 } 03124 } 03125 else 03126 { 03127 pxNewTCB = NULL; 03128 } 03129 } 03130 #endif /* portSTACK_GROWTH */ 03131 03132 if( pxNewTCB != NULL ) 03133 { 03134 /* Avoid dependency on memset() if it is not required. */ 03135 #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) 03136 { 03137 /* Just to help debugging. */ 03138 ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( StackType_t ) ); 03139 } 03140 #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */ 03141 } 03142 03143 return pxNewTCB; 03144 } 03145 /*-----------------------------------------------------------*/ 03146 03147 #if ( configUSE_TRACE_FACILITY == 1 ) 03148 03149 static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) 03150 { 03151 volatile TCB_t *pxNextTCB, *pxFirstTCB; 03152 UBaseType_t uxTask = 0; 03153 03154 if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) 03155 { 03156 listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); 03157 03158 /* Populate an TaskStatus_t structure within the 03159 pxTaskStatusArray array for each task that is referenced from 03160 pxList. See the definition of TaskStatus_t in task.h for the 03161 meaning of each TaskStatus_t structure member. */ 03162 do 03163 { 03164 listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); 03165 03166 pxTaskStatusArray[ uxTask ].xHandle = ( TaskHandle_t ) pxNextTCB; 03167 pxTaskStatusArray[ uxTask ].pcTaskName = ( const char * ) &( pxNextTCB->pcTaskName [ 0 ] ); 03168 pxTaskStatusArray[ uxTask ].xTaskNumber = pxNextTCB->uxTCBNumber; 03169 pxTaskStatusArray[ uxTask ].eCurrentState = eState; 03170 pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority; 03171 03172 #if ( INCLUDE_vTaskSuspend == 1 ) 03173 { 03174 /* If the task is in the suspended list then there is a chance 03175 it is actually just blocked indefinitely - so really it should 03176 be reported as being in the Blocked state. */ 03177 if( eState == eSuspended ) 03178 { 03179 if( listLIST_ITEM_CONTAINER( &( pxNextTCB->xEventListItem ) ) != NULL ) 03180 { 03181 pxTaskStatusArray[ uxTask ].eCurrentState = eBlocked; 03182 } 03183 } 03184 } 03185 #endif /* INCLUDE_vTaskSuspend */ 03186 03187 #if ( configUSE_MUTEXES == 1 ) 03188 { 03189 pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority; 03190 } 03191 #else 03192 { 03193 pxTaskStatusArray[ uxTask ].uxBasePriority = 0; 03194 } 03195 #endif 03196 03197 #if ( configGENERATE_RUN_TIME_STATS == 1 ) 03198 { 03199 pxTaskStatusArray[ uxTask ].ulRunTimeCounter = pxNextTCB->ulRunTimeCounter; 03200 } 03201 #else 03202 { 03203 pxTaskStatusArray[ uxTask ].ulRunTimeCounter = 0; 03204 } 03205 #endif 03206 03207 #if ( portSTACK_GROWTH > 0 ) 03208 { 03209 pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxNextTCB->pxEndOfStack ); 03210 } 03211 #else 03212 { 03213 pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxNextTCB->pxStack ); 03214 } 03215 #endif 03216 03217 uxTask++; 03218 03219 } while( pxNextTCB != pxFirstTCB ); 03220 } 03221 else 03222 { 03223 mtCOVERAGE_TEST_MARKER(); 03224 } 03225 03226 return uxTask; 03227 } 03228 03229 #endif /* configUSE_TRACE_FACILITY */ 03230 /*-----------------------------------------------------------*/ 03231 03232 #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) 03233 03234 static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) 03235 { 03236 uint32_t ulCount = 0U; 03237 03238 while( *pucStackByte == ( uint8_t ) tskSTACK_FILL_BYTE ) 03239 { 03240 pucStackByte -= portSTACK_GROWTH; 03241 ulCount++; 03242 } 03243 03244 ulCount /= ( uint32_t ) sizeof( StackType_t ); /*lint !e961 Casting is not redundant on smaller architectures. */ 03245 03246 return ( uint16_t ) ulCount; 03247 } 03248 03249 #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */ 03250 /*-----------------------------------------------------------*/ 03251 03252 #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) 03253 03254 UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) 03255 { 03256 TCB_t *pxTCB; 03257 uint8_t *pucEndOfStack; 03258 UBaseType_t uxReturn; 03259 03260 pxTCB = prvGetTCBFromHandle( xTask ); 03261 03262 #if portSTACK_GROWTH < 0 03263 { 03264 pucEndOfStack = ( uint8_t * ) pxTCB->pxStack; 03265 } 03266 #else 03267 { 03268 pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack; 03269 } 03270 #endif 03271 03272 uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack ); 03273 03274 return uxReturn; 03275 } 03276 03277 #endif /* INCLUDE_uxTaskGetStackHighWaterMark */ 03278 /*-----------------------------------------------------------*/ 03279 03280 #if ( INCLUDE_vTaskDelete == 1 ) 03281 03282 static void prvDeleteTCB( TCB_t *pxTCB ) 03283 { 03284 /* This call is required specifically for the TriCore port. It must be 03285 above the vPortFree() calls. The call is also used by ports/demos that 03286 want to allocate and clean RAM statically. */ 03287 portCLEAN_UP_TCB( pxTCB ); 03288 03289 /* Free up the memory allocated by the scheduler for the task. It is up 03290 to the task to free any memory allocated at the application level. */ 03291 #if ( configUSE_NEWLIB_REENTRANT == 1 ) 03292 { 03293 _reclaim_reent( &( pxTCB->xNewLib_reent ) ); 03294 } 03295 #endif /* configUSE_NEWLIB_REENTRANT */ 03296 03297 #if( portUSING_MPU_WRAPPERS == 1 ) 03298 { 03299 /* Only free the stack if it was allocated dynamically in the first 03300 place. */ 03301 if( pxTCB->xUsingStaticallyAllocatedStack == pdFALSE ) 03302 { 03303 vPortFreeAligned( pxTCB->pxStack ); 03304 } 03305 } 03306 #else 03307 { 03308 vPortFreeAligned( pxTCB->pxStack ); 03309 } 03310 #endif 03311 03312 vPortFree( pxTCB ); 03313 } 03314 03315 #endif /* INCLUDE_vTaskDelete */ 03316 /*-----------------------------------------------------------*/ 03317 03318 static void prvResetNextTaskUnblockTime( void ) 03319 { 03320 TCB_t *pxTCB; 03321 03322 if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) 03323 { 03324 /* The new current delayed list is empty. Set xNextTaskUnblockTime to 03325 the maximum possible value so it is extremely unlikely that the 03326 if( xTickCount >= xNextTaskUnblockTime ) test will pass until 03327 there is an item in the delayed list. */ 03328 xNextTaskUnblockTime = portMAX_DELAY; 03329 } 03330 else 03331 { 03332 /* The new current delayed list is not empty, get the value of 03333 the item at the head of the delayed list. This is the time at 03334 which the task at the head of the delayed list should be removed 03335 from the Blocked state. */ 03336 ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); 03337 xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xGenericListItem ) ); 03338 } 03339 } 03340 /*-----------------------------------------------------------*/ 03341 03342 #if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) 03343 03344 TaskHandle_t xTaskGetCurrentTaskHandle( void ) 03345 { 03346 TaskHandle_t xReturn; 03347 03348 /* A critical section is not required as this is not called from 03349 an interrupt and the current TCB will always be the same for any 03350 individual execution thread. */ 03351 xReturn = pxCurrentTCB; 03352 03353 return xReturn; 03354 } 03355 03356 #endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ 03357 /*-----------------------------------------------------------*/ 03358 03359 #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) 03360 03361 BaseType_t xTaskGetSchedulerState( void ) 03362 { 03363 BaseType_t xReturn; 03364 03365 if( xSchedulerRunning == pdFALSE ) 03366 { 03367 xReturn = taskSCHEDULER_NOT_STARTED; 03368 } 03369 else 03370 { 03371 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) 03372 { 03373 xReturn = taskSCHEDULER_RUNNING; 03374 } 03375 else 03376 { 03377 xReturn = taskSCHEDULER_SUSPENDED; 03378 } 03379 } 03380 03381 return xReturn; 03382 } 03383 03384 #endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */ 03385 /*-----------------------------------------------------------*/ 03386 03387 #if ( configUSE_MUTEXES == 1 ) 03388 03389 void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) 03390 { 03391 TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; 03392 03393 /* If the mutex was given back by an interrupt while the queue was 03394 locked then the mutex holder might now be NULL. */ 03395 if( pxMutexHolder != NULL ) 03396 { 03397 /* If the holder of the mutex has a priority below the priority of 03398 the task attempting to obtain the mutex then it will temporarily 03399 inherit the priority of the task attempting to obtain the mutex. */ 03400 if( pxTCB->uxPriority < pxCurrentTCB->uxPriority ) 03401 { 03402 /* Adjust the mutex holder state to account for its new 03403 priority. Only reset the event list item value if the value is 03404 not being used for anything else. */ 03405 if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) 03406 { 03407 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 03408 } 03409 else 03410 { 03411 mtCOVERAGE_TEST_MARKER(); 03412 } 03413 03414 /* If the task being modified is in the ready state it will need 03415 to be moved into a new list. */ 03416 if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE ) 03417 { 03418 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 03419 { 03420 taskRESET_READY_PRIORITY( pxTCB->uxPriority ); 03421 } 03422 else 03423 { 03424 mtCOVERAGE_TEST_MARKER(); 03425 } 03426 03427 /* Inherit the priority before being moved into the new list. */ 03428 pxTCB->uxPriority = pxCurrentTCB->uxPriority; 03429 prvAddTaskToReadyList( pxTCB ); 03430 } 03431 else 03432 { 03433 /* Just inherit the priority. */ 03434 pxTCB->uxPriority = pxCurrentTCB->uxPriority; 03435 } 03436 03437 traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority ); 03438 } 03439 else 03440 { 03441 mtCOVERAGE_TEST_MARKER(); 03442 } 03443 } 03444 else 03445 { 03446 mtCOVERAGE_TEST_MARKER(); 03447 } 03448 } 03449 03450 #endif /* configUSE_MUTEXES */ 03451 /*-----------------------------------------------------------*/ 03452 03453 #if ( configUSE_MUTEXES == 1 ) 03454 03455 BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) 03456 { 03457 TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; 03458 BaseType_t xReturn = pdFALSE; 03459 03460 if( pxMutexHolder != NULL ) 03461 { 03462 /* A task can only have an inherited priority if it holds the mutex. 03463 If the mutex is held by a task then it cannot be given from an 03464 interrupt, and if a mutex is given by the holding task then it must 03465 be the running state task. */ 03466 configASSERT( pxTCB == pxCurrentTCB ); 03467 03468 configASSERT( pxTCB->uxMutexesHeld ); 03469 ( pxTCB->uxMutexesHeld )--; 03470 03471 /* Has the holder of the mutex inherited the priority of another 03472 task? */ 03473 if( pxTCB->uxPriority != pxTCB->uxBasePriority ) 03474 { 03475 /* Only disinherit if no other mutexes are held. */ 03476 if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 ) 03477 { 03478 /* A task can only have an inherited priority if it holds 03479 the mutex. If the mutex is held by a task then it cannot be 03480 given from an interrupt, and if a mutex is given by the 03481 holding task then it must be the running state task. Remove 03482 the holding task from the ready list. */ 03483 if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 03484 { 03485 taskRESET_READY_PRIORITY( pxTCB->uxPriority ); 03486 } 03487 else 03488 { 03489 mtCOVERAGE_TEST_MARKER(); 03490 } 03491 03492 /* Disinherit the priority before adding the task into the 03493 new ready list. */ 03494 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); 03495 pxTCB->uxPriority = pxTCB->uxBasePriority; 03496 03497 /* Reset the event list item value. It cannot be in use for 03498 any other purpose if this task is running, and it must be 03499 running to give back the mutex. */ 03500 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 03501 prvAddTaskToReadyList( pxTCB ); 03502 03503 /* Return true to indicate that a context switch is required. 03504 This is only actually required in the corner case whereby 03505 multiple mutexes were held and the mutexes were given back 03506 in an order different to that in which they were taken. 03507 If a context switch did not occur when the first mutex was 03508 returned, even if a task was waiting on it, then a context 03509 switch should occur when the last mutex is returned whether 03510 a task is waiting on it or not. */ 03511 xReturn = pdTRUE; 03512 } 03513 else 03514 { 03515 mtCOVERAGE_TEST_MARKER(); 03516 } 03517 } 03518 else 03519 { 03520 mtCOVERAGE_TEST_MARKER(); 03521 } 03522 } 03523 else 03524 { 03525 mtCOVERAGE_TEST_MARKER(); 03526 } 03527 03528 return xReturn; 03529 } 03530 03531 #endif /* configUSE_MUTEXES */ 03532 /*-----------------------------------------------------------*/ 03533 03534 #if ( portCRITICAL_NESTING_IN_TCB == 1 ) 03535 03536 void vTaskEnterCritical( void ) 03537 { 03538 portDISABLE_INTERRUPTS(); 03539 03540 if( xSchedulerRunning != pdFALSE ) 03541 { 03542 ( pxCurrentTCB->uxCriticalNesting )++; 03543 03544 /* This is not the interrupt safe version of the enter critical 03545 function so assert() if it is being called from an interrupt 03546 context. Only API functions that end in "FromISR" can be used in an 03547 interrupt. Only assert if the critical nesting count is 1 to 03548 protect against recursive calls if the assert function also uses a 03549 critical section. */ 03550 if( pxCurrentTCB->uxCriticalNesting == 1 ) 03551 { 03552 portASSERT_IF_IN_ISR(); 03553 } 03554 03555 } 03556 else 03557 { 03558 mtCOVERAGE_TEST_MARKER(); 03559 } 03560 } 03561 03562 #endif /* portCRITICAL_NESTING_IN_TCB */ 03563 /*-----------------------------------------------------------*/ 03564 03565 #if ( portCRITICAL_NESTING_IN_TCB == 1 ) 03566 03567 void vTaskExitCritical( void ) 03568 { 03569 if( xSchedulerRunning != pdFALSE ) 03570 { 03571 if( pxCurrentTCB->uxCriticalNesting > 0U ) 03572 { 03573 ( pxCurrentTCB->uxCriticalNesting )--; 03574 03575 if( pxCurrentTCB->uxCriticalNesting == 0U ) 03576 { 03577 portENABLE_INTERRUPTS(); 03578 } 03579 else 03580 { 03581 mtCOVERAGE_TEST_MARKER(); 03582 } 03583 } 03584 else 03585 { 03586 mtCOVERAGE_TEST_MARKER(); 03587 } 03588 } 03589 else 03590 { 03591 mtCOVERAGE_TEST_MARKER(); 03592 } 03593 } 03594 03595 #endif /* portCRITICAL_NESTING_IN_TCB */ 03596 /*-----------------------------------------------------------*/ 03597 03598 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) 03599 03600 static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) 03601 { 03602 BaseType_t x; 03603 03604 /* Start by copying the entire string. */ 03605 strcpy( pcBuffer, pcTaskName ); 03606 03607 /* Pad the end of the string with spaces to ensure columns line up when 03608 printed out. */ 03609 for( x = strlen( pcBuffer ); x < ( configMAX_TASK_NAME_LEN - 1 ); x++ ) 03610 { 03611 pcBuffer[ x ] = ' '; 03612 } 03613 03614 /* Terminate. */ 03615 pcBuffer[ x ] = 0x00; 03616 03617 /* Return the new end of string. */ 03618 return &( pcBuffer[ x ] ); 03619 } 03620 03621 #endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */ 03622 /*-----------------------------------------------------------*/ 03623 03624 #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) 03625 03626 void vTaskList( char * pcWriteBuffer ) 03627 { 03628 TaskStatus_t *pxTaskStatusArray; 03629 volatile UBaseType_t uxArraySize, x; 03630 char cStatus; 03631 03632 /* 03633 * PLEASE NOTE: 03634 * 03635 * This function is provided for convenience only, and is used by many 03636 * of the demo applications. Do not consider it to be part of the 03637 * scheduler. 03638 * 03639 * vTaskList() calls uxTaskGetSystemState(), then formats part of the 03640 * uxTaskGetSystemState() output into a human readable table that 03641 * displays task names, states and stack usage. 03642 * 03643 * vTaskList() has a dependency on the sprintf() C library function that 03644 * might bloat the code size, use a lot of stack, and provide different 03645 * results on different platforms. An alternative, tiny, third party, 03646 * and limited functionality implementation of sprintf() is provided in 03647 * many of the FreeRTOS/Demo sub-directories in a file called 03648 * printf-stdarg.c (note printf-stdarg.c does not provide a full 03649 * snprintf() implementation!). 03650 * 03651 * It is recommended that production systems call uxTaskGetSystemState() 03652 * directly to get access to raw stats data, rather than indirectly 03653 * through a call to vTaskList(). 03654 */ 03655 03656 03657 /* Make sure the write buffer does not contain a string. */ 03658 *pcWriteBuffer = 0x00; 03659 03660 /* Take a snapshot of the number of tasks in case it changes while this 03661 function is executing. */ 03662 uxArraySize = uxCurrentNumberOfTasks; 03663 03664 /* Allocate an array index for each task. */ 03665 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); 03666 03667 if( pxTaskStatusArray != NULL ) 03668 { 03669 /* Generate the (binary) data. */ 03670 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL ); 03671 03672 /* Create a human readable table from the binary data. */ 03673 for( x = 0; x < uxArraySize; x++ ) 03674 { 03675 switch( pxTaskStatusArray[ x ].eCurrentState ) 03676 { 03677 case eReady: cStatus = tskREADY_CHAR; 03678 break; 03679 03680 case eBlocked: cStatus = tskBLOCKED_CHAR; 03681 break; 03682 03683 case eSuspended: cStatus = tskSUSPENDED_CHAR; 03684 break; 03685 03686 case eDeleted: cStatus = tskDELETED_CHAR; 03687 break; 03688 03689 default: /* Should not get here, but it is included 03690 to prevent static checking errors. */ 03691 cStatus = 0x00; 03692 break; 03693 } 03694 03695 /* Write the task name to the string, padding with spaces so it 03696 can be printed in tabular form more easily. */ 03697 pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); 03698 03699 /* Write the rest of the string. */ 03700 sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); 03701 pcWriteBuffer += strlen( pcWriteBuffer ); 03702 } 03703 03704 /* Free the array again. */ 03705 vPortFree( pxTaskStatusArray ); 03706 } 03707 else 03708 { 03709 mtCOVERAGE_TEST_MARKER(); 03710 } 03711 } 03712 03713 #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ 03714 /*----------------------------------------------------------*/ 03715 03716 #if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) 03717 03718 void vTaskGetRunTimeStats( char *pcWriteBuffer ) 03719 { 03720 TaskStatus_t *pxTaskStatusArray; 03721 volatile UBaseType_t uxArraySize, x; 03722 uint32_t ulTotalTime, ulStatsAsPercentage; 03723 03724 #if( configUSE_TRACE_FACILITY != 1 ) 03725 { 03726 #error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats(). 03727 } 03728 #endif 03729 03730 /* 03731 * PLEASE NOTE: 03732 * 03733 * This function is provided for convenience only, and is used by many 03734 * of the demo applications. Do not consider it to be part of the 03735 * scheduler. 03736 * 03737 * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part 03738 * of the uxTaskGetSystemState() output into a human readable table that 03739 * displays the amount of time each task has spent in the Running state 03740 * in both absolute and percentage terms. 03741 * 03742 * vTaskGetRunTimeStats() has a dependency on the sprintf() C library 03743 * function that might bloat the code size, use a lot of stack, and 03744 * provide different results on different platforms. An alternative, 03745 * tiny, third party, and limited functionality implementation of 03746 * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in 03747 * a file called printf-stdarg.c (note printf-stdarg.c does not provide 03748 * a full snprintf() implementation!). 03749 * 03750 * It is recommended that production systems call uxTaskGetSystemState() 03751 * directly to get access to raw stats data, rather than indirectly 03752 * through a call to vTaskGetRunTimeStats(). 03753 */ 03754 03755 /* Make sure the write buffer does not contain a string. */ 03756 *pcWriteBuffer = 0x00; 03757 03758 /* Take a snapshot of the number of tasks in case it changes while this 03759 function is executing. */ 03760 uxArraySize = uxCurrentNumberOfTasks; 03761 03762 /* Allocate an array index for each task. */ 03763 pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); 03764 03765 if( pxTaskStatusArray != NULL ) 03766 { 03767 /* Generate the (binary) data. */ 03768 uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime ); 03769 03770 /* For percentage calculations. */ 03771 ulTotalTime /= 100UL; 03772 03773 /* Avoid divide by zero errors. */ 03774 if( ulTotalTime > 0 ) 03775 { 03776 /* Create a human readable table from the binary data. */ 03777 for( x = 0; x < uxArraySize; x++ ) 03778 { 03779 /* What percentage of the total run time has the task used? 03780 This will always be rounded down to the nearest integer. 03781 ulTotalRunTimeDiv100 has already been divided by 100. */ 03782 ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime; 03783 03784 /* Write the task name to the string, padding with 03785 spaces so it can be printed in tabular form more 03786 easily. */ 03787 pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); 03788 03789 if( ulStatsAsPercentage > 0UL ) 03790 { 03791 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED 03792 { 03793 sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); 03794 } 03795 #else 03796 { 03797 /* sizeof( int ) == sizeof( long ) so a smaller 03798 printf() library can be used. */ 03799 sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); 03800 } 03801 #endif 03802 } 03803 else 03804 { 03805 /* If the percentage is zero here then the task has 03806 consumed less than 1% of the total run time. */ 03807 #ifdef portLU_PRINTF_SPECIFIER_REQUIRED 03808 { 03809 sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter ); 03810 } 03811 #else 03812 { 03813 /* sizeof( int ) == sizeof( long ) so a smaller 03814 printf() library can be used. */ 03815 sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); 03816 } 03817 #endif 03818 } 03819 03820 pcWriteBuffer += strlen( pcWriteBuffer ); 03821 } 03822 } 03823 else 03824 { 03825 mtCOVERAGE_TEST_MARKER(); 03826 } 03827 03828 /* Free the array again. */ 03829 vPortFree( pxTaskStatusArray ); 03830 } 03831 else 03832 { 03833 mtCOVERAGE_TEST_MARKER(); 03834 } 03835 } 03836 03837 #endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ 03838 /*-----------------------------------------------------------*/ 03839 03840 TickType_t uxTaskResetEventItemValue( void ) 03841 { 03842 TickType_t uxReturn; 03843 03844 uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ) ); 03845 03846 /* Reset the event list item to its normal value - so it can be used with 03847 queues and semaphores. */ 03848 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 03849 03850 return uxReturn; 03851 } 03852 /*-----------------------------------------------------------*/ 03853 03854 #if ( configUSE_MUTEXES == 1 ) 03855 03856 void *pvTaskIncrementMutexHeldCount( void ) 03857 { 03858 /* If xSemaphoreCreateMutex() is called before any tasks have been created 03859 then pxCurrentTCB will be NULL. */ 03860 if( pxCurrentTCB != NULL ) 03861 { 03862 ( pxCurrentTCB->uxMutexesHeld )++; 03863 } 03864 03865 return pxCurrentTCB; 03866 } 03867 03868 #endif /* configUSE_MUTEXES */ 03869 /*-----------------------------------------------------------*/ 03870 03871 #if( configUSE_TASK_NOTIFICATIONS == 1 ) 03872 03873 uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) 03874 { 03875 TickType_t xTimeToWake; 03876 uint32_t ulReturn; 03877 03878 taskENTER_CRITICAL(); 03879 { 03880 /* Only block if the notification count is not already non-zero. */ 03881 if( pxCurrentTCB->ulNotifiedValue == 0UL ) 03882 { 03883 /* Mark this task as waiting for a notification. */ 03884 pxCurrentTCB->eNotifyState = eWaitingNotification; 03885 03886 if( xTicksToWait > ( TickType_t ) 0 ) 03887 { 03888 /* The task is going to block. First it must be removed 03889 from the ready list. */ 03890 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 03891 { 03892 /* The current task must be in a ready list, so there is 03893 no need to check, and the port reset macro can be called 03894 directly. */ 03895 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 03896 } 03897 else 03898 { 03899 mtCOVERAGE_TEST_MARKER(); 03900 } 03901 03902 #if ( INCLUDE_vTaskSuspend == 1 ) 03903 { 03904 if( xTicksToWait == portMAX_DELAY ) 03905 { 03906 /* Add the task to the suspended task list instead 03907 of a delayed task list to ensure the task is not 03908 woken by a timing event. It will block 03909 indefinitely. */ 03910 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); 03911 } 03912 else 03913 { 03914 /* Calculate the time at which the task should be 03915 woken if no notification events occur. This may 03916 overflow but this doesn't matter, the scheduler will 03917 handle it. */ 03918 xTimeToWake = xTickCount + xTicksToWait; 03919 prvAddCurrentTaskToDelayedList( xTimeToWake ); 03920 } 03921 } 03922 #else /* INCLUDE_vTaskSuspend */ 03923 { 03924 /* Calculate the time at which the task should be 03925 woken if the event does not occur. This may 03926 overflow but this doesn't matter, the scheduler will 03927 handle it. */ 03928 xTimeToWake = xTickCount + xTicksToWait; 03929 prvAddCurrentTaskToDelayedList( xTimeToWake ); 03930 } 03931 #endif /* INCLUDE_vTaskSuspend */ 03932 03933 /* All ports are written to allow a yield in a critical 03934 section (some will yield immediately, others wait until the 03935 critical section exits) - but it is not something that 03936 application code should ever do. */ 03937 portYIELD_WITHIN_API(); 03938 } 03939 else 03940 { 03941 mtCOVERAGE_TEST_MARKER(); 03942 } 03943 } 03944 else 03945 { 03946 mtCOVERAGE_TEST_MARKER(); 03947 } 03948 } 03949 taskEXIT_CRITICAL(); 03950 03951 taskENTER_CRITICAL(); 03952 { 03953 ulReturn = pxCurrentTCB->ulNotifiedValue; 03954 03955 if( ulReturn != 0UL ) 03956 { 03957 if( xClearCountOnExit != pdFALSE ) 03958 { 03959 pxCurrentTCB->ulNotifiedValue = 0UL; 03960 } 03961 else 03962 { 03963 ( pxCurrentTCB->ulNotifiedValue )--; 03964 } 03965 } 03966 else 03967 { 03968 mtCOVERAGE_TEST_MARKER(); 03969 } 03970 03971 pxCurrentTCB->eNotifyState = eNotWaitingNotification; 03972 } 03973 taskEXIT_CRITICAL(); 03974 03975 return ulReturn; 03976 } 03977 03978 #endif /* configUSE_TASK_NOTIFICATIONS */ 03979 /*-----------------------------------------------------------*/ 03980 03981 #if( configUSE_TASK_NOTIFICATIONS == 1 ) 03982 03983 BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) 03984 { 03985 TickType_t xTimeToWake; 03986 BaseType_t xReturn; 03987 03988 taskENTER_CRITICAL(); 03989 { 03990 /* Only block if a notification is not already pending. */ 03991 if( pxCurrentTCB->eNotifyState != eNotified ) 03992 { 03993 /* Clear bits in the task's notification value as bits may get 03994 set by the notifying task or interrupt. This can be used to 03995 clear the value to zero. */ 03996 pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry; 03997 03998 /* Mark this task as waiting for a notification. */ 03999 pxCurrentTCB->eNotifyState = eWaitingNotification; 04000 04001 if( xTicksToWait > ( TickType_t ) 0 ) 04002 { 04003 /* The task is going to block. First it must be removed 04004 from the ready list. */ 04005 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) 04006 { 04007 /* The current task must be in a ready list, so there is 04008 no need to check, and the port reset macro can be called 04009 directly. */ 04010 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); 04011 } 04012 else 04013 { 04014 mtCOVERAGE_TEST_MARKER(); 04015 } 04016 04017 #if ( INCLUDE_vTaskSuspend == 1 ) 04018 { 04019 if( xTicksToWait == portMAX_DELAY ) 04020 { 04021 /* Add the task to the suspended task list instead 04022 of a delayed task list to ensure the task is not 04023 woken by a timing event. It will block 04024 indefinitely. */ 04025 vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); 04026 } 04027 else 04028 { 04029 /* Calculate the time at which the task should be 04030 woken if no notification events occur. This may 04031 overflow but this doesn't matter, the scheduler will 04032 handle it. */ 04033 xTimeToWake = xTickCount + xTicksToWait; 04034 prvAddCurrentTaskToDelayedList( xTimeToWake ); 04035 } 04036 } 04037 #else /* INCLUDE_vTaskSuspend */ 04038 { 04039 /* Calculate the time at which the task should be 04040 woken if the event does not occur. This may 04041 overflow but this doesn't matter, the scheduler will 04042 handle it. */ 04043 xTimeToWake = xTickCount + xTicksToWait; 04044 prvAddCurrentTaskToDelayedList( xTimeToWake ); 04045 } 04046 #endif /* INCLUDE_vTaskSuspend */ 04047 04048 /* All ports are written to allow a yield in a critical 04049 section (some will yield immediately, others wait until the 04050 critical section exits) - but it is not something that 04051 application code should ever do. */ 04052 portYIELD_WITHIN_API(); 04053 } 04054 else 04055 { 04056 mtCOVERAGE_TEST_MARKER(); 04057 } 04058 } 04059 else 04060 { 04061 mtCOVERAGE_TEST_MARKER(); 04062 } 04063 } 04064 taskEXIT_CRITICAL(); 04065 04066 taskENTER_CRITICAL(); 04067 { 04068 if( pulNotificationValue != NULL ) 04069 { 04070 /* Output the current notification value, which may or may not 04071 have changed. */ 04072 *pulNotificationValue = pxCurrentTCB->ulNotifiedValue; 04073 } 04074 04075 /* If eNotifyValue is set then either the task never entered the 04076 blocked state (because a notification was already pending) or the 04077 task unblocked because of a notification. Otherwise the task 04078 unblocked because of a timeout. */ 04079 if( pxCurrentTCB->eNotifyState == eWaitingNotification ) 04080 { 04081 /* A notification was not received. */ 04082 xReturn = pdFALSE; 04083 } 04084 else 04085 { 04086 /* A notification was already pending or a notification was 04087 received while the task was waiting. */ 04088 pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit; 04089 xReturn = pdTRUE; 04090 } 04091 04092 pxCurrentTCB->eNotifyState = eNotWaitingNotification; 04093 } 04094 taskEXIT_CRITICAL(); 04095 04096 return xReturn; 04097 } 04098 04099 #endif /* configUSE_TASK_NOTIFICATIONS */ 04100 /*-----------------------------------------------------------*/ 04101 04102 #if( configUSE_TASK_NOTIFICATIONS == 1 ) 04103 04104 BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) 04105 { 04106 TCB_t * pxTCB; 04107 eNotifyValue eOriginalNotifyState; 04108 BaseType_t xReturn = pdPASS; 04109 04110 configASSERT( xTaskToNotify ); 04111 pxTCB = ( TCB_t * ) xTaskToNotify; 04112 04113 taskENTER_CRITICAL(); 04114 { 04115 if( pulPreviousNotificationValue != NULL ) 04116 { 04117 *pulPreviousNotificationValue = pxTCB->ulNotifiedValue; 04118 } 04119 04120 eOriginalNotifyState = pxTCB->eNotifyState; 04121 04122 pxTCB->eNotifyState = eNotified; 04123 04124 switch( eAction ) 04125 { 04126 case eSetBits : 04127 pxTCB->ulNotifiedValue |= ulValue; 04128 break; 04129 04130 case eIncrement : 04131 ( pxTCB->ulNotifiedValue )++; 04132 break; 04133 04134 case eSetValueWithOverwrite : 04135 pxTCB->ulNotifiedValue = ulValue; 04136 break; 04137 04138 case eSetValueWithoutOverwrite : 04139 if( eOriginalNotifyState != eNotified ) 04140 { 04141 pxTCB->ulNotifiedValue = ulValue; 04142 } 04143 else 04144 { 04145 /* The value could not be written to the task. */ 04146 xReturn = pdFAIL; 04147 } 04148 break; 04149 04150 case eNoAction: 04151 /* The task is being notified without its notify value being 04152 updated. */ 04153 break; 04154 } 04155 04156 04157 /* If the task is in the blocked state specifically to wait for a 04158 notification then unblock it now. */ 04159 if( eOriginalNotifyState == eWaitingNotification ) 04160 { 04161 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 04162 prvAddTaskToReadyList( pxTCB ); 04163 04164 /* The task should not have been on an event list. */ 04165 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); 04166 04167 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) 04168 { 04169 /* The notified task has a priority above the currently 04170 executing task so a yield is required. */ 04171 taskYIELD_IF_USING_PREEMPTION(); 04172 } 04173 else 04174 { 04175 mtCOVERAGE_TEST_MARKER(); 04176 } 04177 } 04178 else 04179 { 04180 mtCOVERAGE_TEST_MARKER(); 04181 } 04182 } 04183 taskEXIT_CRITICAL(); 04184 04185 return xReturn; 04186 } 04187 04188 #endif /* configUSE_TASK_NOTIFICATIONS */ 04189 /*-----------------------------------------------------------*/ 04190 04191 #if( configUSE_TASK_NOTIFICATIONS == 1 ) 04192 04193 BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken ) 04194 { 04195 TCB_t * pxTCB; 04196 eNotifyValue eOriginalNotifyState; 04197 BaseType_t xReturn = pdPASS; 04198 UBaseType_t uxSavedInterruptStatus; 04199 04200 configASSERT( xTaskToNotify ); 04201 04202 /* RTOS ports that support interrupt nesting have the concept of a 04203 maximum system call (or maximum API call) interrupt priority. 04204 Interrupts that are above the maximum system call priority are keep 04205 permanently enabled, even when the RTOS kernel is in a critical section, 04206 but cannot make any calls to FreeRTOS API functions. If configASSERT() 04207 is defined in FreeRTOSConfig.h then 04208 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion 04209 failure if a FreeRTOS API function is called from an interrupt that has 04210 been assigned a priority above the configured maximum system call 04211 priority. Only FreeRTOS functions that end in FromISR can be called 04212 from interrupts that have been assigned a priority at or (logically) 04213 below the maximum system call interrupt priority. FreeRTOS maintains a 04214 separate interrupt safe API to ensure interrupt entry is as fast and as 04215 simple as possible. More information (albeit Cortex-M specific) is 04216 provided on the following link: 04217 http://www.freertos.org/RTOS-Cortex-M3-M4.html */ 04218 portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); 04219 04220 pxTCB = ( TCB_t * ) xTaskToNotify; 04221 04222 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); 04223 { 04224 eOriginalNotifyState = pxTCB->eNotifyState; 04225 04226 pxTCB->eNotifyState = eNotified; 04227 04228 switch( eAction ) 04229 { 04230 case eSetBits : 04231 pxTCB->ulNotifiedValue |= ulValue; 04232 break; 04233 04234 case eIncrement : 04235 ( pxTCB->ulNotifiedValue )++; 04236 break; 04237 04238 case eSetValueWithOverwrite : 04239 pxTCB->ulNotifiedValue = ulValue; 04240 break; 04241 04242 case eSetValueWithoutOverwrite : 04243 if( eOriginalNotifyState != eNotified ) 04244 { 04245 pxTCB->ulNotifiedValue = ulValue; 04246 } 04247 else 04248 { 04249 /* The value could not be written to the task. */ 04250 xReturn = pdFAIL; 04251 } 04252 break; 04253 04254 case eNoAction : 04255 /* The task is being notified without its notify value being 04256 updated. */ 04257 break; 04258 } 04259 04260 04261 /* If the task is in the blocked state specifically to wait for a 04262 notification then unblock it now. */ 04263 if( eOriginalNotifyState == eWaitingNotification ) 04264 { 04265 /* The task should not have been on an event list. */ 04266 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); 04267 04268 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) 04269 { 04270 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 04271 prvAddTaskToReadyList( pxTCB ); 04272 } 04273 else 04274 { 04275 /* The delayed and ready lists cannot be accessed, so hold 04276 this task pending until the scheduler is resumed. */ 04277 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); 04278 } 04279 04280 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) 04281 { 04282 /* The notified task has a priority above the currently 04283 executing task so a yield is required. */ 04284 if( pxHigherPriorityTaskWoken != NULL ) 04285 { 04286 *pxHigherPriorityTaskWoken = pdTRUE; 04287 } 04288 } 04289 else 04290 { 04291 mtCOVERAGE_TEST_MARKER(); 04292 } 04293 } 04294 } 04295 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 04296 04297 return xReturn; 04298 } 04299 04300 #endif /* configUSE_TASK_NOTIFICATIONS */ 04301 /*-----------------------------------------------------------*/ 04302 04303 #if( configUSE_TASK_NOTIFICATIONS == 1 ) 04304 04305 void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken ) 04306 { 04307 TCB_t * pxTCB; 04308 eNotifyValue eOriginalNotifyState; 04309 UBaseType_t uxSavedInterruptStatus; 04310 04311 configASSERT( xTaskToNotify ); 04312 04313 /* RTOS ports that support interrupt nesting have the concept of a 04314 maximum system call (or maximum API call) interrupt priority. 04315 Interrupts that are above the maximum system call priority are keep 04316 permanently enabled, even when the RTOS kernel is in a critical section, 04317 but cannot make any calls to FreeRTOS API functions. If configASSERT() 04318 is defined in FreeRTOSConfig.h then 04319 portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion 04320 failure if a FreeRTOS API function is called from an interrupt that has 04321 been assigned a priority above the configured maximum system call 04322 priority. Only FreeRTOS functions that end in FromISR can be called 04323 from interrupts that have been assigned a priority at or (logically) 04324 below the maximum system call interrupt priority. FreeRTOS maintains a 04325 separate interrupt safe API to ensure interrupt entry is as fast and as 04326 simple as possible. More information (albeit Cortex-M specific) is 04327 provided on the following link: 04328 http://www.freertos.org/RTOS-Cortex-M3-M4.html */ 04329 portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); 04330 04331 pxTCB = ( TCB_t * ) xTaskToNotify; 04332 04333 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); 04334 { 04335 eOriginalNotifyState = pxTCB->eNotifyState; 04336 pxTCB->eNotifyState = eNotified; 04337 04338 /* 'Giving' is equivalent to incrementing a count in a counting 04339 semaphore. */ 04340 ( pxTCB->ulNotifiedValue )++; 04341 04342 /* If the task is in the blocked state specifically to wait for a 04343 notification then unblock it now. */ 04344 if( eOriginalNotifyState == eWaitingNotification ) 04345 { 04346 /* The task should not have been on an event list. */ 04347 configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); 04348 04349 if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) 04350 { 04351 ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); 04352 prvAddTaskToReadyList( pxTCB ); 04353 } 04354 else 04355 { 04356 /* The delayed and ready lists cannot be accessed, so hold 04357 this task pending until the scheduler is resumed. */ 04358 vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); 04359 } 04360 04361 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) 04362 { 04363 /* The notified task has a priority above the currently 04364 executing task so a yield is required. */ 04365 if( pxHigherPriorityTaskWoken != NULL ) 04366 { 04367 *pxHigherPriorityTaskWoken = pdTRUE; 04368 } 04369 } 04370 else 04371 { 04372 mtCOVERAGE_TEST_MARKER(); 04373 } 04374 } 04375 } 04376 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 04377 } 04378 04379 #endif /* configUSE_TASK_NOTIFICATIONS */ 04380 04381 /*-----------------------------------------------------------*/ 04382 04383 04384 #ifdef FREERTOS_MODULE_TEST 04385 #include "tasks_test_access_functions.h" 04386 #endif 04387 04388
Generated on Tue Jul 12 2022 18:55:11 by 1.7.2