Where Does the RTOS Task Entry Function Go After Execution?

1. Introduction

During my work, I found that understanding these concepts only allows one to use RTOS at a basic level. To effectively utilize RTOS, one must understand some detailed mechanisms; otherwise, it is easy to fall into pitfalls and spend a lot of time troubleshooting.

This article discusses related content in conjunction with the TencentOS-Tiny real-time operating system.

2. Common Task Implementations

Following the principle of “yield if not in use,” tasks are usually written in two ways.

Blocking Wait for an event to handle:

void task1_entry(void *arg)
{
 // init...

 while (1) {
  // 1. wait some kernel object...
  // eg. tos_sem_pend, tos_mutex_pend, tos_event_pend.
   
  //  2. wait success, handle!
 }
}

In this implementation, when no event occurs, the task is suspended while waiting for a kernel object, yielding the CPU and not participating in scheduling.

② Timed Execution

void task1_entry(void *arg)
{
// init...

while (1) {
// 1. do some thing...

//  2. sleep!
// eg. tos_task_delay, tos_sleep_ms.
}
}

In this implementation, after completing its work, the task actively enters a sleep state, yielding the CPU and not participating in scheduling.

3. One-time Tasks

The commonality of the above two implementations is that they both have a main loop and do not need to consider the exit of the task entry function. However, in some scenarios, a task only needs to execute once:

void task1_entry(void *arg)
{
 // init...

 // do some thing...

 // exit?
}

At this point, one must consider a question: Where does the task entry function go after execution?

4. Finding the Answer

First, the task entry function is essentially a function, and the instruction to jump to the function is <span>BL</span>. When the CPU executes this instruction to jump to a function, it saves the current PC address as the return address in the LR register, ensuring that after the function executes, it can return here to continue execution, and then loads the function address into the PC register, allowing the program to continue executing in the function. Where Does the RTOS Task Entry Function Go After Execution? So, how is the task entry function executed if it is not called by another function?

Task switching consists of two steps: saving the context and switching the context. Switching the context refers to loading the values of the CPU register set saved in the task stack into the CPU.

Therefore, when the value of the PC register in the initially saved CPU register set in the task stack points to the address of the task entry function, after the context switch loads, since the PC points to the task entry function, the CPU continues running and reaches the task entry function, meaning the task is running.

Similarly, the value of the LR register in the initially saved CPU register set in the task stack determines where to return when the task entry function exits.

Since different CPU architectures have different CPU register sets, the code for initializing the task stack is closely related to the architecture, and there are different implementations corresponding to different architectures in the arch directory.

Here, we take the ARM Cortex-M4 as an example (Arm-v7m) to see how the code is implemented:

Where Does the RTOS Task Entry Function Go After Execution? From the code, we can see that the default exit function for TencentOS-Tiny is specified by the exit parameter. Next, let’s look at the exit function.

5. Task Exit Function

In the API for creating tasks <span>tos_task_create</span>, during the initialization of the task stack, the exit function is specified as <span>task_exit</span>:

task-&gt;sp = cpu_task_stk_init((void *)entry, arg, (void *)task_exit, stk_base, stk_size);

The task_exit function mainly handles the destruction of itself, and the specific implementation is as follows:

__STATIC__ void task_exit(void)
{
    tos_task_destroy(K_NULL);
}

The parameter passed to the destroy function is NULL, indicating that it destroys itself. If it is a static task, it will be destroyed according to the following steps (the destruction of dynamic tasks deserves a separate article):

  • Remove the task from the ready list
  • Remove the task from the waiting list
  • Remove the task from the statistics list
  • Set the task state to K_TASK_STATE_DELETED

6. Conclusion

This article discussed two common implementations of tasks and where the task function goes after execution.

When the task function exits, where it goes is determined by the value of the LR register during task stack initialization. The RTOS kernel provides a default exit function, and the task exit function provided by TencentOS-Tiny automatically destroys the task itself.

Therefore, when writing one-time tasks, there is no need to actively call the destroy API to destroy itself!

Shenzhen International Electronics Fair is about to be held. Are there any friends who want to participate? Scan the code to register for free.Where Does the RTOS Task Entry Function Go After Execution?

———— END ————

Where Does the RTOS Task Entry Function Go After Execution?

● Column “Embedded Tools”

● Column “Embedded Development”

● Column “Keil Tutorials”

● Selected Tutorials in Embedded Column

Follow the public account and reply “Join Group” to join the technical exchange group according to the rules, reply “1024” to see more content.

Click “Read the original text” to see more shares.

Leave a Comment