国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

Linux V2.2.X(i386體系結構)進程管理分析

2024-07-21 02:37:30
字體:
來源:轉載
供稿:網友

  linux V2.2.X(i386體系結構)進程治理分析及最大進程數的限制的突破
  進程治理是操作系統最要害的部分,它的設計和實現直接影響到整個系統的性能。在一個多進程的操作系統中,一個時間段內可以有多個進程“并發”執行。這樣就避免了較為快速的cpu等待較為低速的I/O設備的情況,提高了cpu利用率,從而提高系統的性能。另一個方面,同時運行多個進程,就可以同時提供多種服務或者同時為更多的客戶服務,這也是現代操作系統的基本任務。
  
  在基于Intel i386體系結構的Linux操作系統中,已經提供了這樣的多進程運行的支持。通過合理的選擇進程調度算法,可以獲得比較好的平均相應時間和較高的系統性能。但是,美中不足的是,在目前的2.2.x版本的Linux內核中,存在對最大進程數的限制。也就是說,在目前的Linux系統中,最多只能有4090個用戶進程同時存在。對于一般的桌面應用,這個數目是綽綽有余。但是,對于企業級的服務器應用來說,則是不夠的。
  
  設想一個典型的Web服務器軟件,它們一般都采用多進程/線程的結構。每當接到一個連接請求,就產生一個子進程/線程來處理。顯然,對于一個重負載的服務器來說,同時有成千上萬個連接是很常見的。而這時,采用kernel 2.2.x的系統就不能勝任了。因此,可以說正是因為存在這個最大進程數的限制,使得Linux不能勝任企業級服務器操作系統的工作。事實上,目前這個級別的操作系統一般都是較為成熟,并且沒有上述限制的Solaris、AIX、HP-UX等系統。
  
  值得一提的是,眾多的Linux開發者已經熟悉到了這個問題。kernel 2.2.x的后續版本,例如試驗版本2.3.x和2.4都已經著手解決這個問題。然而,現在離2.4的發布還有很長的時間,同時2.4在使用中達到穩定,又需要一段時間。在這一段時間中,我們是不是只有等待或者選用其他系統呢?或者說,能否有一種方案,可以在2.2.x的內核上突破這個進程數的限制呢?
  
  要回答這個問題,就必須先對2.2.x核心的進程治理加以分析。
  
  一、i386體系結構與kernel V2.2.X存儲治理
  
  提到進程治理就必須首先了解基本的i386體系結構和存儲治理。這是因為體系結構決定了存儲治理的實現,而進程治理又與存儲治理密不可分。在現代操作系統中,存儲治理一般都采用虛擬存儲的方式,也就是系統使用的地址空間與實際物理地址空間不同,是“虛擬”的地址。處理器提供一定的機制將“虛擬”的地址轉換為實際的地址。操作系統的存儲治理就是基于處理器提供的地址轉換機制來實現的。
  
  基本的存儲治理有兩種方式,即段式和頁式。段式治理就是將內存劃分為不同的段(segment),通過段指針來訪問各個段的方法。在比較早的系統中,如pdp-11等就是采用這種方法。這種方法的缺點是在設計程序時必須考慮段的劃分,這是很不方便的。頁式治理就是將內存劃分為固定大小的若干個頁面(page),以頁面為單位分配使用。通過頁映射表完成地址轉換。
  
  i386的存儲治理采用兩級虛擬的段頁式治理,就是說它先分段,再分頁。具體地說,它通過gdt(Global Descriptor Table)和ldt(Local Descriptor Table)進行分段,把虛擬地址轉換為線性地址。然后采用兩級頁表結構進行分頁,把線性地址轉換為物理地址。下圖表示了i386中虛擬地址到物理地址的轉換:
  
  在Linux中,操作系統處于處理器的0特權級,通過設置gdt,將它的代碼和數據放在獨立的段中,以區別于供用戶使用的用戶數據段和代碼段。所有的用戶程序都使用相同的數據段和代碼段,也就是說所有的用戶程序都處于同一個地址空間中。程序之間的保護是通過建立不同的頁表映射來完成的。Linux 2.2.x gdt表中的段描述符如下圖所示:
  
  在實際的使用中,用戶程序還可以通過調用設置ldt的系統調用來擁有自己的地址空間。
  
  二、Kernel 2.2.x進程治理
  
  進程是一個程序的一次執行的過程,是一個動態的概念。在i386體系結構中,任務和進程是等價的概念。進程治理涉及了系統初始化、進程創建/消亡、進程調度以及進程間通訊等等問題。在Linux的內核中,進程實際上是一組數據結構,包括進程的上下文、調度數據、信號處理、進程隊列指針、進程標識、時間數據、信號量數據等。這組數據都包括在進程控制塊PCB(PRocess Control Block)中。
  
  Linux進程治理與前面的i386體系結構關系十分密切。前面已經討論了i386所采用的段頁式內存治理的基本內容,實際上,i386中的段還有很多用處。例如,在進程治理中要用到一種非凡的段,就是任務狀態段tss(Task Status Segment)。每一個進程都必須擁有自己的tss,這是通過設置正確的tr寄存器來完成的。根據i386體系結構的定義,tr寄存器中存放的是tss的選擇符(selector),該選擇符必須由gdt中的項(即描述符descriptor)來映射。同樣的,進程的ldt也有這種限制,即ldtr對應的選擇符也必須由gdt中的項來映射。

  
  在kernel 2.2.x中,為了滿足i386體系結構的這種要求,采用了預先分配進程所需要的gdt項目的方法。也就是為每一個進程保留2項gdt條目。進程PCB中的tr和ldtr值就是它在gdt中的選擇符。進程與它的gdt條目的對應關系可以由task數組來表示。
  
  下面是具體的分析。
  
  1.系統初始化
  
  在Linux 2.2.x中,一些與進程治理相關的數據結構是在系統初始化的時候被初始化的。其中最重要的是gdt和進程表task。
  
  Gdt的初始化主要是確定需要為多少個進程保留空間,也就是需要多大的gdt。這是由一個宏定義NR_TASKS決定的。NR_TASKS的值就是系統的最大進程數,它是在編譯的時候被確定的。由圖2可以知道,gdt的大小是10+2+NR_TASKS*2。
  
  進程表task實際上是一個PCB指針數組,其定義如下: StrUCt task_struct *task[NR_TASKS] = {&init_task,};
  
  其中,init_task是系統的第0號進程,也是所有其它進程的父進程。系統在初始化的時候,必須手工設置這個進程,把它加到進程指針表中去,才能啟動進程治理機制。可以看出,這里task的大小同樣依靠于NR_TASKS的定義。
  
  2.進程創建
  
  在Linux 2.2.x中,進程是通過系統調用fork創建的,新的進程是原來進程的子進程。需要說明的是,在2.2.x中,不存在真正意義上的線程(Thread)。Linux中常用的線程pthread實際上是通過進程來模擬的。也就是說linux中的線程也是通過fork創建的,是“輕”進程。fork系統調用的流程如下:
  
  比較要害的步驟是:
  
  a)將新進程的PCB加入到進程表中。從前面的討論可以知道,進程表task的大小是預先定義的,所以首先要從task中找到一個空的表項:nr = find_empty_process()。假如不能找到空的表項,說明系統已經達到了最大進程數的上限,不能創建新進程。返回的nr是空閑表項的下標。
  
  b)將父進程的地址空間復制到子進程中。在這一步中,還要復制父進程的ldt到子進程,然后在gdt中建立子進程的ldt描述符(descriptor),并將這個選擇符保存在PCB中。
  
  為子進程設置tss。同時在gdt中建立子進程的tss描述符,并將這個選擇符保存在PCB中。
  
  3.進程調度 這里我們暫不討論進程調度的算法,只是看一看進程切換時應該做的工作。在Linux 2.2.x中,進程切換是在switch_to函數中完成的。Switch_to基本操作如下: 1) 設置ltr,加載新進程的tss 2) 保存原進程的fs,gs寄存器到它的PCB中。 3) 假如需要,加載新進程的ldt 4) 加載新進程的頁表 加載新進程的fs和gs 以上的tss和ldt的選擇符都是從進程的PCB中取出的。
  
  三、突破最大進程數的限制
  
  1.限制的起因
  
  通過以上的討論,我們可以看出Linux 2.2.x最大進程數限制產生的原因: Linux 2.2.x中定義的宏NR_TASKS,在編譯時靜態決定了X86系統運行時的進程數上限。該數在系統初始化時靜態決定了gdt表的總長度。但因為i386體系結構的特點,全局描述符表寄存器gdtr長度域為16位,每項描述符為8字節,故可容納的 最大描述符數 = 1《(16-3)=1《13 = 8192 個。 內核在初始化時對gdt表的前12 項已有非凡安排,如下所示: 1) 空描述符(第0項),保留描述符(第1,6,7項) 2) 內核代碼、數據段(第2,3項) 及用戶代碼、數據段(第4,5項) 3) APM BIOS 使用段(第8--11項) 同時由于每個進程需要兩項分別存放tss和ldt描述符,因此理論上 可用于進程的數目為 = (8192-12)/2=4090個。
  
  2.解決方案
  
  可見,突破最大進程數的限制,必須解決沒有足夠的gdt表項的問題。Gdt的大小是硬件限制的,所以只能考慮動態地設置進程的tss和ldt描述符,取消為進程預先分配gdt空間的做法。
  
  事實上,根據進程數據結構PCB的分析可知,內核中可以動態地尋址到每個進程的tss 和ldt (假如有的話)段,因此在任務切換時通過PCB指針即可引用上述兩段的尋址,分別為:
  
  進程tss段:proc->tss 進程ldt段:proc->mm->segments
  
  所以,靜態地分配并保留這兩個段的描述符是完全沒有必要的。我們可以在任何需要的時候建立起它們,例如在切換時將該兩段的段描述符動態設置到gdt表中即可。
  
  這種方法的要害在于在gdt中為每個cpu保留兩個描述符,分別存放該cpu上正在運行的進程的tss、ldt描述符。這兩個描述符則是在進程切換時由操作系統根據進程PCB中的內容建立起來的。
  
  3.方案實現
  
  要突破上述4090進程數的限制,需要動態設置進程的TSS及LDT段描述符。具體體現在兩方面:
  
  1)系統初始化: a)在head.S中將靜態設置的GDT表長度置為最大值8192。 b)在desc.h的GDT表定義中,在進程可用的第一項位置插入NR_CPUS*2項,作為每顆C

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 漳平市| 沾化县| 甘孜县| 乐东| 静安区| 平谷区| 扎赉特旗| 镇宁| 洪洞县| 辽阳县| 卫辉市| 宣武区| 静乐县| 桃园县| 淮北市| 罗江县| 吐鲁番市| 平顺县| 白沙| 巴南区| 灵宝市| 务川| 故城县| 周宁县| 万山特区| 石家庄市| 河曲县| 区。| 若羌县| 五寨县| 汪清县| 元江| 宜川县| 酒泉市| 长子县| 合川市| 阜新| 尤溪县| 阳西县| 永胜县| 专栏|