RM新时代网站-首页

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

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

3天內(nèi)不再提示

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

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

時鐘概念

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

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

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

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

時鐘節(jié)拍由配置為中斷觸發(fā)模式的硬件定時器產(chǎn)生,當(dāng)中斷到來時,將調(diào)用一次: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ā),當(dāng)然這是可以改的
#endif

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

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

它主要干了三件事情

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

#ifndef LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT
#define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 2 //2個時間片,20ms
#endif
//檢查進程和任務(wù)的時間片,如果沒有時間片了直接調(diào)度
LITE_OS_SEC_TEXT VOID OsTimesliceCheck(VOID)
{
    LosTaskCB *runTask = NULL;
    LosProcessCB *runProcess = OsCurrProcessGet();//獲取當(dāng)前進程
    if (runProcess->policy != LOS_SCHED_RR) {//進程調(diào)度算法是否是搶占式
        goto SCHED_TASK;//進程不是搶占式調(diào)度直接去檢查任務(wù)的時間片
    }

    if (runProcess->timeSlice != 0) {//進程還有時間片嗎?
        runProcess->timeSlice--;//進程時間片減少一次
        if (runProcess->timeSlice == 0) {//沒有時間片了
            LOS_Schedule();//進程時間片用完,發(fā)起調(diào)度
        }
    }

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

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

第二:掃描任務(wù),主要是檢查被阻塞的任務(wù)是否可以被重新調(diào)度

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;//獲取任務(wù)的排序鏈表
    taskSortLink->cursor = (taskSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK;
    listObject = taskSortLink->sortLink + taskSortLink->cursor;//只處理這個游標上的鏈表,因為系統(tǒng)對超時任務(wù)都已經(jīng)規(guī)鏈表了.
 //當(dāng)任務(wù)因超時而掛起時,任務(wù)塊處于超時排序鏈接上,(每個cpu)和ipc(互斥鎖、掃描電鏡等)的塊同時被喚醒
    /*不管是超時還是相應(yīng)的ipc,它都在等待?,F(xiàn)在使用synchronize sortlink precedure,因此整個任務(wù)掃描需要保護,防止另一個核心同時刪除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對應(yīng)鏈表的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);//拿任務(wù),這里的任務(wù)都是超時任務(wù)
        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) {//需要調(diào)度
        LOS_MpSchedule(OS_MP_CPU_ALL);//核間通訊,給所有CPU發(fā)送調(diào)度信號
        LOS_Schedule();//開始調(diào)度
    }
}

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

/*
 * Description: Tick interrupt interface module of software timer
 * Return     : LOS_OK on success or error code on failure
 *///OsSwtmrScan 由系統(tǒng)時鐘中斷處理函數(shù)調(diào)用
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;//拿到當(dāng)前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);
}

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

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

    if (!OsPreemptableInSched()) {//是否置了重新調(diào)度標識位
        return;
    }
    runTask = OsCurrTaskGet();//獲取當(dāng)前任務(wù)
    newTask = OsGetTopTask();//獲取優(yōu)先級最最最高的任務(wù)
    /* always be able to get one task */
    LOS_ASSERT(newTask != NULL);//不能沒有需調(diào)度的任務(wù)
    if (runTask == newTask) {//當(dāng)前任務(wù)就是最高任務(wù),那還調(diào)度個啥的,直接退出.
        return;
    }
    runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;//當(dāng)前任務(wù)狀態(tài)位置成不在運行狀態(tài)
    newTask->taskStatus |= OS_TASK_STATUS_RUNNING;//最高任務(wù)狀態(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;//當(dāng)前任務(wù)不占用CPU
    newTask->currCpu = ArchCurrCpuid();//讓新任務(wù)占用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)) {//沒有時間片且是搶占式調(diào)度的方式,注意 非搶占式都不需要時間片的.
        newTask->timeSlice = LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT;//給新任務(wù)時間片 默認 20ms
    }
    OsCurrTaskSet((VOID*)newTask);//設(shè)置新的task為CPU核的當(dāng)前任務(wù)
    if (OsProcessIsUserMode(newProcess)) {//用戶模式下會怎么樣?
        OsCurrUserTaskSet(newTask->userArea);//設(shè)置task??臻g
    }
    /* do the task context switch */
    OsTaskSchedule(newTask, runTask);//切換任務(wù)上下文,注意OsTaskSchedule是一個匯編函數(shù) 見于 los_dispatch.s
}

編輯:hfy

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

    關(guān)注

    37

    文章

    6801

    瀏覽量

    123282
  • 定時器
    +關(guān)注

    關(guān)注

    23

    文章

    3246

    瀏覽量

    114715
  • 系統(tǒng)時鐘
    +關(guān)注

    關(guān)注

    1

    文章

    30

    瀏覽量

    9306
  • 鴻蒙系統(tǒng)
    +關(guān)注

    關(guān)注

    183

    文章

    2634

    瀏覽量

    66302
收藏 人收藏

    評論

    相關(guān)推薦

    鴻蒙內(nèi)核源碼Task/線程技術(shù)分析

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

    【HarmonyOS】鴻蒙內(nèi)核源碼分析(調(diào)度機制篇)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    鴻蒙內(nèi)核源碼分析鴻蒙內(nèi)核的每段匯編代碼解析

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

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

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

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

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

    鴻蒙內(nèi)核源碼分析內(nèi)核最重要結(jié)構(gòu)體

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

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

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