1# Task Management 2 3 4## Basic Concepts 5 6From the perspective of the operating system, tasks are the minimum running units that compete for system resources. They can use or wait for CPUs, use system resources such as memory, and run independently. 7 8The task module of the OpenHarmony LiteOS-M supports switching between tasks to help users manage business process procedures. The task module has the following features: 9 10- Multiple tasks are supported. 11 12- A task represents a thread. 13 14- The preemptive scheduling mechanism is used for tasks. High-priority tasks can interrupt low-priority tasks. Low-priority tasks can be scheduled only after high-priority tasks are blocked or complete. 15 16- Time slice round-robin is used to schedule tasks with the same priority. 17 18- A total of 32 (**0** to **31**) priorities are defined. **0** is the highest priority, and **31** is the lowest. 19 20 21### Task-related Concepts 22 23**Task States** 24 25A task has multiple states. After the system initialization is complete, the created tasks can compete for certain resources in the system according to the scheduling procedure regulated by the kernel. 26 27A task can be in any of the following states: 28 29- Ready: The task is in the ready queue, waiting for execution by a CPU. 30 31- Running: The task is being executed. 32 33- Blocked: The task is not in the ready queue. The task may be suspended, delayed, waiting for a semaphore, waiting to read from or write into a queue, or reading from or writing into an event. 34 35- Dead: The task execution is complete and waiting for the system to reclaim resources. 36 37**Task State Transitions** 38 39**Figure 1** Task state transitions 40 41![](figures/task-state-transitions.png "task-state-transitions") 42 43A system may have multiple tasks at the same time. Therefore, tasks in the Ready state and Blocked state are added to the **Ready** queue and **Blocked** queue respectively. A queue is a collection of tasks in the same state. The sequence of adding tasks to a queue is irrelevant to the sequence of task status transition. There is only one task running at a time. Therefore, there is no queue for the running task. 44 45The task state transition process is as follows: 46 47- Ready → Running 48 49 A task enters Ready state once created. When task switching occurs, the task with the highest priority in the Ready queue will be executed. The task being executed enters the Running state and is removed from the Ready queue. 50- Running → Blocked 51 52 When a running task is blocked (suspended, delayed, or reading semaphores), it will be inserted to the blocked task queue and changes from the Running state to the Blocked state. Then, task switching is triggered to run the task with the highest priority in the Ready queue. 53- Blocked -> Ready (Prerequisites for Blocked -> Running) 54 55 When a blocked task is recovered (for example, the task is resumed, the delay period or semaphore read period times out, or the task successfully reads a semaphore), the task will be added to the Ready queue and change from the Blocked state to the Ready state. If the priority of the recovered task is higher than that of the running task, task switching will be triggered to run the recovered task. Then, the task changes from the Ready state to the Running state. 56- Ready → Blocked 57 58 When a task in the Ready state is blocked (suspended), the task changes to the Blocked state and is removed from the Ready queue. The blocked task will not be scheduled until it is recovered. 59- Running → Ready 60 61 When a task with a higher priority is created or recovered, tasks will be scheduled. The task with the highest priority in the Ready queue changes to the Running state. The originally running task changes to the Ready state and remains in the Ready queue. 62- Running → Dead 63 64 When a running task is complete, it changes to the Dead state. The Dead state includes normal exit state as the task is complete and the Invalid state. For example, if a task is complete but is not automatically deleted, the task is in the Invalid state. 65- Blocked → Dead 66 67 If an API is called to delete a blocked task, the task state change from Blocked to Dead. 68 69**Task ID** 70 71A task ID is returned when a task is created. The task ID uniquely identifies a task in the system. You can suspend, restore, or query tasks by task ID. 72 73**Task Priority** 74 75Tasks are executed based on their priority. When task switching occurs, the task with the highest priority in the Ready queue will be executed. 76 77**Task Entry Function** 78 79Function to be executed when a task is scheduled. This function is implemented by users and set in the task creation structure when a task is created. 80 81**Task Stack** 82 83An independent memory space for each task. The stack stores information such as local variables, registers, function parameters, and function return addresses. 84 85**Task Context** 86 87Resources, such as registers, used during the running of a task. When a task is suspended, other running tasks might modify the register values of the suspended task. If the original task context is not saved when task switching occurs, an unknown error may occur when the task is recovered. The context information of switched-out tasks is saved into their own task stacks so that the context information can be resumed along with tasks and the system can start from the interrupted code after the tasks are resumed. 88 89**TCB** 90 91Each task has a task control block (TCB). A TCB contains task information, such as context stack pointer, state, priority, ID, name, and stack size. The TCB reflects the running status of a task. 92 93**Task Switching** 94 95Task switching involves actions, such as obtaining the task with the highest priority in the Ready queue, saving the context of the switched-out task, and restoring the context of the switched-in task. 96 97 98### Task Running Mechanism 99 100When a task is created, the system initializes the task stack and presets the context. The system places the task entry function in the corresponding position so that the function can be executed when the task enters the running state for the first time. 101 102 103## Available APIs 104 105The following table describes APIs available for the OpenHarmony LiteOS-M task module. For more details about the APIs, see the API reference. 106 107**Table 1** APIs of the task management module 108 109| Category| Description| 110| -------- | -------- | 111| Creating or deleting a task| **LOS_TaskCreateOnly**: creates a task and places the task in the Blocked state.<br>**LOS_TaskCreate**: creates a task and places the task in the Ready state. If there is no task with a higher priority in the Ready queue, the task will be executed.<br>**LOS_TaskDelete**: deletes a task.| 112| Controlling task status| **LOS_TaskResume**: resumes a suspended task to place the task in the Ready state.<br>**LOS_TaskSuspend**: suspends the specified task and performs task switching.<br>**LOS_TaskJoin**: suspends this task till the specified task is complete and the task control block resources are reclaimed.<br>**LOS_TaskDelay**: makes a task wait for a period of time (in ticks) and releases CPU resources. When the delay timer expires, the task enters the Ready state again. The input parameter is the number of ticks.<br>**LOS_Msleep**: makes a task wait for a period of time and releases CPU resources. When the delay timer expires, the task enters the Ready state again. The input parameter is the number of milliseconds.<br>**LOS_TaskYield**: sets the time slice of the current task to **0** to release CPU resources and schedule the task with the highest priority in the Ready queue to run.| 113| Controlling task scheduling| **LOS_TaskLock**: locks task scheduling. However, tasks can still be interrupted.<br>**LOS_TaskUnlock**: unlocks task scheduling.<br>**LOS_Schedule**: triggers task scheduling.| 114| Controlling task priority| **LOS_CurTaskPriSet**: sets the priority for the current task.<br>**LOS_TaskPriSet**: sets the priority for a specified task.<br>**LOS_TaskPriGet**: obtains the priority of a specified task.| 115| Obtaining Job information| **LOS_CurTaskIDGet**: obtains the ID of the current task.<br>**LOS_NextTaskIDGet**: obtains the ID of the task with the highest priority in the Ready queue.<br>**LOS_NewTaskIDGet**: equivalent to **LOS_NextTaskIDGet**.<br>**LOS_CurTaskNameGet**: obtains the name of the current task.<br>**LOS_TaskNameGet**: obtains the name of a task.<br>**LOS_TaskStatusGet**: obtains the state of a task.<br>**LOS_TaskInfoGet**: obtains information about a specified task, including the task state, priority, stack size, stack pointer (SP), task entry function, and used stack space.<br>**LOS_TaskIsRunning**: checks whether the task module has started scheduling.| 116| Updating task information| **LOS_TaskSwitchInfoGet**: obtains the task switching information. The macro **LOSCFG_BASE_CORE_EXC_TSK_SWITCH** must be enabled.| 117 118## How to Develop 119 120The typical development process of the task module is as follows: 121 1221. Use **LOS_TaskLock** to lock task scheduling and prevent high-priority tasks from being scheduled. 123 1242. Use **LOS_TaskCreate** to create a task. 125 1263. Use **LOS_TaskUnlock** to unlock task scheduling so that tasks can be scheduled by priority. 127 1284. Use **LOS_TaskDelay** to delay a task. 129 1305. Use **LOS_TaskSuspend** to suspend a task. 131 1326. Use **LOS_TaskResume** to resume the suspended task. 133 134> **NOTE** 135> - Running idle tasks reclaims the TCBs and stacks in the to-be-recycled linked list. 136> 137> - The task name is a pointer without memory space allocated. When setting the task name, do not assign the local variable address to the task name pointer. 138> 139> - The task stack size is 8-byte aligned. Follow the "nothing more and nothing less" principle while determining the task stack size. 140> 141> - A running task cannot be suspended if task scheduling is locked. 142> 143> - Idle tasks and software timer tasks cannot be suspended or deleted. 144> 145> - In an interrupt handler or when a task is locked, the operation of calling **LOS_TaskDelay** fails. 146> 147> - Locking task scheduling does not disable interrupts. Tasks can still be interrupted while task scheduling is locked. 148> 149> - Locking task scheduling must be used together with unlocking task scheduling. 150> 151> - Task scheduling may occur while a task priority is being set. 152> 153> - The maximum number of tasks that can be set for the operating system is the total number of tasks of the operating system, not the number of tasks available to users. For example, if the system software timer occupies one more task resource, the number of task resources available to users decreases by one. 154> 155> - **LOS_CurTaskPriSet** and **LOS_TaskPriSet** cannot be used in interrupts or used to modify the priorities of software timer tasks. 156> 157> - If the task corresponding to the task ID sent to **LOS_TaskPriGet** has not been created or the task ID exceeds the maximum number of tasks, **-1** will be returned. 158> 159> - Resources such as a mutex or a semaphore allocated to a task must have been released before the task is deleted. 160 161 162## Development Example 163 164This example describes the priority-based task scheduling and use of task-related APIs, including creating, delaying, suspending, and resuming two tasks with different priorities, and locking/unlocking task scheduling. 165 166The sample code is compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. Call **ExampleTask** in **TestTaskEntry**. 167 168 169``` 170#include "los_task.h" 171 172UINT32 g_taskHiId; 173UINT32 g_taskLoId; 174#define TSK_PRIOR_HI 3 /* Priority of a high-priority task. */ 175#define TSK_PRIOR_LO 4 /* Priority of a low-priority task. */ 176 177UINT32 ExampleTaskHi(VOID) 178{ 179 UINT32 ret; 180 181 printf("Enter TaskHi Handler.\n"); 182 183 /* Delay the task for 100 ticks. The task is then suspended, and the remaining task with the highest priority (TaskLo) will be executed. */ 184 ret = LOS_TaskDelay(100); 185 if (ret != LOS_OK) { 186 printf("Delay TaskHi Failed.\n"); 187 return LOS_NOK; 188 } 189 190 /* After 100 ticks elapse, the task is resumed. */ 191 printf("TaskHi LOS_TaskDelay Done.\n"); 192 193 /* Suspend the task. */ 194 ret = LOS_TaskSuspend(g_taskHiId); 195 if (ret != LOS_OK) { 196 printf("Suspend TaskHi Failed.\n"); 197 return LOS_NOK; 198 } 199 printf("TaskHi LOS_TaskResume Success.\n"); 200 return ret; 201} 202 203/* Entry function of low-priority tasks */ 204UINT32 ExampleTaskLo(VOID) 205{ 206 UINT32 ret; 207 208 printf("Enter TaskLo Handler.\n"); 209 210 /* Delay the task for 100 ticks. The task is then suspended, and the remaining task with the highest priority will be executed. */ 211 ret = LOS_TaskDelay(100); 212 if (ret != LOS_OK) { 213 printf("Delay TaskLo Failed.\n"); 214 return LOS_NOK; 215 } 216 217 printf("TaskHi LOS_TaskSuspend Success.\n"); 218 219 /* Resume the suspended task g_taskHiId. */ 220 ret = LOS_TaskResume(g_taskHiId); 221 if (ret != LOS_OK) { 222 printf("Resume TaskHi Failed.\n"); 223 return LOS_NOK; 224 } 225 return ret; 226} 227 228/* Task entry function used to create two tasks with different priorities. */ 229UINT32 ExampleTask(VOID) 230{ 231 UINT32 ret; 232 TSK_INIT_PARAM_S taskParam1 = { 0 }; 233 TSK_INIT_PARAM_S taskParam2 = { 0 }; 234 235 /* Lock task scheduling to prevent newly created tasks from being scheduled prior to this task due to higher priority. */ 236 LOS_TaskLock(); 237 238 printf("LOS_TaskLock() Success!\n"); 239 240 taskParam1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskHi; 241 taskParam1.usTaskPrio = TSK_PRIOR_HI; 242 taskParam1.pcName = "TaskHi"; 243 taskParam1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 244 taskParam1.uwResved = LOS_TASK_ATTR_JOINABLE; /* Detach attribute. */ 245 246 /* Create a task with higher priority. The task will not be executed immediately after being created, because task scheduling is locked. */ 247 ret = LOS_TaskCreate(&g_taskHiId, &taskParam1); 248 if (ret != LOS_OK) { 249 LOS_TaskUnlock(); 250 251 printf("Example_TaskHi create Failed!\n"); 252 return LOS_NOK; 253 } 254 255 printf("Example_TaskHi create Success!\n"); 256 257 taskParam2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskLo; 258 taskParam2.usTaskPrio = TSK_PRIOR_LO; 259 taskParam2.pcName = "TaskLo"; 260 taskParam2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 261 262 /* Create a low-priority task. The task will not be executed immediately after being created, because task scheduling is locked. */ 263 ret = LOS_TaskCreate(&g_taskLoId, &taskParam2); 264 if (ret != LOS_OK) { 265 LOS_TaskUnlock(); 266 printf("Example_TaskLo create Failed!\n"); 267 return LOS_NOK; 268 } 269 270 printf("Example_TaskLo create Success!\n"); 271 272 /* Unlock task scheduling. The task with the highest priority in the Ready queue will be executed. */ 273 LOS_TaskUnlock(); 274 ret = LOS_TaskJoin(g_taskHiId, NULL); 275 if (ret != LOS_OK) { 276 printf("Join Example_TaskHi Failed!, 0x%x\n", ret); 277 } else { 278 printf("Join Example_TaskHi Success!\n"); 279 } 280 return LOS_OK; 281} 282``` 283 284**Verification** 285 286The development is successful if the return result is as follows: 287 288 289``` 290LOS_TaskLock() Success! 291Example_TaskHi create Success! 292Example_TaskLo create Success! 293Enter TaskHi Handler. 294Enter TaskLo Handler. 295TaskHi LOS_TaskDelay Done. 296TaskHi LOS_TaskSuspend Success. 297TaskHi LOS_TaskResume Success. 298Join Example_TaskHi Success! 299``` 300