日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

Linux第六周学习总结——进程额管理和进程的创建

發(fā)布時(shí)間:2025/3/15 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux第六周学习总结——进程额管理和进程的创建 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Linux第六周學(xué)習(xí)總結(jié)——進(jìn)程額管理和進(jìn)程的創(chuàng)建

作者:劉浩晨

【原創(chuàng)作品轉(zhuǎn)載請(qǐng)注明出處】 《Linux內(nèi)核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000

一、 進(jìn)程的描述

操作系統(tǒng)內(nèi)核三大功能:進(jìn)程管理(核心)、內(nèi)存管理和文件系統(tǒng)。

  • 進(jìn)程控制快PCB——進(jìn)程描述符task_struct數(shù)據(jù)結(jié)構(gòu)

    進(jìn)程狀態(tài)(五種狀態(tài))轉(zhuǎn)化:

    注意:就緒狀態(tài)和運(yùn)行狀態(tài)都是TASK_RUNNING,具體是就緒還是執(zhí)行要看系統(tǒng)當(dāng)前的資源分配情況。
  • 進(jìn)程標(biāo)識(shí)符PID
    進(jìn)程標(biāo)識(shí)符pid_t pid唯一地標(biāo)識(shí)進(jìn)程
  • 所有進(jìn)程鏈表struct list_ head tasks;
    雙向循環(huán)鏈表鏈接起了所有的進(jìn)程,也表示了父子、兄弟等進(jìn)程關(guān)系程序創(chuàng)建的進(jìn)程具有父子關(guān)系,在編程時(shí)往往需要引用這樣的父子關(guān)系。
  • Linux為每個(gè)進(jìn)程分配一個(gè)8KB大小的內(nèi)存區(qū)域,用于存放該進(jìn)程兩個(gè)不同的數(shù)據(jù)結(jié)構(gòu):Thread_ info和進(jìn)程的內(nèi)核堆棧。內(nèi)核控制路徑所用的堆棧很少,因此對(duì)棧和Thread_ info來(lái)說(shuō),8KB足夠了。
  • 進(jìn)程處于內(nèi)核態(tài)時(shí)使用,不同于用戶態(tài)堆棧,即PCB中指定了內(nèi)核棧。
  • struct thread_ struct thread; //與當(dāng)前任務(wù)CPU狀態(tài)相關(guān),對(duì)進(jìn)程上下文切換有關(guān)鍵性作用
  • struct mm_struct mm, active_mm; //內(nèi)存管理進(jìn)程的地址空間
  • struct files_struct *files; //打開(kāi)文件描述符列表

  • 二、 進(jìn)程的創(chuàng)建

    1. 進(jìn)程的創(chuàng)建概覽及fork一個(gè)進(jìn)程的源代碼

    進(jìn)程的起源回顧:

    start_ kernel創(chuàng)建了cpu_ idle,即0號(hào)進(jìn)程。0號(hào)進(jìn)程又創(chuàng)建了兩個(gè)線程,一個(gè)是kernel_ init,即1號(hào)進(jìn)程,這個(gè)進(jìn)程最終啟動(dòng)了用戶態(tài);另一個(gè)是kthreadd。0號(hào)進(jìn)程是固定的代碼,1號(hào)進(jìn)程是通過(guò)復(fù)制0號(hào)進(jìn)程PCB之后在此基礎(chǔ)上做修改得到的。

    2.fork代碼

    #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char * argv[]) {int pid;/* fork another process */pid = fork();if (pid < 0) { /* error occurred */fprintf(stderr,"Fork Failed!");exit(-1);} else if (pid == 0) //pid == 0和下面的else都會(huì)被執(zhí)行到(一個(gè)是在父進(jìn)程中即pid ==0的情況,一個(gè)是 在子進(jìn)程中,即pid不等于0){/* child process */printf("This is Child Process!\n");} else { /* parent process */printf("This is Parent Process!\n");/* parent will wait for the child to complete*/wait(NULL);printf("Child Complete!\n");} }

    3. 系統(tǒng)調(diào)用回顧



    • iret與int 0x80指令對(duì)應(yīng),一個(gè)是彈出寄存器值,一個(gè)是壓入寄存器的值。
    • 如果將系統(tǒng)調(diào)用類(lèi)比于fork();那么就相當(dāng)于系統(tǒng)調(diào)用創(chuàng)建了一個(gè)子進(jìn)程,然后子進(jìn)程返回之后將在內(nèi)核態(tài)運(yùn)行,而返回到父進(jìn)程后仍然在用戶態(tài)運(yùn)行。

    4.創(chuàng)建一個(gè)新進(jìn)程在內(nèi)核中的執(zhí)行過(guò)程

    fork、vork和clone三個(gè)系統(tǒng)調(diào)用都可以創(chuàng)建一個(gè)新進(jìn)程,都通過(guò)調(diào)用do_fork()實(shí)現(xiàn)進(jìn)程創(chuàng)建。

    Linux通過(guò)復(fù)制父進(jìn)程創(chuàng)建新進(jìn)程:

    ? 復(fù)制一個(gè)PCB——task_struct

    err = arch_dup_task_struct(tsk, orig);

    ? 給新進(jìn)程分配一個(gè)新的內(nèi)核堆棧

    ti = alloc_ thread_ info_ node(tsk, node);

    tsk->stack = ti;

    setup_ thread_ stack(tsk, orig); //這里只是復(fù)制thread_ info,而非復(fù)制內(nèi)核堆棧

    ? 從用戶態(tài)的代碼看fork(),函數(shù)返回了兩次,即在父子進(jìn)程中各返回一次。這就涉及子進(jìn)程的內(nèi)核堆棧數(shù)據(jù)狀態(tài)和task_struct中thread記錄的sp和ip的一致性問(wèn)題,這是在哪里設(shè)定的——copy_thread in copy_process

    *childregs = *current_pt_regs(); //復(fù)制內(nèi)核堆棧,并不是全部,只是regs結(jié)構(gòu)體(內(nèi)核堆棧棧底的程序)
    childregs->ax = 0; //為什么子進(jìn)程的fork返回0,這里就是原因!

    p->thread.sp = (unsigned long) childregs; //調(diào)度到子進(jìn)程時(shí)的內(nèi)核棧頂
    p->thread.ip = (unsigned long) ret_from_fork; //調(diào)度到子進(jìn)程時(shí)的第一條指令地址,也就是說(shuō)返回的就是子進(jìn)程的空間了

    5.創(chuàng)建的新進(jìn)程從哪里開(kāi)始執(zhí)行?

    一個(gè)新創(chuàng)建的子進(jìn)程,獲得CPU之后,從哪一行代碼進(jìn)程執(zhí)行:

    ? 與之前寫(xiě)過(guò)的my_ kernel相比較,kernel中是可以指定新進(jìn)程開(kāi)始的位置(也就是通過(guò)eip寄存器指定代碼行)。fork中也有相似的機(jī)制

    ? 這涉及子進(jìn)程的內(nèi)核堆棧數(shù)據(jù)狀態(tài)和task_ struct中thread記錄的sp和ip的一致性問(wèn)題,這是在copy_ thread in copy_ process設(shè)定的

    *childregs = *current_pt_regs(); //復(fù)制內(nèi)核堆棧,并不是全部,只是regs結(jié)構(gòu)體(內(nèi)核堆棧棧底的程序)
    childregs->ax = 0; //為什么子進(jìn)程的fork返回0,這里就是原因!

    p->thread.sp = (unsigned long) childregs; //調(diào)度到子進(jìn)程時(shí)的內(nèi)核棧頂
    p->thread.ip = (unsigned long) ret_from_fork; //調(diào)度到子進(jìn)程時(shí)的第一條指令地址,也就是說(shuō)返回的就是子進(jìn)程的空間了

    三、 實(shí)驗(yàn)——分析Linux內(nèi)核創(chuàng)建一個(gè)新進(jìn)程的過(guò)程

    1.更新menu內(nèi)核,刪除test_fork.c以及test.cc,并重新執(zhí)行make rootfs

    2.比原先多出fork命令,編譯內(nèi)核查看:

    3.啟動(dòng)gdb跟蹤調(diào)試內(nèi)核,在一些重要函數(shù)處設(shè)置斷點(diǎn):

    4.在MenuOS中執(zhí)行fork,停在父進(jìn)程中。繼續(xù)執(zhí)行后,停在do_fork的位置:

    5.n命令進(jìn)行單步執(zhí)行,依次進(jìn)入copy_process、dup_task_struct。此時(shí)父進(jìn)程的PCB(task_struct數(shù)據(jù)結(jié)構(gòu))已經(jīng)復(fù)制過(guò)來(lái)。s命令進(jìn)入函數(shù),可以看到dst = src:

    6.copy_thread函數(shù)中,把task_pg_regs(p)也就是內(nèi)核堆棧特定的地址找到并初始化

    7.當(dāng)前進(jìn)程的內(nèi)核堆棧寄存器中的值復(fù)制到子進(jìn)程中

    8.164行:p->thread.ip = (unsigned long) ret_from_fork; //確定返回地址

    9.當(dāng)程序跳轉(zhuǎn)到syscall_exit,就不能再繼續(xù)gdb跟蹤調(diào)試,輸入finish使得進(jìn)程運(yùn)行完。

    總結(jié):

    1.Linux通過(guò)復(fù)制父進(jìn)程來(lái)創(chuàng)建一個(gè)新進(jìn)程,通過(guò)調(diào)用do_fork來(lái)實(shí)現(xiàn)。

    2.Linux為每個(gè)新創(chuàng)建的進(jìn)程動(dòng)態(tài)地分配一個(gè)task_struct結(jié)構(gòu)。

    3.為了把內(nèi)核中的所有進(jìn)程組織起來(lái),Linux提供了幾種組織方式,其中哈希表和雙向循環(huán)鏈表方式是針對(duì)系統(tǒng)中的所有進(jìn)程(包括內(nèi)核線程),而運(yùn)行隊(duì)列和等待隊(duì)列是把處于同一狀態(tài)的進(jìn)程組織起來(lái)。

    4.fork()函數(shù)被調(diào)用一次,但返回兩次。

    轉(zhuǎn)載于:https://www.cnblogs.com/lhc-java/p/5340414.html

    總結(jié)

    以上是生活随笔為你收集整理的Linux第六周学习总结——进程额管理和进程的创建的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。