In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)05/31 Report--
This article introduces the knowledge of "the method of creating FreeRTOS tasks". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Let's review the declaration of this function first:
BaseType_t xTaskCreate (TaskFunction_tp vTaskCode, const char * constpcName, unsigned short usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t * pvCreatedTask)
The purpose of this API function is to create a new task and add it to the task ready list. The function arguments mean:
PvTaskCode: function pointer to the entry of the task function. The task never returns (in an endless loop). The parameter type TaskFunction_t is defined in the file projdefs.h as: typedef void (* TaskFunction_t) (void *), that is, the parameter is a null pointer type and returns a null type. PcName: task description. Mainly used for debugging. The maximum length of the string, including the end-of-string character, is specified by the macro configMax _ TASK_NAME_LEN, which is located in the FreeRTOSConfig.h file. UsStackDepth: specifies the task stack size and the number of stack variables that can be supported (stack depth) instead of bytes. For example, under a 16-bit stack, where usStackDepth is defined as 100, 200 bytes of stack storage space is actually used. The width of the stack multiplied by the depth must not exceed the maximum that the size_t type can represent. For example, if size_t is 16 bits, you can indicate that the maximum value of the stack is 65535 bytes. This is because the stack is applied in bytes, and the number of bytes requested is the stack width multiplied by depth. If this product is beyond the range indicated by size_t, it will overflow and the stack space allocated is not what we want. PvParameters: pointer, passed to the task as a parameter when the task is created. UxPriority: priority of the task. Systems with MPU support can arbitrarily create tasks in privileged (system) mode by setting the portPRIVILEGE_BIT bit of the priority parameter. For example, create a privileged task with priority 2, and the parameter uxPriority can be set to (2 | portPRIVILEGE_BIT). PvCreatedTask: used to return a handle (ID) that can be used to reference a task after it is created.
Although xTaskCreate () looks like a function, it is actually a macro. The function that is actually called is xTaskGenericCreate (). The definition of the xTaskCreate () macro is as follows:
# define xTaskCreate (pvTaskCode, pcName, usStackDepth,pvParameters, uxPriority, pxCreatedTask)\ xTaskGenericCreate ((pvTaskCode), (pcName), (usStackDepth), (pvParameters), (uxPriority), (pxCreatedTask), (NULL), (NULL), (NULL)
As you can see, xTaskCreate has three less parameters than xTaskGenericCreate, which are set to NULL in the macro definition. These three parameters are used to allocate stack, task TCB space, and set MPU-related parameters using static variable methods. In general, these three parameters are not used, so when the task creates a macro xTaskCreate definition, it hides them from the user. In the following sections, for convenience, we still call xTaskCreate () a function, although it is a macro definition.
Above we mentioned the task TCB (task control block), which is a key point that needs to be highlighted. It is used to store the status information of the task, including the environment in which the task runs. Each task has its own task TCB. Task TCB is a relatively large data structure, which is reasonable, because task-related codes account for about half of the total FreeRTOS code, and most of these codes are related to task TCB. Let's first introduce the definition of task TCB data structure:
Typedef struct tskTaskControlBlock {volatile StackType_t * pxTopOfStack; / * the top of the current stack must be in the first * / # if (portUSING_MPU_WRAPPERS = = 1) xMPU_SETTINGS xMPUSettings; / * MPU setting of the structure, and must be in the second * / # endif ListItem_t xStateListItem of the structure / * status list item of a task, which indicates the status of the task by reference * / ListItem_t xEventListItem; / * event list item, which is used to connect the task to the event list by reference * / UBaseType_t uxPriority; / * Save task priority. 0 indicates the lowest priority * / StackType_t * pxStack / * point to the start of the stack * / char pcTaskName [configMAX_TASK_NAME_LEN]; / * Task name * / # if (portSTACK_GROWTH > 0) StackType_t * pxEndOfStack; / * point to the end of the stack * / # endif # if (portCRITICAL_NESTING_IN_TCB = = 1) UBaseType_t uxCriticalNesting / * Save critical section nesting depth * / # endif # if (configUSE_TRACE_FACILITY = = 1) UBaseType_t uxTCBNumber; / * Save a numeric value, and each task has a unique value * / UBaseType_t uxTaskNumber; / * stores a specific value * / # endif # if (configUSE_MUTEXES = = 1) UBaseType_t uxBasePriority / * basic priority of the save task * / UBaseType_t uxMutexesHeld; # endif # if (configUSE_APPLICATION_TASK_TAG = = 1) TaskHookFunction_t pxTaskTag; # endif # if (configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0) void * pvThreadLocalStoragePoints [configNUM _ THREAD_LOCAL_STORAGE_POINTERS]; # endif # if (configGENERATE_RUN_TIME_STATS = = 1) uint32_t ulRunTimeCounter / * record the total time that the task was executed in the running state * / # endif # if (configUSE_NEWLIB_REENTRANT = = 1) / * assign a Newlibreent structure variable to the task. Newlib is a C library function that is not maintained by FreeRTOS, and FreeRTOS is not responsible for usage results. If you use Newlib, you must be familiar with Newlib details * / struct _ reent xNewLib_reent; # endif # if (configUSE_TASK_NOTIFICATIONS = = 1) volatile uint32_t ulNotifiedValue; / * related to task notification * / volatile uint8_t ucNotifyState; # endif # if (configSUPPORT_STATIC_ALLOCATION = = 1) uint8_t ucStaticAllocationFlags / * set to pdTRUE if the stack is allocated by a static array, or pdFALSE*/ # endif # if (INCLUDE_xTaskAbortDelay = = 1) uint8_t ucDelayAborted; # endif} tskTCB; typedef tskTCB TCB_t if the stack is allocated dynamically
Let's take a detailed look at the main members of this data structure:
The pointer pxTopOfStack must be at the first item of the structure, pointing to the top of the current stack, and for a growing stack, pxTopOfStack always points to the last item on the stack.
If you use MPU,xMPUSettings, you must be in the second item of the structure, for the MPU setting.
Next comes the status list item xStateListItem and the event list item xEventListItem, which we mentioned in the previous chapter on lists and list items: lists are used by the FreeRTOS scheduler to track tasks, and tasks that are ready, pending, or delayed are attached to their respective lists. The scheduler implements the above process by attaching the status list item xStateListItem and event list item xEventListItem in the task TCB to different lists. In task.c, static list variables are defined, including ready, blocking, and pending lists. For example, when a task is in a ready state, the scheduler attaches the xStateListItem list items of the task TCB to the ready list. Similarly, when the queue is full and the task is blocked by the queuing operation, the event list item is attached to the queue waiting list.
UxPriority is used to save the priority of the task, 0 is the lowest priority. When a task is created, the specified task priority is saved to this variable.
The pointer pxStack points to the starting position of the stack, a specified number of task stacks are allocated when the task is created, and the pointer returned by the request stack memory function is assigned to this variable. Many people who have just come into contact with FreeRTOS will not be able to tell the difference between pointer pxTopOfStack and pxStack. To put it simply here: pxTopOfStack points to the top of the current stack, and the position of pxTopOfStack points to the starting position of the current stack as it enters and leaves the stack. Once allocated, the starting position of the stack will be fixed and will not be changed. So why do you need the pxStack variable, because as the task runs, the stack may overflow. In systems where the stack is growing down, this variable can be used to check whether the stack is overflowing; if in systems where the stack is growing up, to determine whether the stack is overflowing, you need another variable, pxEndOfStack, to help diagnose whether the stack is overflowing. This variable will be discussed later.
The character array pcTaskName is used to hold the description or name of the task, which is specified by the parameter when the task is created. The length of the name is specified by the macro configMax _ TASK_NAME_LEN (located in FreeRTOSConfig.h) and contains the string end flag.
If the stack grows up (portSTACK_GROWTH > 0), the pointer pxEndOfStack points to the end of the stack, which is used to check if the stack overflows.
The variable uxCriticalNesting is used to hold the nesting depth of the critical section, with an initial value of 0.
The next two variables are used for visual tracking and are valid only if the macro configUSE_TRACE_FACILITY (in FreeRTOSConfig.h) is 1. The variable uxTCBNumber stores a numeric value that is automatically assigned by the kernel when the task is created (usually the value increases by 1 for each task created). The uxTCBNumber value for each task is different and is mainly used for debugging. The variable uxTaskNumber is used to store a specific value. Unlike the variable uxTCBNumber, the value of uxTaskNumber is not assigned by the kernel, but is set by the API function vTaskSetTaskNumber (), and the value is specified by the function parameter.
If a mutex (configUSE_MUTEXES = = 1) is used, the variable uxBasePriority is used to hold the task's original priority when the task priority is temporarily raised.
The variable ucStaticAllocationFlags also needs to be explained. As we said earlier, the task creation API function xTaskCreate () can only use dynamic memory allocation to create task stacks and task TCB. If you want to use static variables to implement task stacks and task TCB, you need to use the function xTaskGenericCreate (). If the task stack or task TCB is implemented by static arrays and static variables, set this variable to pdTRUE (0x01 when the task stack space is implemented by static array variables, 0x02 when task TCB is implemented by static variables, 0x03 when both task stack and task TCB are implemented by static variables), or set this variable to pdFALSE if the stack is dynamically allocated.
This is the end of the data structure of the task TCB. Let's use an example to illustrate the process of task creation. For convenience, suppose the created task is called "Task A" and the task function is vTask_A ():
TaskHandle_t xHandle; xTaskCreate (vTask_A, "Task A", 120, null, 1, Task, handle)
Here, a task is created with a priority of 1. Since the hardware platform is 32 for architecture, a task stack of 120 bytes, 4 bytes and 480 bytes is specified. The parameter passed to the task function vTask_A () is NULL, and the task handle is saved by the variable xHandle. When this statement is executed, Task An is created and added to the ready task list. The main purpose of this chapter is to see what happens during the execution of this statement.
1. Create task stack and task TCB
Call the function prvAllocateTCBAndStack () to create the task stack and task TCB. There are two ways to create a task stack and a task TCB. One is to use the dynamic memory allocation method, so that when a task is deleted, the task stack and task control block space are freed for other tasks. The other is to use static variables to define global or static stack array and task control block variables before creating a task. When calling the create task API function, pass these two variables as parameters to the task creation function xTaskGenericCreate (). If you use the default xTaskCreate () to create a task function, use dynamic memory allocation because the parameters related to static memory allocation are not visible (we said at the beginning of this article that xTaskCreate () is actually a macro definition with parameters, and the function that is really executed is xTaskGenericCreate (). Referring to the definition of macro xTaskCreate (), we can see that xTaskCreate () hides the parameters that use static memory allocation, when calling xTaskGenericCreate () These parameters are set to NULL).
After the task stack is successfully allocated, the aligned stack start address is saved to the pxStack field of the task TCB. If stack overflow checking is enabled or visual tracing is used, the stack is populated with a fixed value tskSTACK_FILL_BYTE (0xa5).
The source code of the function prvAllocateTCBAndStack () is compiled with the removal of assertions and uncommonly used conditions as follows:
Static TCB_t * prvAllocateTCBAndStack (const uint16_t usStackDepth, StackType_t * const puxStackBuffer, TCB_t * const pxTaskBuffer) {TCB_t * pxNewTCB;StackType_t * pxStack; / * allocate stack space * / pxStack = (StackType_t *) pvPortMallocAligned (size_t) usStackDepth) * sizeof (StackType_t)), puxStackBuffer) If (pxStack! = NULL) {/ * allocate TCB space * / pxNewTCB = (TCB_t *) pvPortMallocAligned (sizeof (TCB_t), pxTaskBuffer); if (pxNewTCB! = NULL) {/ * store the stack start position in TCB*/ pxNewTCB- > pxStack = pxStack } else {/ * if TCB allocation fails, release previously requested stack space * / if (puxStackBuffer = = NULL) {vPortFree (pxStack);} else {pxNewTCB = NULL } if (pxNewTCB! = NULL) {/ * if needed Populate the stack * / # if ((configCHECK_FOR_STACK_OVERFLOW > 1) | | (configUSE_TRACE_FACILITY = = 1) | | (INCLUDE_uxTaskGetStackHighWaterMark== 1)) {/ * for debugging * / (void) memset only (pxNewTCB- > pxStack, (int) tskSTACK_FILL_BYTE, (size_t) usStackDepth * sizeof (StackType_t)) } # endif} return pxNewTCB;}
two。 Fields necessary to initialize task TCB
Call the function prvInitialiseTCBVariables () to initialize the necessary fields for the task TCB. When calling the create task API function xTaskCreate (), the parameters pcName (task description) and uxPriority (task priority) will be written to the corresponding fields of the task TCB, and the xStateListItem and xEventListItem list items in the TCB field will also be initialized, as shown in figure 2-1. In figure 2-1, the member list item value xItemValue of the list item xEventListItem is initially 4, because the maximum number of priorities (configMAX_PRIORITIES) I set in the application is 5, while xEventListItem. XItemValue equals configMAX_PRIORITIES minus the priority of task A (1), that is, 5-1-4. This is important, where xItemValue does not directly save the task priority, but the complement of the priority, which means that the higher the value of xItemValue, the lower the corresponding task priority. The FreeRTOS kernel uses the vListInsert function (see Chapter 1 of the advanced article for details) to insert event list items into a list, which inserts according to the order of values of the xItemValue. Using the macro listGet _ OWNER_OF_HEAD_ENTRY to get the xItemValue value of the first list item in the list is always the lowest, that is, the task with the highest priority!
Figure 2-1: initialization status and event list items
In addition, some other fields of TCB are also initialized, such as critical section nesting times, run time counter, task notification value, task notification status, and so on. The source code of the function prvInitialiseTCBVariables () is as follows:
Static void prvInitialiseTCBVariables (TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority,\ const MemoryRegion_t * const xRegions, const uint16_t usStackDepth) {UBaseType_t x; / * store the task description in TCB * / for (x = (UBaseType_t) 0; x
< ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) { pxTCB->PcTaskName [x] = pcName [x]; if (pcName [x] = = 0x00) {break;}} / * make sure the string ends * / pxTCB- > pcTaskName [configMAX_TASK_NAME_LEN-1] ='\ 0' / * adjust the priority. The value of macro configMax _ PRIORITIES is set in FreeRTOSConfig.h * / if (uxPriority > = (UBaseType_t) configMAX_PRIORITIES) {uxPriority = (UBaseType_t) configMAX_PRIORITIES-(UBaseType_t) 1U;} pxTCB- > uxPriority = uxPriority; # if (configUSE_MUTEXES = = 1) / * use mutex * / {pxTCB- > uxBasePriority = uxPriority; pxTCB- > uxMutexesHeld = 0 } # endif / * configUSE_MUTEXES * / / * initialize the list item * / vListInitialiseItem (& (pxTCB- > xStateListItem)); vListInitialiseItem (& (pxTCB- > xEventListItem)); / * set the pvOwner of the list item xStateListItem to point to the current task control block * / listSET_LIST_ITEM_OWNER (& (pxTCB- > xStateListItem), pxTCB) / * set xItemValue*/ listSET_LIST_ITEM_VALUE (& (pxTCB- > xEventListItem), (TickType_t) configMAX_PRIORITIES-(TickType_t) uxPriority) of the list item xEventListItem; / * set the member pvOwner of the list item xEventListItem to point to the current task control block * / listSET_LIST_ITEM_OWNER (& (pxTCB- > xEventListItem), pxTCB) # if (portCRITICAL_NESTING_IN_TCB = = 1) / * enable critical section nesting function * / {pxTCB- > uxCriticalNesting = (UBaseType_t) 0U;} # endif / * portCRITICAL_NESTING_IN_TCB * / # if (configUSE_APPLICATION_TASK_TAG = = 1) / * enable task tag function * / {pxTCB- > pxTaskTag = NULL } # endif / * configUSE_APPLICATION_TASK_TAG * / # if (configGENERATE_RUN_TIME_STATS = = 1) / * enable event statistics * / {pxTCB- > ulRunTimeCounter = 0ul;} # endif / * configGENERATE_RUN_TIME_STATS * / # if (portUSING_MPU_WRAPPERS = = 1) / * use the MPU function * / {vPortStoreTaskMPUSettings (& (pxTCB- > xMPUSettings), xRegions, pxTCB- > pxStack, usStackDepth) } # else / * portUSING_MPU_WRAPPERS * / {(void) xRegions; (void) usStackDepth;} # endif / * portUSING_MPU_WRAPPERS * / # if (configNUM_THREAD_LOCAL_STORAGE_POINTERS! = 0) / * enable thread local storage pointers * / {for (x = 0; x)
< ( UBaseType_t )configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ ) { pxTCB->PvThreadLocalStoragePointers [x] = NULL;} # endif # if (configUSE_TASK_NOTIFICATIONS = = 1) / * enable task notification * / {pxTCB- > ulNotifiedValue = 0; pxTCB- > ucNotifyState = taskNOT_WAITING_NOTIFICATION } # endif # if (configUSE_NEWLIB_REENTRANT = = 1) / * use Newlib*/ {_ REENT_INIT_PTR (& (pxTCB- > xNewLib_reent);} # endif # if (INCLUDE_xTaskAbortDelay = = 1) {pxTCB- > ucDelayAborted = pdFALSE;} # endif}
3. Initialize the task stack
Call the function pxPortInitialiseStack () to initialize the task stack and assign the latest top pointer to the pxTopOfStack field of the task TCB.
After calling the function pxPortInitialiseStack (), it is equivalent to executing a system beat clock interrupt: putting some important registers on the stack. Although the task hasn't been executed yet, and no interruption has occurred, it looks as if the register has been stacked, and some of the stack values have been modified to the known values we need. For different hardware architectures, the registers on the stack are also different, so we see that this function is provided by the migration layer. For the Cortex-M3 architecture, you need to enter the stack xPSR, PC, LR, R12, R3~R0, R11~R4 in turn, assuming that the stack is growing downward, and the initialized stack is shown in figure 3-1.
In figure 3-1, we see that the register xPSR is initially 0x01000000, where bit24 is set to 1, indicating that the Thumb instruction is used; the register PC is initialized to the task function pointer vTask_A, so that when a task is switched, task A gains CPU control, and the task function vTask_A is unstacked to the PC register, after which the task A code is executed. The LR register is initialized to the function pointer prvTaskExitError, which is an error handler provided by the migration layer. When an interrupt occurs, LR is set to the address to be returned by the interrupt, but each task is an endless loop, so normally you should not exit the task function, so once you exit from the task function, indicating that there is an error, the function pointed to by the register LR, namely prvTaskExitError, will be called to handle the error. According to ATPCS (ARM-Thumb procedure call standard), we know that subfunction calls pass parameters through the register R0~R3. At the beginning of the article, when talking about the xTaskCreate () function, it is mentioned that this function has a parameter pvParameters of null pointer type, which is passed to the task as a parameter when the task is created, so this parameter is saved in R0 to pass parameters to the task.
Task TCB structure member pxTopOfStack represents the top of the current stack, which points to the last item on the stack, so in the figure it points to R4 pxStack, another member of the TCB structure, which represents the start of the stack, so in the figure it points to the beginning of the stack.
Figure 3-1: initializing the task stack
4. Enter the critical area
Call taskENTER_CRITICAL () to enter the critical section, which is a macro definition, and the code that finally enters the critical area is provided by the migration layer.
5. Increase the number of current tasks by 1
In tasks.c, static private variables are defined to track the number or status of tasks, and so on, where the variable uxCurrentNumberOfTasks represents the total number of current tasks, which is incremented by 1 for each task created.
6. Do the necessary initialization for the first run
If this is the first task (uxCurrentNumberOfTasks equals 1), the function prvInitialiseTaskLists () is called to initialize the task list. FreeRTOS uses lists to track tasks, and in tasks.c, list variables of static types are defined:
PRIVILEGED_DATAstatic List_t pxReadyTasksLists [configMAX_PRIORITIES]; / * ready tasks by priority * / PRIVILEGED_DATAstatic List_t xDelayedTaskList1; / * deferred tasks * / PRIVILEGED_DATAstatic List_t xDelayedTaskList2; / * deferred tasks * / PRIVILEGED_DATAstatic List_t xPendingReadyList / * Task is ready, but scheduler is suspended * / # if (INCLUDE_vTaskDelete = = 1) PRIVILEGED_DATA static List_t xTasksWaitingTermination; / * Task has been deleted, but memory has not been freed * / # endif # if (INCLUDE_vTaskSuspend = = 1) PRIVILEGED_DATA static List_t xSuspendedTaskList; / * currently pending task * / # endif
Now these lists need to be initialized, and the API function vListInitialise () will be called to initialize the list. As mentioned in "FreeRTOS Advanced 1---FreeRTOS lists and list items", each list is initialized in the same way. Take the ready list pxReadyTasksLists [0] as an example, as shown in figure 6-1:
Figure 6-1: list after initialization
The source code of the function prvInitialiseTaskLists () is as follows:
Static void prvInitialiseTaskLists (void) {UBaseType_tuxPriority; for (uxPriority = (UBaseType_t) 0U; uxPriority)
< ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ ) { vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) ); } vListInitialise( &xDelayedTaskList1 ); vListInitialise( &xDelayedTaskList2 ); vListInitialise( &xPendingReadyList ); #if ( INCLUDE_vTaskDelete == 1 ) { vListInitialise( &xTasksWaitingTermination ); } #endif /* INCLUDE_vTaskDelete */ #if ( INCLUDE_vTaskSuspend == 1 ) { vListInitialise( &xSuspendedTaskList ); } #endif /* INCLUDE_vTaskSuspend */ /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskListusing list2. */ pxDelayedTaskList = &xDelayedTaskList1; pxOverflowDelayedTaskList = &xDelayedTaskList2;} 7.更新当前正在运行的任务TCB指针 tasks.c中定义了一个任务TCB指针型变量: PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB= NULL; 这是一个全局变量,在tasks.c中只定义了这一个全局变量。这个变量用来指向当前正在运行的任务TCB,我们需要多了解一下这个变量。FreeRTOS的核心是确保处于优先级最高的就绪任务获得CPU运行权。在下一章讲述任务切换时会知道,任务切换就是找到优先级最高的就绪任务,而找出的这个最高优先级任务的TCB,就被赋给变量pxCurrentTCB。 如果调度器还没有准备好(程序刚开始运行时,可能会先创建几个任务,之后才会启动调度器),并且新创建的任务优先级大于变量pxCurrentTCB指向的任务优先级,则设置pxCurrentTCB指向当前新创建的任务TCB(确保pxCurrentTCB指向优先级最高的就绪任务)。 if( xSchedulerRunning == pdFALSE ){ if( pxCurrentTCB->UxPriority uxPriority);\ vListInsertEnd (& (pxReadyTasksLists [(pxTCB)-> uxPriority]), & ((pxTCB)-> xStateListItem))
The macro taskRECORD _ READY_PRIORITY () is used to update the variable uxTopReadyPriority, which is defined in tasks.c as a static variable and records at the highest task priority in the ready state. This variable participates in the core code of FreeRTOS: ensuring that the ready task with the highest priority gets the right to run CPU. It is here to participate in how to find the highest priority ready task as quickly as possible. For the fastest, different architectures will show their own powers, and some architectures have special instructions available, so this macro is provided by the migration layer. When we introduce task switching in the next chapter, we will use the Cortex-M3 architecture as an example to explain in detail how to find the highest priority ready task as quickly as possible.
The function vListInsertEnd () inserts list items at the end of the list, which is already mentioned in "FreeRTOS Advanced articles 1---FreeRTOS lists and list items". Here we will take another look at this function with examples. From the beginning until, before calling the function vListInsertEnd (), the ready list pxReadyTasksLists [1] and the status list item xStateListItem of the task TCB have been initialized, as shown in figures 6-1 and 2-1. For ease of viewing, we combine these two images, as shown in figure 8-1.
Figure 8-1: list and list items after initialization
Calling vListInsertEnd (aformab) inserts the list item b after list a. After the function is executed, the relationship between the list and the list item is shown in figure 8-2.
Figure 8-2: list after inserting a list item
On this basis, assume that task B is created, and task An and task B have the same priority, both 1. Like Task A, Task B has its own task TCB, where the status list item field xStateListItem is also inserted into the list pxReadyTasksLists [1], and the new list and list items are shown in figure 8-3.
Figure 8-3: two list items attached to the same priority ready list
9. Exit the critical area
Call taskEXIT_CRITICAL () to exit the critical section, which is a macro definition, and the code that eventually exits the critical area is provided by the migration layer.
10. Perform context switch
If all the above steps are performed correctly and the scheduler starts to work, determine whether the priority of the current task is higher than the priority of the newly created task. If the newly created task has a higher priority, call taskYIELD_IF_USING_PREEMPTION () to force a context switch, and after the switch, the newly created task will gain control of CPU, as shown below.
If (xReturn = = pdPASS) {if (xSchedulerRunning! = pdFALSE) {/ * if the newly created task priority is higher than the current task priority, the newly created task should be executed immediately. * / if (pxCurrentTCB- > uxPriority < uxPriority) {taskYIELD_IF_USING_PREEMPTION ();} "method for creating FreeRTOS tasks" ends here. Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.