chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

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

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

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

鴻蒙內(nèi)核源碼:誰來觸發(fā)調(diào)度工作?

鴻蒙系統(tǒng)HarmonyOS ? 來源:my.oschina ? 作者:鴻蒙內(nèi)核源碼分析 ? 2021-04-24 10:50 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

為什么學(xué)個東西要學(xué)那么多的概念?

鴻蒙的內(nèi)核中 Task和 線程在廣義上可以理解為是一個東西,但狹義上肯定會有區(qū)別,區(qū)別在于管理體系的不同,Task是調(diào)度層面的概念,線程是進程層面概念。比如 main()函數(shù)中首個函數(shù) OsSetMainTask();就是設(shè)置啟動任務(wù),但此時啥都還沒開始呢,Kprocess進程都沒創(chuàng)建,怎么會有大家一般意義上所理解的線程呢。狹義上的后續(xù)有鴻蒙內(nèi)核源碼分析(啟動過程篇)來說明。不知道大家有沒有這種體會,學(xué)一個東西的過程中要接觸很多新概念,尤其像 Java/android 的生態(tài),概念賊多,很多同學(xué)都被繞在概念中出不來,痛苦不堪。那問題是為什么需要這么多的概念呢?

舉個例子就明白了:

假如您去深圳參加一個面試老板問你哪里人?你會說是江西人,湖南人...而不會說是張家村二組的張全蛋,這樣還誰敢要你。但如果你參加同鄉(xiāng)會別人問你同樣問題,你不會說是來自東北那旮沓的,卻反而要說張家村二組的張全蛋。明白了嗎?張全蛋還是那個張全蛋,但因為場景變了,您的說法就得必須跟著變,否則沒法愉快的聊天。程序設(shè)計就是源于生活,歸于生活,大家對程序的理解就是要用生活中的場景去打比方,更好的理解概念。

那在內(nèi)核的調(diào)度層面,咱們只說task,task是內(nèi)核調(diào)度的單元,調(diào)度就是圍著它轉(zhuǎn)。

進程和線程的狀態(tài)遷移圖

先看看task從哪些渠道產(chǎn)生:

pIYBAGCDhyqAWWxqAAC5d6zzcxM391.png

渠道很多,可能是shell的一個命令,也可能由內(nèi)核創(chuàng)建,更多的是大家編寫應(yīng)用程序new出來的一個線程。

調(diào)度的內(nèi)容task已經(jīng)有了,那他們是如何被有序調(diào)度的呢?答案:是32個進程和線程就緒隊列,各32個哈,為什么是32個,鴻蒙系統(tǒng)源碼分析(總目錄) 文章里有詳細說明,自行去翻。這張進程狀態(tài)遷移示意圖一定要看明白.

注意:進程和線程的隊列內(nèi)的內(nèi)容只針對就緒狀態(tài),其他狀態(tài)內(nèi)核并沒有用隊列去描述它,(線程的阻塞狀態(tài)用的是pendlist鏈表),因為就緒就意味著工作都準備好了就等著被調(diào)度到CPU來執(zhí)行了。所以理解就緒隊列很關(guān)鍵,有三種情況會加入就緒隊列。

pIYBAGCDh0GAJo5tAAAmNpJIbNI565.png

Init→Ready:

進程創(chuàng)建或fork時,拿到該進程控制塊后進入Init狀態(tài),處于進程初始化階段,當(dāng)進程初始化完成將進程插入調(diào)度隊列,此時進程進入就緒狀態(tài)。

Pend→Ready / Pend→Running:

阻塞進程內(nèi)的任意線程恢復(fù)就緒態(tài)時,進程被加入到就緒隊列,同步轉(zhuǎn)為就緒態(tài),若此時發(fā)生進程切換,則進程狀態(tài)由就緒態(tài)轉(zhuǎn)為運行態(tài)。

Running→Ready:

進程由運行態(tài)轉(zhuǎn)為就緒態(tài)的情況有以下兩種:

有更高優(yōu)先級的進程創(chuàng)建或者恢復(fù)后,會發(fā)生進程調(diào)度,此刻就緒列表中最高優(yōu)先級進程變?yōu)檫\行態(tài),那么原先運行的進程由運行態(tài)變?yōu)榫途w態(tài)。

若進程的調(diào)度策略為SCHED_RR,且存在同一優(yōu)先級的另一個進程處于就緒態(tài),則該進程的時間片消耗光之后,該進程由運行態(tài)轉(zhuǎn)為就緒態(tài),另一個同優(yōu)先級的進程由就緒態(tài)轉(zhuǎn)為運行態(tài)。

誰來觸發(fā)調(diào)度工作?

就緒隊列讓task各就各位,在其生命周期內(nèi)不停的進行狀態(tài)流轉(zhuǎn),調(diào)度是讓task交給CPU處理,那又是什么讓調(diào)度去工作的呢?它是如何被觸發(fā)的?

筆者能想到的觸發(fā)方式是以下四個:

Tick(時鐘管理),類似于JAVA的定時任務(wù),時間到了就觸發(fā)。系統(tǒng)定時器是內(nèi)核時間機制中最重要的一部分,它提供了一種周期性觸發(fā)中斷機制,即系統(tǒng)定時器以HZ(時鐘節(jié)拍率)為頻率自行觸發(fā)時鐘中斷。當(dāng)時鐘中斷發(fā)生時,內(nèi)核就通過時鐘中斷處理程序OsTickHandler對其進行處理。鴻蒙內(nèi)核默認是10ms觸發(fā)一次,執(zhí)行以下中斷函數(shù):

/*
 * 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 *///任務(wù)掃描,發(fā)起調(diào)度

#if (LOSCFG_BASE_CORE_SWTMR == YES)
    OsSwtmrScan();//軟時鐘掃描檢查
#endif
}

里面對任務(wù)進行了掃描,時間片到了或就緒隊列有高或同級task,會執(zhí)行調(diào)度。

第二個是各種軟硬中斷,如何USB插拔,鍵盤,鼠標這些外設(shè)引起的中斷,需要去執(zhí)行中斷處理函數(shù)。

第三個是程序主動中斷,比如運行過程中需要申請其他資源,而主動讓出控制權(quán),重新調(diào)度。

最后一個是創(chuàng)建一個新進程或新任務(wù)后主動發(fā)起的搶占式調(diào)度,新進程會默認創(chuàng)建一個main task, task的首條指令(入口函數(shù))就是我們上層程序的main函數(shù),它被放在代碼段的第一的位置。

哪些地方會申請調(diào)度?看一張圖。

o4YBAGCDh06ABuMFAADGKhz-zEg614.png

這里提下圖中的OsCopyProcess(),這是fork進程的主體函數(shù),可以看出fork之后立即申請了一次調(diào)度。

LITE_OS_SEC_TEXT INT32 LOS_Fork(UINT32 flags, const CHAR *name, const TSK_ENTRY_FUNC entry, UINT32 stackSize)
{
    UINT32 cloneFlag = CLONE_PARENT | CLONE_THREAD | CLONE_VFORK | CLONE_FILES;

    if (flags & (~cloneFlag)) {
        PRINT_WARN("Clone dont support some flags!\n");
    }

    flags |= CLONE_FILES;
    return OsCopyProcess(cloneFlag & flags, name, (UINTPTR)entry, stackSize);
}

STATIC INT32 OsCopyProcess(UINT32 flags, const CHAR *name, UINTPTR sp, UINT32 size)
{
    UINT32 intSave, ret, processID;
    LosProcessCB *run = OsCurrProcessGet();

    LosProcessCB *child = OsGetFreePCB();
    if (child == NULL) {
        return -LOS_EAGAIN;
    }
    processID = child->processID;

    ret = OsForkInitPCB(flags, child, name, sp, size);
    if (ret != LOS_OK) {
        goto ERROR_INIT;
    }

    ret = OsCopyProcessResources(flags, child, run);
    if (ret != LOS_OK) {
        goto ERROR_TASK;
    }

    ret = OsChildSetProcessGroupAndSched(child, run);
    if (ret != LOS_OK) {
        goto ERROR_TASK;
    }

    LOS_MpSchedule(OS_MP_CPU_ALL);
    if (OS_SCHEDULER_ACTIVE) {
        LOS_Schedule();// 申請調(diào)度
    }

    return processID;

ERROR_TASK:
    SCHEDULER_LOCK(intSave);
    (VOID)OsTaskDeleteUnsafe(OS_TCB_FROM_TID(child->threadGroupID), OS_PRO_EXIT_OK, intSave);
ERROR_INIT:
    OsDeInitPCB(child);
    return -ret;
}

原來創(chuàng)建一個進程這么簡單,真的就是在COPY!

源碼告訴你調(diào)度過程是怎樣的

以上是需要提前了解的信息,接下來直接上源碼看調(diào)度過程吧,文件就三個函數(shù),主要就是這個了:

VOID OsSchedResched(VOID)
{
    LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));//調(diào)度過程要上鎖
    newTask = OsGetTopTask(); //獲取最高優(yōu)先級任務(wù)
    OsSchedSwitchProcess(runProcess, newProcess);//切換進程
    (VOID)OsTaskSwitchCheck(runTask, newTask);//任務(wù)檢查
    OsCurrTaskSet((VOID*)newTask);//*設(shè)置當(dāng)前任務(wù)
    if (OsProcessIsUserMode(newProcess)) {//判斷是否為用戶態(tài),使用用戶空間
        OsCurrUserTaskSet(newTask->userArea);//設(shè)置任務(wù)空間
    }
    /* do the task context switch */
    OsTaskSchedule(newTask, runTask); //切換CPU任務(wù)上下文,匯編代碼實現(xiàn)
}

函數(shù)有點長,筆者留了最重要的幾行,看這幾行就夠了,流程如下:

調(diào)度過程要自旋鎖,多核情況下只能被一個CPU core執(zhí)行. 不允許任何中斷發(fā)生, 沒錯,說的是任何事是不能去打斷它,否則后果太嚴重了,這可是內(nèi)核在切換進程和線程的操作啊。

在就緒隊列里找個最高優(yōu)先級的task

切換進程,就是task歸屬的那個進程設(shè)為運行進程,這里要注意,老的task和老進程只是讓出了CPU指令執(zhí)行權(quán),其他都還在內(nèi)存,資源也都沒有釋放.

設(shè)置新任務(wù)為當(dāng)前任務(wù)

用戶模式下需要設(shè)置task運行空間,因為每個task棧是不一樣的.空間部分具體在系列篇內(nèi)存中查看

是最重要的,切換任務(wù)上下文,參數(shù)是新老兩個任務(wù),一個要保存現(xiàn)場,一個要恢復(fù)現(xiàn)場。

什么是任務(wù)上下文?鴻蒙內(nèi)核源碼分析(總目錄)任務(wù)切換篇已有詳細的描述,請自行翻看.

讀懂OsGetTopTask()

讀懂OsGetTopTask(),就明白了就緒隊列是怎么回事了。這里提下goto語句,幾乎所有內(nèi)核代碼都會大量的使用goto語句,鴻蒙內(nèi)核有617個goto遠大于264個break,還有人說要廢掉goto,你知道內(nèi)核開發(fā)者青睞goto的真正原因嗎?

LITE_OS_SEC_TEXT_MINOR LosTaskCB *OsGetTopTask(VOID)
{
    UINT32 priority, processPriority;
    UINT32 bitmap;
    UINT32 processBitmap;
    LosTaskCB *newTask = NULL;
#if (LOSCFG_KERNEL_SMP == YES)
    UINT32 cpuid = ArchCurrCpuid();
#endif
    LosProcessCB *processCB = NULL;
    processBitmap = g_priQueueBitmap;
    while (processBitmap) {
        processPriority = CLZ(processBitmap);
        LOS_DL_LIST_FOR_EACH_ENTRY(processCB, &g_priQueueList[processPriority], LosProcessCB, pendList) {
            bitmap = processCB->threadScheduleMap;
            while (bitmap) {
                priority = CLZ(bitmap);
                LOS_DL_LIST_FOR_EACH_ENTRY(newTask, &processCB->threadPriQueueList[priority], LosTaskCB, pendList) {
#if (LOSCFG_KERNEL_SMP == YES)
                    if (newTask->cpuAffiMask & (1U << cpuid)) {
#endif
                        newTask->taskStatus &= ~OS_TASK_STATUS_READY;
                        OsPriQueueDequeue(processCB->threadPriQueueList,
                                          &processCB->threadScheduleMap,
                                          &newTask->pendList);
                        OsDequeEmptySchedMap(processCB);
                        goto OUT;
#if (LOSCFG_KERNEL_SMP == YES)
                    }
#endif
                }
                bitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - priority - 1));
            }
        }
        processBitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - processPriority - 1));
    }

OUT:
    return newTask;
}

#ifdef __cplusplus
#if __cplusplus
}

編輯:hfy

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

    關(guān)注

    68

    文章

    11187

    瀏覽量

    221320
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    508

    瀏覽量

    20656
  • 進程
    +關(guān)注

    關(guān)注

    0

    文章

    208

    瀏覽量

    14451
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

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

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

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

    詳見:../kernel/base/sched/sched_sq/los_sched.c目錄建議先閱讀為什么學(xué)一個東西要學(xué)那么多的概念?進程和線程的狀態(tài)遷移圖誰來觸發(fā)調(diào)度工作?
    發(fā)表于 10-14 14:00

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

    內(nèi)核源碼分析(時鐘管理篇) | 觸發(fā)調(diào)度最大的源動力|-鴻蒙內(nèi)核
    發(fā)表于 11-20 11:24

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

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

    鴻蒙內(nèi)核源碼分析(調(diào)度隊列篇):進程和Task的就緒隊列對調(diào)度的作用

    的數(shù)據(jù)結(jié)構(gòu)實現(xiàn)采用的都是雙向循環(huán)鏈表,LOS_DL_LIST實在是太重要了,是理解鴻蒙內(nèi)核的關(guān)鍵,說是最重要的代碼一點也不為過,源碼出現(xiàn)在 sched_sq模塊,說明是用于任務(wù)的調(diào)度
    發(fā)表于 11-23 11:09

    鴻蒙內(nèi)核源碼分析(Task管理篇):task是內(nèi)核調(diào)度的單元

    獨立運行、獨立調(diào)度,當(dāng)前進程內(nèi)線程的調(diào)度不受其它進程內(nèi)線程的影響。鴻蒙內(nèi)核中的線程采用搶占式調(diào)度機制,同時支持時間片輪轉(zhuǎn)
    發(fā)表于 11-23 14:01

    鴻蒙內(nèi)核源碼分析(Task管理篇):task是內(nèi)核調(diào)度的單元

    等待CPU、使用內(nèi)存空間等系統(tǒng)資源,并獨立于其它線程運行。鴻蒙內(nèi)核每個進程內(nèi)的線程獨立運行、獨立調(diào)度,當(dāng)前進程內(nèi)線程的調(diào)度不受其它進程內(nèi)線程的影響。
    發(fā)表于 11-24 10:24

    鴻蒙內(nèi)核源碼分析(調(diào)度故事篇)

    不在這里說明,后續(xù)也有專門講這塊的故事.故事想說什么呢?故事到底想說什么呢?這就是操作系統(tǒng)的調(diào)度機制,熟悉了這個故事就熟悉了鴻蒙系統(tǒng)內(nèi)核任務(wù)調(diào)度
    發(fā)表于 05-25 11:50

    淺談鴻蒙內(nèi)核代碼調(diào)度隊列

    鴻蒙內(nèi)核代碼中有兩個源文件是關(guān)于隊列的,一個是用于調(diào)度的隊列,另一個是用于線程間通訊的IPC隊列。
    的頭像 發(fā)表于 10-23 11:00 ?2482次閱讀

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

    本篇說清楚CPU的工作模式 讀本篇之前建議先讀鴻蒙內(nèi)核源碼分析(總目錄)其他篇. 正如一個互聯(lián)網(wǎng)項目的后臺管理系統(tǒng)有權(quán)限管理一樣,CPU工作
    的頭像 發(fā)表于 03-02 09:56 ?4960次閱讀
    <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>的每段匯編代碼解析

    鴻蒙內(nèi)核源碼分析:task是內(nèi)核調(diào)度的單元

    從系統(tǒng)的角度看,線程是競爭系統(tǒng)資源的最小運行單元。線程可以使用或等待CPU、使用內(nèi)存空間等系統(tǒng)資源,并獨立于其它線程運行。 鴻蒙內(nèi)核每個進程內(nèi)的線程獨立運行、獨立調(diào)度,當(dāng)前進程內(nèi)線程的調(diào)度
    發(fā)表于 11-23 15:51 ?22次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b>分析:task是<b class='flag-5'>內(nèi)核</b><b class='flag-5'>調(diào)度</b>的單元

    鴻蒙內(nèi)核源碼分析:進程和Task的就緒隊列對調(diào)度的作用

    鴻蒙內(nèi)核代碼中有兩個源文件是關(guān)于隊列的,一個是用于調(diào)度的隊列,另一個是用于線程間通訊的IPC隊列。 鴻蒙內(nèi)核進程和線程各有32個就緒隊列,進
    發(fā)表于 11-23 15:48 ?31次下載
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>源碼</b>分析:進程和Task的就緒隊列對<b class='flag-5'>調(diào)度</b>的作用

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

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

    鴻蒙內(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'>內(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次下載