吴忠躺衫网络科技有限公司

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

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

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

Linux內(nèi)核睡眠的三種狀態(tài)講解

B4Pb_gh_6fde77c ? 來源:Linux內(nèi)核遠(yuǎn)航者 ? 作者:Linux內(nèi)核遠(yuǎn)航者 ? 2021-08-16 15:13 ? 次閱讀

1開場白

環(huán)境:

處理器架構(gòu):arm64

內(nèi)核源碼:linux-5.10.50

ubuntu版本:20.04.1

代碼閱讀工具:vim+ctags+cscope

無論是任務(wù)處于用戶態(tài)還是內(nèi)核態(tài),經(jīng)常會因?yàn)榈却承┦录撸赡苁堑却齀O讀寫完成,也可能等待其他內(nèi)核路徑釋放一把鎖等)。本文來探討一下,任務(wù)處于睡眠中有哪些狀態(tài)?睡眠對于任務(wù)來說究竟意味著什么?內(nèi)核是如何管理睡眠的任務(wù)的?我們會結(jié)合內(nèi)核源代碼來分析任務(wù)的睡眠,力求全方位角度來剖析。

注:由于篇幅問題,文章分為上下兩篇,且這里不區(qū)分進(jìn)程和任務(wù),統(tǒng)一使用任務(wù)來表示進(jìn)程。

主要講解以下內(nèi)容:

睡眠的三種狀態(tài)

睡眠的內(nèi)核原理

用戶態(tài)睡眠

內(nèi)核態(tài)睡眠

總結(jié)

2. 睡眠的三種狀態(tài)

任務(wù)睡眠有三種狀態(tài):

淺度睡眠

中度睡眠

深度睡眠

2.1 淺度睡眠

進(jìn)程描述符的state使用TASK_INTERRUPTIBLE表示這種狀態(tài)。

為可中斷的睡眠狀態(tài),這里可中斷是可以被信號所打斷(喚醒)。

這里給出被信號打斷/喚醒的代碼路徑:

kernel/signal.c

SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)

->kill_something_info

->__kill_pgrp_info

->group_send_sig_info

->do_send_sig_info

->send_signal

->__send_signal

->complete_signal

->signal_wake_up

-> signal_wake_up_state(t, resume ? TASK_WAKEKILL : 0)

->wake_up_state(t, state | TASK_INTERRUPTIBLE)

->try_to_wake_up

可以看到在信號傳遞的時候,會通過signal_wake_up喚醒從處于可中斷睡眠狀態(tài)的任務(wù)。

2.2 中度睡眠

進(jìn)程描述符的state使用TASK_KILLABLE表示這種狀態(tài)。

可以被致命信號所打斷。

這里給出被致命信號打斷/喚醒的代碼路徑:

include/linux/sched.h

#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)

kernel/signal.c

SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)

->kill_something_info

->__kill_pgrp_info

->group_send_sig_info

->do_send_sig_info

->send_signal

->__send_signal

->complete_signal

->

if (sig_fatal(p, sig) &&

| !(signal->flags & SIGNAL_GROUP_EXIT) &&

| !sigismember(&t->real_blocked, sig) &&

| (sig == SIGKILL || !p->ptrace)) { //致命信號

...

signal_wake_up(t, 1);

-> signal_wake_up_state(t, resume ? TASK_WAKEKILL : 0) // resume == 1

-> wake_up_state(t, state | TASK_INTERRUPTIBLE)

->try_to_wake_up

...

}

2.3 深度睡眠

進(jìn)程描述符的state使用TASK_UNINTERRUPTIBLE表示這種狀態(tài)。

為不可中斷的睡眠狀態(tài),不能被任何信號所喚醒(特定條件沒有滿足發(fā)生信號喚醒可能導(dǎo)致數(shù)據(jù)不一致等問題,這種場景使用這種睡眠狀態(tài),如等待IO讀寫完成)。

3. 睡眠的內(nèi)核原理

睡眠都是主動發(fā)生調(diào)度,即主動調(diào)用主調(diào)度器。

睡眠的主要步驟如下:

1)設(shè)置任務(wù)狀態(tài)為睡眠狀態(tài)

2)記錄睡眠的任務(wù)

3)發(fā)起主動調(diào)度

下面我們來詳細(xì)解讀下這幾個步驟:

3.1 設(shè)置任務(wù)狀態(tài)為睡眠狀態(tài)

這一步很有必要,一來標(biāo)識進(jìn)入了睡眠狀態(tài),二來是主調(diào)度器會根據(jù)睡眠標(biāo)志將任務(wù)從運(yùn)行隊(duì)列刪除。

注:睡眠狀態(tài)描述見上一小節(jié)!

3.2 記錄睡眠的任務(wù)

這一步也非常有必要,內(nèi)核會將即將睡眠的任務(wù)記錄下來,要么加入到鏈表中管理,要么使用數(shù)據(jù)結(jié)構(gòu)記錄。

如延遲睡眠場景,內(nèi)核將即將睡眠的任務(wù)記錄在定時器相關(guān)的數(shù)據(jù)結(jié)構(gòu)中;可睡眠的信號量場景中,內(nèi)核將即將睡眠的任務(wù)加入到信號量的相關(guān)鏈表中。

記錄的目的在于:當(dāng)喚醒條件滿足時,喚醒函數(shù)能夠找到想要喚醒的任務(wù)。

3.3 發(fā)起主動調(diào)度

這一步是真正進(jìn)行睡眠的操作,主要是調(diào)用主調(diào)度器來發(fā)起主動調(diào)度讓出處理器。

下面我們來看下主調(diào)度器為任務(wù)睡眠所作的處理:

kernel/sched/core.c

__schedule

->

prev_state = prev->state; //獲得前一個任務(wù)狀態(tài)

if (!preempt && prev_state) { //如果是主動調(diào)度 且任務(wù)狀態(tài)不為0

if (signal_pending_state(prev_state, prev)) { //有掛起的信號

prev->state = TASK_RUNNING; //設(shè)置狀態(tài)為可運(yùn)行

} else {

deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK); //cpu運(yùn)行隊(duì)列中刪除任務(wù)

}

}

next = pick_next_task(rq, prev, &rf); //選擇下一個任務(wù)

context_switch //進(jìn)行上下文切換

來看下deactivate_task對于睡眠任務(wù)做的主要工作:

deactivate_task

->deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK)

->p->on_rq = (flags & DEQUEUE_SLEEP) ? 0 : TASK_ON_RQ_MIGRATING; //設(shè)置任務(wù)的on_rq 為0 標(biāo)識是睡眠

dequeue_task(rq, p, flags);

->p->sched_class->dequeue_task(rq, p, flags)

->dequeue_task_fair

->dequeue_entity

...

if (se != cfs_rq->curr) //不是cpu當(dāng)前 任務(wù)

__dequeue_entity(cfs_rq, se); //cfs運(yùn)行隊(duì)列刪除

->se->on_rq = 0; //標(biāo)識調(diào)度實(shí)體不在運(yùn)行隊(duì)列!!!

->if (!(flags & DEQUEUE_SLEEP))

se->vruntime -= cfs_rq->min_vruntime; //調(diào)度實(shí)體的虛擬運(yùn)行時間 減去 cfs運(yùn)行隊(duì)列的最小虛擬運(yùn)行時間

deactivate_task會設(shè)置任務(wù)的on_rq 為0來 標(biāo)識是睡眠 ,然后 調(diào)用到調(diào)度類的dequeue_task方法,在cfs中設(shè)置se->on_rq = 0標(biāo)識調(diào)度實(shí)體不在cfs隊(duì)列。

可以看到,發(fā)起主動調(diào)度的時候,在主調(diào)度器中會做判斷:如果是主動調(diào)度且任務(wù)狀態(tài)不為0 (即為不是可運(yùn)行的TASK_RUNNING)時,如果沒有掛起的信號,就會將任務(wù)從cpu的運(yùn)行隊(duì)列中“刪除”,然后選擇下一個任務(wù),進(jìn)行上下文切換。

將即將睡眠的任務(wù)從cpu的運(yùn)行隊(duì)列中“刪除”意義重大:主調(diào)度器再次選擇下一個任務(wù)的時候不會在選擇睡眠的任務(wù)(因?yàn)橹髡{(diào)度器總是在運(yùn)行隊(duì)列中選擇任務(wù)運(yùn)行,除非任務(wù)被喚醒,重新加入運(yùn)行隊(duì)列)。

注意:1.這里的刪除指的是設(shè)置對應(yīng)標(biāo)志如p->on_rq=0,se->on_rq = 0,當(dāng)選擇下一個任務(wù)的時候不會在加入運(yùn)行隊(duì)列中。2.即將睡眠的任務(wù)是cpu上的當(dāng)前任務(wù)(curr指向)。3.調(diào)用主調(diào)度器后,即將睡眠的任務(wù)不會再次加入cpu運(yùn)行隊(duì)列,除非被喚醒。

再來看下選擇下一個任務(wù)的時候會做哪些事情和睡眠有關(guān)(暫不考慮組調(diào)度情況):

pick_next_task

->class->pick_next_task

->pick_next_task_fair //kernel/sched/fair.c

->if (prev)

put_prev_task(rq, prev); //對前一個任務(wù)處理

se = pick_next_entity(cfs_rq, NULL); //選擇下一個任務(wù)

set_next_entity(cfs_rq, se);

主要看下put_prev_task:

put_prev_task

->prev->sched_class->put_prev_task(rq, prev)

->put_prev_task_fair

->put_prev_entity

-> if (prev->on_rq) { //前一個任務(wù)的調(diào)度實(shí)體on_rq不為0?

update_stats_wait_start(cfs_rq, prev);

/* Put ‘current’ back into the tree. */

__enqueue_entity(cfs_rq, prev); //重新加入cfs運(yùn)行隊(duì)列

/* in !on_rq case, update occurred at dequeue */

update_load_avg(cfs_rq, prev, 0);

}

cfs_rq->curr = NULL; //設(shè)置cfs運(yùn)行隊(duì)列的curr為NULL

put_prev_task所做的主要工作就是將前一個任務(wù)從cfs運(yùn)行隊(duì)列中刪除,在這里就是通過調(diào)用__enqueue_entity將對應(yīng)的調(diào)度實(shí)體重新加入cfs隊(duì)列的紅黑樹,但是對于即將睡眠的任務(wù)之前在主調(diào)度器中通過deactivate_task將prev->on_rq設(shè)置為0了,所以對于即將睡眠的任務(wù)來說,它對應(yīng)的調(diào)度實(shí)體不會在重新加入cfs運(yùn)行隊(duì)列的紅黑樹。

責(zé)任編輯:haq

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

    關(guān)注

    3

    文章

    1382

    瀏覽量

    40430
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11345

    瀏覽量

    210417

原文標(biāo)題:深入理解Linux內(nèi)核之進(jìn)程睡眠(上)

文章出處:【微信號:gh_6fde77c41971,微信公眾號:FPGA干貨】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    嵌入式學(xué)習(xí)-飛凌嵌入式ElfBoard ELF 1板卡-Linux內(nèi)核移植之內(nèi)核簡介

    用戶提供移植好的板級開發(fā)包。板卡廠商也會對移植好的內(nèi)核版本進(jìn)行維護(hù),例如一些BUG修復(fù)或者物料替換。接下來講一下獲取這三種源碼的方法:獲取linux官網(wǎng)源碼 地址:https
    發(fā)表于 12-16 13:08

    飛凌嵌入式ElfBoard ELF 1板卡-Linux內(nèi)核移植之內(nèi)核簡介

    用戶提供移植好的板級開發(fā)包。板卡廠商也會對移植好的內(nèi)核版本進(jìn)行維護(hù),例如一些BUG修復(fù)或者物料替換。接下來講一下獲取這三種源碼的方法:獲取linux官網(wǎng)源碼地址:https
    發(fā)表于 12-13 09:03

    一文搞懂Linux進(jìn)程的睡眠和喚醒

    ): 進(jìn)程在等待某個條件滿足(如I/O操作),可以被信號喚醒。 Linux通過內(nèi)核提供的系統(tǒng)調(diào)用來控制進(jìn)程的睡眠。常用的系統(tǒng)調(diào)用有: sleep(): 使進(jìn)程暫停指定的秒數(shù)。 usleep(): 使進(jìn)程暫停
    發(fā)表于 11-04 15:15

    高頻諧振功率放大器的三種工作狀態(tài)是什么

    功率放大器的三種工作狀態(tài)通常指的是:截止狀態(tài)、放大狀態(tài)和飽和狀態(tài)。 1. 截止狀態(tài)(Cutoff
    的頭像 發(fā)表于 10-10 15:09 ?1112次閱讀

    mosfet的三種工作狀態(tài)及工作條件是什么

    的工作狀態(tài)及工作條件對于理解和設(shè)計(jì)相關(guān)電路至關(guān)重要。以下是MOSFET的三種主要工作狀態(tài)及其工作條件的介紹。 一、MOSFET的三種工作狀態(tài)
    的頭像 發(fā)表于 10-06 16:51 ?2738次閱讀

    linux驅(qū)動程序如何加載進(jìn)內(nèi)核

    ,需要了解Linux內(nèi)核的基本概念和API。以下是一些關(guān)鍵概念: 1.1 內(nèi)核模塊:Linux內(nèi)核模塊是一
    的頭像 發(fā)表于 08-30 15:02 ?592次閱讀

    NPN型晶體管三種狀態(tài)判斷方法

    NPN型晶體管作為電子學(xué)中的基礎(chǔ)元件,具有放大、開關(guān)等多種功能。其工作狀態(tài)根據(jù)基極、發(fā)射極和集電極之間的電壓和電流關(guān)系可分為截止狀態(tài)、放大狀態(tài)和飽和狀態(tài)。以下是對NPN型晶體管
    的頭像 發(fā)表于 08-13 17:33 ?2957次閱讀

    Linux內(nèi)核測試技術(shù)

    Linux 內(nèi)核Linux操作系統(tǒng)的核心部分,負(fù)責(zé)管理硬件資源和提供系統(tǒng)調(diào)用接口。隨著 Linux 內(nèi)核的不斷發(fā)展和更新,其復(fù)雜性和代碼規(guī)
    的頭像 發(fā)表于 08-13 13:42 ?589次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>測試技術(shù)

    丙類諧振功率放大器有哪三種工作狀態(tài)

    丙類諧振功率放大器是一廣泛應(yīng)用于通信、廣播、雷達(dá)等領(lǐng)域的高頻功率放大器。它利用非線性元件的非線性特性,通過調(diào)整工作狀態(tài),實(shí)現(xiàn)高效率、高功率輸出。丙類諧振功率放大器有三種工作狀態(tài):截止
    的頭像 發(fā)表于 08-01 11:05 ?1894次閱讀

    態(tài)門電路的輸出有哪三種狀態(tài)

    態(tài)門電路是一特殊的數(shù)字邏輯電路,其輸出可以有三種狀態(tài):高電平、低電平和高阻抗狀態(tài)。這種電路在數(shù)字系統(tǒng)中有著廣泛的應(yīng)用,如數(shù)據(jù)總線、地址總
    的頭像 發(fā)表于 07-30 15:17 ?6731次閱讀

    態(tài)緩沖器的三種狀態(tài)分別是什么

    態(tài)緩沖器之所以得名,是因?yàn)樗邆?b class='flag-5'>三種不同的工作狀態(tài):正常邏輯狀態(tài)輸出、高阻狀態(tài)和使能狀態(tài)。這
    的頭像 發(fā)表于 06-27 16:01 ?1490次閱讀

    晶體管的三種工作狀態(tài)

    晶體管作為現(xiàn)代電子技術(shù)的基石,其工作狀態(tài)直接影響電子設(shè)備的性能和功能。晶體管通常具備三種基本的工作狀態(tài):截止狀態(tài)、放大狀態(tài)和飽和
    的頭像 發(fā)表于 05-28 14:53 ?1716次閱讀

    STM32 Cortex M3內(nèi)核的3低功耗模式,睡眠、停機(jī)和待機(jī),在M0內(nèi)核也適用嗎?

    M3內(nèi)核的3低功耗模式,睡眠、停機(jī)和待機(jī),在M0內(nèi)核也適用嗎
    發(fā)表于 05-16 06:56

    淺析FreeRTOS任務(wù)調(diào)度器的三種調(diào)度算法和應(yīng)用

    FreeRTOS在MCU領(lǐng)域應(yīng)用非常廣泛,今天就給大家講解一下FreeRTOS調(diào)度器中的三種調(diào)度算法,以及在瑞薩RZ/T2L MPU中的應(yīng)用。
    的頭像 發(fā)表于 05-10 14:02 ?7825次閱讀
    淺析FreeRTOS任務(wù)調(diào)度器的<b class='flag-5'>三種</b>調(diào)度算法和應(yīng)用

    極管的三種工作狀態(tài)是什么

    極管是一由兩個PN結(jié)構(gòu)成的半導(dǎo)體器件。根據(jù)其基極、集電極和發(fā)射極的摻雜類型不同,可以分為NPN型和PNP型兩。在電子電路中,極管可以控制電流的大小,并有
    的頭像 發(fā)表于 05-02 16:24 ?6044次閱讀
    <b class='flag-5'>三</b>極管的<b class='flag-5'>三種</b>工作<b class='flag-5'>狀態(tài)</b>是什么
    象山县| 缅甸百家乐网站是多少| 百家乐官网路单资料| 全迅网百家乐的玩法技巧和规则 | 威尼斯人娱乐城真实网址| 恒丰百家乐官网的玩法技巧和规则| 博发| 皇冠网百家乐官网啊| 乐亭县| 德州百家乐扑克桌| 百家乐智能分析软| 爱拼百家乐官网现金网| 大发888官网游| 作弊百家乐赌具价格| 澳门百家乐官网怎么赢钱| 大发888可靠吗| 百家乐平台注册送彩金| 白金娱乐城| 太阳城房价| 百家乐吹| 谁会玩百家乐官网的玩法技巧和规则| 百家乐官网论坛白菜| 大发888帐号注册| 罗浮宫百家乐官网的玩法技巧和规则| 清涧县| 大发888真钱娱乐游戏| 百家乐论坛博彩拉| 二爷百家乐官网的玩法技巧和规则| 真人百家乐官网是啥游戏| 38坊| 全讯网新2网址| 百家乐三珠连跳打法| 基础百家乐官网的玩法技巧和规则| 线上百家乐官网可靠吗| 黄金城| 大发888可靠吗| 百家乐一年诈骗多少钱| 百家乐游戏下载| 属鼠做生意办公桌摆貔貅好不好| 乐天堂百家乐官网娱乐平台| 百家乐官网庄比闲多多少|