Hongmeng kernel source code analysis (tick clock 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. All articles in this series enter to view the  source code analysis of Hongmeng system (general catalog)


table of Contents

How often do I tick?

Where to set the tick callback function?

OsTaskScan()

In addition to tick triggers scheduling, what other situations trigger scheduling?


The clock management module is very simple, but there is the kernel's most important code segment, OsTickHandler(). What is this, can be understood as a JAVA timing task, but this is a timer of the system kernel. Since Hongmeng is currently opening the lightweight kernel lite os (LOS), the frequency of tick will not be too high

See the code for details: los_tick.c      los_timeslice.c

How often do I tick?

/**
 * @ingroup los_config
 * Number of Ticks in one second
 */
#ifndef LOSCFG_BASE_CORE_TICK_PER_SECOND
#define LOSCFG_BASE_CORE_TICK_PER_SECOND 100 //*kfy 默认每秒100次触发,当然这是可以改的
#endif

100 tick per second, that is, the clock interrupt handler is called 100 times per second, and the unit of time slice is 10ms

How much time is allocated for the process to execute a task? The answer is 2 time slices, namely 20ms

/**
 * @ingroup los_config
 * Longest execution time of tasks with the same priorities
 */
#ifndef LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT
#define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 2
#endif

/**
 * @ingroup los_process
 * Hold the time slice process
 */
#define OS_PROCESS_SCHED_RR_INTERVAL     LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT

It can be redistributed when it is used up, but only 2 time slices are given at a time. Detailed code: OsSchedResched(VOID)

VOID OsSchedResched(VOID)
{
    LosTaskCB *runTask = NULL;
    LosTaskCB *newTask = NULL;
    LosProcessCB *runProcess = NULL;
    LosProcessCB *newProcess = NULL;

    LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));

    if (!OsPreemptableInSched()) {
        return;
    }

    runTask = OsCurrTaskGet();
    newTask = OsGetTopTask();

    /* always be able to get one task */
    LOS_ASSERT(newTask != NULL);

    if (runTask == newTask) {
        return;
    }

    runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;
    newTask->taskStatus |= OS_TASK_STATUS_RUNNING;

    runProcess = OS_PCB_FROM_PID(runTask->processID);
    newProcess = OS_PCB_FROM_PID(newTask->processID);

    OsSchedSwitchProcess(runProcess, newProcess);

#if (LOSCFG_KERNEL_SMP == YES)
    /* mask new running task's owner processor */
    runTask->currCpu = OS_TASK_INVALID_CPUID;
    newTask->currCpu = ArchCurrCpuid();
#endif

    (VOID)OsTaskSwitchCheck(runTask, newTask);

#if (LOSCFG_KERNEL_SCHED_STATISTICS == YES)
    OsSchedStatistics(runTask, newTask);
#endif

    if ((newTask->timeSlice == 0) && (newTask->policy == LOS_SCHED_RR)) {
        newTask->timeSlice = LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT; //只给两个时间片
    }

    OsCurrTaskSet((VOID*)newTask);

    if (OsProcessIsUserMode(newProcess)) {
        OsCurrUserTaskSet(newTask->userArea);
    }

    PRINT_TRACE("cpu%d run process name: (%s) pid: %d status: %x threadMap: %x task name: (%s) tid: %d status: %x ->\n"
                "     new process name: (%s) pid: %d status: %x threadMap: %x task name: (%s) tid: %d status: %x!\n",
                ArchCurrCpuid(),
                runProcess->processName, runProcess->processID, runProcess->processStatus,
                runProcess->threadScheduleMap, runTask->taskName,  runTask->taskID, runTask->taskStatus,
                newProcess->processName, newProcess->processID, newProcess->processStatus,
                newProcess->threadScheduleMap, newTask->taskName, newTask->taskID, newTask->taskStatus);

    /* do the task context switch */
    OsTaskSchedule(newTask, runTask);
}

Where to set the tick callback function?

You can see the initialization of tick and the registration of the interrupt service program from main

// 中断处理函数
VOID OsTickEntry(VOID)
{
    OsTickHandler(); //最最关键函数

    /* clear private timer */
    g_privateTimer->intStatus = 0x01;
}


// 由 main 函数调用,注册中断处理函数 OsTickEntry
VOID HalClockInit(VOID)
{
    UINT32 ret;

    ret =  LOS_HwiCreate(PRVTIMER_INT_NUM, 0xa0, 0, OsTickEntry, NULL);
    if (ret != LOS_OK) {
        PRINT_ERR("%s, %d create tick irq failed, ret:0x%x\n", __FUNCTION__, __LINE__, ret);
    }
}

OsTickHandler is a tick interrupt handler, which completes the time slice check and task scan.

/*
 * Description : Tick interruption handler
 */
LITE_OS_SEC_TEXT VOID OsTickHandler(VOID)
{
    UINT32 intSave;

    TICK_LOCK(intSave);
    g_tickCount[ArchCurrCpuid()]++;
    TICK_UNLOCK(intSave);

#ifdef LOSCFG_KERNEL_VDSO
    OsUpdateVdsoTimeval();
#endif

#ifdef LOSCFG_KERNEL_TICKLESS
    OsTickIrqFlagSet(OsTicklessFlagGet());
#endif

#if (LOSCFG_BASE_CORE_TICK_HW_TIME == YES)
    HalClockIrqClear(); /* diff from every platform */
#endif

    OsTimesliceCheck();

    OsTaskScan(); /* task timeout scan */

#if (LOSCFG_BASE_CORE_SWTMR == YES)
    OsSwtmrScan();
#endif
}
LITE_OS_SEC_TEXT VOID OsTimesliceCheck(VOID)
{
    LosTaskCB *runTask = NULL;
    LosProcessCB *runProcess = OsCurrProcessGet();
    if (runProcess->policy != LOS_SCHED_RR) {
        goto SCHED_TASK;
    }

    if (runProcess->timeSlice != 0) {
        runProcess->timeSlice--;//进程时间片减少一次
        if (runProcess->timeSlice == 0) {
            LOS_Schedule();//进程时间片用完,发起调度
        }
    }

SCHED_TASK:
    runTask = OsCurrTaskGet();
    if (runTask->policy != LOS_SCHED_RR) {
        return;
    }

    if (runTask->timeSlice != 0) {
        runTask->timeSlice--;//对应任务时间片也减少一次
        if (runTask->timeSlice == 0) {
            LOS_Schedule();
        }
    }
}

OsTaskScan()

OsTaskScan() constantly checks the status of the task, and executes it when there is a task. It is no exaggeration to say that it is the source of the orderly execution of the process!

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;
    taskSortLink->cursor = (taskSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK;
    listObject = taskSortLink->sortLink + taskSortLink->cursor;

    /*
     * 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);
    ROLLNUM_DEC(sortList->idxRollNum);

    while (ROLLNUM(sortList->idxRollNum) == 0) {
        LOS_ListDelete(&sortList->sortLinkNode);
        taskCB = LOS_DL_LIST_ENTRY(sortList, LosTaskCB, sortList);
        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) {
        LOS_MpSchedule(OS_MP_CPU_ALL);
        LOS_Schedule();
    }
}

In addition to tick triggers scheduling, what other situations trigger scheduling?

If you think about it, please leave a message in the comment area. More articles in this series will enter  Hongmeng system source code analysis (general catalog)  .

Guess you like

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