The Master said, “If you speak eloquence, you flatter yourself, and respect your feet, you will see shame on your left qiu, and shame on your own Qiu. If you are a friend with a grudge, you should be ashamed of yourself and ashamed of yourself.” “The Analects of Confucius” : Gong Ye chang

A hundred blog series. This is: the v03. Xx HongMeng kernel source code analysis task (clock), whose biggest contribution | trigger scheduling

Task management related articles are:

  • V03. Xx HongMeng kernel source code analysis (the clock) whose biggest contribution | trigger scheduling
  • V04. Xx HongMeng kernel source code analysis (scheduling) | is the kernel task scheduling unit
  • V05. Xx HongMeng kernel source code analysis (task management) | pool of task is how to manage
  • V06. Xx HongMeng kernel source code analysis (scheduling queue) | how many scheduling are the kernel queue
  • V07. Xx HongMeng kernel source code analysis (scheduling) scheduler | task is how to
  • V21. Xx HongMeng kernel source code analysis concept (thread) | who is constantly with the CPU
  • V25. Xx HongMeng kernel source code analysis (concurrent parallel) | heard countless times two concepts
  • V37. Xx HongMeng kernel source code analysis (system calls) | forever mantra
  • V41. Xx HongMeng kernel source code analysis (task switching) switch | see how assembly task

The clock concept

  • Time is a very important concept, and one thing that is very important throughout our student life is the school bell. It controls the rhythm of class, dismissal, eating, and sleeping. Without it, the management of the school would be chaotic. The teacher would drag the class for as long as he wanted to. That can’t do, the bell rang after class is to tell the teacher that it is time to stop and let the students HAPPY.

  • The operating system also needs time to perform tasks. The smallest unit of time in an operating system is the OS Tick. Any operating system needs to provide a clock beat so that the system can handle all time-related events, such as thread delay, thread time slice rotation scheduling, and timer timeout. Ticks are specific periodic interruptions, heartbeat, the interrupt is seen as a system interrupt the time interval between depends on the different application, the general is 1 ms – 100 ms, the faster the rate of ticks, the faster the real-time response of the system, but the greater the overhead of system, start from the system began to count the number of ticks is called the system time.

  • In the Hung Moon kernel, the length of the clock beat can be adjusted according to the definition of LOSCFG_BASE_CORE_TICK_PER_SECOND, which is equal to 1/LOSCFG_BASE_CORE_TICK_PER_SECOND.

The implementation of clock beats

The clock beat is generated by a hardware timer configured for interrupt-triggered mode. When an interrupt occurs, the following void OsTickHandler(void) is called to notify the operating system that a system clock has passed. Different hardware timer interrupt implementation is different,

/** * @ingroup los_config * Number of Ticks in one second */
#ifndef LOSCFG_BASE_CORE_TICK_PER_SECOND
#define LOSCFG_BASE_CORE_TICK_PER_SECOND 100 // The default is 100 times per second, but this can be changed
#endif
Copy the code

100 ticks per second, the time unit is 10 milliseconds, that is, call the clock interrupt handler 100 times per second.

/* * Description : Tick interruption handler */// Beat interrupt processing function, hongming default 10ms trigger once
LITE_OS_SEC_TEXT VOID OsTickHandler(VOID)
{
    / /...
    OsTimesliceCheck(a);// Time slice checks for processes and tasks
    OsTaskScan(a);/* task timeout scan */// Task scan
#if (LOSCFG_BASE_CORE_SWTMR == YES)
    OsSwtmrScan(a);// Scan the timer to see if there is a timeout timer
#endif
}
Copy the code

It does three main things

First: check the time slice of the current task. How much time is allocated for each task execution? The answer is 2 time slices, i.e. 20ms.

#ifndef LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT
#define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 2 //2 time slices,20ms
#endif
// Check the time slice of the process and task, if there is no time slice directly schedule
LITE_OS_SEC_TEXT VOID OsTimesliceCheck(VOID)
{
    LosTaskCB *runTask = NULL;
    LosProcessCB *runProcess = OsCurrProcessGet(a);// Get the current process
    if(runProcess->policy ! = LOS_SCHED_RR) {// Whether the process scheduling algorithm is preemptive
        goto SCHED_TASK;// The process is not preemptively scheduled to check the time slice of the task directly
    }

    if(runProcess->timeSlice ! =0) {// Does the process still have time slices?
        runProcess->timeSlice--;// The process time slice is reduced once
        if (runProcess->timeSlice == 0) {// There are no more time slots
            LOS_Schedule(a);// The process runs out of time
        }
    }

SCHED_TASK:
    runTask = OsCurrTaskGet(a);// Get the current task
    if(runTask->policy ! = LOS_SCHED_RR) {// Whether the task scheduling algorithm is preemptive
        return;// Tasks are not preemptively scheduled to end the check directly
    }

    if(runTask->timeSlice ! =0) {// Will there be a time slot for the mission?
        runTask->timeSlice--;// The task time slice is also reduced once
        if (runTask->timeSlice == 0) {// There are no more time slots
            LOS_Schedule(a);// The task time slice is used up}}}Copy the code

Second: scanning tasks, mainly to check whether blocked tasks can be rescheduled

LITE_OS_SEC_TEXT VOID OsTaskScan(VOID)
{
    SortLinkList *sortList = NULL;
    LosTaskCB *taskCB = NULL;
    BOOL needSchedule = FALSE;
    UINT16 tempStatus;
    LOS_DL_LIST *listObject = NULL;
    SortLinkAttribute *taskSortLink = NULL;

    taskSortLink = &OsPercpuGet()->taskSortLink;// Get the sorted list of tasks
    taskSortLink->cursor = (taskSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK;
    listObject = taskSortLink->sortLink + taskSortLink->cursor;// Process only the linked list on this cursor, because the system already lists timeout tasks.
 // When a task is suspended due to timeout, the task block is on the timeout sort link, and the blocks (per CPU) and IPC (mutex, SEM, etc.) are woken up at the same time
    /* It is waiting for either a timeout or the corresponding IPC. Now use Synchronize SortLink PRECEDure, so the entire task scan needs protection to prevent another core from deleting sortLink at the same time. * When task is pended with timeout, the task block is on the timeout sortlink * (per cpu) and ipc(mutex,sem and etc.)'s block at the same time, it can be waken * up by either timeout or corresponding ipc it's waiting. * * Now synchronize sortlink preocedure is used, therefore the whole task scan needs * to be protected, preventing another core from doing sortlink deletion at same time. */
    LOS_SpinLock(&g_taskSpin);

    if (LOS_ListEmpty(listObject)) {
        LOS_SpinUnlock(&g_taskSpin);
        return;
    }
    sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);// Tick the first node of SortLinkList sortLinkNode
    ROLLNUM_DEC(sortList->idxRollNum);// Roll count --

    while (ROLLNUM(sortList->idxRollNum) == 0) {// Find the time is up node, note that these nodes are generated by the timer,
        LOS_ListDelete(&sortList->sortLinkNode);
        taskCB = LOS_DL_LIST_ENTRY(sortList, LosTaskCB, sortList);// Take the tasks, where the tasks are timeout tasks
        taskCB->taskStatus &= ~OS_TASK_STATUS_PEND_TIME;
        tempStatus = taskCB->taskStatus;
        if (tempStatus & OS_TASK_STATUS_PEND) {
            taskCB->taskStatus &= ~OS_TASK_STATUS_PEND;
#if (LOSCFG_KERNEL_LITEIPC == YES)
            taskCB->ipcStatus &= ~IPC_THREAD_STATUS_PEND;
#endif
            taskCB->taskStatus |= OS_TASK_STATUS_TIMEOUT;
            LOS_ListDelete(&taskCB->pendList);
            taskCB->taskSem = NULL;
            taskCB->taskMux = NULL;
        } else {
            taskCB->taskStatus &= ~OS_TASK_STATUS_DELAY;
        }

        if(! (tempStatus & OS_TASK_STATUS_SUSPEND)) {OS_TASK_SCHED_QUEUE_ENQUEUE(taskCB, OS_PROCESS_STATUS_PEND);
            needSchedule = TRUE;
        }

        if (LOS_ListEmpty(listObject)) {
            break;
        }

        sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
    }

    LOS_SpinUnlock(&g_taskSpin);

    if(needSchedule ! = FALSE) {// Need scheduling
        LOS_MpSchedule(OS_MP_CPU_ALL);// Intercore communication, send scheduling signal to all cpus
        LOS_Schedule(a);// Start scheduling}}Copy the code

Third: timer scan to see if there is a timeout timer

/* * Description: Tick interrupt interface module of software timer * Return : LOS_OK on success or error code on failure */OsSwtmrScan is called by the system clock interrupt handler
LITE_OS_SEC_TEXT VOID OsSwtmrScan(VOID)// Scan timer, if encounter timeout, put into the timeout queue
{
    SortLinkList *sortList = NULL;
    SWTMR_CTRL_S *swtmr = NULL;
    SwtmrHandlerItemPtr swtmrHandler = NULL;
    LOS_DL_LIST *listObject = NULL;
    SortLinkAttribute* swtmrSortLink = &OsPercpuGet()->swtmrSortLink;// Get the current CPU timer list

    swtmrSortLink->cursor = (swtmrSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK;
    listObject = swtmrSortLink->sortLink + swtmrSortLink->cursor;
 // Since SWTMR is in a specific sortlink, it needs to be handled very carefully, but other CPU cores still have a chance to handle it, such as stopping timers
    /* * it needs to be carefully coped with, since the swtmr is in specific sortlink * while other cores still has the chance to process it, like stop the timer. */
    LOS_SpinLock(&g_swtmrSpin);

    if (LOS_ListEmpty(listObject)) {
        LOS_SpinUnlock(&g_swtmrSpin);
        return;
    }
    sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
    ROLLNUM_DEC(sortList->idxRollNum);

    while (ROLLNUM(sortList->idxRollNum) == 0) {
        sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
        LOS_ListDelete(&sortList->sortLinkNode);
        swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);

        swtmrHandler = (SwtmrHandlerItemPtr)LOS_MemboxAlloc(g_swtmrHandlerPool);// Retrieves an available soft clock handler
        if(swtmrHandler ! =NULL) {
            swtmrHandler->handler = swtmr->pfnHandler;
            swtmrHandler->arg = swtmr->uwArg;

            if (LOS_QueueWrite(OsPercpuGet()->swtmrHandlerQueue, swtmrHandler, sizeof(CHAR *), LOS_NO_WAIT)) {
                (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandler); }}if (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) {
            OsSwtmrDelete(swtmr);

            if (swtmr->usTimerID < (OS_SWTMR_MAX_TIMERID - LOSCFG_BASE_CORE_SWTMR_LIMIT)) {
                swtmr->usTimerID += LOSCFG_BASE_CORE_SWTMR_LIMIT;
            } else{ swtmr->usTimerID %= LOSCFG_BASE_CORE_SWTMR_LIMIT; }}else if (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE) {
            swtmr->ucState = OS_SWTMR_STATUS_CREATED;
        } else {
            swtmr->ucOverrun++;
            OsSwtmrStart(swtmr);
        }

        if (LOS_ListEmpty(listObject)) {
            break;
        }

        sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
    }

    LOS_SpinUnlock(&g_swtmrSpin);
}
Copy the code

Finally, the implementation of the scheduling algorithm

// Implementation of the scheduling algorithm
VOID OsSchedResched(VOID)
{
    LosTaskCB *runTask = NULL;
    LosTaskCB *newTask = NULL;
    LosProcessCB *runProcess = NULL;
    LosProcessCB *newProcess = NULL;
    LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));// The task spinlock must be held. The spinlock is not a process-level fight for the lock, but a fight between CPU cores

    if (!OsPreemptableInSched()) {// Whether the rescheduling flag bit is set
        return;
    }
    runTask = OsCurrTaskGet(a);// Get the current task
    newTask = OsGetTopTask(a);// Get the highest priority task
    /* always be able to get one task */
    LOS_ASSERT(newTask ! =NULL);// Can't have no tasks to schedule
    if (runTask == newTask) {// The current task is the highest task.
        return;
    }
    runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;// The current task status is not running
    newTask->taskStatus |= OS_TASK_STATUS_RUNNING;// The highest task status position is in the running state
    runProcess = OS_PCB_FROM_PID(runTask->processID);// Retrieve the process entity from the process ID index
    newProcess = OS_PCB_FROM_PID(newTask->processID);/ / same as above
    OsSchedSwitchProcess(runProcess, newProcess);// Switch the process, which mainly involves the process space switch, that is, MMU context switch.
#if (LOSCFG_KERNEL_SMP == YES)// Multiple CPU cores
    /* mask new running task's owner processor */
    runTask->currCpu = OS_TASK_INVALID_CPUID;// The current task consumes no CPU
    newTask->currCpu = ArchCurrCpuid(a);// Make the new task consume CPU
#endif
    (VOID)OsTaskSwitchCheck(runTask, newTask);// Switch the task check
#if (LOSCFG_KERNEL_SCHED_STATISTICS == YES)
    OsSchedStatistics(runTask, newTask);
#endif
    if ((newTask->timeSlice == 0) && (newTask->policy == LOS_SCHED_RR)) {// No time slice and preemptive scheduling. Note that non-preemptive scheduling does not require time slices.
        newTask->timeSlice = LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT;// Give the new task time slice default 20ms
    }
    OsCurrTaskSet((VOID*)newTask);// Set the new task to the current task of the CPU core
    if (OsProcessIsUserMode(newProcess)) {// What happens in user mode?
        OsCurrUserTaskSet(newTask->userArea);// Set the task stack space
    }
    /* do the task context switch */
    OsTaskSchedule(newTask, runTask);// Switch the task context, noting that OsTaskSchedule is an assembly function seen in los_dispatch.s
}
Copy the code

Intensive reading of the kernel source code

Four code stores synchronous annotation kernel source code, >> view the Gitee repository

Analysis of 100 blogs. Dig deep into the core

Add comments to hongmeng kernel source code process, sort out the following article. Content based on the source code, often in life scene analogy as much as possible into the kernel knowledge of a scene, with a pictorial sense, easy to understand memory. It’s important to speak in a way that others can understand! The 100 blogs are by no means a bunch of ridiculously difficult concepts being put forward by Baidu. That’s not interesting. More hope to make the kernel become lifelike, feel more intimate. It’s hard, it’s hard, but there’s no turning back. 😛 and code bugs need to be constantly debug, there will be many mistakes and omissions in the article and annotation content, please forgive, but will be repeatedly amended, continuous update. Xx represents the number of modifications, refined, concise and comprehensive, and strive to create high-quality content.

Compile build The fundamental tools Loading operation Process management
Compile environment

The build process

Environment script

Build tools

Designed.the gn application

Ninja ninja

Two-way linked list

Bitmap management

In the stack way

The timer

Atomic operation

Time management

The ELF format

The ELF parsing

Static link

relocation

Process image

Process management

Process concept

Fork

Special process

Process recycling

Signal production

Signal consumption

Shell editor

Shell parsing

Process of communication Memory management Ins and outs Task management
spinlocks

The mutex

Process of communication

A semaphore

Incident control

The message queue

Memory allocation

Memory management

Memory assembly

The memory mapping

Rules of memory

Physical memory

Total directory

Scheduling the story

Main memory slave

The source code comments

Source structure

Static site

The clock task

Task scheduling

Task management

The scheduling queue

Scheduling mechanism

Thread concept

Concurrent parallel

The system calls

Task switching

The file system Hardware architecture
File concept

The file system

The index node

Mount the directory

Root file system

Character device

VFS

File handle

Pipeline file

Compilation basis

Assembly and the cords

Working mode

register

Anomaly over

Assembly summary

Interrupt switch

Interrupt concept

Interrupt management

HongMeng station | into a little bit every day, the original is not easy, welcome to reprint, please indicate the source.