在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

3天內不再提示

Linux內核睡眠的三種狀態講解

B4Pb_gh_6fde77c ? 來源:Linux內核遠航者 ? 作者:Linux內核遠航者 ? 2021-08-16 15:13 ? 次閱讀

1開場白

環境:

處理器架構:arm64

內核源碼:linux-5.10.50

ubuntu版本:20.04.1

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

無論是任務處于用戶態還是內核態,經常會因為等待某些事件而睡眠(可能是等待IO讀寫完成,也可能等待其他內核路徑釋放一把鎖等)。本文來探討一下,任務處于睡眠中有哪些狀態?睡眠對于任務來說究竟意味著什么?內核是如何管理睡眠的任務的?我們會結合內核源代碼來分析任務的睡眠,力求全方位角度來剖析。

注:由于篇幅問題,文章分為上下兩篇,且這里不區分進程和任務,統一使用任務來表示進程。

主要講解以下內容:

睡眠的三種狀態

睡眠的內核原理

用戶態睡眠

內核態睡眠

總結

2. 睡眠的三種狀態

任務睡眠有三種狀態:

淺度睡眠

中度睡眠

深度睡眠

2.1 淺度睡眠

進程描述符的state使用TASK_INTERRUPTIBLE表示這種狀態。

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

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

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喚醒從處于可中斷睡眠狀態的任務。

2.2 中度睡眠

進程描述符的state使用TASK_KILLABLE表示這種狀態。

可以被致命信號所打斷。

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

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 深度睡眠

進程描述符的state使用TASK_UNINTERRUPTIBLE表示這種狀態。

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

3. 睡眠的內核原理

睡眠都是主動發生調度,即主動調用主調度器。

睡眠的主要步驟如下:

1)設置任務狀態為睡眠狀態

2)記錄睡眠的任務

3)發起主動調度

下面我們來詳細解讀下這幾個步驟:

3.1 設置任務狀態為睡眠狀態

這一步很有必要,一來標識進入了睡眠狀態,二來是主調度器會根據睡眠標志將任務從運行隊列刪除。

注:睡眠狀態描述見上一小節!

3.2 記錄睡眠的任務

這一步也非常有必要,內核會將即將睡眠的任務記錄下來,要么加入到鏈表中管理,要么使用數據結構記錄。

如延遲睡眠場景,內核將即將睡眠的任務記錄在定時器相關的數據結構中;可睡眠的信號量場景中,內核將即將睡眠的任務加入到信號量的相關鏈表中。

記錄的目的在于:當喚醒條件滿足時,喚醒函數能夠找到想要喚醒的任務。

3.3 發起主動調度

這一步是真正進行睡眠的操作,主要是調用主調度器來發起主動調度讓出處理器。

下面我們來看下主調度器為任務睡眠所作的處理:

kernel/sched/core.c

__schedule

->

prev_state = prev->state; //獲得前一個任務狀態

if (!preempt && prev_state) { //如果是主動調度 且任務狀態不為0

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

prev->state = TASK_RUNNING; //設置狀態為可運行

} else {

deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK); //cpu運行隊列中刪除任務

}

}

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

context_switch //進行上下文切換

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

deactivate_task

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

->p->on_rq = (flags & DEQUEUE_SLEEP) ? 0 : TASK_ON_RQ_MIGRATING; //設置任務的on_rq 為0 標識是睡眠

dequeue_task(rq, p, flags);

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

->dequeue_task_fair

->dequeue_entity

...

if (se != cfs_rq->curr) //不是cpu當前 任務

__dequeue_entity(cfs_rq, se); //cfs運行隊列刪除

->se->on_rq = 0; //標識調度實體不在運行隊列!!!

->if (!(flags & DEQUEUE_SLEEP))

se->vruntime -= cfs_rq->min_vruntime; //調度實體的虛擬運行時間 減去 cfs運行隊列的最小虛擬運行時間

deactivate_task會設置任務的on_rq 為0來 標識是睡眠 ,然后 調用到調度類的dequeue_task方法,在cfs中設置se->on_rq = 0標識調度實體不在cfs隊列。

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

將即將睡眠的任務從cpu的運行隊列中“刪除”意義重大:主調度器再次選擇下一個任務的時候不會在選擇睡眠的任務(因為主調度器總是在運行隊列中選擇任務運行,除非任務被喚醒,重新加入運行隊列)。

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

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

pick_next_task

->class->pick_next_task

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

->if (prev)

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

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

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) { //前一個任務的調度實體on_rq不為0?

update_stats_wait_start(cfs_rq, prev);

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

__enqueue_entity(cfs_rq, prev); //重新加入cfs運行隊列

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

update_load_avg(cfs_rq, prev, 0);

}

cfs_rq->curr = NULL; //設置cfs運行隊列的curr為NULL

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

責任編輯:haq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內核
    +關注

    關注

    3

    文章

    1405

    瀏覽量

    40978
  • Linux
    +關注

    關注

    87

    文章

    11427

    瀏覽量

    212417

原文標題:深入理解Linux內核之進程睡眠(上)

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

收藏 人收藏

    評論

    相關推薦
    熱點推薦

    redis三種集群方案詳解

    在Redis中提供的集群方案總共有三種(一般一個redis節點不超過10G內存)。
    的頭像 發表于 03-31 10:46 ?420次閱讀
    redis<b class='flag-5'>三種</b>集群方案詳解

    嵌入式學習-飛凌嵌入式ElfBoard ELF 1板卡-Linux內核移植之內核簡介

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

    飛凌嵌入式ElfBoard ELF 1板卡-Linux內核移植之內核簡介

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

    一文搞懂Linux進程的睡眠和喚醒

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

    高頻諧振功率放大器的三種工作狀態是什么

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

    mosfet的三種工作狀態及工作條件是什么

    的工作狀態及工作條件對于理解和設計相關電路至關重要。以下是MOSFET的三種主要工作狀態及其工作條件的介紹。 一、MOSFET的三種工作狀態
    的頭像 發表于 10-06 16:51 ?4788次閱讀

    linux驅動程序如何加載進內核

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

    NPN型晶體管三種狀態判斷方法

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

    Linux內核測試技術

    Linux 內核Linux操作系統的核心部分,負責管理硬件資源和提供系統調用接口。隨著 Linux 內核的不斷發展和更新,其復雜性和代碼規
    的頭像 發表于 08-13 13:42 ?845次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b>測試技術

    丙類諧振功率放大器有哪三種工作狀態

    丙類諧振功率放大器是一廣泛應用于通信、廣播、雷達等領域的高頻功率放大器。它利用非線性元件的非線性特性,通過調整工作狀態,實現高效率、高功率輸出。丙類諧振功率放大器有三種工作狀態:截止
    的頭像 發表于 08-01 11:05 ?2500次閱讀

    態門電路的輸出有哪三種狀態

    態門電路是一特殊的數字邏輯電路,其輸出可以有三種狀態:高電平、低電平和高阻抗狀態。這種電路在數字系統中有著廣泛的應用,如數據總線、地址總
    的頭像 發表于 07-30 15:17 ?7614次閱讀

    態緩沖器的三種狀態分別是什么

    態緩沖器之所以得名,是因為它具備三種不同的工作狀態:正常邏輯狀態輸出、高阻狀態和使能狀態。這
    的頭像 發表于 06-27 16:01 ?1880次閱讀

    晶體管的三種工作狀態

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

    STM32 Cortex M3內核的3低功耗模式,睡眠、停機和待機,在M0內核也適用嗎?

    M3內核的3低功耗模式,睡眠、停機和待機,在M0內核也適用嗎
    發表于 05-16 06:56

    淺析FreeRTOS任務調度器的三種調度算法和應用

    FreeRTOS在MCU領域應用非常廣泛,今天就給大家講解一下FreeRTOS調度器中的三種調度算法,以及在瑞薩RZ/T2L MPU中的應用。
    的頭像 發表于 05-10 14:02 ?8638次閱讀
    淺析FreeRTOS任務調度器的<b class='flag-5'>三種</b>調度算法和應用
    主站蜘蛛池模板: 伊人网大香| 日本不卡视频在线 | 四虎影视色费永久在线观看 | 草草影院www色极品欧美 | 久久九九国产 | 可以直接看的黄色网址 | 五月天婷婷在线观看高清 | 狠狠躁夜夜躁人人躁婷婷视频 | 国内精品久久影视 | 亚洲a网站 | 午夜影院404 | 天天草天天干天天 | 久久天天躁狠狠躁夜夜不卡 | 九九精品影院 | 中文字字幕码一二区 | 女同在线视频 | 日韩无| 天天透天天操 | 黄色一级大片视频 | 最新仑乱免费视频 | 操操操综合 | 成人午夜网址 | 亚洲精品456人成在线 | 国产精品久久久久久吹潮 | 天天在线天天看成人免费视频 | 亚洲欧洲国产精品你懂的 | 国产精品www夜色影视 | sihu永久在线播放地址 | a视频免费看 | 午夜亚洲福利 | 女攻各种play男受h | 添人人躁日日躁夜夜躁夜夜揉 | 精品卡1卡2卡三卡免费视频 | 精品国产第一页 | 综合色婷婷 | 日本免费性 | 噜噜噜噜噜久久久久久91 | 狠狠狠 | 刺激一区 | 久久综合免费视频 | 九九碰 |