日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2025/3/15 linux 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux第六周学习总结——进程额管理和进程的创建 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Linux第六周學習總結——進程額管理和進程的創建

作者:劉浩晨

【原創作品轉載請注明出處】 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000

一、 進程的描述

操作系統內核三大功能:進程管理(核心)、內存管理和文件系統。

  • 進程控制快PCB——進程描述符task_struct數據結構

    進程狀態(五種狀態)轉化:

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

  • 二、 進程的創建

    1. 進程的創建概覽及fork一個進程的源代碼

    進程的起源回顧:

    start_ kernel創建了cpu_ idle,即0號進程。0號進程又創建了兩個線程,一個是kernel_ init,即1號進程,這個進程最終啟動了用戶態;另一個是kthreadd。0號進程是固定的代碼,1號進程是通過復制0號進程PCB之后在此基礎上做修改得到的。

    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都會被執行到(一個是在父進程中即pid ==0的情況,一個是 在子進程中,即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. 系統調用回顧



    • iret與int 0x80指令對應,一個是彈出寄存器值,一個是壓入寄存器的值。
    • 如果將系統調用類比于fork();那么就相當于系統調用創建了一個子進程,然后子進程返回之后將在內核態運行,而返回到父進程后仍然在用戶態運行。

    4.創建一個新進程在內核中的執行過程

    fork、vork和clone三個系統調用都可以創建一個新進程,都通過調用do_fork()實現進程創建。

    Linux通過復制父進程創建新進程:

    ? 復制一個PCB——task_struct

    err = arch_dup_task_struct(tsk, orig);

    ? 給新進程分配一個新的內核堆棧

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

    tsk->stack = ti;

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

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

    *childregs = *current_pt_regs(); //復制內核堆棧,并不是全部,只是regs結構體(內核堆棧棧底的程序)
    childregs->ax = 0; //為什么子進程的fork返回0,這里就是原因!

    p->thread.sp = (unsigned long) childregs; //調度到子進程時的內核棧頂
    p->thread.ip = (unsigned long) ret_from_fork; //調度到子進程時的第一條指令地址,也就是說返回的就是子進程的空間了

    5.創建的新進程從哪里開始執行?

    一個新創建的子進程,獲得CPU之后,從哪一行代碼進程執行:

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

    ? 這涉及子進程的內核堆棧數據狀態和task_ struct中thread記錄的sp和ip的一致性問題,這是在copy_ thread in copy_ process設定的

    *childregs = *current_pt_regs(); //復制內核堆棧,并不是全部,只是regs結構體(內核堆棧棧底的程序)
    childregs->ax = 0; //為什么子進程的fork返回0,這里就是原因!

    p->thread.sp = (unsigned long) childregs; //調度到子進程時的內核棧頂
    p->thread.ip = (unsigned long) ret_from_fork; //調度到子進程時的第一條指令地址,也就是說返回的就是子進程的空間了

    三、 實驗——分析Linux內核創建一個新進程的過程

    1.更新menu內核,刪除test_fork.c以及test.cc,并重新執行make rootfs

    2.比原先多出fork命令,編譯內核查看:

    3.啟動gdb跟蹤調試內核,在一些重要函數處設置斷點:

    4.在MenuOS中執行fork,停在父進程中。繼續執行后,停在do_fork的位置:

    5.n命令進行單步執行,依次進入copy_process、dup_task_struct。此時父進程的PCB(task_struct數據結構)已經復制過來。s命令進入函數,可以看到dst = src:

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

    7.當前進程的內核堆棧寄存器中的值復制到子進程中

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

    9.當程序跳轉到syscall_exit,就不能再繼續gdb跟蹤調試,輸入finish使得進程運行完。

    總結:

    1.Linux通過復制父進程來創建一個新進程,通過調用do_fork來實現。

    2.Linux為每個新創建的進程動態地分配一個task_struct結構。

    3.為了把內核中的所有進程組織起來,Linux提供了幾種組織方式,其中哈希表和雙向循環鏈表方式是針對系統中的所有進程(包括內核線程),而運行隊列和等待隊列是把處于同一狀態的進程組織起來。

    4.fork()函數被調用一次,但返回兩次。

    轉載于:https://www.cnblogs.com/lhc-java/p/5340414.html

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。