First, when the task is running, it is used to save some local variables;
Second, when a task is suspended, it is responsible for saving the running scene of the task, that is, the value of the CPU register.
The stack is used to save local variables. In essence, the CPU register value is saved to ram. In UCOS, each task has an independent task stack. To better understand the role of the task stack, we may analyze the entire process from "birth" to "extinction" of the task, specifically the creation and running of the task, changes to the task stack in several pending states.
Now we assume that the system runs a task tprint created by the user to complete the printing. Tprint was initially created through the ostaskcreate () function. The first piece of code related to the task stack in this function is the familiar function ostaskstkinit (), this function must be implemented in the UCOS porting process. Its function is to "initialize the stack ", in fact, it is to prepare the status (correct value) of the CPU register when the task starts to run in a region in Ram in advance. After that, when the task is scheduled to run by the kernel Scheduler for the first time, push the prepared data (register value) to the CPU register. If the data is properly designed, the CPU will run according to our pre-designed ideas. Therefore, the "initialization stack" is actually a "precaution. There are two points in this process that must be carefully considered. One is how to locate the PC, and the other is how to handle other CPU registers (except the PC. First, let's talk about the first point. Because the task is the first time running, and the task is essentially a piece of code, the PC pointer should be located at the first line of the Code, that is, the so-called entry address (Entry
Point), the address is saved by the task pointer, so you can assign the pointer value to the PC. Second, this code has not been executed, so the variables in the Code and other registers of the CPU has no relationship, so the R0-R12, R14 can be random value, or no value can also be, keeping these registers with their original values is obviously easier for the latter. Finally, assign a value to CPSR. You can run the system in system mode or management mode as needed. After the inbound and outbound stacks, the SP points to the bottom of the task stack (that is, the last element of the defined Task Stack Array ).
Then the task code starts to run. Because the CPU registers are limited, some temporary variables must be saved to the stack temporarily during running. Which address should be saved to? Don't worry, SP knows (this address is the address of the last element of the Task Stack Array during the first running of the task ). The size of the task stack is related to the number of temporary variables in the task code. If the Code contains many temporary variables, the stack should be designed to be larger.
Then, the tprint task will be suspended for some reason, so we should put the task running site in the stack to protect it. When the tprint task is run again, we will restore the field, the task can be run immediately from the last breakpoint. So what is the scene? In essence, the tprint task runs a specific piece of code on the CPU, so this field is the CPU site, that is, the register value. These register values contain all information during code execution, including the location at which the code is currently running (indicated by the PC value ). Therefore, push the value of the CPU Register into the stack and remember the position of the top pointer of the stack (SP is saved by ostcbcur-> ostcbstkptr). Before the task is to run again, place the previously saved CPU register values in the CPU register from the SP-pointed address in sequence, and the task can be executed accurately from the last interrupted location. This process is like suddenly freezing a task, and nothing related to the task can be moved. After a while, the task will be restored, and the things related to the task will become available again, as a result, the task can run freely.
From the above analysis, we can see that the task stack is accompanied by the task from the beginning to the end, and its function can be summarized as two points:First, when a task is running, it is used to save some local variables; second, when the task is suspended, it is responsible for saving the job's run site, that is, the value of the CPU register.Some friends ignored the first point and raised the question "The task stack size should be a fixed value ". I think this may be related to the understanding of the function ostaskstkinit (). We call it a stack initialization function, but the "initialization" here is not the same as the initialization we understand, the initialization of variables usually refers to initializing all the members of the variables one by one. The initialization of the stack here is only a small part of the initialization of a large stack, because currently only this part is useful, and most of the remaining is not used, so Initialization is not required, just as some variables do not need initialization (with default values or random values ). When a task is suspended, the continuous area of the CPU register before the task is suspended must be at the top of the entire stack. When the task starts to run again, the value of the SP pop-up register. This area is blank. In addition, the continuous area used to save the current CPU register before each task suspension is floating in the entire task stack space.
First, when the task is running, it is used to save some local variables;
Second, when a task is suspended, it is responsible for saving the running scene of the task, that is, the value of the CPU register.
The stack is used to save local variables. In essence, the CPU register value is saved to ram. In UCOS, each task has an independent task stack. To better understand the role of the task stack, we may analyze the entire process from "birth" to "extinction" of the task, specifically the creation and running of the task, changes to the task stack in several pending states.
Now we assume that the system runs a task tprint created by the user to complete the printing. Tprint was initially created through the ostaskcreate () function. The first piece of code related to the task stack in this function is the familiar function ostaskstkinit (), this function must be implemented in the UCOS porting process. Its function is to "initialize the stack ", in fact, it is to prepare the status (correct value) of the CPU register when the task starts to run in a region in Ram in advance. After that, when the task is scheduled to run by the kernel Scheduler for the first time, push the prepared data (register value) to the CPU register. If the data is properly designed, the CPU will run according to our pre-designed ideas. Therefore, the "initialization stack" is actually a "precaution. There are two points in this process that must be carefully considered. One is how to locate the PC, and the other is how to handle other CPU registers (except the PC. First, let's talk about the first point. Because the task is the first time running, and the task is essentially a piece of code, the PC pointer should be located at the first line of the Code, that is, the so-called entry address (Entry
Point), the address is saved by the task pointer, so you can assign the pointer value to the PC. Second, this code has not been executed, so the variables in the Code and other registers of the CPU has no relationship, so the R0-R12, R14 can be random value, or no value can also be, keeping these registers with their original values is obviously easier for the latter. Finally, assign a value to CPSR. You can run the system in system mode or management mode as needed. After the inbound and outbound stacks, the SP points to the bottom of the task stack (that is, the last element of the defined Task Stack Array ).
Then the task code starts to run. Because the CPU registers are limited, some temporary variables must be saved to the stack temporarily during running. Which address should be saved to? Don't worry, SP knows (this address is the address of the last element of the Task Stack Array during the first running of the task ). The size of the task stack is related to the number of temporary variables in the task code. If the Code contains many temporary variables, the stack should be designed to be larger.
Then, the tprint task will be suspended for some reason, so we should put the task running site in the stack to protect it. When the tprint task is run again, we will restore the field, the task can be run immediately from the last breakpoint. So what is the scene? In essence, the tprint task runs a specific piece of code on the CPU, so this field is the CPU site, that is, the register value. These register values contain all information during code execution, including the location at which the code is currently running (indicated by the PC value ). Therefore, push the value of the CPU Register into the stack and remember the position of the top pointer of the stack (SP is saved by ostcbcur-> ostcbstkptr). Before the task is to run again, place the previously saved CPU register values in the CPU register from the SP-pointed address in sequence, and the task can be executed accurately from the last interrupted location. This process is like suddenly freezing a task, and nothing related to the task can be moved. After a while, the task will be restored, and the things related to the task will become available again, as a result, the task can run freely.
From the above analysis, we can see that the task stack is accompanied by the task from the beginning to the end, and its function can be summarized as two points:First, when a task is running, it is used to save some local variables; second, when the task is suspended, it is responsible for saving the job's run site, that is, the value of the CPU register.Some friends ignored the first point and raised the question "The task stack size should be a fixed value ". I think this may be related to the understanding of the function ostaskstkinit (). We call it a stack initialization function, but the "initialization" here is not the same as the initialization we understand, the initialization of variables usually refers to initializing all the members of the variables one by one. The initialization of the stack here is only a small part of the initialization of a large stack, because currently only this part is useful, and most of the remaining is not used, so Initialization is not required, just as some variables do not need initialization (with default values or random values ). When a task is suspended, the continuous area of the CPU register before the task is suspended must be at the top of the entire stack. When the task starts to run again, the value of the SP pop-up register. This area is blank. In addition, the continuous area used to save the current CPU register before each task suspension is floating in the entire task stack space.