HongMeng kernel source code comments in Chinese (Gitee warehouse | CSDN warehouse | | making storehouse Coding warehouse 】 intensive kernel source code, Chinese annotation analysis. Deep dig foundation project, construct bottom network map.

HongMeng source code analysis series articles 【 CSDN | OSCHINA | HarmonyOS 】 question-and-answer takeaway, metaphor of life type, graphical display, layer upon layer peeling kernel mysterious coat.


Tasks are threads

In the Cloud kernel, it can be understood that a task is a thread

What is the official description of threads

Basic Concepts From a system perspective, threads are the smallest running units that compete for system resources. Threads can use or wait for CPU, use system resources such as memory space, and run independently of other threads.

In hongmeng kernel, threads in each process run independently and are scheduled independently. The scheduling of threads in the current process is not affected by threads in other processes.

The thread in hongmeng kernel adopts preemptive scheduling mechanism and supports time slice rotation scheduling and FIFO scheduling.

The kernel thread has a total of 32 priorities (0-31), with the highest priority being 0 and the lowest priority being 31.

The thread with a higher priority in the current process can preempt the thread with a lower priority in the current process. The thread with a lower priority in the current process can be scheduled only after the thread with a higher priority in the current process blocks or finishes.

Thread status description:

Init: The thread is being created.

Ready: This thread is in the Ready list, waiting for CPU scheduling.

Running: The thread is Running.

Blocked: The thread is Blocked and suspended. Blocked states include pend(Blocked due to lock, event, semaphore, etc.), suspend (active pend), Delay (delayed blocking), and Pendtime (wait due to lock, event, semaphore time timeout).

Exit: The thread finishes running and waits for the parent thread to reclaim its control block resources.

Figure 1 schematic diagram of thread state migration



Note that the official documentation says threads, not tasks, but there is a lot of task code in the kernel source code, and very little thread code.

In fact, in the Kernel, a task is a thread, which can be understood by beginners, but there are still differences between the two, otherwise why split the description into two words.

What difference would it make? Task refers to the scheduling level, while thread refers to the process level. Just as the same person can have different identities in different management systems, a man can be a child, a father, a husband, or a programmer with different perspectives and functions.

How to prove is a thing, go on and read more.

Executing the task command

View the result of shell task:

The task command displays information about each task in its life cycle, including its memory space, priority, time slice, entry execution function, process ID, and status. Such complex information requires a structure to carry it. And that structure is LosTaskCB

Task is a program in a user’s program list, and the user’s general list is a process, so there are many programs on it.

What does Task look like

Task and thread are the same thing.

#define OS_TASK_STATUS_INIT         0x0001U
#define OS_TASK_STATUS_READY        0x0002U
#define OS_TASK_STATUS_RUNNING      0x0004U
#define OS_TASK_STATUS_SUSPEND      0x0008U
#define OS_TASK_STATUS_PEND         0x0010U
#define OS_TASK_STATUS_DELAY        0x0020U
#define OS_TASK_STATUS_TIMEOUT      0x0040U
#define OS_TASK_STATUS_PEND_TIME    0x0080U
#define OS_TASK_STATUS_EXIT         0x0100U
Copy the code

What does LosTaskCB look like? Sorry, it’s a little long, but post the full picture.

typedef struct {
    VOID            *stackPointer;      /**< Task stack pointer */	// Stack pointer in non-user mode
    UINT16          taskStatus;         /**< Task status */			// Various status labels, can have a variety of labels, according to the bit identifier
    UINT16          priority;           /**< Task priority */		// Task priority [0:31], the default level is 31
    UINT16          policy;				// Task scheduling mode (three kinds.. LOS_SCHED_RR )
    UINT16          timeSlice;          /**< Remaining time slice */// Remaining time slice
    UINT32          stackSize;          /**< Task stack size */		// Stack size in non-user mode
    UINTPTR         topOfStack;         /**< Task stack top */		// Stack bottom in non-user mode = top + size
    UINT32          taskID;             /**< Task ID */				// Task ID, the task pool is essentially a large array, ID is the array index, default < 128
    TSK_ENTRY_FUNC  taskEntry;          /**< Task entrance function */	// The task executes the entry function
    VOID            *joinRetval;        /**< pthread adaption */	// Used to store the return value of the join thread
    VOID            *taskSem;           /**< Task-held semaphore */	// Task is waiting for a semaphore
    VOID            *taskMux;           /**< Task-held mutex */		// Task is waiting for a lock
    VOID            *taskEvent;         /**< Task-held event */		// Task is waiting for an event
    UINTPTR         args[4];            /**< Parameter, of which the maximum number is 4 */	Int argc,char *argv[]
    CHAR            taskName[OS_TCB_NAME_LEN]; /**< Task name */	// The task name
    LOS_DL_LIST     pendList;           /**< Task pend node */		// If the task is blocked, it is used to hang to the list of various blocking cases, such as OsTaskWait
    LOS_DL_LIST     threadList;         /**< thread list */			// Attach to the thread list of the owning process
    SortLinkList    sortList;           /**< Task sortlink node */	// Attach to the CPU core task execution list
    UINT32          eventMask;          /**< Event mask */			// Event masking
    UINT32          eventMode;          /**< Event mode */			// Event mode
    UINT32          priBitMap;          /**< BitMap for recording the change of task priority, The priority can not be greater than 31 */			// The priority of the pass, for example.. 01001011 used to have priority 0,1,3,6
    INT32           errorNo;            /**< Error Num */
    UINT32          signal;             /**< Task signal */ SIGNAL_NONE,SIGNAL_KILL,SIGNAL_SUSPEND,SIGNAL_AFFI)
    sig_cb          sig;				// Signal control block, used here for interprocess communication signals, similar to the Linux Singal module
#if (LOSCFG_KERNEL_SMP == YES)
    UINT16          currCpu;            /**< CPU core number of this task is running on */	// The CPU kernel number that is running this task
    UINT16          lastCpu;            /**< CPU core number of this task is running on last time */ // The CPU kernel number of the last time this task was run
    UINT16          cpuAffiMask;        /**< CPU affinity mask, support up to 16 cores */	//CPU affinity mask, support a maximum of 16 cores, affinity is very important, in the case of multiple cores, try to run one task on one CPU core, improve efficiency
    UINT32          timerCpu;           /**< CPU core number of this task is delayed or pended */	// The CPU kernel number for this task is delayed or suspended
#if (LOSCFG_KERNEL_SMP_TASK_SYNC == YES)
    UINT32          syncSignal;         /**< Synchronization for signal handling */	// For synchronizing signals between cpus
#endif
#if (LOSCFG_KERNEL_SMP_LOCKDEP == YES)	// Deadlock detection switch
    LockDep         lockDep;
#endif
#if (LOSCFG_KERNEL_SCHED_STATISTICS == YES) // Scheduling statistics switch, obviously this switch will affect performance, the default is off
    SchedStat       schedStat;          /**< Schedule statistics */	// Scheduling statistics
#endif
#endif
    UINTPTR         userArea;			// The usage area is defined by the runtime and varies according to the runtime state
    UINTPTR         userMapBase;		// Bottom of the stack in user mode
    UINT32          userMapSize;        /**< user thread stack size ,real size : userMapSize + USER_STACK_MIN_SIZE */
    UINT32          processID;          /**< Which belong process */// ID of the owning process
    FutexNode       futex;				// Implement fast lock
    LOS_DL_LIST     joinList;           /**< join list */ // Join linked lists to allow tasks to release each other
    LOS_DL_LIST     lockList;           /**< Hold the lock list */	// Get the chain list
    UINT32          waitID;             /**< Wait for the PID or GID of the child process */	// Wait for the child's PID or GID process
    UINT16          waitFlag;           /**< The type of child process that is waiting, belonging to a group or parent, a specific child process, or any child process */
#if (LOSCFG_KERNEL_LITEIPC == YES)
    UINT32          ipcStatus;			/ / the IPC state
    LOS_DL_LIST     msgListHead;		// Message queue header, which is attached to the message to be read by the task
    BOOL            accessMap[LOSCFG_BASE_CORE_TSK_LIMIT];LOSCFG_BASE_CORE_TSK_LIMIT indicates the total number of tasks in the pool
#endif
} LosTaskCB;
Copy the code

The structure LosTaskCB is a lot of stuff. What does it mean? LosTaskCB is the task’s ID card in the kernel, which reflects how each task runs during its lifetime. Since be cycle there will be a state, to run requires memory space and will need to be the kernel algorithm of scheduling, the CPU is selected to execute the code segment instruction, the CPU to perform need to tell it where to start, because is multithreaded, but only one CPU needs constantly switching tasks, the implementation will be interrupted, also need to continue to be executed after recovery, How to ensure that the recovery task does not go wrong? These problems need to be explained.

How to manage tasks

What is a task pool?

As mentioned above, tasks are the concept of kernel scheduling, and scheduling algorithms ensure orderly execution of tasks. See the introduction of scheduling mechanisms in other sister articles. How to manage and execute so many tasks? Management depends on task pools and ready queues, and execution depends on scheduling algorithms. The code is as follows (OsTaskInit) :

LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(VOID)
{
    UINT32 index;
    UINT32 ret;
    UINT32 size;

    g_taskMaxNum = LOSCFG_BASE_CORE_TSK_LIMIT;// The maximum number of threads in the task pool is 128 by default
    size = (g_taskMaxNum + 1) * sizeof(LosTaskCB);// Calculate the total size of memory to be allocated
    /* * This memory is resident memory and is used to save the system resources * of task control block and will not be freed. */
    g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size);// The task pool is resident in memory and is not released
    if (g_taskCBArray == NULL) {
        return LOS_ERRNO_TSK_NO_MEMORY;
    }
    (VOID)memset_s(g_taskCBArray, size, 0, size);

    LOS_ListInit(&g_losFreeTask);// List of idle tasks
    LOS_ListInit(&g_taskRecyleList);// List of tasks to be reclaimed
    for (index = 0; index < g_taskMaxNum; index++) {
        g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED;
        g_taskCBArray[index].taskID = index;// The maximum task ID is 127
        LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList);// Insert the free task list
    }OS_TCB_FROM_PENDLIST OS_TCB_FROM_PENDLIST OS_TCB_FROM_PENDLIST

    ret = OsPriQueueInit(a);// Create 32 task priority queues, i.e. 32 bidirectional circular lists
    if(ret ! = LOS_OK) {return LOS_ERRNO_TSK_NO_MEMORY;
    }

    /* init sortlink for each core */
    for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
        ret = OsSortLinkInit(&g_percpu[index].taskSortLink);// Each CPU core has a linked list of tasks to perform
        if(ret ! = LOS_OK) {returnLOS_ERRNO_TSK_NO_MEMORY; }}return LOS_OK;
}
Copy the code

G_taskCBArray is a task pool. By default, 128 tasks are created in memory and are not released. G_losFreeTask is a linked list of free tasks. If you want to create a task, you can apply for a free task here. G_taskRecyleList is a linked list of recycling tasks, specially used to recycle exit tasks. The resources occupied by the task will be completely deleted after being confirmed and returned. It is just like an employee leaving a job.

Corresponding to Uncle Zhang’s story: users want to come to the venue to get forms to fill in the program, the venue only prepared 128 forms, but after the performance of the show will be recycled forms, so that one more form can be given to others to get, the 128 forms correspond to the hongmeng core, this is the task pool, simple.

What about ready queues

CPU execution speed is very fast, hongmeng kernel default a time slice is 10ms, resources are limited, need to switch back and forth in many tasks, so must not let THE CPU wait for the task, CPU is like the company’s largest leader, the following many departments and other leaders to approve, eat. Only we wait for the leadership, which has the reason for the leadership to wait for you, so the work should be prepared in advance, the priority of each department is not the same, so each department should have a task queue, which is put in the leadership can directly deal with the task, not ready to put in, because this is to the CPU prepared food in advance! This is how ready queues work. There are 32 ready queues, both processes and threads, because threads have a default priority of 32, and each queue puts tasks of the same priority. Or look at the source code

#define OS_PRIORITY_QUEUE_NUM 32
LITE_OS_SEC_BSS LOS_DL_LIST *g_priQueueList = NULL;// Queue linked list
LITE_OS_SEC_BSS UINT32 g_priQueueBitmap;// Queue bitmap UINT32 Each byte represents one priority, which indicates 32 priorities
// The internal queue is initialized
UINT32 OsPriQueueInit(VOID)
{
    UINT32 priority;

    /* system resident resource */// Resident memory
    g_priQueueList = (LOS_DL_LIST *)LOS_MemAlloc(m_aucSysMem0, (OS_PRIORITY_QUEUE_NUM * sizeof(LOS_DL_LIST)));Allocate 32 queue head nodes
    if (g_priQueueList == NULL) {
        return LOS_NOK;
    }

    for (priority = 0; priority < OS_PRIORITY_QUEUE_NUM; ++priority) {
        LOS_ListInit(&g_priQueueList[priority]);// The queue is initialized with a pointer to itself
    }
    return LOS_OK;
}
Copy the code

G_priQueueList = 32 LOS_DL_LIST = 32 LOS_DL_LIST = 32 LOS_DL_LIST = 32

Corresponding to uncle Zhang’s story: those queuing at the gate all have at least one program in line with the performance standards, the resources are in place, and those who do not even have the qualification to queue, just wait.

What is the task stack

Each task is separate, between tasks are independent of each other, also through communication between IPC and the “independent” here refers to each task has its own runtime environment — stack space, called a task stack, stack space saved information is contained in the local variables, registers, function parameters, the function returns the address and so on But there is only one CPU in the system, The task is independent, the nature of scheduling is that the CPU executes a new task, where the old task is interrupted is not clear, it is random. So how do you make sure that the old task will pick up where it left off when it’s scheduled again?

The answer is: task context, CPU has a bunch of registers, the essence of CPU operation is the constant change of the value of these registers, as long as these values are saved when switching, and then restored to ensure the continuous execution of task, so that users do not know. The Kernel gives a task a time of 20ms, which means switching back and forth up to 50 times a second in a multi-task race.

Corresponding to the story of the big ye: performed is met show no must be interrupted, need to record the situation down at that time, such as children at play hide-and-seek game, not out of the half, zhang SAN is a tree, hide to li si is the toilet, all down, come back next time which will be the last time you where to stay, continue to perform in place. So it’s connected, and the audience can’t feel it. What about the TaskContext? Or directly look at the source code

/* The size of this structure must be smaller than or equal to the size specified by OS_TSK_STACK_ALIGN (16 bytes). */
typedef struct {
   
#if! defined(LOSCFG_ARCH_FPU_DISABLE)
    UINT64 D[FP_REGS_NUM]; /* D0-D31 */
    UINT32 regFPSCR;       /* FPSCR */
    UINT32 regFPEXC;       /* FPEXC */
#endif
    UINT32 resved;          /* It's stack 8 aligned */
    UINT32 regPSR;
    UINT32 R[GEN_REGS_NUM]; /* R0-R12 */
    UINT32 SP;              /* R13 */
    UINT32 LR;              /* R14 */
    UINT32 PC;              /* R15 */
} TaskContext;
Copy the code

It is found that the basic RECOVERY of THE FIELD value of CPU registers, the specific role of each register we can go to the Internet for detailed investigation, followed by a special article to introduce. It says three registers SP, LR, PC

LR has two purposes. First, it saves the return address of the subroutine. When the jump instructions such as BL, BX and BLX are called, the return address will be automatically saved to LR. The other is to save the return address of the exception.

PC (Program Counter) is the Program Counter, which is used to save the execution address of the Program. In the three-level pipeline architecture of ARM, the Program pipeline includes three stages: addressing, decoding and execution. PC points to the current address of the Program, so in 32-bit ARM, The decoding address (parsing the program that has not yet been executed) is PC-4, the execution address (currently executing the program address) is PC-8, and the ADDRESS of the PC is saved when a sudden interruption occurs.

SP each exception mode has its own independent R13, which usually points to the special stack for the exception mode. When ARM enters the exception mode, the program can push the general general register onto the stack and return to the stack again, ensuring the integrity of the state of the program in various modes.

Task stack initialization

The initialization of the task stack is the initialization of the task context. Since the task is not executed, there is no other content but the context. Note that the context is stored at the bottom of the stack. In the initial state, sp is pointing to the bottom of the stack, and the top of the stack is always 0xCCCCCCCC, “Hot, hot, hot”. If it’s not there, it means the stack is overflowing, and we’ll talk about that in a sequel, but you can look at the code for yourself, it’s fun.

Set of Task functions

LITE_OS_SEC_TEXT_INIT VOID *OsTaskStackInit(UINT32 taskID, UINT32 stackSize, VOID *topStack, BOOL initFlag)
{
   
    UINT32 index = 1;
    TaskContext *taskContext = NULL;

    if (initFlag == TRUE) {
   
        OsStackInit(topStack, stackSize);
    }
    taskContext = (TaskContext *)(((UINTPTR)topStack + stackSize) - sizeof(TaskContext));// Note that the following will be stored at the bottom of the stack

    /* initialize the task context */
#ifdef LOSCFG_GDB
    taskContext->PC = (UINTPTR)OsTaskEntrySetupLoopFrame;
#else
    taskContext->PC = (UINTPTR)OsTaskEntry;// Program counter, the first instruction that the CPU runs when it executes a task for the first time
#endif
    taskContext->LR = (UINTPTR)OsTaskExit;  /* LR should be kept, to distinguish it's THUMB or ARM instruction */
    taskContext->resved = 0x0;
    taskContext->R[0] = taskID;             /* R0 */
    taskContext->R[index++] = 0x01010101;   /* R1, 0x01010101 : reg initialed magic word */
    for (; index < GEN_REGS_NUM; index++) {
   // R2-r12 initializes r2-r12.
        taskContext->R[index] = taskContext->R[index - 1] + taskContext->R[1]; /* R2 - R12 */
    }

#ifdef LOSCFG_INTERWORK_THUMB // 16-bit mode
    taskContext->regPSR = PSR_MODE_SVC_THUMB; /* CPSR (Enable IRQ and FIQ interrupts, THUMNB-mode) */
#else
    taskContext->regPSR = PSR_MODE_SVC_ARM;   /* CPSR (Enable IRQ and FIQ interrupts, ARM-mode) */
#endif

#if! defined(LOSCFG_ARCH_FPU_DISABLE)
    /* 0xAAA0000000000000LL : float reg initialed magic word */
    for (index = 0; index < FP_REGS_NUM; index++) {
   
        taskContext->D[index] = 0xAAA0000000000000LL + index; /* D0 - D31 */
    }
    taskContext->regFPSCR = 0;
    taskContext->regFPEXC = FP_EN;
#endif

    return (VOID *)taskContext;
}
Copy the code

Usage scenarios and functions

After a task is created, the kernel can perform operations such as lock task scheduling, unlock task scheduling, suspend, resume, delay, etc. At the same time, it can also set the task priority and obtain the task priority. When the task is complete, the current task is automatically deleted. The task management module in Huawei LiteOS provides the following functions for users.

Functional classification The interface name describe
Create and delete tasks LOS_TaskCreateOnly Creates a task and makes it enter the suspend state without scheduling it.
  LOS_TaskCreate Create a task, make the task ready, and schedule it.
  LOS_TaskDelete Example Delete a specified task.
Task state control LOS_TaskResume Resume pending tasks.
  LOS_TaskSuspend Suspends the specified task.
  LOS_TaskDelay The task is delayed.
  LOS_TaskYield You can adjust the task scheduling sequence of a specified priority by explicitly delegating rights.
Control of task scheduling LOS_TaskLock Lock task scheduling.
  LOS_TaskUnlock Unlock task scheduling.
Task priority control LOS_CurTaskPriSet Set the priority of the current task.
  LOS_TaskPriSet Sets the priority of a task.
  LOS_TaskPriGet Gets the priority of the specified task.
Task Information acquisition LOS_CurTaskIDGet Gets the ID of the current task.
  LOS_TaskInfoGet Sets the priority of a task.
  LOS_TaskPriGet Gets information about the specified task.
  LOS_TaskStatusGet Gets the status of the specified task.
  LOS_TaskNameGet Gets the name of the specified task.
  LOS_TaskInfoMonitor Monitor all tasks and obtain information about all tasks.
  LOS_NextTaskIDGet Gets the ID of the task to be scheduled.

The process of creating a task

Learn about another structure, tagTskInitParam, before you create the task

typedef struct tagTskInitParam {//Task initialization parameters
    TSK_ENTRY_FUNC  pfnTaskEntry;  /**< Task entrance function */	// The entry function of the task
    UINT16          usTaskPrio;    /**< Task priority */	// Task priority
    UINT16          policy;        /**< Task policy */		// Task scheduling mode
    UINTPTR         auwArgs[4];    /**< Task parameters, of which the maximum number is four */	// Entry function parameters, up to four
    UINT32          uwStackSize;   /**< Task stack size */	// Task stack size
    CHAR            *pcName;       /**< Task name */		// Task name
#if (LOSCFG_KERNEL_SMP == YES)
    UINT16          usCpuAffiMask; /**< Task cpu affinity mask */	// Task CPU affinity mask
#endif
    UINT32          uwResved;      /**< It is automatically deleted if set to LOS_TASK_STATUS_DETACHED. It is unable to be deleted if set to 0. */ // If set to LOS_TASK_STATUS_DETACHED, automatically delete. If the value is set to 0, it cannot be deleted
    UINT16          consoleID;     /**< The console id of task belongs */ // The task's console ID belongs to
    UINT32          processID;	/ / process ID
    UserTaskParam   userParam;	// Stack parameters when running in user mode
} TSK_INIT_PARAM_S;
Copy the code

These initialization parameters are the exposed task initialization parameters. PfnTaskEntry to Java is the run() of your new process and needs to be provided by the upper level user. Take an example: ping in the shell to see how it is created

u32_t osShellPing(int argc, const char **argv)
{
   
    int ret;
    u32_t i = 0;
    u32_t count = 0;
    int count_set = 0;
    u32_t interval = 1000; /* default ping interval */
    u32_t data_len = 48; /* default data length */
    ip4_addr_t dst_ipaddr;
    TSK_INIT_PARAM_S stPingTask;
    / /... Leave out some intermediate code
    /* start one task if ping forever or ping count greater than 60 */
    if (count == 0 || count > LWIP_SHELL_CMD_PING_RETRY_TIMES) {
   
        if (ping_taskid > 0) {
   
            PRINTK("Ping task already running and only support one now\n");
            return LOS_NOK;
        }
        stPingTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ping_cmd;// The thread's execution function
        stPingTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//0x4000 = 16K 
        stPingTask.pcName = "ping_task";
        stPingTask.usTaskPrio = 8; /* Higher than the shell priority is higher than 10 
        stPingTask.uwResved = LOS_TASK_STATUS_DETACHED;
        stPingTask.auwArgs[0] = dst_ipaddr.addr; /* network order */
        stPingTask.auwArgs[1] = count;
        stPingTask.auwArgs[2] = interval;
        stPingTask.auwArgs[3] = data_len;
        ret = LOS_TaskCreate((UINT32 *)(&ping_taskid), &stPingTask);
    }
	// ...
    return LOS_OK;
ping_error:
    lwip_ping_usage(a);return LOS_NOK;
}
Copy the code

Ping has a scheduling priority of 8, which is higher than shell. The answer is: read the source code is 9

LITE_OS_SEC_TEXT_MINOR UINT32 ShellTaskInit(ShellCB *shellCB)
{
   
    CHAR *name = NULL;
    TSK_INIT_PARAM_S initParam = {
   0};
    if (shellCB->consoleID == CONSOLE_SERIAL) {
   
        name = SERIAL_SHELL_TASK_NAME;
    } else if (shellCB->consoleID == CONSOLE_TELNET) {
   
        name = TELNET_SHELL_TASK_NAME;
    } else {
   
        return LOS_NOK;
    }
    initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellTask;
    initParam.usTaskPrio   = 9; /* 9:shell task priority */
    initParam.auwArgs[0]   = (UINTPTR)shellCB;
    initParam.uwStackSize  = 0x3000;
    initParam.pcName       = name;
    initParam.uwResved     = LOS_TASK_STATUS_DETACHED;
    (VOID)LOS_EventInit(&shellCB->shellEvent);
    return LOS_TaskCreate(&shellCB->shellTaskHandle, &initParam);
}
Copy the code

Shell will be introduced in detail in the future, please continue to pay attention. Once you understand the preconditions, see how the task is created step by step, how it is bound to the process, join the dispatch ready queue, or continue to see the source code

/ / create a Task
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *initParam)
{
    UINT32 ret;
    UINT32 intSave;
    LosTaskCB *taskCB = NULL;

    if (initParam == NULL) {
        return LOS_ERRNO_TSK_PTR_NULL;
    }

    if (OS_INT_ACTIVE) {
        return LOS_ERRNO_TSK_YIELD_IN_INT;
    }

    if (initParam->uwResved & OS_TASK_FLAG_IDLEFLAG) {OS_TASK_FLAG_IDLEFLAG Specifies the idle process in the kernel
        initParam->processID = OsGetIdleProcessID(a);// Get the idle process
    } else if (OsProcessIsUserMode(OsCurrProcessGet())) {// Whether the current process is in user mode
        initParam->processID = OsGetKernelInitProcessID(a);// If not, take the "Kernel" process
    } else {
        initParam->processID = OsCurrProcessGet()->processID;// Get the current process ID assignment
    }
    initParam->uwResved &= ~OS_TASK_FLAG_IDLEFLAG;// It cannot be OS_TASK_FLAG_IDLEFLAG
    initParam->uwResved &= ~OS_TASK_FLAG_PTHREAD_JOIN;// It cannot be OS_TASK_FLAG_PTHREAD_JOIN
    if (initParam->uwResved & LOS_TASK_STATUS_DETACHED) {// Whether automatic deletion is enabled
        initParam->uwResved = OS_TASK_FLAG_DETACHED;OS_TASK_FLAG_DETACHED () {// Delete automatically
    }

    ret = LOS_TaskCreateOnly(taskID, initParam);// Create a task. This is the entity created by the task
    if(ret ! = LOS_OK) {return ret;
    }
    taskCB = OS_TCB_FROM_TID(*taskID);// Get the task entity by ID

    SCHEDULER_LOCK(intSave);
    taskCB->taskStatus &= ~OS_TASK_STATUS_INIT;// Tasks are no longer initialized
    OS_TASK_SCHED_QUEUE_ENQUEUE(taskCB, 0);// The new task enters the ready queue directly
    SCHEDULER_UNLOCK(intSave);

    /* in case created task not running on this core, schedule or not depends on other schedulers status. */
    LOS_MpSchedule(OS_MP_CPU_ALL);// If the created task is not running on this core, scheduling depends on the state of the other schedulers.
    if (OS_SCHEDULER_ACTIVE) {// The CPU core is in the schedulable state
        LOS_Schedule(a);// Initiate scheduling
    }

    return LOS_OK;
}
Copy the code

Corresponding to uncle Zhang’s story: how to fill in the program, according to the format, where to start the performance, how much space, wang Stadium to coordinate the site environment. Note here that as long as the program is not finished in the same program list, the space applied by Wang Pavilion cannot be used by others. This space corresponds to the stack space of Hongmeng task, unless the whole program is finished, it will be recycled. Leave the whole place clean for the next person’s playlist.

LOS_Schedule(); LOS_Schedule(); Because the scheduling mode of Hongmeng is preemptive, if the priority of this task is higher than other ready queues, then the next task to execute is it!

4. What important contents are left unmentioned in Task?

How do Task states operate, block, and wake up? How memory is allocated, how tasks communicate with each other, how stacks are executed at run time, as described in detail in the series memory, IPC

Like to pay attention to it, your attention is really important

Email :[email protected]


HongMeng kernel source code comments in Chinese (Gitee warehouse | CSDN warehouse | | making storehouse Coding warehouse 】 intensive kernel source code, detailed notes in Chinese. Deep dig foundation project, construct bottom network map.

HongMeng source code analysis series articles 【 CSDN | OSCHINA | HarmonyOS 】 question-and-answer takeaway, metaphor of life type, graphical display, layer upon layer peeling kernel mysterious coat.