Hongmeng Kernel Source Code Analysis (Task/Thread Management)

Note: Based on core open source obscurity analysis, the official source [ kernel_liteos_a ] official documents [ docs ] Reference Document [ Huawei LiteOS ]
author: Hong Meng core enthusiasts, will continue to study obscurity kernel, update blog, so stay tuned. The content only represents personal views, errors are welcome, everyone is welcome to correct and improve. View all articles in this series into the
obscurity system source code analysis (List)


This article analyzes the source code of Task/thread management in detail: los_task.c

table of Contents

Preface

1. How to understand Task

1. How does the official document describe threads

2. Execute the task command

3. What does the task look like?

Second, how to manage Task

1. What is a task pool?

2. What's the matter with the ready queue

3. What's the matter with the task stack

4. Task stack initialization

Three, Task function set

1. Usage scenarios and functions

2. The process of creating tasks

3. What are the important contents of the Task/Thread part that have not been mentioned?

For more information, click Hongmeng System Source Code Analysis (General Catalog)


Preface

In the Hongmeng kernel, a task can be understood as a thread in a broad sense


1. How to understand Task

1. How does the official document describe threads

Basic Concepts
From a system perspective, a thread is the smallest unit of operation that competes for system resources. Threads can use or wait for system resources such as CPU and memory space, and run independently of other threads.

The threads in each process of Hongmeng Kernel run independently and are scheduled independently, and the scheduling of threads in the current process is not affected by other threads in the process.

The threads in the Hongmeng kernel adopt a preemptive scheduling mechanism, and support time slice round-robin scheduling and FIFO scheduling.

The threads of the Hongmeng kernel have a total of 32 priorities (0-31), the highest priority is 0, and the lowest priority is 31.

The high-priority thread in the current process can preempt the low-priority thread in the current process, and the low-priority thread in the current process can only be scheduled after the high-priority thread in the current process is blocked or terminated.

Thread status description:

Initialization (Init): The thread is being created.

Ready (Ready): The 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 (because of locks, events, semaphores, etc.), suspend (active pend), delay (delayed blocking), pendtime (because of locks, events, semaphore time, etc. overtime waiting).

Exit (Exit): The thread ends, waiting for the parent thread to reclaim its control block resources.

Figure 1 Schematic diagram of thread state migration.
Insert picture description here
Note that the official document talks about threads and does not mention tasks. However, there are a lot of task codes in the kernel source code and very few thread codes. What is going on?
In fact, in the Hongmeng kernel, tasks are threads. Beginners can understand them in this way, but there are still differences between the two. Otherwise, why should they be described in two words.
What is the difference? It is the difference in management. Task is the concept of scheduling level, and thread is the concept of process level. Just as the same person has 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 it is one thing, continue to look down.

2. Execute the task command

The execution result of the Hongmeng task command:
Insert picture description here

The task command finds out the running status of each task in the life cycle, its running memory space, priority, time slice, entry execution function, process ID, status and other information, which is very complicated. Such complex information needs a structure to carry. And this structure is LosTaskCB (task control block)

3. What does the task look like?

Before talking about LosTaskCB, let's talk about the define corresponding to the task state of the official document. It can be seen that 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

What does LosTaskCB look like? Sorry, it is a bit long, but I still have to post the full picture.

typedef struct {
    VOID            *stackPointer;      /**< Task stack pointer */
    UINT16          taskStatus;         /**< Task status */
    UINT16          priority;           /**< Task priority */
    UINT16          policy;
    UINT16          timeSlice;          /**< Remaining time slice */
    UINT32          stackSize;          /**< Task stack size */
    UINTPTR         topOfStack;         /**< Task stack top */
    UINT32          taskID;             /**< Task ID */
    TSK_ENTRY_FUNC  taskEntry;          /**< Task entrance function */
    VOID            *joinRetval;        /**< pthread adaption */
    VOID            *taskSem;           /**< Task-held semaphore */
    VOID            *taskMux;           /**< Task-held mutex */
    VOID            *taskEvent;         /**< Task-held event */
    UINTPTR         args[4];            /**< Parameter, of which the maximum number is 4 */
    CHAR            taskName[OS_TCB_NAME_LEN]; /**< Task name */
    LOS_DL_LIST     pendList;           /**< Task pend node */
    LOS_DL_LIST     threadList;         /**< thread list */
    SortLinkList    sortList;           /**< Task sortlink node */
    UINT32          eventMask;          /**< Event mask */
    UINT32          eventMode;          /**< Event mode */
    UINT32          priBitMap;          /**< BitMap for recording the change of task priority,
                                             the priority can not be greater than 31 */
    INT32           errorNo;            /**< Error Num */
    UINT32          signal;             /**< Task signal */
    sig_cb          sig;
#if (LOSCFG_KERNEL_SMP == YES)
    UINT16          currCpu;            /**< CPU core number of this task is running on */
    UINT16          lastCpu;            /**< CPU core number of this task is running on last time */
    UINT16          cpuAffiMask;        /**< CPU affinity mask, support up to 16 cores */
    UINT32          timerCpu;           /**< CPU core number of this task is delayed or pended */
#if (LOSCFG_KERNEL_SMP_TASK_SYNC == YES)
    UINT32          syncSignal;         /**< Synchronization for signal handling */
#endif
#if (LOSCFG_KERNEL_SMP_LOCKDEP == YES)
    LockDep         lockDep;
#endif
#if (LOSCFG_KERNEL_SCHED_STATISTICS == YES)
    SchedStat       schedStat;          /**< Schedule statistics */
#endif
#endif
    UINTPTR         userArea;
    UINTPTR         userMapBase;
    UINT32          userMapSize;        /**< user thread stack size ,real size : userMapSize + USER_STACK_MIN_SIZE */
    UINT32          processID;          /**< Which belong process */
    FutexNode       futex;
    LOS_DL_LIST     joinList;           /**< join list */
    LOS_DL_LIST     lockList;           /**< Hold the lock list */
    UINT32          waitID;             /**< Wait for the PID or GID of the child 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;
    LOS_DL_LIST     msgListHead;
    BOOL            accessMap[LOSCFG_BASE_CORE_TSK_LIMIT];
#endif
} LosTaskCB;

The structure of LosTaskCB has a lot of content, what do they mean?
LosTaskCB is equivalent to the ID of the task in the kernel, which reflects the operation of each task in the life cycle. Since it is a cycle, there is a state, and it needs memory space to run, and it needs to be scheduled by the kernel algorithm. The selected CPU executes the code segment instructions. If the CPU wants to execute, it needs to tell it where to start execution, because it is multithreaded, but Only one CPU needs to constantly switch tasks, then the execution will be interrupted, and the execution needs to be resumed. How to ensure that the resumed task execution will not go wrong? These problems need to be clarified.

Second, how to manage Task

1. What is a task pool?

As mentioned above, tasks are the concept of kernel scheduling level. The scheduling algorithm ensures the orderly execution of tasks. There will be detailed chapters on scheduling algorithms in the follow-up.
How to manage and execute so many tasks? Management relies on task pools and ready queues, and execution relies 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;//任务池中最多默认128个,可谓铁打的任务池流水的线程
    size = (g_taskMaxNum + 1) * sizeof(LosTaskCB);
    /* * 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);//任务池 常驻内存,不被释放
    if (g_taskCBArray == NULL) {
   
        return LOS_ERRNO_TSK_NO_MEMORY;
    }
    (VOID)memset_s(g_taskCBArray, size, 0, size);

    LOS_ListInit(&g_losFreeTask);//空闲任务链表
    LOS_ListInit(&g_taskRecyleList);//需回收任务链表
    for (index = 0; index < g_taskMaxNum; index++) {
   
        g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED;
        g_taskCBArray[index].taskID = index;//任务ID最大默认127
        LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList);//都插入空闲任务链表
    }

    ret = OsPriQueueInit();//创建32个任务优先级队列,即32个双向循环链表
    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);//每个CPU内核都有一个执行任务链表
        if (ret != LOS_OK) {
   
            return LOS_ERRNO_TSK_NO_MEMORY;
        }
    }
    return LOS_OK;
}

g_taskCBArray is a task pool, 128 tasks are created by default, resident in memory, and not released.
g_losFreeTask is a linked list of idle tasks. When you want to create a task, come here to apply for a free task. When it is used up, it will be recycled and continue to be used for subsequent applications.
g_taskRecyleList is a list of recycling tasks, dedicated to recycling exit tasks. The resources occupied by tasks are completely deleted after they are confirmed and returned. Just like employee resignation, there must be a resignation queue and process. The computer and mailbox must be returned. And other operations.

2. What's the matter with the ready queue

The CPU execution speed is very fast. The default time slice of the Hongmeng kernel is 10ms. The resources are limited and need to switch back and forth among many tasks. Therefore, the CPU must not be allowed to wait for tasks. The CPU is like the company's biggest leader, many departments below, etc. The leaders come to approve and eat. Only everyone is waiting for the leader, there is no reason for the leader to wait for you, so the work must be prepared in advance, and the priority of each department is different, so each department must have a task queue, which is placed in the leader can directly handle Tasks, don't put them in if you are not ready, because this is food prepared in advance for the CPU!
This is the principle of the ready queue. There are 32 ready queues, both processes and threads. Because the thread priority is 32 by default, each queue puts tasks of the same priority.
Let's see the source code .

#define OS_PRIORITY_QUEUE_NUM 32
UINT32 OsPriQueueInit(VOID)
{
   
    UINT32 priority;

    /* system resident resource */
    g_priQueueList = (LOS_DL_LIST *)LOS_MemAlloc(m_aucSysMem0, (OS_PRIORITY_QUEUE_NUM * sizeof(LOS_DL_LIST)));//常驻内存,不被释放
    if (g_priQueueList == NULL) {
   
        return LOS_NOK;
    }

    for (priority = 0; priority < OS_PRIORITY_QUEUE_NUM; ++priority) {
   
        LOS_ListInit(&g_priQueueList[priority]);
    }
    return LOS_OK;
}

Pay attention to the memory allocation of g_priQueueList, which is 32 LOS_DL_LIST. Do you remember the magical effect of LOS_DL_LIST? Go to Hongmeng System Source Code Analysis (General Catalog) if you are not sure  .

3. What's the matter with the task stack

Each task is opened independently, and the tasks are also independent of each other. The communication between them is through IPC. The "independent" here means that each task has its own operating environment-stack space, called task stack, stack The information stored in the space includes local variables, registers, function parameters, function return addresses, etc.
However, there is only one CPU in the system, and the tasks are independent. The essence of scheduling is that the CPU executes a new task, and where is the old task interrupted? It's not clear, it's random. So how to ensure that the old task can continue to play from the place where it was interrupted last time when it is scheduled again?

The answer is: task context, there are a bunch of registers in the CPU. The essence of CPU operation is that the values ​​of these registers are constantly changing. As long as these values ​​are saved when switching, and then restored, the continuous execution of the task can be guaranteed, leaving the user without Perception.

This is the same as when we played peekaboo games when we were young. We were interrupted by our parents halfway through the game and called back to eat. We continued to play in the afternoon. Zhang San, you should go back to the tree and hide, Li Si continued to hide under the bed, Wang The fifth is to catch Zhang San and Li Si continue to catch, first restore the scene, and then continue to play. This records everyone's location, and the role information is the task context. In fact, a task is to be repeatedly interrupted. The Hongmeng kernel gives a task execution time of 20ms, which means that in the case of multi-task competition, it has to switch back and forth 50 times in one second at most.


What is the task context (TaskContext)? Still look at the source code directly

/* 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;

It is found that it is basically the recovery field value of the CPU register. You can check the specific functions of each register on the Internet, and there will be a special article to introduce it later. Here are three of the registers SP, LR, PC

LR
has two purposes. The first is to save the return address of the subroutine. When a jump instruction such as BL, BX, BLX, etc. is called, the return address is automatically saved to LR; the second is to save the exception return address when an exception occurs.

PC (Program Counter)
is the program counter, used to save the execution address of the program. In ARM's three-stage pipeline architecture, the program pipeline includes three stages: addressing, decoding, and execution. PC points to the program address of the current address , So in 32-bit ARM, the decoding address (the program being parsed and not yet executed) is PC-4, and the execution address (the address of the program currently being executed) is PC-8. When an interruption occurs suddenly, the PC is saved the address of.


Each exception mode of SP has its own independent r13, which usually points to the stack dedicated to the exception mode. When ARM enters the exception mode, the program can push general-purpose registers onto the stack, and then pop the stack when it returns. The completeness of the state of the program under various modes.

4. Task stack initialization

The initialization of the task stack is the initialization of the task context, because the task has not started to execute, there will be no other content except the context. Note that the context is stored at the bottom of the stack.

Three, Task function set

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));//注意看上下文将存放在栈的底部

    /* initialize the task context */
#ifdef LOSCFG_GDB
    taskContext->PC = (UINTPTR)OsTaskEntrySetupLoopFrame;
#else
    taskContext->PC = (UINTPTR)OsTaskEntry;//程序计数器,CPU首次执行task时跑的第一条指令位置
#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的初始化很有意思,为什么要这么做?
        taskContext->R[index] = taskContext->R[index - 1] + taskContext->R[1]; /* R2 - R12 */
    }

#ifdef LOSCFG_INTERWORK_THUMB // 16位模式
    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;
}

1. Usage scenarios and functions

After the task is created, the kernel can perform operations such as locking task scheduling, unlocking task scheduling, suspending, resuming, and delaying. At the same time, it can also set task priority and obtain task priority. When the task ends, the current task self-delete operation is performed.
The task management module in the Huawei LiteOS system provides users with the following functions.

Function classification Interface name description
Task creation and deletion LOS_TaskCreateOnly Create a task and make the task enter the suspend state without scheduling.
  LOS_TaskCreate Create a task, make the task enter the ready state, and schedule it.
  LOS_TaskDelete Delete the specified task.
Task status control LOS_TaskResume Resume suspended tasks.
  LOS_TaskSuspend Suspend the specified task.
  LOS_TaskDelay The task is delayed.
  LOS_TaskYield Explicit decentralization, adjust the task scheduling order of the specified priority.
Task scheduling control LOS_TaskLock Lock task scheduling.
  LOS_TaskUnlock Unlock task scheduling.
Task priority control LOS_CurTaskPriSet Set the priority of the current task.
  LOS_TaskPriSet Set the priority of the specified task.
  LOS_TaskPriGet Get the priority of the specified task.
Task information acquisition LOS_CurTaskIDGet Get the ID of the current task.
  LOS_TaskInfoGet Set the priority of the specified task.
  LOS_TaskPriGet Get information about the specified task.
  LOS_TaskStatusGet Get the status of the specified task.
  LOS_TaskNameGet Get the name of the specified task.
  LOS_TaskInfoMonitor Monitor all tasks and obtain information about all tasks.
  LOS_NextTaskIDGet Get the ID of the task to be scheduled.

2. The process of creating tasks

Before creating a task, learn about another structure tagTskInitParam

typedef struct tagTskInitParam {
   
    TSK_ENTRY_FUNC  pfnTaskEntry;  /**< Task entrance function */
    UINT16          usTaskPrio;    /**< Task priority */
    UINT16          policy;        /**< Task policy */
    UINTPTR         auwArgs[4];    /**< Task parameters, of which the maximum number is four */
    UINT32          uwStackSize;   /**< Task stack size */
    CHAR            *pcName;       /**< Task name */
#if (LOSCFG_KERNEL_SMP == YES)
    UINT16          usCpuAffiMask; /**< 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. */
    UINT16          consoleID;     /**< The console id of task belongs */
    UINT32          processID;
    UserTaskParam   userParam;
} TSK_INIT_PARAM_S;

These initialization parameters are the exposed initial parameters of the task and pfnTaskEntry 对java来说就是你new进程的run(),need to be provided by the upper user.

Let's look at an example: type the ping command in the shell to see the process of its creation

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;
    // ...省去一些中间代码
    /* 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;//线程的执行函数
        stPingTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//0x4000 = 16K 
        stPingTask.pcName = "ping_task";
        stPingTask.usTaskPrio = 8; /* higher than shell 优先级高于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();
    return LOS_NOK;
}

It is found that the scheduling priority of ping is 8, which is higher than that of shell. What is the priority of shell? The answer is: see 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);
}

Please continue to pay attention to the detailed introduction of shell in the follow-up.
After understanding the preconditions, it depends on how the task is created step by step, how to bind to the process, join the scheduling ready queue, or continue to look at the source code

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) {
        initParam->processID = OsGetIdleProcessID();
    } else if (OsProcessIsUserMode(OsCurrProcessGet())) {
        initParam->processID = OsGetKernelInitProcessID();
    } else {
        initParam->processID = OsCurrProcessGet()->processID;
    }
    initParam->uwResved &= ~OS_TASK_FLAG_IDLEFLAG;
    initParam->uwResved &= ~OS_TASK_FLAG_PTHREAD_JOIN;
    if (initParam->uwResved & LOS_TASK_STATUS_DETACHED) {
        initParam->uwResved = OS_TASK_FLAG_DETACHED;
    }

    ret = LOS_TaskCreateOnly(taskID, initParam);
    if (ret != LOS_OK) {
        return ret;
    }
    taskCB = OS_TCB_FROM_TID(*taskID);

    SCHEDULER_LOCK(intSave);
    taskCB->taskStatus &= ~OS_TASK_STATUS_INIT;
    OS_TASK_SCHED_QUEUE_ENQUEUE(taskCB, 0);
    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 (OS_SCHEDULER_ACTIVE) {
        LOS_Schedule();//*kyf 任务创建完了 申请调度
    }

    return LOS_OK;
}

So far, the creation has been completed, and they are all in place. The source code finally applied for LOS_Schedule(); because Hongmeng's scheduling method is preemptive, how the task priority of this task is higher than other ready queues, then the task to be executed next That's it!

3. What are the important contents of the Task/Thread part that have not been mentioned?

How the memory is allocated, how to communicate between threads, and how the stack is executed during operation. After the follow-up talk about memory, the IPC part will be disassembled for analysis.

For more information, click  Hongmeng System Source Code Analysis (General Catalog)

 

Guess you like

Origin blog.csdn.net/kuangyufei/article/details/108621428