0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

鴻蒙內核源碼分析之時鐘節(jié)拍的實現(xiàn)方式

鴻蒙系統(tǒng)HarmonyOS ? 來源:my.oschina ? 作者: 鴻蒙內核源碼分析 ? 2021-04-25 15:13 ? 次閱讀

時鐘概念

時間是非常重要的概念,我們整個學生階段有個東西很重要,就是校園鈴聲. 它控制著上課,下課,吃飯,睡覺的節(jié)奏.沒有它學校的管理就亂套了,老師拖課想拖多久就多久,那可不行,下課鈴聲一響就是在告訴老師時間到了,該停止了讓學生HAPPY去了.

操作系統(tǒng)也一樣,需要通過時間來規(guī)范其任務的執(zhí)行,操作系統(tǒng)中最小的時間單位是時鐘節(jié)拍 (OS Tick)。任何操作系統(tǒng)都需要提供一個時鐘節(jié)拍,以供系統(tǒng)處理所有和時間有關的事件,如線程的延時、線程的時間片輪轉調度以及定時器超時等。時鐘節(jié)拍是特定的周期性中斷,這個中斷可以看做是系統(tǒng)心跳,中斷之間的時間間隔取決于不同的應用,一般是 1ms–100ms,時鐘節(jié)拍率越快,系統(tǒng)的實時響應越快,但是系統(tǒng)的額外開銷就越大,從系統(tǒng)啟動開始計數(shù)的時鐘節(jié)拍數(shù)稱為系統(tǒng)時間。

鴻蒙內核中,時鐘節(jié)拍的長度可以根據(jù) LOSCFG_BASE_CORE_TICK_PER_SECOND 的定義來調整,等于 1/LOSCFG_BASE_CORE_TICK_PER_SECOND 秒。

時鐘節(jié)拍的實現(xiàn)方式

時鐘節(jié)拍由配置為中斷觸發(fā)模式的硬件定時器產(chǎn)生,當中斷到來時,將調用一次:void OsTickHandler(void),通知操作系統(tǒng)已經(jīng)過去一個系統(tǒng)時鐘;不同硬件定時器中斷實現(xiàn)都不同,

/**
 * @ingroup los_config
 * Number of Ticks in one second
 */
#ifndef LOSCFG_BASE_CORE_TICK_PER_SECOND
#define LOSCFG_BASE_CORE_TICK_PER_SECOND 100 //默認每秒100次觸發(fā),當然這是可以改的
#endif

每秒100個tick,時間單位為10毫秒, 即每秒調用時鐘中斷處理程序100次.

/*
 * Description : Tick interruption handler
 *///節(jié)拍中斷處理函數(shù) ,鴻蒙默認10ms觸發(fā)一次
LITE_OS_SEC_TEXT VOID OsTickHandler(VOID)
{
    //...
    OsTimesliceCheck();//進程和任務的時間片檢查
    OsTaskScan(); /* task timeout scan *///任務掃描
#if (LOSCFG_BASE_CORE_SWTMR == YES)
    OsSwtmrScan();//定時器掃描,看是否有超時的定時器
#endif
}

它主要干了三件事情

第一:檢查當前任務的時間片,任務執(zhí)行一次分配多少時間呢?答案是2個時間片,即 20ms.

#ifndef LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT
#define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 2 //2個時間片,20ms
#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();//進程時間片用完,發(fā)起調度
        }
    }

SCHED_TASK:
    runTask = OsCurrTaskGet();//獲取當前任務
    if (runTask->policy != LOS_SCHED_RR) {//任務調度算法是否是搶占式
        return;//任務不是搶占式調度直接結束檢查
    }

    if (runTask->timeSlice != 0) {//任務還有時間片嗎?
        runTask->timeSlice--;//任務時間片也減少一次
        if (runTask->timeSlice == 0) {//沒有時間片了
            LOS_Schedule();//任務時間片用完,發(fā)起調度
        }
    }
}

第二:掃描任務,主要是檢查被阻塞的任務是否可以被重新調度

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;//只處理這個游標上的鏈表,因為系統(tǒng)對超時任務都已經(jīng)規(guī)鏈表了.
 //當任務因超時而掛起時,任務塊處于超時排序鏈接上,(每個cpu)和ipc(互斥鎖、掃描電鏡等)的塊同時被喚醒
    /*不管是超時還是相應的ipc,它都在等待?,F(xiàn)在使用synchronize sortlink precedure,因此整個任務掃描需要保護,防止另一個核心同時刪除sortlink。
     * 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對應鏈表的SortLinkList的第一個節(jié)點sortLinkNode
    ROLLNUM_DEC(sortList->idxRollNum);//滾動數(shù)--

    while (ROLLNUM(sortList->idxRollNum) == 0) {//找到時間到了節(jié)點,注意這些節(jié)點都是由定時器產(chǎn)生的,
        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);//核間通訊,給所有CPU發(fā)送調度信號
        LOS_Schedule();//開始調度
    }
}

第三:定時器掃描,看是否有超時的定時器

/*
 * Description: Tick interrupt interface module of software timer
 * Return     : LOS_OK on success or error code on failure
 *///OsSwtmrScan 由系統(tǒng)時鐘中斷處理函數(shù)調用
LITE_OS_SEC_TEXT VOID OsSwtmrScan(VOID)//掃描定時器,如果碰到超時的,就放入超時隊列
{
    SortLinkList *sortList = NULL;
    SWTMR_CTRL_S *swtmr = NULL;
    SwtmrHandlerItemPtr swtmrHandler = NULL;
    LOS_DL_LIST *listObject = NULL;
    SortLinkAttribute* swtmrSortLink = &OsPercpuGet()->swtmrSortLink;//拿到當前CPU的定時器鏈表

    swtmrSortLink->cursor = (swtmrSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK;
    listObject = swtmrSortLink->sortLink + swtmrSortLink->cursor;
 //由于swtmr是在特定的sortlink中,所以需要很小心的處理它,但其他CPU Core仍然有機會處理它,比如停止計時器
    /*
     * 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);//取出一個可用的軟時鐘處理項
        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);
}

最后看調度算法的實現(xiàn)

//調度算法的實現(xiàn)
VOID OsSchedResched(VOID)
{
    LosTaskCB *runTask = NULL;
    LosTaskCB *newTask = NULL;
    LosProcessCB *runProcess = NULL;
    LosProcessCB *newProcess = NULL;
    LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));//必須持有任務自旋鎖,自旋鎖是不是進程層面去搶鎖,而是CPU各自核之間去爭奪鎖

    if (!OsPreemptableInSched()) {//是否置了重新調度標識位
        return;
    }
    runTask = OsCurrTaskGet();//獲取當前任務
    newTask = OsGetTopTask();//獲取優(yōu)先級最最最高的任務
    /* always be able to get one task */
    LOS_ASSERT(newTask != NULL);//不能沒有需調度的任務
    if (runTask == newTask) {//當前任務就是最高任務,那還調度個啥的,直接退出.
        return;
    }
    runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;//當前任務狀態(tài)位置成不在運行狀態(tài)
    newTask->taskStatus |= OS_TASK_STATUS_RUNNING;//最高任務狀態(tài)位置成在運行狀態(tài)
    runProcess = OS_PCB_FROM_PID(runTask->processID);//通過進程ID索引拿到進程實體
    newProcess = OS_PCB_FROM_PID(newTask->processID);//同上
    OsSchedSwitchProcess(runProcess, newProcess);//切換進程,里面主要涉及進程空間的切換,也就是MMU的上下文切換.
#if (LOSCFG_KERNEL_SMP == YES)//CPU多核的情況
    /* mask new running task's owner processor */
    runTask->currCpu = OS_TASK_INVALID_CPUID;//當前任務不占用CPU
    newTask->currCpu = ArchCurrCpuid();//讓新任務占用CPU
#endif
    (VOID)OsTaskSwitchCheck(runTask, newTask);//切換task的檢查
#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;//給新任務時間片 默認 20ms
    }
    OsCurrTaskSet((VOID*)newTask);//設置新的task為CPU核的當前任務
    if (OsProcessIsUserMode(newProcess)) {//用戶模式下會怎么樣?
        OsCurrUserTaskSet(newTask->userArea);//設置task??臻g
    }
    /* do the task context switch */
    OsTaskSchedule(newTask, runTask);//切換任務上下文,注意OsTaskSchedule是一個匯編函數(shù) 見于 los_dispatch.s
}

編輯:hfy

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
收藏 人收藏

    評論

    相關推薦

    鴻蒙內核源碼Task/線程技術分析

    、使用內存空間等系統(tǒng)資源,并獨立于其它線程運行。 鴻蒙內核每個進程內的線程獨立運行、獨立調度,當前進程內線程的調度不受其它進程內線程的影響。 鴻蒙內核中的線程采用搶占式調度機制,同時支
    的頭像 發(fā)表于 10-18 10:42 ?2102次閱讀
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內核</b><b class='flag-5'>源碼</b>Task/線程技術<b class='flag-5'>分析</b>

    【HarmonyOS】鴻蒙內核源碼分析(調度機制篇)

    意義上所理解的線程呢。狹義上的后續(xù)有 鴻蒙內核源碼分析(啟動過程篇) 來說明。不知道大家有沒有這種體會,學一個東西的過程中要接觸很多新概念,尤其像 Java/android 的生態(tài),概
    發(fā)表于 10-14 14:00

    鴻蒙內核源碼分析:用通俗易懂的語言告訴你鴻蒙內核發(fā)生了什么?

    查看。內存在內核的比重極大內存模塊占了鴻蒙內核約15%代碼量, 近50個文件,非常復雜。鴻蒙源碼分析
    發(fā)表于 11-19 10:14

    鴻蒙內核源碼分析源碼注釋篇):給HarmonyOS源碼逐行加上中文注釋

    設計的系統(tǒng),高瞻遠矚,格局遠大,設計精良, 知識點巨多, 把研究過程心得寫成鴻蒙源碼分析系列篇,如此 源碼中文注釋+系列篇文章 將加速理解鴻蒙
    發(fā)表于 11-19 10:32

    鴻蒙內核源碼分析:給HarmonyOS源碼逐行加上中文注釋

    ,如此 源碼中文注釋+系列篇文章 將加速理解鴻蒙內核實現(xiàn)過程。系列篇文章 進入 >> 鴻蒙系統(tǒng)源碼分析
    發(fā)表于 11-19 15:06

    鴻蒙源碼分析系列(總目錄) | 給HarmonyOS源碼逐行加上中文注釋

    注解|-鴻蒙內核源碼分析(內存映射篇) | 虛擬內存和物理內存之間是怎么映射的|-鴻蒙內核
    發(fā)表于 11-20 11:24

    鴻蒙內核源碼分析(必讀篇):用故事說內核

    本文基于開源鴻蒙內核分析,官方源碼【kernel_liteos_a】官方文檔【docs】參考文檔【Huawei LiteOS】本文作者:鴻蒙
    發(fā)表于 11-23 10:15

    鴻蒙內核源碼分析(調度機制篇):Task是如何被調度執(zhí)行的

    本文分析任務調度機制源碼 詳見:代碼庫建議先閱讀閱讀之前建議先讀本系列其他文章,進入鴻蒙系統(tǒng)源碼分析(總目錄),以便對本文任務調度機制的理解
    發(fā)表于 11-23 10:53

    HarmonyOS內核源碼分析(上)電子書-上線了

    `為方便大家開發(fā)鴻蒙系統(tǒng),小編為大家編輯整理了一本HarmonyOS內核源碼分析系列電子書,需要參考學習的朋友快來下吧!本電子書主要介紹如何給鴻蒙
    發(fā)表于 11-25 17:13

    鴻蒙內核源碼分析(百篇博客分析.挖透鴻蒙內核)

    致敬內核開發(fā)者感謝開放原子開源基金會,致敬鴻蒙內核開發(fā)者??梢院敛豢鋸埖恼f鴻蒙內核源碼可作為大學
    發(fā)表于 07-04 17:16

    鴻蒙內核源碼分析鴻蒙內核的每段匯編代碼解析

    本篇說清楚CPU的工作模式 讀本篇之前建議先讀鴻蒙內核源碼分析(總目錄)其他篇. 正如一個互聯(lián)網(wǎng)項目的后臺管理系統(tǒng)有權限管理一樣,CPU工作是否也有權限(模式)? 一個成熟的軟硬件架構
    的頭像 發(fā)表于 03-02 09:56 ?4104次閱讀
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b>:<b class='flag-5'>鴻蒙</b><b class='flag-5'>內核</b>的每段匯編代碼解析

    鴻蒙內核源碼分析: 虛擬內存和物理內存是怎么管理的

    有了上篇鴻蒙內核源碼分析(內存概念篇)的基礎,本篇講內存管理部分,本章源碼超級多,很燒腦,但筆者關鍵處都加了注釋。廢話不多說,開始吧。內存一
    發(fā)表于 11-23 11:45 ?19次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b>: 虛擬內存和物理內存是怎么管理的

    鴻蒙內核源碼分析時鐘是觸發(fā)調度最大的源動力

    時鐘管理模塊很簡單,但卻有內核最重要的代碼段 OsTickHandler(),這是干嘛的,可以理解為 JAVA的定時任務,但這是系統(tǒng)內核的定時器。因鴻蒙目前開放的是 輕量級的
    發(fā)表于 11-24 17:50 ?32次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b>:<b class='flag-5'>時鐘</b>是觸發(fā)調度最大的源動力

    鴻蒙內核源碼分析內核最重要結構體

    為何鴻蒙內核源碼分析系列開篇就說 LOS_DL_LIST ? 因為它在鴻蒙 LOS 內核中無處
    發(fā)表于 11-24 17:54 ?35次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b> :<b class='flag-5'>內核</b>最重要結構體

    華為鴻蒙系統(tǒng)內核源碼分析上冊

    鴻蒙內核源碼注釋中文版【 Gitee倉】給 Harmoηy○S源碼逐行加上中文注解,詳細闡述設計細節(jié),助你快速精讀 Harmonyos內核源碼
    發(fā)表于 04-09 14:40 ?17次下載