日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁(yè) > > 嵌入式大雜燴
[導(dǎo)讀]一文帶你初步了解進(jìn)程描述符task_struct。


一、Linux 內(nèi)核如何描述一個(gè)進(jìn)程?

目的:

  • 初步了解進(jìn)程描述符 task_struct。

目錄:

  1. Linux 的進(jìn)程
  2. Linux 的進(jìn)程描述符
  • task_struct
  • 內(nèi)核如何找到 task_struct
  • task_struct 的分配和初始化
  • 實(shí)驗(yàn):打印 task_struct / thread_info / kernel mode stack
  • 環(huán)境:

    • Linux-4.14 + ARMv7

    1. Linux 的進(jìn)程

    進(jìn)程的術(shù)語(yǔ)是 process,是 Linux 最基礎(chǔ)的抽象,另一個(gè)基礎(chǔ)抽象是文件。

    最簡(jiǎn)單的理解,進(jìn)程就是執(zhí)行中 (executing, 不等于running) 的程序。

    更準(zhǔn)確一點(diǎn)的理解,進(jìn)程包括執(zhí)行中的程序以及相關(guān)的資源 (包括cpu狀態(tài)、打開(kāi)的文件、掛起的信號(hào)、tty、內(nèi)存地址空間等)。

    一種簡(jiǎn)潔的說(shuō)法:進(jìn)程 = n*執(zhí)行流 + 資源,n>=1。


    Linux 進(jìn)程的特點(diǎn):

    • 通過(guò)系統(tǒng)調(diào)用 fork() 創(chuàng)建進(jìn)程,fork() 會(huì)復(fù)制現(xiàn)有進(jìn)程來(lái)創(chuàng)建一個(gè)全新的進(jìn)程。

    • 內(nèi)核里,并不嚴(yán)格區(qū)分進(jìn)程和線程。

    • 從內(nèi)核的角度看,調(diào)度單位是線程 (即執(zhí)行流)??梢园丫€程看做是進(jìn)程里的一條執(zhí)行流,1個(gè)進(jìn)程里可以有1個(gè)或者多個(gè)線程。

    • 內(nèi)核里,常把進(jìn)程稱(chēng)為 task 或者 thread,這樣描述更準(zhǔn)確,因?yàn)樵S多進(jìn)程就只有1條執(zhí)行流。

    • 內(nèi)核通過(guò)輕量級(jí)進(jìn)程 (lightweight process) 來(lái)支持多線程。1個(gè)輕量級(jí)進(jìn)程就對(duì)應(yīng)1個(gè)線程,輕量級(jí)進(jìn)程之間可以共享打開(kāi)的文件、地址空間等資源。

    2. Linux 的進(jìn)程描述符

    2.1 task_struct

    內(nèi)核里,通過(guò) task_struct 結(jié)構(gòu)體來(lái)描述一個(gè)進(jìn)程,稱(chēng)為進(jìn)程描述符 (process descriptor),它保存著支撐一個(gè)進(jìn)程正常運(yùn)行的所有信息。

    每一個(gè)進(jìn)程,即便是輕量級(jí)進(jìn)程(即線程),都有1個(gè) task_struct。

    sched.h?(include\linux)

    struct?task_struct?{
    ????struct?thread_info?thread_info;
    ????volatile?long?state;
    ????void?*stack;

    ????[...]
    ????struct?mm_struct?*mm;

    ????[...]
    ????pid_t?pid;

    ????[...]
    ????struct?task_struct?*parent;

    ????[...]
    ????char?comm[TASK_COMM_LEN];

    ????[...]
    ?struct?files_struct?*files;

    ?[...]
    ?struct?signal_struct?*signal;
    }

    這是一個(gè)龐大的結(jié)構(gòu)體,不僅有許多進(jìn)程相關(guān)的基礎(chǔ)字段,還有許多指向其他數(shù)據(jù)結(jié)構(gòu)的指針。

    它包含的字段能完整地描述一個(gè)正在執(zhí)行的程序,包括 cpu 狀態(tài)、打開(kāi)的文件、地址空間、掛起的信號(hào)、進(jìn)程狀態(tài)等。

    點(diǎn)擊查看大圖

    作為初學(xué)者,先簡(jiǎn)單地了解部分字段就好:

    • struct thread_info thread_info: 進(jìn)程底層信息,平臺(tái)相關(guān),下面會(huì)詳細(xì)描述。

    • long state: 進(jìn)程當(dāng)前的狀態(tài),下面是幾個(gè)比較重要的進(jìn)程狀態(tài)以及它們之間的轉(zhuǎn)換流程。

    點(diǎn)擊查看大圖
    • void *stack: 指向進(jìn)程內(nèi)核棧,下面會(huì)解釋。

    • struct mm_struct *mm: 與進(jìn)程地址空間相關(guān)的信息都保存在一個(gè)叫內(nèi)存描述符 (memory descriptor) 的結(jié)構(gòu)體 (mm_struct) 中。

    點(diǎn)擊查看大圖
    • pid_t pid: 進(jìn)程標(biāo)識(shí)符,本質(zhì)就是一個(gè)數(shù)字,是用戶空間引用進(jìn)程的唯一標(biāo)識(shí)。

    • struct task_struct *parent: 父進(jìn)程的 task_struct。

    • char comm[TASK_COMM_LEN]: 進(jìn)程的名稱(chēng)。

    • struct files_struct *files: 打開(kāi)的文件表。

    • struct signal_struct *signal: 信號(hào)處理相關(guān)。

    其他字段,等到有需要的時(shí)候再回過(guò)頭來(lái)學(xué)習(xí)。

    2.2 當(dāng)發(fā)生系統(tǒng)調(diào)用或者進(jìn)程切換時(shí),內(nèi)核如何找到 task_struct ?

    對(duì)于 ARM 架構(gòu),答案是:通過(guò)內(nèi)核棧 (kernel mode stack)。

    為什么要有內(nèi)核棧?

    • 因?yàn)閮?nèi)核是可重入的,在內(nèi)核中會(huì)有多條與不同進(jìn)程相關(guān)聯(lián)的執(zhí)行路徑。因此不同的進(jìn)程處于內(nèi)核態(tài)時(shí),都需要有自己私有的進(jìn)程內(nèi)核棧 (process kernel stack)。

    當(dāng)進(jìn)程從用戶態(tài)切換到內(nèi)核態(tài)時(shí),所使用的棧會(huì)從用戶棧切換到內(nèi)核棧。

    • 至于是如何切換的,關(guān)鍵詞是系統(tǒng)調(diào)用,這不是本文關(guān)注的重點(diǎn),先放一邊,學(xué)習(xí)內(nèi)核要懂得恰當(dāng)?shù)臅r(shí)候忽略細(xì)節(jié)。

    當(dāng)發(fā)生進(jìn)程切換時(shí),也會(huì)切換到目標(biāo)進(jìn)程的內(nèi)核棧。

    • 同上,關(guān)鍵詞是硬件上下文切換 (hardware context switch),忽略具體實(shí)現(xiàn)。

    無(wú)論何時(shí),只要進(jìn)程處于內(nèi)核態(tài),就會(huì)有內(nèi)核??梢允褂茫駝t系統(tǒng)就離崩潰不遠(yuǎn)了。

    ARM 架構(gòu)的內(nèi)核棧和 task_struct 的關(guān)系如下:

    點(diǎn)擊查看大圖

    內(nèi)核棧的長(zhǎng)度是 THREAD_SIZE,對(duì)于 ARM 架構(gòu),一般是 2 個(gè)頁(yè)框的大小,即 8KB。

    內(nèi)核將一個(gè)較小的數(shù)據(jù)結(jié)構(gòu) thread_info 放在內(nèi)核棧的底部,它負(fù)責(zé)將內(nèi)核棧和 task_struct 串聯(lián)起來(lái)。thread_info 是平臺(tái)相關(guān)的,在 ARM 架構(gòu)中的定義如下:

    //?thread_info.h?(arch\arm\include\asm)

    struct?thread_info?{
    ?unsigned?long?flags;??/*?low?level?flags?*/
    ?int?preempt_count;?/*?0?=>?preemptable,?<0?=>?bug?*/
    ?mm_segment_t?addr_limit;?/*?address?limit?*/
    ?struct?task_struct?*task;??/*?main?task?structure?*/
    ????[...]
    ?struct?cpu_context_save?cpu_context;?/*?cpu?context?*/
    ?[...]
    };

    thread_info 保存了一個(gè)進(jìn)程能被調(diào)度執(zhí)行的最底層信息(low level task data),例如struct cpu_context_save cpu_context 會(huì)在進(jìn)程切換時(shí)用來(lái)保存/恢復(fù)寄存器上下文。

    內(nèi)核通過(guò)內(nèi)核棧的棧指針可以快速地拿到 thread_info:

    //?thread_info.h?(include\linux)

    static?inline?struct?thread_info?*current_thread_info(void)
    {
    ????//?current_stack_pointer?是當(dāng)前進(jìn)程內(nèi)核棧的棧指針
    ?return?(struct?thread_info?*)
    ??(current_stack_pointer?&?~(THREAD_SIZE?-?1));
    }

    然后通過(guò) thread_info 找到 task_struct:

    //?current.h?(include\asm-generic)

    #define?current?(current_thread_info()->task)

    內(nèi)核里通過(guò) current 宏可以獲得當(dāng)前進(jìn)程的 task_struct。

    2.3 task_struct 的分配和初始化

    當(dāng)上層應(yīng)用使用 fork() 創(chuàng)建進(jìn)程時(shí),內(nèi)核會(huì)新建一個(gè) task_struct。

    進(jìn)程的創(chuàng)建是個(gè)復(fù)雜的工作,可以延伸出無(wú)數(shù)的細(xì)節(jié)。這里我們只是簡(jiǎn)單地了解一下 task_struct 的分配和部分初始化的流程。

    fork() 在內(nèi)核里的核心流程

    點(diǎn)擊查看大圖

    dup_task_struct() 做了什么?

    點(diǎn)擊查看大圖

    至于設(shè)置內(nèi)核棧里做了什么,涉及到了進(jìn)程的創(chuàng)建與切換,不在本文的關(guān)注范圍內(nèi),以后再研究了。

    3. 實(shí)驗(yàn):打印 task_struct / thread_info / kernel mode stack

    實(shí)驗(yàn)?zāi)康模?/strong>

    • 梳理 task_struct / thread_info / kernel mode stack 的關(guān)系。

    實(shí)驗(yàn)代碼:

    #include?
    #include?
    #include?

    static?void?print_task_info(struct?task_struct?*task)
    {
    ????printk(KERN_NOTICE?"%10s?%5d?task_struct?(%p)?/?stack(%p~%p)?/?thread_info->task?(%p)",
    ????????task->comm,?
    ????????task->pid,
    ????????task,
    ????????task->stack,
    ????????((unsigned?long?*)task->stack)?+?THREAD_SIZE,
    ????????task_thread_info(task)->task);
    }

    static?int?__init?task_init(void)
    {
    ????struct?task_struct?*task?=?current;

    ????printk(KERN_INFO?"task?module?init\n");

    ????print_task_info(task);
    ????do?{
    ????????task?=?task->parent;
    ????????print_task_info(task);
    ????}?while?(task->pid?!=?0);

    ????return?0;
    }
    module_init(task_init);

    static?void?__exit?task_exit(void)
    {
    ????printk(KERN_INFO?"task?module?exit\n?");
    }
    module_exit(task_exit);

    運(yùn)行效果:

    task?module?init
    ????insmod??3123?task_struct?(edb42580)?/?stack(ed46c000~ed474000)?/?thread_info->task?(edb42580)
    ??????bash??2393?task_struct?(eda13e80)?/?stack(c9dda000~c9de2000)?/?thread_info->task?(eda13e80)
    ??????sshd??2255?task_struct?(ee5c9f40)?/?stack(c9d2e000~c9d36000)?/?thread_info->task?(ee5c9f40)
    ??????sshd???543?task_struct?(ef15f080)?/?stack(ee554000~ee55c000)?/?thread_info->task?(ef15f080)
    ???systemd?????1?task_struct?(ef058000)?/?stack(ef04c000~ef054000)?/?thread_info->task?(ef058000)

    在程序里,我們通過(guò) task_struct 找到 stack,然后通過(guò) stack 找到 thread_info,最后又通過(guò) thread_info->task 找到 task_struct。

    4. 相關(guān)參考

    • Linux 內(nèi)核設(shè)計(jì)與實(shí)現(xiàn) / 第 3.1 章節(jié)

    • 深入理解 Linux 內(nèi)核 / 3

    • Linux 內(nèi)核深度解析 / 2.5.1

    • 深入Linux 內(nèi)核架構(gòu) / 2.3

    猜你喜歡

    簡(jiǎn)單認(rèn)識(shí)認(rèn)識(shí)mqtt及mosquitto

    什么是Linux內(nèi)核空間與用戶空間?


    1024G 嵌入式資源大放送!包括但不限于C/C++、單片機(jī)、Linux等。在公眾號(hào)聊天界面回復(fù)1024,即可免費(fèi)獲取!


    免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

    本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
    換一批
    延伸閱讀

    LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

    關(guān)鍵字: 驅(qū)動(dòng)電源

    在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢(shì)抑制與過(guò)流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

    關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

    LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問(wèn)題卻十分常見(jiàn),不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問(wèn)題,需從設(shè)計(jì)、生...

    關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

    根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

    關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

    電動(dòng)汽車(chē)(EV)作為新能源汽車(chē)的重要代表,正逐漸成為全球汽車(chē)產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車(chē)的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車(chē)的動(dòng)力性能和...

    關(guān)鍵字: 電動(dòng)汽車(chē) 新能源 驅(qū)動(dòng)電源

    在現(xiàn)代城市建設(shè)中,街道及停車(chē)場(chǎng)照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢(shì)逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

    關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

    LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

    關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

    在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問(wèn)題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對(duì)周?chē)娮釉O(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來(lái)解決L...

    關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

    開(kāi)關(guān)電源具有效率高的特性,而且開(kāi)關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

    關(guān)鍵字: LED 驅(qū)動(dòng)電源 開(kāi)關(guān)電源

    LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

    關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
    關(guān)閉