• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-80  評論-24  文章-0  trackbacks-0
            該文件是進程實現(xiàn)以及啟動第一個進程的主要實現(xiàn)部分。
            還是從文件開頭說起,先看代碼:

             1 #include <string.h>
             2 #include <asm/system.h>
             3 #include <winixj/mm.h>
             4 #include <winixj/int.h>
             5 #include <winixj/mailbox.h>
             6 #include <winixj/process.h>
             7 #include <winixj/schedule.h>
             8 
             9 //所有進程所擁有的內(nèi)核態(tài)堆棧都放到一起
            10 //進程的內(nèi)核態(tài)堆棧的作用主要是用來保存
            11 //進程被打斷時的現(xiàn)場信息
            12 KSTACK kstack_list[NR_PROCS];
            13 
            14 /*********************************************
            15  * 這只是權(quán)宜之計,因為我們還沒有實現(xiàn)內(nèi)存管理
            16  * 所以暫時使每個進程都有一個獨立的用戶態(tài)堆棧
            17  *********************************************/
            18 //所有進程所擁有的用戶太堆棧也都放到一起
            19 USTACK ustack_list[NR_PROCS];
            20 
            21 //進程鏈表,保存所有的進程控制塊信息
            22 //這是全局變量
            23 PROCESS proc_list[NR_PROCS];
            24 
            25 PROCESS *current; //指向當(dāng)前正在運行的進程
            26 

            先看幾個變量的含義:
            首先是kstack_list和ustack_list,在該博文中已經(jīng)說到了,每個進程都有自己單獨的用戶態(tài)棧和核心態(tài)棧,在這里的WinixJ的實現(xiàn)目前比較幼稚,就是申請一個數(shù)組,將所有的用戶態(tài)棧放到一起成為數(shù)組,將所有的核心態(tài)放到一起組成數(shù)組,這樣做是有嚴(yán)重問題的:每個進程的數(shù)據(jù)段和堆棧段是分開放置的,數(shù)據(jù)段在進程地址空間中,而堆棧段則在內(nèi)核空間中,這樣極不利于進程之間的隔離與保護,但是誰讓我們是miniOS呢,這樣實現(xiàn)至少現(xiàn)在也能用,等實現(xiàn)了分頁機制以及內(nèi)存管理后再改進也不遲。
            然后是proc_list數(shù)組,該數(shù)組是整個進程的核心,它其中的每一項都是一個進程的心臟---進程控制塊。先看進程控制塊的定義,看它有哪些字段組成:

             1 //目前的進程控制塊結(jié)構(gòu)不妨盡量簡單
             2 //因為我們要實現(xiàn)的是簡陋的進程,請忍受這一點
             3 typedef struct task_struct
             4 {
             5     uint32    state;                    //進程狀態(tài)
             6     uint32    priority;                //進程優(yōu)先級
             7     uint32    time_slices;            //進程的剩余時間片
             8     uint32    pid;                    //進程的pid
             9     uint32    ppid;                    //父進程的pid
            10 #define PROC_NAME_LEN    32            //進程名的最大長度為32字節(jié)
            11     char    name[PROC_NAME_LEN];
            12     uint32    *kstack;                //指向內(nèi)核態(tài)堆棧頂
            13     uint32    *ustack;                //指向用戶態(tài)堆棧頂
            14     uint32    running_time;            //進程一共運行了的時間
            15     struct seg_struct ldt[3];        //進程的局部描述符表一項為空、一項為cs、一項為ds和ss
            16     TSS tss;
            17 } PROCESS;
            18 

            可以看到,我們所熟知的字段都包含了,有:進程狀態(tài)、進程優(yōu)先級、進程運行時間片、進程pid、父進程pid、進程名等等,還有我們剛才提到的該進程的用戶態(tài)棧和核心態(tài)棧指針,以及該進程運行了多長時間(該參數(shù)目前版本的WinixJ還沒有用到),還有l(wèi)dt、tss。下面依次對其進行介紹:
            1、state,有如下幾種狀態(tài):

            1 #define PROC_RUNNING        1
            2 #define PROC_INTERRUPTIBLE    2
            3 #define PROC_UNINTERRUPTIBLE    3
            4 #define PROC_ZOMBIE        4
            5 #define PROC_STOPPED        5
            6 

            這些定義符合大部分UNIX類系統(tǒng)的規(guī)定。不過在WinixJ中第2、3、4種狀態(tài)目前沒有用到,進程只有正在運行、就緒兩種狀態(tài),而RUNNING則代表了這兩種狀態(tài),STOPPED是進程控制塊中的初始狀態(tài),代表進程不存在(這里與UNIX類系統(tǒng)有些沖突,不過可以很容易修正),目前還不支持進程的死亡退出以及僵尸進程。
            2、priority,進程的優(yōu)先級,WinixJ目前采用的是時間片輪轉(zhuǎn)調(diào)度,因此priority和進程的初始時間片相同。
            3、time_slices,進程時間片,該值越大則進程獲得運行的時間越長。
            4、pid,進程pid。
            5、ppid,父進程pid。
            6、name[32],進程名。
            7、kstack,核心態(tài)堆棧頂,前面介紹過了。
            8、ustack,用戶態(tài)堆棧頂,核心態(tài)堆棧和用戶態(tài)堆棧都是1KB大小,見下面的定義:

            1 //進程所擁有的內(nèi)核態(tài)以及用戶態(tài)堆棧
            2 //大小為1KB,短期內(nèi)應(yīng)該夠用
            3 typedef struct kstack
            4 {
            5     uint8 res[1024];
            6 } KSTACK, USTACK;
            7 

            9、running_time,進程已經(jīng)運行了多長時間,目前未使用該變量。
            10、ldt[3],局部描述符表,定義和GDT相同,如下:

             1 //定義段描述符結(jié)構(gòu),每個描述符占用8個字節(jié)
             2 typedef struct seg_struct
             3 {
             4     uint16    seg_limit_low16;
             5     uint16    seg_base_low16;
             6     uint8    seg_base_mid8;
             7     uint8    attr1;
             8     uint8    attr2_limit_high4;
             9     uint8    seg_base_high8;
            10 };
            11 

            ldt是進程間隔離的核心部件之一,每個進程都有自己的ldt,它的含義和gdt項沒有什么不同,只不過它僅包含三項,第一項和GDT的第一項一樣未空,不使用,第二項為局部CS段描述符,第三項為局部DS和SS段描述符。而這個ldt又如何使用呢?暫時不需要管,只需要知道,當(dāng)發(fā)生進程切換的時候,進程的CS段和DS段基地址是從該進程的ldt中獲得的。
            11、tss,這是TSS段,在進行任務(wù)切換的時候用于進程現(xiàn)場的保護和恢復(fù)。

            再繼續(xù)往下看代碼:

             1 extern void init();
             2 extern void sys();
             3 
             4 static void set_tss_seg(int n, void *addr)
             5 {
             6     gdt[n].seg_limit_low16        = 0x0068//tss段長為104個字節(jié),不能多也不能少
             7     gdt[n].seg_base_low16        = (uint16)(((uint32)addr) & 0xffff); //段地址的低16位
             8     gdt[n].seg_base_mid8        = (uint8)((((uint32)addr) >> 16& 0xff); //段地址的中間8位
             9     gdt[n].attr1                = 0x89//該段在內(nèi)存中存在,DPL=0,是TSS描述符
            10     gdt[n].attr2_limit_high4    = 0x40//段界限粒度是字節(jié)
            11     gdt[n].seg_base_high8        = (uint8)((((uint32)addr) >> 24& 0xff); //段地址的高8位
            12 }
            13 
            14 static void set_ldt_seg(int n, void *addr)
            15 {
            16     gdt[n].seg_limit_low16        = 0x0018//所有進程的ldt均只包含三個描述符,因此ldt段長為24個字節(jié)
            17     gdt[n].seg_base_low16        = (uint16)(((uint32)addr) & 0xffff); //段地址的低16位
            18     gdt[n].seg_base_mid8        = (uint8)((((uint32)addr) >> 16& 0xff); //段地址的中間8位
            19     gdt[n].attr1                = 0x82//該段在內(nèi)存中存在,DPL=0,是LDT描述符
            20     gdt[n].attr2_limit_high4    = 0x40//段界限粒度是字節(jié)
            21     gdt[n].seg_base_high8        = (uint8)((((uint32)addr) >> 24& 0xff); //段地址的高8位
            22 }
            23 

            這兩個函數(shù)不長,代碼也很相似,他們完成的功能如下:
            set_tss_seg()函數(shù)用于設(shè)置GDT中的某一描述符表項為指向進程控制塊中的tss的起始地址。
            set_ldt_seg()函數(shù)用于設(shè)置GDT中的某一描述符表項為指向進程控制塊中的ldt的起始地址。
            我們可以先預(yù)覽一下WinixJ的GDT表的樣子:
            DUMMY
            kernel-cs
            kernel-ds
            unused
            process-0-tss
            process-0-ldt
            process-1-tss
            process-1-ldt
            process-2-tss
            process-2-ldt
            ...
            ...
            process-124-tss
            process-124-ldt
            unused
            unused
            其中每個GDT表項占用8字節(jié),每個進程在gdt表中占用2項---1項是該進程的tss,1項是該進程的ldt。
            ldtr寄存器中的值是ldt選擇子,即相對于GDT起始地址的偏移,據(jù)此它能索引到對應(yīng)的ldt,進而取得對應(yīng)的段基地址。
            posted on 2012-02-14 17:30 myjfm 閱讀(460) 評論(0)  編輯 收藏 引用 所屬分類: 操作系統(tǒng)
            久久笫一福利免费导航| 亚洲国产成人久久综合区| 青青青国产成人久久111网站| 亚洲国产成人久久综合碰碰动漫3d| 久久人人爽人人澡人人高潮AV | 狠狠狠色丁香婷婷综合久久五月| 2022年国产精品久久久久| 久久综合鬼色88久久精品综合自在自线噜噜 | 亚洲AⅤ优女AV综合久久久| 久久精品亚洲一区二区三区浴池| 成人a毛片久久免费播放| 亚洲午夜久久久影院| 人妻中文久久久久| 国产午夜精品久久久久九九电影| 麻豆成人久久精品二区三区免费| 久久精品中文字幕大胸| 久久se精品一区二区影院 | 国产99久久久国产精品~~牛| 777午夜精品久久av蜜臀| 亚洲欧美成人久久综合中文网| 91久久精品无码一区二区毛片| 国产亚洲精品自在久久| 亚洲人成伊人成综合网久久久| 久久一区二区免费播放| 精品国产乱码久久久久久浪潮| 国产精品久久久天天影视| 久久综合九色综合网站| 97久久国产综合精品女不卡| 精品久久久久久中文字幕大豆网 | 好久久免费视频高清| 久久香蕉超碰97国产精品| 亚洲精品无码久久千人斩| 久久久久人妻一区二区三区| 久久国产免费直播| 亚洲精品乱码久久久久久蜜桃不卡| 久久频这里精品99香蕉久| 亚洲国产视频久久| 久久香综合精品久久伊人| 中文无码久久精品| 69国产成人综合久久精品| 伊人色综合久久|