Linux 進程管理淺析

來源:互聯網
上載者:User

標籤:

劉柳 + 原創作品轉載請註明出處 + 《Linux核心分析》MOOC課程+http://mooc.study.163.com/course/[email protected]

進程的描述ulk那個大圖 for task_struct

提綱挈領,看代碼前總覽

序言 進程式控制制塊PCB——task_struct

為了管理進程,核心必須對每個進程進行清晰的描述,進程描述符提供了核心所需瞭解的進程資訊。

struct task_struct資料結構很龐大

Linux進程的狀態與作業系統原理中的描述的進程狀態似乎有所不同,比如就緒狀態和運行狀態都是TASK_RUNNING,為什麼呢?
A66:取決於是否獲得cpu的控制權

進程的標示pid

每個進程唯一的標示

調度相關的

核心關鍵詞有:
runqueue
優先順序
搶佔
調度資訊

struct task_struct {...    int on_rq;    int prio, static_prio, normal_prio;    unsigned int rt_priority;    const struct sched_class *sched_class;    struct sched_entity se;    struct sched_rt_entity rt;...    struct sched_dl_entity dl;...    unsigned int policy;    int nr_cpus_allowed;    cpumask_t cpus_allowed;#ifdef CONFIG_PREEMPT_RCU    int rcu_read_lock_nesting;    union rcu_special rcu_read_unlock_special;    struct list_head rcu_node_entry;#endif /* #ifdef CONFIG_PREEMPT_RCU */#ifdef CONFIG_TREE_PREEMPT_RCU    struct rcu_node *rcu_blocked_node;#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */#ifdef CONFIG_TASKS_RCU    unsigned long rcu_tasks_nvcsw;    bool rcu_tasks_holdout;    struct list_head rcu_tasks_holdout_list;    int rcu_tasks_idle_cpu;#endif /* #ifdef CONFIG_TASKS_RCU */#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)    struct sched_info sched_info;#endif...}
所有進程鏈表struct list_head tasks;

核心的雙向迴圈鏈表的實現方法 - 一個更簡略的雙向迴圈鏈表

獨立操作

父子關係

程式建立的進程具有父子關係,在編程時往往需要引用這樣的父子關係。進程描述符中有幾個域用來表示這樣的關係

/*     * pointers to (original) parent process, youngest child, younger sibling,     * older sibling, respectively.  (p->father can be replaced with     * p->real_parent->pid)     */    struct task_struct __rcu *real_parent; /* real parent process */    struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */    /*     * children/sibling forms the list of my natural children     */    struct list_head children;  /* list of my children */    struct list_head sibling;   /* linkage in my parent‘s children list */    struct task_struct *group_leader;   /* threadgroup leader */
mm_struct

非本章重點,待後面章節展開,
linux進程的地址空間,是個有趣的話題

cpu相關

與我們menuos相關的,注意其中sp/ip指標。

struct thread_struct {    /* Cached TLS descriptors: */    struct desc_struct  tls_array[GDT_ENTRY_TLS_ENTRIES];    unsigned long       sp0;    unsigned long       sp;#ifdef CONFIG_X86_32    unsigned long       sysenter_cs;#else    unsigned long       usersp; /* Copy from PDA */    unsigned short      es;    unsigned short      ds;    unsigned short      fsindex;    unsigned short      gsindex;#endif#ifdef CONFIG_X86_32    unsigned long       ip;#endif...}

至此,400行左右的task_struct大致介紹到此

記憶體地區

? Linux為每個進程分配一個8KB大小的記憶體地區,用於存放該進程兩個不同的資料結構:Thread_info和進程的核心堆棧

? 進程處於核心態時使用,不同於使用者態堆棧,即PCB中指定了核心棧,那為什麼PCB中沒有使用者態堆棧?使用者態堆棧是怎麼設定的?

? 核心控制路徑所用的堆棧很少,因此對棧和Thread_info來說,8KB足夠了

? struct thread_struct thread;?//CPU-specific state of this task

? 檔案系統和檔案描述符

記憶體管理——進程的地址空間

不深入mmu

二. 進程的建立回顧

start_kernel —>
kernel_init —>
kthreadd

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)     {        /* 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");    }}
系統調用回顧

不僅僅是調用一個fork


int 0x80和iret的一個配合

試問fork進程的來源?我們來看下文

建立一個新進程在核心中的執行過程(sys_clone–>do_fork)

fork、vfork和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,而非複製核心堆棧

要修改複製過來的進程資料,比如pid、進程鏈表等等都要改改吧,見copy_process內部。
從使用者態的代碼看fork();函數返回了兩次,即在父子進程中各返回一次,父進程從系統調用中返回比較容易理解,子進程從系統調用中返回,那它在系統調用處理過程中的哪裡開始執行的呢?這就涉及子進程的核心堆棧資料狀態和task_struct中thread記錄的sp和ip的一致性問題,這是在哪裡設定的?copy_thread in copy_process

進程資料的修改
*childregs = *current_pt_regs(); //複製核心堆棧childregs->ax = 0; //為什麼子進程的fork返回0,這裡就是原因!p->thread.sp = (unsigned long) childregs; //調度到子進程時的核心棧頂p->thread.ip = (unsigned long) ret_from_fork; //調度到子進程時的第一條指令地址
代碼情景分析

fork.c
do_fork –>copy_process–>dup_task_struct

dup_task_struct
 {   alloc_task_sturct //slab管理 task_stuct...   alloc_thread_info //keme_pages   stack   }
copy_thread

do_fork –>copy_process–>dup_task_struct
—>子進程初始化(很多)–>copy_thread

copy_thread{sp指標核心堆棧資料拷貝(重點展開)}

附圖

  childregs->ax=0;

這裡看到傳回值(pid)賦值的位置

子進程啟動位置

本質原因是ret_from_fork

先展開pt_regs內容,這也是int指令和save_all壓到堆棧的內容

struct pt_regs {    long ebx;    long ecx;    long edx;    long esi;    long edi;    long ebp;    long eax;    int  xds;    int  xes;    int  xfs;    int  xgs;    long orig_eax;    long eip;    int  xcs;    long eflags;    long esp;    int  xss;};

以系統調用位列,ax為調用號。

展開ret_from_fork

ENTRY(ret_from_fork)    movi    a4, schedule_tail    callx4  a4    movi    a4, do_syscall_trace_leave    mov a6, a1    callx4  a4    j   common_exception_returnENDPROC(ret_from_fork)...

展開syscall_exit

syscall_exit:    LOCKDEP_SYS_EXIT    DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don‘t miss an interrupt                    # setting need_resched or sigpending                    # between sampling and the iret    TRACE_IRQS_OFF    movl TI_flags(%ebp), %ecx    testl $_TIF_ALLWORK_MASK, %ecx # current->work    jne syscall_exit_workrestore_all:    TRACE_IRQS_IRET

以後的流程其實就是上節課的內容啦

子進程返回使用者台之前會發生系統調用嗎?

個人認為,會。
原因從下面這個圖(ULK)就可以說明。

三.動手實驗
  • rm menu
  • git clone
  • mv test_fork.c test.c
  • make rootfs

now, enjoy the work see the “fork”

the information to debug

  • sys_clone
  • do_fork
  • dup_task_struct
  • copy_process
  • copy_thread
  • ret_from_fork (*)

the result of debugging

- copy_process  alloc_thread_info  arc_dup_task_struct  setup_thread_stack- copy_thread  childregs //ptype  current_pt_regs()//前後堆棧變化  ip- ret_from_fork    //step by step  不跟蹤schedule,continue- syscall_exit (直到這個位置)
todo

添加動手

其他

gdb調試器,堆棧可以即時修改嗎?

感謝:
圖片路徑問題
http://www.v2ex.com/t/57063
圖片路徑:C:/Users/Vanny/Downloads/MarkdownEditor/ 本地hard

注釋中的 條件編譯 被 錯誤解釋了
注釋的三個引號如何輸入啦
用戶端不支援 文法嵌套?比如注釋裡面加粗
還有回退功能有限,僅一步
還有左右的呼喚,編輯器的find..
如何讓#不顯示轉義
二級目錄

綠色版等等需要改進

Linux 進程管理淺析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.