Task

Basic Concepts

Tasks are the minimum running units that compete for system resources. They can use or wait to use CPUs and use system resources such as memory. They run independently from one another.

A task represents a thread in the OpenHarmony kernel, and tasks in the processes of the same priority are scheduled and run in a unified manner.

Tasks in the OpenHarmony kernel use the preemptive scheduling mechanism, either round-robin (RR) scheduling or First In First Out (FIFO) scheduling.

Tasks in the OpenHarmony kernel are assigned 32 priorities, ranging from 0 (highest) to 31 (lowest).

In the same process, a higher-priority process can preempt resources of a lower-priority process. The lower-priority process can be scheduled only after the higher-priority process is blocked or terminated.

Task States:

  • Init: The task is being created.

  • Ready: The task is in the Ready queue and waits for being scheduled by the CPU.

  • Running: The task is running.

  • Blocked: The task is blocked and suspended. The Blocked states include pending (blocked due to lock, event, or semaphore issues), suspended (active pending), delay (blocked due to delays), and pendtime (blocked by waiting timeout of locks, events, or semaphores).

  • Exit: The task stops running and waits for the parent task to reclaim its control block resources.

Figure 1 Task state transition

Task State Transition:

  • Init→Ready:

    When a task is created, the task obtains the control block and enters the Init state (initialization). After the initialization is complete, the task is inserted into the scheduling queue and enters the Ready state.

  • Ready→Running:

    When a task switching is triggered, the task with the highest priority in the Ready queue is executed and enters the Running state. Then, this task is deleted from the Ready queue.

  • Running→Blocked:

    When a running task is blocked (for example, is pended, delayed, or reading semaphores), its state changes from Running to Blocked. Then, a task switching is triggered to run the task with the highest priority in the Ready queue.

  • Blocked→Ready:

    After the blocked task is restored (the task is restored, the delay times out, the semaphore reading times out, or the semaphore is read), the task is added to the Ready queue and changes from the Blocked state to the Ready state.

  • Ready→Blocked:

    A task may also be blocked (suspended) in the Ready state. The blocked task will change from the Ready state to the Blocked state and is deleted from the Ready queue. The task will not be scheduled until it is restored.

  • Running→Ready:

    After a task with a higher priority is created or restored, tasks will be scheduled. The task with the highest priority in the Ready queue will change to the Running state. The originally running task will change from the Running state to the Ready state and be added to the Ready queue.

  • Running→Exit:

    When a running task is terminated, its state changes from Running to Exit. If the task is set with a detach attribute (LOS_TASK_STATUS_DETACHED), it will be directly destroyed after the running is complete.

Working Principles

The OpenHarmony task management module provides the following functions: creating, delaying, suspending, and restoring tasks, locking and unlocking task scheduling, and querying task control block information by ID.

When 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 will be executed when the task enters the Running state for the first time.

Development Guidelines

Available APIs

Category

API

Description

Task creation and deletion

LOS_TaskCreateOnly

Creates a task and places the task in the Init state but not be scheduled.

LOS_TaskCreate

Creates a task and places the task in the Init state and be scheduled.

LOS_TaskDelete

Deletes the specified task.

Task status control

LOS_TaskResume

Resumes a suspended task.

LOS_TaskSuspend

Suspends the specified task.

LOS_TaskDelay

Delays a task.

LOS_TaskYield

Adjusts the scheduling sequence of tasks that call the task priority.

Task scheduling control

LOS_TaskLock

Locks task scheduling.

LOS_TaskUnlock

Unlocks task scheduling.

Task priority control

LOS_CurTaskPriSet

Sets the priority for the current task.

LOS_TaskPriSet

Sets the priority of the specified task.

LOS_TaskPriGet

Obtains the priority of the specified task.

Obtaining task information

LOS_CurTaskIDGet

Obtains the ID of the current task.

LOS_TaskInfoGet

Obtains information about the specific task.

Binding tasks to CPU cores

LOS_TaskCpuAffiSet

Binds a specified task to a specified CPU. It is used only in multi-core scenarios.

LOS_TaskCpuAffiGet

Obtains the core binding information of a specified task. It is used only in multi-core scenarios.

Task scheduling parameter control

LOS_GetTaskScheduler

Obtains the scheduling policy of the specified task.

LOS_SetTaskScheduler

Sets the scheduling parameters, including the priority and scheduling policy, for the specified task.

Maximum number of tasks supported

LOS_GetSystemTaskMaximum

Obtains the maximum number of tasks supported by the system.

How to Develop

The typical task development process is as follows:

  1. Call LOS_TaskCreate to create a task.

    • Specify the execution entry function for the task.

    • Specify the task name.

    • Specify the task stack size.

    • Specify the priority of the task.

    • Specify the task attribute, that is, whether to support the LOS_TASK_STATUS_DETACHED attribute.

    • Specify the task-core binding attribute for multi-core environment.

  2. Run the service code to implement task scheduling.

  3. After the task execution is complete, the task resources are automatically reclaimed if the LOS_TASK_STATUS_DETACHED attribute is set. If the LOS_TASK_STATUS_DETACHED attribute is not set, call the LOS_TaskDelete API to reclaim the task resources.

NOTE:

  • The kernel space has the highest permission and can operate tasks in any process.
  • The task created by calling a user-space process in the kernel space is a KProcess, not a user-space process.

Development Example

The sample code is as follows:

UINT32 g_taskLoID;
UINT32 g_taskHiID; 
#define TSK_PRIOR_HI 4 
#define TSK_PRIOR_LO 5  
UINT32 ExampleTaskHi(VOID) 
{     
    UINT32 ret;
    PRINTK("Enter TaskHi Handler.\n"); 
    /* Delay the task for 2 ticks. The task is then suspended, and the remaining task with the highest priority (g_taskLoID) will be executed.*/
    ret = LOS_TaskDelay(2);
    if (ret != LOS_OK) { 
        PRINTK("Delay Task Failed.\n");
        return LOS_NOK;     
    }      
    /*After 2 ticks elapse, the task is resumed and executed.*/
    PRINTK("TaskHi LOS_TaskDelay Done.\n"); 
    /* Suspend the task.*/
    ret = LOS_TaskSuspend(g_taskHiID); 
    if (ret != LOS_OK) {
        PRINTK("Suspend TaskHi Failed.\n"); 
        return LOS_NOK;
    }     
    PRINTK("TaskHi LOS_TaskResume Success.\n"); 
    return LOS_OK;
}

/* Entry function of the lower-priority task */
UINT32 ExampleTaskLo(VOID)
{     
    UINT32 ret;         
    PRINTK("Enter TaskLo Handler.\n");      
    /* Delay the task for 2 ticks. The task is then suspended, and the remaining task with the highest priority (background task) will be executed.*/
    ret = LOS_TaskDelay(2);     
    if (ret != LOS_OK) {         
        PRINTK("Delay TaskLo Failed.\n");         
        return LOS_NOK;     
    }      
    PRINTK("TaskHi LOS_TaskSuspend Success.\n");
    /* Resume the suspended task g_taskHiID.*/
    ret = LOS_TaskResume(g_taskHiID);
    if (ret != LOS_OK) {
        PRINTK("Resume TaskHi Failed.\n");
        return LOS_NOK;
    }      
    PRINTK("TaskHi LOS_TaskDelete Success.\n"); 
    return LOS_OK;
}  
/* Task test entry function, which is used to create two tasks with different priorities.*/
UINT32 ExampleTaskCaseEntry(VOID) 
{     
    UINT32 ret;     
    TSK_INIT_PARAM_S initParam = {0};

    /* Lock task scheduling.*/
    LOS_TaskLock();
    PRINTK("LOS_TaskLock() Success!\n");
    initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskHi;
    initParam.usTaskPrio = TSK_PRIOR_HI; 
    initParam.pcName = "HIGH_NAME";
    initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE;
    initParam.uwResved   = LOS_TASK_STATUS_DETACHED;

    /* Create a task with a higher priority. The task will not be executed immediately after being created, because task scheduling is locked.*/
    ret = LOS_TaskCreate(&g_taskHiID, &initParam);
    if (ret != LOS_OK) {
        LOS_TaskUnlock();
        PRINTK("ExampleTaskHi create Failed! ret=%d\n", ret);
        return LOS_NOK;
    }      
    PRINTK("ExampleTaskHi create Success!\n");

    initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskLo;
    initParam.usTaskPrio = TSK_PRIOR_LO;
    initParam.pcName = "LOW_NAME";
    initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE;
    initParam.uwResved   = LOS_TASK_STATUS_DETACHED;

    /*Create a task with a lower priority. The task will not be executed immediately after being created, because task scheduling is locked.*/
    ret = LOS_TaskCreate(&g_taskLoID, &initParam);
    if (ret!= LOS_OK) {         
        LOS_TaskUnlock();          
        PRINTK("ExampleTaskLo create Failed!\n");
        return LOS_NOK;     
    }      
    PRINTK("ExampleTaskLo create Success!\n");  

    /* Unlock task scheduling. The task with the highest priority in the Ready queue will be executed.*/
    LOS_TaskUnlock();

    while(1){};
    return LOS_OK;
}  

The development is successful if the return result is as follows:

LOS_TaskLock() Success!
ExampleTaskHi create Success!
ExampleTaskLo create Success!
Enter TaskHi Handler.
Enter TaskLo Handler.
TaskHi LOS_TaskDelay Done.
TaskHi LOS_TaskSuspend Success.
TaskHi LOS_TaskResume Success.
TaskHi LOS_TaskDelete Success.