欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
進(jìn)程的創(chuàng )建過(guò)程

進(jìn)程的創(chuàng )建過(guò)程

------基于Linux0.11源碼分析

1. 背景

進(jìn)程的創(chuàng )建過(guò)程無(wú)疑是最重要的操作系統處理過(guò)程之一,很多書(shū)和教材上說(shuō)的最多的還是一些原理的部分,忽略了很多細節。比如,子進(jìn)程復制父進(jìn)程所擁有的資源,或者子進(jìn)程和父進(jìn)程共享相同的物理頁(yè)面,擁有自己的地址空間,子進(jìn)程創(chuàng )建后接受統一調度執行等等。

原理性的書(shū)籍更多地關(guān)注了進(jìn)程創(chuàng )建過(guò)程中各個(gè)關(guān)鍵部分的功能,但由于過(guò)于抽象,很難理解,因此如果自己能夠實(shí)際操作,實(shí)踐這個(gè)過(guò)程就很重要,可以讓那些看起來(lái)抽象的概念變的現實(shí)而容易理解,比如所謂的父進(jìn)程的資源,父進(jìn)程所擁有的物理頁(yè)面,甚至父進(jìn)程的地址空間等等,這些抽象的概念其實(shí)只要實(shí)際操作一次就更能有感性的認識。本人參考Linux0.11源代碼實(shí)踐了創(chuàng )建進(jìn)程和調度,這個(gè)過(guò)程獲益匪淺,這里把主要的學(xué)習成果結合實(shí)踐總結一下。

 

2.  0號進(jìn)程

子進(jìn)程的創(chuàng )建是基于父進(jìn)程的,因此一直追溯上去,總有一個(gè)進(jìn)程是原始的,即沒(méi)有父進(jìn)程的。這個(gè)進(jìn)程在Linux中的進(jìn)程號是0,也就是傳說(shuō)中的0號進(jìn)程(可惜很多理論書(shū)上對這個(gè)重要的進(jìn)程只字不提)。

如果說(shuō)子進(jìn)程可以通過(guò)規范的創(chuàng )建進(jìn)程的函數(如:fork())基于父進(jìn)程復制創(chuàng )建,那么0號進(jìn)程并沒(méi)有可以復制和參考的對象,也就是說(shuō)0號進(jìn)程擁有的所有信息和資源都是強制設置的,不是復制的,這個(gè)過(guò)程我稱(chēng)為手工設置,也就是說(shuō)0號進(jìn)程是“純手工打造”,這是操作系統中“最原始”的一個(gè)進(jìn)程,它是一個(gè)模子,后面的任何進(jìn)程都是基于0號進(jìn)程生成的。

手工打造0號進(jìn)程最主要包括兩個(gè)部分:創(chuàng )建進(jìn)程0運行時(shí)所需的所有信息,即填充0號進(jìn)程,讓它充滿(mǎn)“血肉”;二是調度0號進(jìn)程的執行,即讓它“動(dòng)”起來(lái),只有動(dòng)起來(lái),才是真正意義上的進(jìn)程,因為進(jìn)程本身實(shí)際上是個(gè)動(dòng)態(tài)的概念。

    不同的操作系統或者同一個(gè)操作系統的不同版本進(jìn)程信息的內涵可能會(huì )有些細微的差距,但大體上關(guān)鍵的部分和邏輯是沒(méi)有什么不同的,我這里只是基于Linux0.11的實(shí)現來(lái)描述進(jìn)程創(chuàng )建的關(guān)鍵步驟和關(guān)鍵細節。

 

1)填充0號進(jìn)程信息

       進(jìn)程包括的內容非常復雜,但總的來(lái)說(shuō)進(jìn)程的信息都是由進(jìn)程的描述符引導標識的,因此填充0號進(jìn)程的過(guò)程邏輯上是以填充其描述符為牽引完成的(也有書(shū)將進(jìn)程描述符稱(chēng)為進(jìn)程控制塊)。下面是Linux0.11版進(jìn)程的描述符信息結構體:

struct task_struct {

       long state,counter,priority, signal;

       struct sigaction sigaction[32];

       long blocked; 

       int exit_code;

       unsigned long start_code,end_code,end_data,brk,start_stack;

       long pid,father,pgrp,session,leader;

       unsigned short uid,euid,suid,gid,egid,sgid;

       long alarm;

       long utime,stime,cutime,cstime,start_time;

       unsigned short used_math;

       int tty;    

       unsigned short umask;

       struct m_inode * pwd;

       struct m_inode * root;

       struct m_inode * executable;

       unsigned long close_on_exec;

       struct file * filp[NR_OPEN];

       struct desc_struct ldt[3];

       struct tss_struct tss;

};

可以看到進(jìn)程描述符里的信息很多,大體上有幾部分:

a. 進(jìn)程的運行信息,如進(jìn)程的當前狀態(tài)(state),進(jìn)程的各種時(shí)間片消耗記錄(utime、stime等),進(jìn)程的信號(signal)和優(yōu)先級(priority)等。

b. 進(jìn)程的基本創(chuàng )建信息,如進(jìn)程號(pid),進(jìn)程的創(chuàng )建用戶(hù)(uid)等。

c. 進(jìn)程的資源類(lèi)信息,如使用的tty自設備號(tty),文件根目錄i節點(diǎn)結構(root)等。

d. 進(jìn)程執行和切換CPU需要使用的關(guān)鍵信息:局部描述符表(LDT)、任務(wù)狀態(tài)段(TSS)信息。

 

這些信息并不是在進(jìn)程創(chuàng )建的時(shí)候就全部確定的,大部分只是暫時(shí)賦一個(gè)初值,在運行的時(shí)候會(huì )動(dòng)態(tài)更改,也有一些是要在進(jìn)程運行前設置好的,才能保證進(jìn)程被正確地執行起來(lái)。實(shí)際上,我們最需要填充的信息是那些使得操作系統可以順利切換到0號進(jìn)程的信息,最重要的顯然是進(jìn)程的LDT和TSS信息。TSS是CPU在切換任務(wù)時(shí)需要使用的信息,而LDT是局部描述符表,0號進(jìn)程是第一個(gè)運行在用戶(hù)態(tài)的進(jìn)程,需要使用自己的LDT。TSS和LDT是保證不同進(jìn)程之間相互隔離的重要機制。

實(shí)際上還有一個(gè)重要的信息不是放在進(jìn)程本身的描述符里的,而是放在全局描述符表GDT中,因為所有的進(jìn)程是由操作系統統一管理的,因此操作系統至少要保持對它們的索引,這種索引性質(zhì)的信息放在操作系統內核的GDT中。對于Linux0.11來(lái)說(shuō),每個(gè)進(jìn)程都有一個(gè)LDT和一個(gè)TSS描述符,而Linux2.4之后是每個(gè)CPU一個(gè)TSS描述符并存儲在GDT中,而不是每個(gè)進(jìn)程一個(gè)。當然這種區別會(huì )造成進(jìn)程創(chuàng )建和切換過(guò)程中一些細節上的差異,但本質(zhì)的部分和任務(wù)的切換過(guò)程并沒(méi)有任何不同。

下面是Linux0.11手動(dòng)填充進(jìn)程0的進(jìn)程描述符信息的宏:

#define INIT_TASK \

  { 0,15,15, \

    0,{{},},0, \

0,0,0,0,0,0, \

  0,-1,0,0,0, \

    0,0,0,0,0,0, \

      0,0,0,0,0,0, \

      0, \

    -1,0022,NULL,NULL,NULL,0, \

  {NULL,}, \

{ \

             {0,0}, \

         {0x9f,0xc0fa00}, \

                {0x9f,0xc0f200}, \

          }, \

  0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\

             0,0,0,0,0,0,0,0, \

             0,0,0x17,0x17,0x17,0x17,0x17,0x17, \

             _LDT(0),0x80000000, {} \

          }, \

}

除了填充進(jìn)程描述符的信息外,還需要在GDT中設置相關(guān)的項,即進(jìn)程0的LDT和TSS選擇符,這個(gè)工作是在sched_init()里完成的:

void sched_init(void){

...

set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));

       set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));

...

ltr(0);

       lldt(0);

}

可以看到,在進(jìn)程0的TSS和LDT描述符信息設置到GDT中后,立刻設置了TR寄存器和LDTR寄存器,為即將運行0號進(jìn)程作準備。

 

2)運行0號進(jìn)程

   進(jìn)程0是運行在用戶(hù)態(tài)下的進(jìn)程,因此就意味著(zhù)進(jìn)程0的運行過(guò)程實(shí)際上是一個(gè)從0級特權級到3級特權級切換的過(guò)程,使用的是CPU指令iret,模擬了中斷調用的返回過(guò)程,具體執行過(guò)程由move_to_user_mode完成:

#define move_to_user_mode() \

__asm__ ("movl %%esp,%%eax\n\t" \

              "pushl $0x17\n\t" \

              "pushl %%eax\n\t" \

              "pushfl\n\t" \

              "pushl $0x0f\n\t" \

              "pushl $1f\n\t" \

              "iret\n" \

              "1:\tmovl $0x17,%%eax\n\t" \

...)

這個(gè)宏將進(jìn)程0執行時(shí)的ss,esp,eflags.cs,eip信息全部壓棧,待到執行iret指令時(shí),CPU將這幾項信息從棧中彈出加載到相應的寄存器中,這樣就實(shí)現了進(jìn)程0的啟動(dòng)執行。從這里也可以看出,進(jìn)程0剛開(kāi)始執行時(shí)幾個(gè)關(guān)鍵寄存器的信息也是在其運行前事先設定好的,從進(jìn)程描述符信息到執行信息均是人為設置,因此我稱(chēng)之為“純手工打造的進(jìn)程”。

      

3. 子進(jìn)程的創(chuàng )建

       有了0號進(jìn)程這個(gè)原始的進(jìn)程,再來(lái)看子進(jìn)程的創(chuàng )建就比較容易理解一些。除了0號進(jìn)程外,其余的進(jìn)程均使用系統調用fork()完成,其具體工作由內核態(tài)的_sys_fork實(shí)現:

_sys_fork:

       call _find_empty_process

       testl %eax,%eax

       js 1f

       push %gs

       pushl %esi

       pushl %edi

       pushl %ebp

       pushl %eax

       call _copy_process

       addl $20,%esp

1:     ret

       可以看到,一個(gè)進(jìn)程的創(chuàng )建主要有兩個(gè)步驟:一是找到一個(gè)空閑進(jìn)程資源(find_empty_process),Linux0.11來(lái)說(shuō)可以同時(shí)運行的進(jìn)程數目是64個(gè),是有限的,因此需要先得到一個(gè)空閑的進(jìn)程表中的一項用來(lái)索引即將創(chuàng )建的進(jìn)程信息;第二個(gè)主要步驟就是復制(copy_process),這個(gè)函數具體來(lái)實(shí)現子進(jìn)程基于父進(jìn)程的復制創(chuàng )建。

主要包括的步驟和內容是:

1)  為新進(jìn)程在內存中分配一個(gè)物理頁(yè),將新進(jìn)程的描述符信息填充在該頁(yè)的開(kāi)頭,并設置新進(jìn)程的描述符里各項信息;

2)  拷貝父進(jìn)程的頁(yè)表,使得它們共同指向相同的物理頁(yè),同時(shí)將父進(jìn)程的各個(gè)頁(yè)表屬性改為只讀,這樣將來(lái)可以使用寫(xiě)時(shí)復制機制。

3)  在GDT中設置該進(jìn)程項的TSS和LDT選擇符。

       Linux0.11版本子進(jìn)程內容的設置主要內容就是這些,當然不同版本會(huì )有不同,在改進(jìn)執行性能上也會(huì )有改進(jìn),但這個(gè)版本體現出來(lái)的最基本創(chuàng )建過(guò)程基本上反映了操作系統創(chuàng )建進(jìn)程的主要過(guò)程。

 

4. 子進(jìn)程的運行

       子進(jìn)程在創(chuàng )建好后并不能立即執行,至少需要一次調度,而這個(gè)調度到子進(jìn)程的運行過(guò)程就完全不需要像進(jìn)程0那樣人為在棧上設置信息然后用iret方式,而是執行的任務(wù)的切換過(guò)程。不考慮進(jìn)程調度的各個(gè)算法和選擇細節,最終負責完成切換操作的函數如下:

#define switch_to(n) {\

struct {long a,b;} __tmp; \

__asm__("cmpl %%ecx,_current\n\t" \

       "je 1f\n\t" \

       "movw %%dx,%1\n\t" \

       "xchgl %%ecx,_current\n\t" \

       "ljmp %0\n\t" \

       "cmpl %%ecx,_last_task_used_math\n\t" \

       "jne 1f\n\t" \

       "clts\n" \

       "1:" \

       ::"m" (*&__tmp.a),"m" (*&__tmp.b), \

       "d" (_TSS(n)),"c" ((long) task[n])); \

}

       最終的切換執行了一個(gè)ljmp操作,它的操作數是一個(gè)任務(wù)描述符,這會(huì )導致CPU執行一次任務(wù)切換,根據新進(jìn)程的TSS信息將相關(guān)信息加載進(jìn)cs,eip,eflags,ss,esp寄存器開(kāi)始執行新的代碼。當然由于先前拷貝的父進(jìn)程的相關(guān)頁(yè)面被設置為只讀,子進(jìn)程第一次執行到該頁(yè)面時(shí)會(huì )觸發(fā)頁(yè)保護的異常,這時(shí)會(huì )觸發(fā)寫(xiě)時(shí)復制操作,為子進(jìn)程分配自己的相應頁(yè)面。

      

符:任務(wù)(task)和進(jìn)程(process)的區別

    任務(wù)和進(jìn)程很容易被人混淆,甚至在Linux中進(jìn)程描述符結構體也是用task_struct表示,而不是process,這更讓人有的時(shí)候搞不清楚。我個(gè)人認為,其實(shí)任務(wù)的概念更底層,可以認為是基于CPU的角度來(lái)考慮的,進(jìn)程所處的層次更高一些,應當可以認為是操作系統一級的概念。

    任務(wù)關(guān)注點(diǎn)是一組程序操作,這組操作實(shí)現了某個(gè)功能,它最終會(huì )涉及到指令級別,我們說(shuō)任務(wù)的切換最終需要關(guān)注的還是CPU的相關(guān)指令。

    進(jìn)程的概念通常是指程序的執行,是動(dòng)態(tài)的過(guò)程。進(jìn)程除了包含其要運行的程序之外,還包括運行時(shí)的諸多信息,如運行時(shí)間,信號等等。

 原文地址 http://x86.eefocus.com/article/09-12/1628861261320676.html
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Linux進(jìn)程-進(jìn)程的創(chuàng )建
總結一下linux中的分段機制
Linux 內核
分段與分頁(yè)機制小結
Linux0.11小結
邏輯地址、線(xiàn)性地址、物理地址和虛擬地址 - Linux - ***林電子科技有限公司
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久