版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
前言操作系統(tǒng)是一種簡潔的系統(tǒng)軟件。本書通過介紹操作系統(tǒng)的根本概念和原理,并結合操作系統(tǒng)原理來分析一個小型但全面的操作系統(tǒng)xv6,并進一步進展各種基于xv6操作系統(tǒng)的試驗,來讓讀者了解和把握操作系統(tǒng)的設計與實現(xiàn)。xv6x86架構的計算機系統(tǒng)上UNIX的教學用操作系統(tǒng)。xv6起源于MIT2023年秋季,F(xiàn)ransKaashoek,JoshCates,andEmilSitMIT開設了一門的試驗型課程“操作系統(tǒng)工程”,英文名稱是“OperatingSystemsEngineering”,課程代號是“6.097”,后改為“6.828”,在此課程上,一開頭承受了“萊昂UNIX源代碼分析”〔英文書名是“Lion”CornmentaryonUNIX6thEditionWithSourceCode”〕UNIXv6〔V6〕PDP-11計算機系統(tǒng)上。為了讓學生更好地理解V6的實現(xiàn),F(xiàn)ransKaashoek等從2023年夏季開頭,參考V6的架構,x86計算機系統(tǒng)上重實現(xiàn)了一個支持多處理器計算機系統(tǒng)的類似UNIX的教學用操作系統(tǒng),xv6MIT本科生課程“6.828:OperatingSystemsEngineering中,xv6主要exokernelJOSxv6MIT的網(wǎng)址在“:///6.828/xv6/“:///6.828/xv6/第零章安裝使用LinuxFUbuntuLinuxUbuntuLinux下編程。編譯[needupdate]UbuntuLinux8.10Capt工具進一步安裝相關軟件包$sudoapt-getinstallgccbinutilslibc6-devgdbxv6軟件包,到某一名目,然后到此名目下執(zhí)行$make就可以生成相關執(zhí)行文件和鏡像,包括xv6.img(bootloaderxv6kernel)fs.img(包含應用程序)運行[needupdate]UbuntuLinux8.10apt工具進一步安裝相關軟件包$sudoapt-getinstallqemubochsbiosvgabioslibsdl1.2debiankvmqemu執(zhí)行,可執(zhí)行如下命令qemu-smp4-parallelstdio-hdbfs.img-hdaxv6.imgkvm執(zhí)行,可執(zhí)行如下命令kvm-smp4-parallelstdio-hdbfs.imgxv6.imgqemukvmB。調試[needupdate]qemuqemudebugger調試〔patch并qemuC源碼級調試〕和gdb遠程調試〔C源碼級調試,缺點是可能會有驚異的問題,對硬件把握不夠。gdb遠程調試的方法如下:aqemu調試方式啟動qemu-S-s -smp2-monitorstdio-hdbfs.img-hdaxv6.imgbgdb啟動并調試gdbkernel(gdb)targetremote:1234(gdb)breakFUNCTION-NAME(gdb)continue...(gdb)quitqemuinternaldebugger調試aqemu啟動命令qemu-smp2-monitorstdio-hdbfs.img-hdaxv6.imgqemu的monitor中可執(zhí)行如下命令進展調試分析x/fmtaddr--virtualmemorydumpstartingat”addr”infocpus--showinfosforeachCPUinforegisters--showthecpuregisterssinglestepsinglestap_enabled--togglesinglestepmodebreakpoint_insertaddr--insertbreakpointbreakpoint_removeaddr--removebreakpointbreakpoint_show--showbreakpointwatchpoint_insertaddrtype--insertwatchpointtype0=read1=writewatchpoint_removeaddr--removewatchpointwatchpoint_show--showwatchpointwhere--showcallsstack第一章總體構造和系統(tǒng)組成本章將給出xv6啟動實現(xiàn)的概貌。讀者將學習以下一些內容:操作系統(tǒng)是什么?xv6是如何產(chǎn)生的?xv6的總體構造是什么?xv6包含哪些重要的組成局部?操作系統(tǒng)是一種軟件,操作系統(tǒng)沒有一個準確和統(tǒng)一的定義。操作系統(tǒng)是一種比較簡潔的軟件,我們可以從多種角度來了解操作系統(tǒng)。從操作系統(tǒng)的任務來看,操作系統(tǒng)的任務主要是把握和治理計算機系統(tǒng)中的硬件資源并對應用軟件和用戶供給各種便利使用計算機的功能。通過操作系統(tǒng),能有效地組織和治理計算機系統(tǒng)中的硬件資源和其他軟件資源,向用戶和應用軟件供給各種效勞功能,使得用戶和應用軟件能夠靈敏、便利、有效地使用計算機,并使整個計算機系統(tǒng)能高效地運行。從操作系統(tǒng)在計算機系統(tǒng)中的實現(xiàn)層次上看,操作系統(tǒng)位于計算機硬件之上,應用軟件之下。由于操作系統(tǒng)是一個簡潔的軟件系統(tǒng),為了能夠更好地設計和實現(xiàn)操作系統(tǒng),我們可以從功能上對操作系統(tǒng)進展分解,可把操作系統(tǒng)分解為系統(tǒng)調用、進程調度、內存治理、中斷處理、文件系統(tǒng)和設備治理等功能模塊,在具體實現(xiàn)上可承受模塊化、層次化和面對對象等設計方法來設計實現(xiàn)操作系統(tǒng)。OS組成構造圖[needtoupdate]。要了解xv6,首先我們需要了解操作系統(tǒng)的一些根本概念(請參考A)xv6〔xv6-rev2版本〕是一個支持對稱多處理器(SMP)的類Unix系統(tǒng)。它包含操作系統(tǒng)一些最根本的要素,包括系統(tǒng)調用、進程調度、內存治理、中斷處理和文件系統(tǒng)等。xv6xv6UNIX操作系統(tǒng)設計思路。簡潔地說,xv6基于扁平內存治理的層次型單體內核,應用程序和操作系統(tǒng)是處于不同的特權狀態(tài)和地址空間。代表應用程序的用戶態(tài)進程運行在CPU的用戶態(tài)〔又稱非特權模式,用戶模式,無法直接訪問系統(tǒng)硬件和操作系統(tǒng)中的系統(tǒng)數(shù)據(jù),而操作系統(tǒng)運行在CPU的核心態(tài)〔又稱特權模式,內核模式,可以訪問系統(tǒng)硬件和核心數(shù)據(jù)。下面分別從系統(tǒng)調用接口、進程/文件系統(tǒng)、I/O系統(tǒng)調用是應用程序訪問操作系統(tǒng)的接口。在系統(tǒng)調用接口上,通用操作系統(tǒng)與基于此操作系統(tǒng)的應用程序處于兩個不同的CPU特權態(tài),操作系統(tǒng)處于核心態(tài),而應用程序處于用戶態(tài)。在核心態(tài)可以執(zhí)行CPU特權指令,而用戶態(tài)無法執(zhí)行特權指令,且只能通過特定的指令或中斷來訪問操作系統(tǒng)供給的各種功能。這在確定程度上保證了系統(tǒng)整體的安全,避開應用程序對操作系統(tǒng)可能的破壞。在內存治理方面,通用操作系統(tǒng)承受了虛擬內存治理方式,這樣可以讓內存需求超過實際物理內存的進程/線程能夠執(zhí)行,其主要思想是把重要和常用的數(shù)據(jù)和執(zhí)行代碼放在物理內存中,把不常用的數(shù)據(jù)和執(zhí)行代碼放到二級存儲〔這里主要指的是硬盤等可在掉電后保存數(shù)據(jù)的存儲介質同內存區(qū)域的保護,不同進程之間,或者應用程序和操作系統(tǒng)之間的地址空間相對隔離。這樣一般狀況下不同進程的地址空間不能直接訪問,且應用程序不能直接訪問內核地址空間。所以一個與錯誤的應用程序不會導致系統(tǒng)的崩潰,從而增加了系統(tǒng)的牢靠性。xv6操作系統(tǒng)沒有承受X86段模式的單一地址空間治理方式。在內存安排和釋放的治理上,xv6相對實現(xiàn)得比較簡潔,承受基于可變分區(qū)安排的首次適配算法,簡潔產(chǎn)生內存碎片。在進程/線程治理方面,當前通用操作系統(tǒng)結合虛存治理,承受進程和線程結合的治理方式。進程代表了一個程序執(zhí)行的過程以及其所占用的計算機資源〔包括CPU、內存、文件等,進程的執(zhí)行流可用線程來表示。操作系統(tǒng)的調度單位可以是進程或線程。一個進程可以包含多個線程,屬于同一進程的多個線程共享進程治理的資源,比方屬于同一進程的多個線程共享進程所治理的內存,這樣這些線程可以直接訪問屬于進程的全局地址空間。xv6操作系統(tǒng)實現(xiàn)了一個基于進程〔沒有實現(xiàn)線程〕的簡潔進程治理機制。在文件系統(tǒng)治理方面,當前通用操作系統(tǒng)結合虛存治理,實現(xiàn)了多種簡潔、高效且牢靠的文件系統(tǒng),且建立了一個統(tǒng)一的虛擬文件系統(tǒng)層,屏蔽不同文件系統(tǒng)的差異,對上層供給統(tǒng)一的接口。且與用戶治理和進程治理結合,可實現(xiàn)安全治理,保證對文件的安全訪問。xv6操作系統(tǒng)inode索引方式的文件系統(tǒng)。在I/O治理方面,xv6操作系統(tǒng)與通用操作系統(tǒng)〔特別是類UNIX操作系統(tǒng)〕差異不是特別大,都把設備“看成”是一種特別的設備文件,有設備號,用文件的訪問接口來進展翻開、關閉、讀、寫和把握等操作。在靈敏性方面,xv6驅動程序不能象通用操作系統(tǒng)那樣依據(jù)硬件狀況動態(tài)加載,而是在編譯時候就靜態(tài)確定的。xv6總體架構從操作系統(tǒng)模型上來看,xv6是一個單地址空間的層次式單體內核,不是微內核〔microkernel〕模型的操作系統(tǒng)〔如Mach,QNX,與通用操作系統(tǒng)〔如Linux〕空間和特權模式上也有確定的差異。下面主要分進程調度、內存治理、同步互斥、文件系統(tǒng)幾xv6進展介紹。同步互斥SMPCPU中都是共享的,所以在需要某xv6spinlock,從而可以對共享CPU數(shù)量。內存治理在內存治理方面,xv6承受了段式虛擬內存的治理方式。每個用戶進程所占用的內存都是在一個連續(xù)的段中。用戶進程內存的分布為:代碼段、靜態(tài)變量段、固定大小的棧和可變大小的堆空間。由于進程內存是依據(jù)段治理的,因此在每次安排進程內存時,xv6進程治理SMPCPU執(zhí)行CPUCPU的操作系統(tǒng)治理問題,具體包括假設創(chuàng)立進程、如何刪除進程、選擇哪個進程占用哪個CPU,何時進展進程切換,進程能夠持續(xù)占用CPU的時間片段的大小設定等。在xv6中,首先其進程是基于時間片來調度的。每次進程的調度是由時鐘中斷產(chǎn)生的,或者是因當CPU之間都共享一個進程池〔具體實現(xiàn)為一個全局數(shù)組,其中有全部待運行的進程。在每個時間片中,CPU文件系統(tǒng)xv6中供給了一個簡潔的文件系統(tǒng),這個文件系統(tǒng)供給了大多數(shù)POSIX標準的接口。由于這個文件系統(tǒng)比較簡潔,其中一個文件最多由(12+128)也被限制在(12+128)*512Bytes。在這個文件系統(tǒng)中供給了一個Buf層,用來緩存磁盤上的數(shù)據(jù)。但是此文件系統(tǒng)是寫直達的,因此每次更都會直接寫到磁盤上。中斷治理和系統(tǒng)調用治理[NTU]外設治理[NTU](boot)概述本章將給出xv6啟動實現(xiàn)的概貌。讀者將學習以下一些內容:bootloader是什么?bootloader做了哪些事情?xv6是如何被加載并啟動的?xv6的初始內存治理是如何實現(xiàn)的?xv6的初始中斷治理是如何實現(xiàn)的?xv6如何實現(xiàn)內核態(tài)到用戶態(tài)的轉變的?xv6啟動用戶態(tài)進程前需要完成哪些事情?xv6如何創(chuàng)立并啟動第一個用戶態(tài)進程?當計算機加電后,一般不直接執(zhí)行操作系統(tǒng),而是執(zhí)行引導加載程序。簡潔地說,引導加載程序就是在操作系統(tǒng)內核運行之前運行的一段小程序。通過這段小程序,我們可以初始化硬件設備、建立系統(tǒng)的內存空間映射圖,從而將系統(tǒng)的軟硬件環(huán)境帶到一個適宜的狀態(tài),以便為最終調用操作系統(tǒng)內核預備好正確的環(huán)境。最終引導加載程序把操作系統(tǒng)內核映像加載到RAM中,并將系統(tǒng)把握權傳遞給它。對于絕大多數(shù)計算機系統(tǒng)而言,操作系統(tǒng)和應用軟件是存放在磁盤〔硬盤/軟盤、光盤、EPROM、ROM、Flash等可在掉電后連續(xù)保存數(shù)據(jù)的存儲介質上。計算機啟動后,CPU一開頭會到一個特定的地址開頭執(zhí)行指令,這個特定的地址存放了系統(tǒng)軟件〔不僅是操作系統(tǒng),還可能是引導加載程序等。引導加載程序(bootloader)PC386PCBIOS(BasicInputOutputSystem,即根本輸入/輸出系統(tǒng),其本質Flash/CMOS上的軟件)和位于軟盤/OSBootLoader一起組成。BIOS實際上是被固化在計算機ROM〔只讀存儲器〕芯片上的一個特別的軟件,為上層軟件BIOS就是PC計算機硬件與上層軟件程序之間的一個“橋梁“,負責訪問和把握硬件。以PC386為例,計算機加電后,CPU從物理地址0xFFFFFFF0〔由初始化的CS:EIP確定,此時CSIP0xF0000xFFF0)〕開頭執(zhí)行。在0xFFFFFFF0這里只是存放了一條跳轉指令,通過跳轉指令跳到BIOS例行程序起始點。BIOS做完計算機硬件自檢和初始化后,會選擇一個啟動設備〔例如軟盤、硬盤、光盤等個特定的地址0x7c00處,然后CPU把握權會轉移到那個地址連續(xù)執(zhí)行。至此BIOS的初始化工作xv6。xv6系統(tǒng)的啟動流程大致是這樣的:做為多處理系統(tǒng),啟動是首先從一個CPU的啟動CPUBIOSOSBootLoader從磁盤上〔一般是位于第一個扇區(qū)〕拷貝到內存當中。當BIOSBootLoaderBootLoaderCPUCPU將把啟動代碼拷貝到內存中,然后喚起其他CPU執(zhí)行這一段代碼,完成它們的初始化過程。xv6的源碼中,整個啟動過程主要牽涉到如下幾個文件:bootloaderbootasm.Sbootmain.cxv6初始化模塊main.cbootother.S下面將針對這些文件進展分析,對啟動過程分成兩局部進展介紹。代碼分析bootloader代碼分析bootloader的組成makefile50行~56行有如下語句50: bootblock:bootasm.Sbootmain.c51: $(CC)$(CFLAGS)-O-nostdinc-I.-cbootmain.c52: $(CC)$(CFLAGS)-nostdinc-I.-cbootasm.S53: -N-estart-Ttext0x7C00-obootblock.obootasm.obootmain.o54: $(OBJDUMP)-Sbootblock.o>bootblock.asm55: $(OBJCOPY)-S-Obinarybootblock.obootblock56: ./sign.plbootblockbootloader包含兩個文件,bootasm.Sbootmain.c。生成的bootloader會寫到一個主引導扇區(qū)上面。作為主引導扇區(qū),其位置在軟盤或硬盤的第一個扇區(qū),其大小為512個字節(jié),在此扇區(qū)的最終兩個字節(jié)是一個主引導扇區(qū)特征碼為”55AA”。Makefile的51行和52gccbootmain.cbootasm.Sbootmain.obootasm.o。Makefile53ldbootmain.obootasm.o鏈接成目標文件bootblock.o,且定義了起始執(zhí)行的點〔也稱入口點〕為start函數(shù),具體的代碼段起始地址為0x7C00[Q]大家還0x7C00這個特別的地址的含義嗎?Makefile54行是通過objdumpbootblock.obootlock.asm。Makefile55objcopy程序把bootblock.o變成二進制碼bootlock。[Q]bootlock的大小可以大于512字節(jié)嗎?Makefile的56sign.pl程序把bootlock512個字節(jié),并把最終兩個字節(jié)寫成”55AA”。[小試驗]xv6.img512個字節(jié)取出來,反匯編它的內容,并與bootasm.S和bootmain.c的內容〔bootblock.asm〕進展比較,512個字節(jié)的最終兩個字節(jié)的內容是否是“55AA”代碼分析bootloader的啟動主要涉及到bootasm.S、bootmain.c。其中bootasm.S的主要作用是從實模bootmain的作用是把內核從磁盤拷貝到內存中。bootasm.S在進入實模式向保護模式切換之前,首先需要把中斷關閉(“cli“atline15),保證轉換過程不被硬件中斷打斷。19~22DS,ES,SS進展清零。20~42(A20地址線)[歷史]在8086年月,8086供給了20跟地址線,那么供給的可尋址空間范圍即0~2^20(00000H~FFFFFH)的1M8086的數(shù)據(jù)處理位寬位16位,8086供給了段地址加偏移地址的地址轉換機制,就是我們常見的”段地址:偏移地址(或有效地址)”,實際的計算方法為:”段地址*10H+偏移地址”,作為段地址的數(shù)據(jù)是放在段存放器中的(16位),而座位偏移地址的數(shù)據(jù)則是通過8086供給的尋址方式來計算而來的(16位)。而“段值:偏移”這種表示法能夠表示的最大內存為10FFEEh(FFFF0 + FFFF),所以當尋址到超過1MB的內存時,會發(fā)生“回卷”〔不會發(fā)生特別。但是到了80286供給了24根地址線,cpu的尋址范圍變?yōu)?^24=16M,同時也供給了保護模式,真的可以訪問到1MB以上的內存了,此時假設遇到“尋址超過1MB”的狀況,系統(tǒng)不會再“回卷”了,這就造成了向上不兼容。為了保持完全的兼容性,IBM打算在PCAT系統(tǒng)上加個規(guī)律,來仿照以上的繚繞特征。他們的方法就是把A20和鍵盤把握器的一個輸出進展AND,這樣來把握A20的翻開和關閉。一開頭時A20是被屏蔽的〔總為0,直到系統(tǒng)軟件去翻開它。留意A20而非A20~A31被把握,所以在A20關閉時會發(fā)生一些好玩的副作用。就是在訪問奇當A20Gate制止時,則程序就像在8086中運行,100000h~100FFEFh的地是不行訪問的。A20Gate是要翻開的。為了使能全部地址位的尋址力氣當A20Gate制止時,則程序就像在8086中運行,100000h~100FFEFh的地是不行訪問的。A20Gate是要翻開的。為了使能全部地址位的尋址力氣,必需向鍵盤把握器8042發(fā)送一個命令。鍵盤把握器8042將會將它的的某個輸出引腳的輸出置高電平,作為A20門的輸入。一旦設置成功之后,內存將不會再被繞回(memorywrapping),這樣我們就可以尋址整個286的16M內存,或者是尋址803864G內存了。8042IO0x60~0x6fIBMPC/AT使用的只有0x60和0x64兩個端口〔0x61、0x62和0x63用于與XT兼容目的。8042通過這些端口給鍵盤把握器或鍵盤發(fā)送命令或讀取狀態(tài)。輸出端口P2用于特定目的。位0〔P20引腳〕用于實現(xiàn)CPU復位操作,位1〔P21引腳〕用戶把握A20信號線的開啟與否。系統(tǒng)向輸入緩沖〔端口0x64〕寫入一個字節(jié),即發(fā)送一個鍵盤把握器命令??梢詭б粋€參數(shù)。參數(shù)是通過0x60端口發(fā)送的。命令的返回值也從端口0x60去讀。圖Intel8042芯片或其兼容芯片的規(guī)律示意圖28~31I/O0x64I/O0x641位〔0位〕00x64busy10為止。33~340xd1I/O0x64;0xd1命令是寫輸出端口,bit0是復位,bit1是GateA20.36~39I/O0x64I/O0x641位〔最低位為第0位〕00x64busy10為止。41~420xdfI/O0x60;0xdfA20至此,A20地址線已經(jīng)使能。48行,“l(fā)gdtgdtdesc“gdtdesc中給出了段表有效大小,和所在地址(gdt)gdt01段是21、2段的范圍都是0x0~0xffffffff。在第49~51行中,通過將CR0的第0位置1,把保護模式設置為翻開。但此時段模式并沒有55ljmpcs變成$PROT_MODE_CSEG所指向的段〔8>>3=1,gdt1段,即代碼段ljmp后,32位模式。59~65gdt2段,即數(shù)據(jù)段。bootmain.c68行,將棧頂指針指向$start坐在位置即(0x7c00)69bootmain過程,進展內核的加載。bootmain.c在這個文件中主要有四個函數(shù):bootmain、waitdisk、readsect和readseg。其中bootmain是加載內核,其余三個都是對磁盤進展訪問的程序。waitdisk、readsectreadsegreadsegoffset處開頭countvareadsect以扇區(qū)為單位進展的。因此在88行保證va是從一個扇區(qū)起始位置開頭,因此要對va進展對齊。readsect是對磁盤進展讀取,waitdisk等待磁盤的預備過程,一旦磁盤預備好后就可以進展讀取了。然后看一下bootmain過程。bootmain的目的是從磁盤中加載內核到內存中,其中內核是以ELF執(zhí)行文件格式存在磁盤上的。首先將從磁盤讀取一頁大小(8*512B=4KB)的信息,其中包含了ELF(34~37行。當完成拷貝后,bootmain獵取內核入口程序的地址(見40~41行,然后進入該入口(即main.c中的main函數(shù))。操作系統(tǒng)初始化模塊代碼分析操作系統(tǒng)初始化模塊代碼分析操作系統(tǒng)的啟動局部包含如下文件main.cbootother.Smain.cmain.c的作用是進展對系統(tǒng)各方面的初始化工作,然后喚起其他CPU的初始化。首先我們看processtablebuffercachePICinterruptcontrollerIOAPICinterruptcontrollerphysicalmemoryallocatortrapvectorsfiletableinodecacheconsoledevice&interruptIDEprocesstablebuffercachePICinterruptcontrollerIOAPICinterruptcontrollerphysicalmemoryallocatortrapvectorsfiletableinodecacheconsoledevice&interruptIDEdevice&interrupttimer〔onlyforuniprocessor〕firstuserprocess這些將在后面的文章具體介紹。在初始話內存、中斷表、文件系統(tǒng)、I/O設備等之后,第一個CPUbootothersCPUbootothers之前,第一個用戶進程將通過userint進展初始化。在初始化其他AP后,將進入scheduler過程。scheduler過程CPU的進展進程調度的,這將在以后進展爭論。bootothersbootstrapCPUCPU進展啟動。啟動時這樣進展的,首先把bootother.S的代碼拷貝到0x7000起始的這塊內存里。bootother.S然后在0x7000-4、0x7000-8兩個內存單元記錄下bootother.S中將要進展跳轉的內核棧位置以及mpmainCPUbootother.Smpmain過程。在mpmain中,每個CPU將進展中斷表和段表的初始化,然后翻開中斷進入scheduler過程。bootother.Sbootother.SCPUMakefile5862行:58:bootother:bootother.S59: $(CC)$(CFLAGS)-nostdinc-I.-cbootother.S60: $(LD)$(LDFLAGS)-N-estart-Ttext0x7000-obootother.outbootother.o61: $(OBJCOPY)-S-Obinarybootother.outbootother62: $(OBJDUMP)-Sbootother.o>bootother.asm可以了解到:Makefile59gccbootother.Sbootother.o。Makefile60ldbootother.o進展地址重定位,start,起始地0x7000bootother.out。Makefile61objcopy把bootother.outbootother。Makefile62objdumpbootother.obootother.asm。bootother.S的執(zhí)行內容格外類似之前的bootasm.S。在這個文件中晚啟動的CPU將會進展從實模式到保護模式的轉化〔4249行。然后重設段存放器〔5459行kernelmpmain〔61-63行[Q]這個棧的內容是什么?(spinlock)概述本章將給出xv6同步互斥實現(xiàn)的概貌。讀者將學習以下一些內容:什么是競爭狀態(tài)?什么是互斥?什么是同步?[NUD]xv6中的臨界區(qū)代碼是什么?xv6是怎樣處理臨界區(qū)代碼的?當兩個或多個線程在執(zhí)行一些關鍵性的臨界區(qū)代碼時〔如對共享資源的訪問們不會相互阻礙?當線程之間存在著某種依存關系時,如何來調整它們的運行次序?當線程經(jīng)常需要與其它線程進展通信,那么如何依據(jù)需要供給有效的通信手段?這實際上需要操作系統(tǒng)供給同步互斥與通信的手段才能解決上述問題。任何為進程所占用的實體都可稱為資源。資源可以是CPU、內存,也可以是I/O設備,還可以是一個變量,一個構造或一個數(shù)組等??梢员灰粋€以上進程使用的資源叫做共享資源。為了防止數(shù)據(jù)被任憑訪問〔特別是執(zhí)行寫操作這叫做互斥〔mutualexclusion。需要互斥訪問的共享資源稱為臨界資源。假設兩個或多個進程對同一共享資源同時進展讀寫操作,而最終的結果是不行推想的,該結果取決于各個進程具體運行狀況。則稱此狀態(tài)為競爭狀態(tài)〔racecondition問,可能導致競爭狀態(tài)的消滅。我們把可能消滅競爭態(tài)的程序片斷稱為程序臨界區(qū)。程序臨界區(qū)在處理時不行以被中斷,要保證其操作的原子性。為確保臨界區(qū)程序執(zhí)行過程中不被中斷,在進入臨界區(qū)之前要屏蔽中斷,而臨界區(qū)代碼執(zhí)行完以后要馬上使能中斷,以削減對中斷處理延遲的影響。Spinlock的引入是為了進展資源的互斥訪問。在SMP架構下,每個CPU的權限都是一樣的,但是某些狀況下,一個CPU需要對資源進展獨占,此時就可以通過spinlock來進展。spinlockCPUxchg完成的。具體的實現(xiàn)方法如下。2.2.代碼分析spinlock.hspinlock構造的定義如下:structspinlock{structspinlock{uintlocked;//Isthelockheld?//Fordebugging:char*name;intlock.cpu;//Nameoflock.//Thenumberofthecpuholdingtheuintpcs[10]; //Thecallstack(anarrayofprogramcounters)//thatlockedthelock.};locked變量,這個用來表示當前鎖是否被鎖上。其他的變量name,cpu和pcsname記錄鎖的用途,cpucpu取得了這把鎖,pcs記錄了獲得這把鎖時的棧的內容。spinlock.cspinlock.cspinlock的各種操作:初始化、獵取鎖,釋放鎖等。我們依次閱讀文件中的每個過程。初始化鎖initlockname、lockedcpu三個域。cpu0xffffffff,cpu全部。獵取鎖acquire過程是獵取鎖(lock)28~29pushcli屏蔽中斷,檢查當前鎖是否CPUcliCPU的中斷關閉(CPU的中斷并不受到影響,而且其他軟中斷也并沒有被關閉35while將直到成功獵取鎖為止。在35cmpxchg去獵取鎖。其指令格式為:xchg(va,newvalue)。作用是交換內存地址vanewvaluevaxchglocked=0表示這把xchg(va,1)0whilewhile循環(huán)中打轉。跳出while表示獲得了鎖,42CPUID。43getcallerpcs記錄獲得鎖時的函數(shù)調用棧。釋放鎖releaseCPU拿到這把鎖,假設不是,則報錯;假設是,那CPUCPU已經(jīng)沒有拿popcli將中斷翻開。第四章內存治理概述本章將給出xv6內存治理實現(xiàn)的概貌。讀者將學習以下一些內容:xv6如何進展內存治理初始化的?xv6的靜態(tài)內存安排的空間包括什么?xv6的動態(tài)內存安排的空間包括什么?xv6的動態(tài)內存安排是如何實現(xiàn)的?xv6的動態(tài)內存安排的空間?內存治理機制是實時操作系統(tǒng)的重要組成局部。xv6不支持虛擬存儲治理,不支持簡潔的段頁式的保護機制,而承受線性編址方式,即規(guī)律地址和物理地址一一對應的平面模式。這樣沒有虛擬存儲治理供給的不受限于物理內存大小的大地址空間、地址保護等功能。xv6同時支持靜態(tài)內存安排和動態(tài)內存安排兩種治理方式。靜態(tài)內存安排是指在編譯或鏈接時將應用所需的內存空間安排好。承受這種安排方案的xv6內核映像所占內存空間〔代碼段和數(shù)據(jù)段等〕的大小一般在編譯時就能夠確定,中斷向量表等其它區(qū)域所占用的內存空間大小是個定值。這樣承受靜態(tài)的內存安排機制,在編譯時就可以確定xv6而動態(tài)內存安排是指系統(tǒng)運行時依據(jù)應用需要動態(tài)地安排內存。動態(tài)內存安排的實現(xiàn)機制靈敏,給程序實現(xiàn)帶來極大的便利,有的應用環(huán)境中動態(tài)內存安排甚至是必不行少的。xv6xv6.img所在內存的末尾開頭,增加一塊1MB1MBxv6中動態(tài)安排和釋放。在初始化完動態(tài)內存空間后的內存布局如下:代碼分析kalloc.c動態(tài)內存治理初始化內存空間初始化工作由函數(shù)kini完成,執(zhí)行完kinit后,內存布局如下所示:bootloaderx0x10000mainkalloc.c文件中的kinit函數(shù)對內存進展初始化。其執(zhí)行流程如下:initlockkalloc_lock〔32行〕endstartstart指針startxv6所治理的空閑區(qū)域的起始地址〔3334行〕2564Kkfreestart指針指向的地址為256*4*1024〔3537行〕動態(tài)內存安排與釋放kalloc.ckfree是回收一段內存,而kalloc是安排一段內存。xv6的內存治理是格外簡潔的。由于內存安排是以連續(xù)的段的方式進展的,通過單鏈表方式鏈接空閑的段。因此經(jīng)過確定時間的安排,空閑空間將由一個個地址不連續(xù)的段組成。xv6用freelist將其按起始地址從左至右排列串起來。每次回收時,將回收的段參與段序列中。假設覺察參與段之后能夠合并,則將其合并成一個段。當進展安排時,則遍歷整個鏈表,直到找到一個比需求大的段,則將相應的段安排出去。初始化后第一次安排N次安排和釋放后第五章進程治理與調度概述本章將給出xv6進程治理實現(xiàn)的概貌。讀者將學習以下一些內容:什么是進程?xv6的進程治理數(shù)據(jù)構造〔進程把握塊,PCB〕包含哪些內容?xv6是如何組織進程治理數(shù)據(jù)構造?xv6如何進展進程治理初始化的?xv6怎樣啟動多進程的(即需要做哪些初始化工作)?xv6何時進展進程調度?xv6是如何調度進程的〔CPU運行〕?xv6是如何完成進程切換的?xv6如何啟動并執(zhí)行用戶態(tài)的進程的?進程的概念程序與進程的概念是不行分的。當用戶在計算機上運行一個程序時,此程序對應的進程就誕生了,并實際完成各種程序供給的功能,而用戶關閉一個程序時,進程也隨之終止。程序是為了完成某項任務編排的語句序列,它要告知計算機如何執(zhí)行,因此程序是需要通過CPU來運行的,且在程序的運行過程中需要占有計算機的各種資源〔比方內存等〕才能運行下去。假設計算機系統(tǒng)在任一時刻限制只有一個程序在運行,則程序在整個運行過程中獨占計算機中的全部資源,這樣整個程序運行和治理就簡潔了。就象在一個家中只住了一個人A,他想看書就到書房去看書,想睡覺就到睡房的床上去睡覺,想看電視就到電視廳看電視,想吃飯就去餐廳吃飯,沒人和他搶占資源。但為了提高計算機系統(tǒng)的資源利用率,需要支持多個程序并發(fā)執(zhí)行。這就會帶來很多的問題,如資源的共享與競爭,同步與互斥等。比方此人與B成家并有了小孩C,那就是三口之家同時住一套房,當A想去看足球競賽直播電視節(jié)目的時候,假設覺察電視廳已經(jīng)有B在坐著看連續(xù)劇電視節(jié)目了,A就得等待或干別的事情。除非A并在另外一個房間看他的球競賽直播。由于程序是靜態(tài)的,我們看到的程序是存儲在存儲介質〔如硬盤、光盤等〕上的,它無法反映出程序執(zhí)行過程中的動態(tài)特性,而且程序在執(zhí)行過程中會不斷申請資源或釋放資源,這樣讓程序作為共享資源的根本單位是不適宜的,所以需要引入一個概念,它能描述程序的執(zhí)行過程而且可以作為共享資源的根本單位,這個概念就是進程。簡潔地說,一個進程是一個具有確定獨立功能的程序在一個數(shù)據(jù)集合上的一次動態(tài)執(zhí)行過程。每個進程都是整個應用的某一局部。操作系統(tǒng)在規(guī)律上維護了進程的運行狀態(tài)信息,即與進程CPU存放器和棧空間〔只有這樣才能實現(xiàn)進程切換。操作系統(tǒng)依據(jù)當前進程的狀況設置進程的狀態(tài),并依據(jù)進程的狀態(tài)〔比方優(yōu)先級〕CPU并運行,這個過程成為調度。進程的狀態(tài)進程從誕生到死亡要經(jīng)受假設干個階段,也會有生老病死。簡潔地說,進程有三種狀態(tài):就緒、執(zhí)行、等待。多種緣由可以導致創(chuàng)立一個進程,比方,當操作系統(tǒng)把一個程序從硬盤調入內存后,在開頭執(zhí)行前,操作系統(tǒng)就要為此程序創(chuàng)立一個對應的進程。又比方,一個進程可以自己創(chuàng)立一個子進程,子進程被創(chuàng)立后就是在內存中,處于就緒態(tài),所謂就緒態(tài)就是萬事具備,只CPUCPU,就可以執(zhí)行實際的工作了,其狀態(tài)就變成了執(zhí)行態(tài);進程在執(zhí)行中假設需要等待某個資源〔如等硬盤輸入數(shù)據(jù)CPU,且其狀態(tài)就變?yōu)榈却龖B(tài),這時操作系統(tǒng)又會從處于就緒態(tài)的另一個進程中選擇一個進程占有CPU,則這另一個進程的狀態(tài)就變成了執(zhí)行態(tài)。當前一個進程所等到數(shù)據(jù)到來后,處于等待態(tài)的前一個進程又被喚醒,并把狀態(tài)變成為就緒態(tài)。xv6中,進程具有多種狀態(tài),包括:EMBRO,SLEEPING,RUNNABLE,RUNNINGZOMBIEproc.h文件中:enumproc_state{UNUSED,EMBRYO,SLEEPING,RUNNABLE,RUNNING,ZOMBIE};狀態(tài)的含義如下:UNUSED:進程未被創(chuàng)立〔即進程把握塊空閑〕時的狀態(tài);EMBRYO:需要安排一個進程把握塊且找到一個處于UNUSED狀態(tài)的進程把握塊時,把此進程把握塊狀態(tài)設置為要使用的狀態(tài);SLEEPING:進程由于等待某資源等緣由無法執(zhí)行,進入睡眠狀態(tài),即等待態(tài);RUNNABLE:進程獲得了除CPU之外的全部資源,處于可運行狀態(tài),即就緒態(tài);RUNNINGCPU,正在運行的狀態(tài),即執(zhí)行態(tài);ZOMBIE:進程完畢的狀態(tài)5.1〔左〕SMPCPU獵取進程調度的權利是一樣的。CPUscheduler里面進展輪詢操作,每次從線程池中選擇一個RUNNABLE的進程進展運行。直到運行完畢,或一單位時間片完畢,或者進程主動yield或sleep。CPU5.1〔右〕所示。5.1狀態(tài)轉換的過程[即哪些大事促使了狀態(tài)的轉換TODO]進程把握塊程序的運行是通過進程表達的,操作系統(tǒng)對進程進展治理和把握,那么操作系統(tǒng)怎么了解到CPU的現(xiàn)場保存在那呢?這實際是通過進程把握快〔ProcessControlBlock,簡稱PCB。PCB是進程的唯一標志,在PCB感知進程的存在,通過PCBxv6CPU共享一個進程把握塊池,即源代碼proc.cproc〔即進程把握塊〕類:一類是未使用的進程把握塊構造,另一類是正在使用的進程把握塊構造。每次要創(chuàng)立一個進程時,只需要從進程把握塊數(shù)組中取得一個未使用進程把握塊構造進展相應的處理即可。代碼分析構造與變量構造與變量proc.h文件中定義了幾個關鍵的數(shù)據(jù)構造。其中context是在內核進展上下文切換需要保存的存放器〔定義在proc.h中:structcontext{inteip;intesp;intebx;intecx;intedx;intesi;intedi;intebp;};[Q]eax?proc構造描述了進程運行需要的數(shù)據(jù):structproc{char*mem;processmemory(kerneladdress)uintsz;ofprocessmemory(bytes)char*kstack;kernelstackforthisprocessenumproc_statestate;intpid;ProcessID
//Processstate
//Startof//Size//Bottomof//structproc*parent;void*chan;zero,sleepingonchanintkilled;Ifnon-zero,havebeenkilledstructfile*ofile[NOFILE];structinode*cwd;structcontextcontext;structtrapframe*tf;interruptcharname[16];(debugging)};
//Parentprocess//Ifnon-////Openfiles//Currentdirectory//Switchheretorunprocess//Trapframeforcurrent//Processname其中:其中:memmem記錄了進程在內核的起始地址;sz是記錄進程所占有的內存空間大?。籯stack是進程在內核態(tài)的棧;state是進程的狀態(tài);pidID;chanNULL時,是進程睡眠時所掛的睡眠隊列;killed0時,表示進程被殺死了;ofile數(shù)組是進程翻開的文件數(shù)組;cwd是進程運行時所處的當前名目;context是切換進程需要維護的硬件存放器內容;tf是中斷進程后,需要恢復進程連續(xù)執(zhí)行所保存的存放器內容;name保存了進程的名字〔用于調試。進程在內存中的布局如下:expandableheapexpandableheap〔堆〕fixed-sizestack〔?!硂riginaldataandbss〔數(shù)據(jù)〕Text〔代碼〕proc[NPROC]數(shù)組〔proc.c11行〕xv6所能夠支持的進程所需的相關數(shù)據(jù),NPROCxv6可支持進程個數(shù)。cpuCPU的相關信息:structcpu{ucharapicid;LocalAPICIDstructproc*curproc;running.structcontextcontext;schedulerstructtaskstatets;tofindstackforinterrupt////Processcurrently//Switchheretoenter//Usedbyx86structsegdescgdt[NSEGS];volatileuintbooted;started?intncli;//Depthofpushcliintena;//x86globaldescriptortable//HastheCPU//Wereinterruptsenabledbeforepushcli?};其中:apicidCPUid編號;curprocCPU上運行的進程把握塊;context[] ;ts是Taskstatesegment,用于在中斷時找到棧[] ;gdt是此CPU的全局描述符表〔GDT;bootedCPU已經(jīng)啟動了;nclipushcli函數(shù)的次數(shù);intena表示[] ;全局變量進程數(shù)組proc[NPROC]數(shù)組就是進程池。進程池訪問鎖proc_table_lockspinlock是用來保護對進程池的臨界區(qū)訪問。當前運行進程curproccpu當前運行的進程。第一個進程initproc是記錄第一個創(chuàng)立的進程。這個進程格外特別,它將托管全部沒有父進程的進程〔也就是父進程先于子進程完畢。下一進程號nextid是用來產(chǎn)生進程號的,在系統(tǒng)啟動后會始終保持遞增。處理過程與進程相關的處理函數(shù)集中在proc.c中,下面將依次介紹相關處理過程。進程治理初始化pinitproc_table_lock鎖。初始化用戶進程inituserinit是初始化第一個用戶進程init。其處理過程如下所示:156copyproccopyproc0,這表示是第一個用戶進程。由于是第一個進程,因此在copyproc中沒有進展內存等相關構造的初始化;156~173是對相關構造〔包括內存、當前名目cwd、trapframe〕進展初始化。留意的是,161~162行將進程的段加上了用戶態(tài)權限而不是內核態(tài)權限;p->tf->eip=0表0地址。p->tf->esp=p->sz的含義是174~176行是將第一個用戶進程的代碼〔initcode.S〕拷貝到進程的內存中,然后把進程名字指定為“initcoe設置進程狀態(tài)為RUNNABLE;178pinitproc。創(chuàng)立子進程在xv6中,可以通過sys_fork來復制父進程內容并創(chuàng)立一個的子進程。其處理過程如下所示:11copyproc函數(shù)創(chuàng)立一個的進程,留意這里調用copyproc函數(shù)的參數(shù)是p,p的相關內容來創(chuàng)立子進程;把創(chuàng)立的子進程狀態(tài)設置為RUNNABLE,返回子進程的pid。留意這也是fork返回后,確定是父進程還是子進程返回的一個標志。復制進程copyprocsys_forkcopyproc函數(shù),完成對userinitcopyproc函數(shù),完成對第一個用戶態(tài)進程的創(chuàng)立。其處理過程如下所示:108~109PCB復制;112~115np開拓內核??臻g;116行是將其trapframe所占的空間放在內核棧棧頂,大小位sizeof(structtrapframe),np->tf指向棧頂-sizeof(structtrapframe)的位置;p〔即父進程〕非空,119~121npparentpp中的狀態(tài)復制到nptrapframe中;p〔即父進程〕非空,124psz〔進程空間大小〕npmem內存空間;p〔即父進程〕非空,131pmemnpmem;p〔即父進程〕非空,133~135filedup函數(shù)復制父進程翻開的文件給子進np;p〔即父進程〕非空,136idupnp;139~142shedulereipforkretscheduler中加上的鎖給釋放。esp指向安排的棧地址;144~145fork產(chǎn)生的,因此其作為子進程0。進程構造的空間安排allocproc是進展進程安排,也就是在進程池中找出一個狀態(tài)為UNUSED的進程返回。選出來EMBRYOproc_table_lock。增加進程的地址空間growprocsbrk調用。xv6的內存治理格外簡潔。當要增大n時,假設原內存空間為sz,xv6將首先嘗試開拓一個為sz+n的空間(55~57行)。假設(58~63行)。設置內核空間和用戶空間段描述符setupsegstaskstatep0時,IDLE進程,只運行在內核態(tài),并且是在初始化生成的。因此對于這個進程不TSesp00xffffffff81~85CPU設置段描述符,TSS87~88為用戶端,段的基址和大小由當前進程打算。設置完成后,lgdtltr進展加載。調度進程scheduler對每個CPU進展進程調度。CPU到?jīng)]有運行用戶進程時,就會進入這個過程中。這個過程不停的從進程中選出一個RUNNABLE的進程,然后運行這個進程〔通過swtch.S中的swtch函數(shù)進展。[TODO]schedschedulerswtch進展上下文切換即可。CPUyield是用戶進程用來主動放棄當前CPUschedulerscheduler需要加鎖所proc_table_lock加上。設置用戶進程返回forkretforksys_fork創(chuàng)立的進程是通過shcedulerproc_table_lock鎖釋放。睡眠進程sleep功能是讓進程休眠。首先獲得proc_table_lockchan,也就是說只有相關的chanschedchan等記錄清proc_table_locklk鎖。喚醒進程wakeup功能是喚醒進程。先獵取proc_table_lock,然后調用函數(shù)wakeup1,然后釋放proc_table_lock。wakeup1chanSLEEPINGRUNNABLE。殺死進程killIDkilled狀態(tài)置1即可。假設目標進程出于sleeping狀態(tài)則將其設置成RUNNABLE使其盡早被殺掉。退出進程exit的是用于用戶進程退出。在退出之前,用戶進程需要關閉翻開的文件(351~356行,將翻開的文件夾關閉(358~359)wait狀態(tài)。并將其子進程托管init。然后轉變其狀態(tài)為ZOMBIE〔等待父進程進展回收schedCPU。等待進程完畢wait是用于父進程等待子進程完畢只用的。做法是不斷的循環(huán)知道找到一個子進程變成ZOMBIE狀態(tài),則釋放ZOMBIE子進程〔回收其資源,然后完畢循環(huán)返回其子進程的進程ID在循環(huán)的時候需要推斷是否被外部進程Kill,或有無活潑子進程,假設被殺死或無活潑子進程,則推出循環(huán)。進程上下文切換在操作系統(tǒng)中通常也把上下文切換稱為進程切換〔processswitch。當操作系統(tǒng)打算運行另外的進程時,它需要保存當前正在運行進程的當前上下文〔Context,也可稱“運行狀態(tài)信息”,即CPU存放器中的全部內容。這些內容保存在進程的堆??臻g或特定的上下文保存區(qū)。完成保存工作后,操作系統(tǒng)就可以把下一個將要運行進程的當前上下文從該進程的?;蛏舷挛腃PU一般有兩種狀況的上下文切換:高優(yōu)先級的進程由于需要某種臨界資源,主動懇求堵塞,讓出處理器,此時將調度就緒狀態(tài)的低優(yōu)先級進程獲得執(zhí)行。這種切換稱為進程級的上下文切換。進程由于時鐘中斷或其它中斷到來而被打斷,在中斷效勞例程處理完畢后,內核覺察有更高優(yōu)先級進程處于就緒態(tài),則在中斷處理完畢后直接切換到高優(yōu)先級進程執(zhí)行。這種調度也稱為中斷級的上下文切換。swtch.S這個程序是進展上下文切換。9oldcontext11~18行將當前的context存入。留意:eipnewcontext的指針,將全部存放器復原,然后將要運行的eip壓入棧,利用ret切換到的進程。留意,在切換回去后,的進程仍處于內核態(tài)。(trap&systemcall)概述本章將給出xv6中斷處理和系統(tǒng)調用實現(xiàn)的概貌。讀者將學習以下一些內容:什么是中斷?什么是系統(tǒng)調用?中斷與系統(tǒng)調用有何關系?xv6如何處理中斷?xv6的時鐘中斷處理有何特別的作用?xv6的各種實現(xiàn)功能?xv6如何處理系統(tǒng)調用?操作系統(tǒng)需要對計算機系統(tǒng)中的各種外設進展治理,這就需要CPU和外設能夠相互通信才行。一般外設的速度遠慢于CPU的速度。假設讓操作系統(tǒng)通過CPU“主動關心”外設的大事,即承受通常的輪詢〔polling〕機制,則太鋪張CPU資源了。所以需要操作系統(tǒng)和CPU能夠一起供給某種機制,讓外設在需要操作系統(tǒng)處理外設相關大事的時候,能夠“主動通知”操作系統(tǒng),即打斷操作系統(tǒng)和應用的正常執(zhí)行,讓操作系統(tǒng)完成外設的相關處理,然后在恢復操作系統(tǒng)和應用的正常執(zhí)行。在操作系統(tǒng)中,這種機制稱為中斷機制。中斷機制給操作系統(tǒng)供給了處理意外狀況的力氣,同時它也是實現(xiàn)進程/線程搶占式調度的一個重要基石。在操作系統(tǒng)中,把三種特別的中斷大事。由CPU外部設備引起的外部大事如I/O中斷、時鐘中斷、把握臺中斷等是異步產(chǎn)生的,與CPU的執(zhí)行無關,我們稱之為異步中斷〔asynchronousinterrupt〕也稱外部中斷,簡稱中斷(interrupt)。而把在CPU執(zhí)行指令期間檢測到不正常的或非法的條件〔如除零錯、地址訪問越界〕所引起的內部大事稱作同步中斷〔synchronousinterrupt,也稱內部中斷,簡稱特別〔exception。把在程序中使用懇求系統(tǒng)效勞的系統(tǒng)調用而引發(fā)的大事,稱作陷入中斷(trapinterrupt,也稱軟中斷〔softinterrupt〔systemcall〕trap。在后面的表達中,假設沒有特別指出,我們將用簡稱中斷、特別、陷入來表示這三種特別的中斷大事。2.源碼分析trap.cxv6對不同的中斷的處理過程以及中斷表的初始化。中斷初始化tvinit2.源碼分析trap.cxv6對不同的中斷的處理過程以及中斷表的初始化。中斷初始化tvinit過程中主要是對idt表進展初始化。其中vectors中存放的是每個中斷處理程序的入口地址。vectorsvectors.Sperlvectors.pl2223可以看到,Systemcall中斷權限為用戶權限,也就是說只能int0x30tickslock這個鎖進展初始化,這個鎖是用來處理時鐘中斷的。idtinitidt表的。idtinittvinitidtinitCPU調用。而tvinit過程只需要被調用一次。vectors.S&vectors.plvectors.Svectors.pl生成的。其中定義了每個中斷的入口程序和入口地址〔存儲在vecotrs數(shù)組中??梢粤粢獾?,中斷分成兩類:一類是壓入錯誤編碼的(errorcode)另一類不會壓入錯誤編碼。因此對于其次類,vectors.S將壓入一個0。此外vectors.S還會將中斷號壓入棧。在壓完兩個必要的值之后,全部中斷都將統(tǒng)一的跳轉進入alltraps入口程序。中斷處理過程trap函數(shù)的實現(xiàn)trap過程便是對中斷進展處理的。全部的中斷在經(jīng)過中斷入口程序(trapasm.S中定義〕后,都會最終跳轉到這里。其處理過程如下:在37~45行,假設中斷是系統(tǒng)調用,則通過syscall過程完成系統(tǒng)調用的處理。值得留意的是,這里進展了當前進程是否被其他進程kill的狀況。也就是說,假設一個進程被Kill,那么此進程將在進入或退出內核態(tài)時被切斷。48~56行是對不同的中斷進展處理。caseIRQ_OFFSET+IRQ_TIMER是處理時鐘中CPU0CPUtickssleeping狀態(tài)的進程進展檢查〔通過wakeup)。在wakeup則RUNNABLE;57~60ide_intr完成磁盤中斷處理;61~64kbd_intr完成鍵盤中斷處理;6~69行打印出產(chǎn)生的IRQ_SPURIOUS[]72~82行,推斷假設是在內核執(zhí)行時產(chǎn)生的中斷,則系統(tǒng)掛起;假設是在用戶態(tài)執(zhí)行p->killed=1,表示要殺死此進程84~88行,將檢查當前進程的p->killed,假設是非零且在用戶態(tài)引起的中斷,則調用exit函數(shù)退出此進程;9~93行,推斷假設當前進程占用了CPU〔即cp->state==RUNNING,且是時鐘中斷,則調用yield函數(shù),讓當前進程放棄所在CPU,選擇其他進程占用當前CPU。trapasm.Strapasm.S在這個文件中,主要是將存放器進展保存。9~11行都是將相關存放器壓入到棧。存放器值在棧中的布局可以參考x86.h中trapframe的定義。需要留意到的是棧底是在內存的高地址位置,trapframe構造是從低到高放置的。14~16trap.c中traptraptrapframeesp存放器壓入棧,其正好是trapframe的地址。在從trap返回之后,將開頭保存的全部存放器恢復〔26~28行,然后將中斷編號和錯誤號彈出棧即可。然后調用iret進展返回。syscall.c這個文件的主要目的是處理系統(tǒng)調用,依據(jù)系統(tǒng)調用的編號安排到不同的處理函數(shù)中去。其中文件中還供給了提取參數(shù)的過程。fetchintfetchstr是從進程〔p)addrkernelip。由于addr是進程中的地址,其對應的物理地址在內核態(tài)的虛擬地址是不同的,因此需要轉換。轉換是十paddrp->mem+addrpp->memp->sz大小的連續(xù)空間。需要留意的是,fetchintfetchstr都需要推斷參數(shù)給出的內存地址是否超過了進程所安排的內存范圍。argint,argptrargstrsystemcall中傳入的參數(shù)。進程在進程調用前,都會把參數(shù)壓入fetchintfetchstr獵取參argintnncp->tf->esp+4+4*n。syscall過程是將系統(tǒng)調用安排到不同的處理函數(shù)。處理后的返回結果存到cp->tf->eax中。這eax〔trapasm.S)。sysproc.cproc.c中的函數(shù)sys_sleep。一進入這個函數(shù)時,ticksticks0中。接著始終ticks-ticks0即實際睡眠時間超過預定的時間后就返回。由于不能始終占用CPU,sleepSleeping狀態(tài),參與休眠隊列。(filesystem)概述本章將給出xv6文件系統(tǒng)實現(xiàn)的概貌。讀者將學習以下一些內容:什么是文件系統(tǒng)?什么是文件?什么是名目?I/OBuffer有何作用?xv6的文件系統(tǒng)有哪些重要局部組成?xv6如何實現(xiàn)創(chuàng)立一個文件?xv6如何實現(xiàn)讀寫文件?很多應用需要對數(shù)據(jù)進展長期保存和訪問,這樣就需要文件系統(tǒng)的支持。操作系統(tǒng)中負責治理和存儲文件信息的軟件機構稱為文件治理系統(tǒng),簡稱文件系統(tǒng)。文件系統(tǒng)由三局部組成:與文件治理有關的軟件、被治理的文件以及實施文件治理所需的數(shù)據(jù)構造。從系統(tǒng)角度來看,文件系統(tǒng)是對文件存儲器空間進展組織和安排,負責文件的存儲并對存入的文件進展保護和檢索的系統(tǒng)。具體地說,它負責為用戶建立文件,存入、讀出、修改、轉儲文件,把握文件的存取,當用戶不再使用時刪除文件等。xv6的文件系統(tǒng)是整個操作系統(tǒng)中代碼量最大的一局部了,但照舊只是一個格外簡潔的實現(xiàn)。UnixUNIX文件系統(tǒng)種類具有類似的通用構造,其中心概念是超級塊〔superblock〕,i節(jié)點〔inode〕,數(shù)據(jù)塊〔datablock〕名目塊〔directoryblock〕,和間接塊〔indirectionblock。超級塊包括文件系統(tǒng)的總體信息,比方大小(其準確信息依靠文件系統(tǒng))。i節(jié)點包括除了名字外的一個文件的全部信息,名字與i節(jié)點數(shù)目一起存在名目中,名目條目包括文件名和文件的i節(jié)點數(shù)目。i節(jié)點包括幾個數(shù)據(jù)塊的數(shù)目,用于存儲文件的數(shù)據(jù)。i節(jié)點中只有少量數(shù)據(jù)塊數(shù)的空間,假設需要更多,會動態(tài)安排指向數(shù)據(jù)塊的指針空間。這些動態(tài)安排的塊是間接塊;為了找到數(shù)據(jù)塊,這名字指出它必需先找到間接塊的號碼。xv6API、文件系統(tǒng)、BufI/O通訊。FDFileRead和Write等函數(shù)與硬件設備進展交互,從而隱蔽了很多實現(xiàn)的細節(jié),簡化了很多上層程序的操作。Buf緩存構造是用來緩存需要寫入硬件設備的數(shù)據(jù)和從硬件設備上讀出的數(shù)據(jù)。Buf可以對硬件設備的操作進展統(tǒng)一的調度,從而提高效率。最底層的便是直接對硬件設備進展調度。7.1xv6文件系統(tǒng)構造FD文件描述符,F(xiàn)ile文件構造和源碼分析sysfile.c此文件定義了很多有關文件系統(tǒng)的系統(tǒng)調用。xv6中的系統(tǒng)調用是針對文件描述符進展的。每File。有可能多個文件描述指向同一個文件。每個文件描ofile記錄了其指向的文件構造。下面對每個過程進展介紹。argfdnn個參數(shù)讀取出來(20行)ofile找到相應的文件構造〔22行。ofile數(shù)組中查找一個沒有使用的文件描述符,然后返回即可。sys_readosfile讀取出文件描述符所指向文件構造fileread進展文件讀取。sys_writesys_read類似,只需要找到相應的文件構造,調用filewrite對文件構造進展寫操作。同樣,sys_dup、sys_closesys_fstat都是API進展操作,這里就不再贅述了。sys_linkxv6中,一個名目中存儲的是一個個文inodeinodeinode。sys_link就是用來建立這種指向的。為了避開形成大于1的環(huán),dir的link只能指向一個文件,而不能是名目(122~124行116~128inode1。然后在130~136sys_unlink是用來取消一個硬鏈接。就是在名目中找到相應的表項,進展刪除。create過程是用于建立相應的file.h每個文件構造都對應著一個磁盤設備上的真實文件、或一個硬件設備、或者通訊管道。從File的構造定義可以看出,F(xiàn)ile構造主要分成兩種類型,一種是INODE(可能是磁盤上的文件,也可能是硬件設備,另一種是Pip〔管道。假設是INODE型,則ip指針則指向其對應的pipePIPEreadablewritable是用來加ref則是表示被整個系統(tǒng)的用戶進程應用了多少次(TODO:不同進程INODE層?)。file.c此文件中供給了對FILE構造的一些根本操作,例如FILE文件構造的安排〔filealloc的復制〔filedup、文件構造的關閉(fileclose)、文件讀取(fileread)和文件寫入(filewrite)。全部FILE文件構造在系統(tǒng)中都有一個統(tǒng)一的列表保存,這個列表的大小限制了整個系統(tǒng)可以SMP構造,在訪問這個列表時需要加上鎖來保證互斥的資源訪問。filealloc是用來安排一個FILE構造的,也就是從文件列表中選取一個狀態(tài)為FD_CLOSED的FD_NONE1。fork中。fileclose是將一個文件的引用計數(shù)減一。比方某個用戶進程將此文件構造關閉了。當引用計數(shù)變?yōu)?時,說明系統(tǒng)中沒有任何一處翻開此文件,此時可以收回此文件構造。在回收時,同時要調用文件構造下層構造(PIPEINODE)的關閉。filestat是返回一個文件構造的統(tǒng)計信息。只有當此文件構造類型是INODEC時才有效。返回的統(tǒng)計信息有文件大小,文件鏈接數(shù)等等。分別是通文件構造讀取和寫入數(shù)據(jù)。兩個函數(shù)都是調用下層構造相應的函數(shù)file_table_lock鎖。但全部的下層構造都有其自身的加鎖機制。磁盤文件系統(tǒng)和源碼分析文件系統(tǒng)主要是以INODE構造進展操作的。INODE可以是一個文件,也可以是一個文件夾。用戶進程通過文件路徑來進展對INODE的查詢和訪問。INODE在xv6文件系統(tǒng)中有兩種類型,一種是在系統(tǒng)實際運行時在內存中的INODE〔即fsvar.h中的inode構造,另一種是在磁盤上INODE〔fs.hdinode)INODE是用于操作系統(tǒng)對文件訪問進展控INODEdinode則是用于組織這個文件系統(tǒng)在磁盤上的存儲構造。fsvar.h&fs.hxv6文件系統(tǒng)在磁盤上的組織構造。xv6對磁盤空間的劃分是以塊〔block)為單dinodeblock組成。在磁盤上,xv6文件系統(tǒng)從低地址到高地址(即從0塊到最終一塊〕的布局為:超級塊(superblock)、dinode構造列表(inodes)用狀況的統(tǒng)計表(blockin-use-bitmap)和數(shù)據(jù)塊。其中超級塊的作用是給出磁盤文件系統(tǒng)的根本信息,包括文件系統(tǒng)總的塊數(shù),數(shù)據(jù)塊的數(shù)目以及dinode的數(shù)目。超級塊只占一個塊〔blockdinodedinodedinode都有自己的編號。dinode構造中記錄的文件類型(文件或名目、設備、硬鏈接數(shù)、文件大小和此文件所占用的數(shù)據(jù)塊。占用數(shù)據(jù)塊的編號存在addrs中,其中addrs[0]~addrs[NDIRECT-1]直接指向一個數(shù)據(jù)塊;而addrs[INDIRECT]指向一個塊,塊里存放的都是其他被此文件占用的數(shù)據(jù)塊的地址,因此是addrs[INDIRECT]是間接指針。磁盤塊使用狀況統(tǒng)計表是一段連續(xù)的磁盤空間,其中每一比特對應了整個盤上某塊的使用狀況。假設第ibit為1,則表示磁盤上的第0塊被占用。磁盤中剩下的塊都為數(shù)據(jù)塊。留意:以上每一局部都占用整數(shù)個塊,有些構造可能沒有把其最終一0。fs.creadsbsuperblock。bzero,balloc,bfree都是數(shù)據(jù)塊相關的操作。在操作中都是對有bufblockballoc,bfree在操作之后都需要修改磁盤塊使用狀況統(tǒng)計相應的比特位。inode操作相關的函數(shù)。在文件系統(tǒng)中,icache構造緩存當前系統(tǒng)中全部inodeinodeFile文件構造或者是進程所處的當前名目cwdinode0時,inodeinode都有一個inumdinode的列表的編號。igeticacheinuminodeicacheinode,則inoderef1。idupinodeforkFile文件構造被復制是會發(fā)生這個狀況。ilockinodeinodeI_BUSY,同inodeinode使用權時,假設覺察已被其他進程SLEEP狀態(tài)。知道其他進程放棄使用權后,用wakeup將其喚醒。需要留意的是在搶inode使用權時,照舊可能消滅RACE狀態(tài)(TODO)。搶到使用權后,假設覺察ip->flagsI_VALID,則從磁盤上讀入。iunlockinode的使用權,同時喚醒等待這把鎖的進程。iput1inode。iallocinode進展安排。這個算法對磁盤進展挨次查找空閑的inode,速度實際上比較慢。iupdate是將內存中的內容更到磁盤。bmapinoden個塊(block)n塊是直接塊,則可以馬上返回。否則要加載block然后讀到相應的塊,然后返回。itrunc、stati、readiwriteiinode的數(shù)據(jù)訪問。dirlookup、dirlink、skipelem、_namei都是對文件路徑進展處理,相比照較簡潔,這里便不再贅述。需要留意的是,dirinodedirent項,描述了文件夾inode編號。I/O緩存Buf構造和源碼分析xv6bufblock塊進展緩存。bufLRUbuf總是放在鏈表的首部。bio.cbinitbuf鏈表初始化,并將其鏈成一個表。bgetbuf。首先在bufbufbuf存儲扇區(qū)。bread是bgetbufB_VALID,則通過ide_rw進展磁盤同步。bwritebufbwrite之前需要在外部對buf,從而保證全都性。brelsebufbuf訪問完畢時調用的。此時基于LRUbufbuf鏈表的頭部。ide.cide磁盤進展讀寫操作。I/O讀寫是異步的。ide_rwide_queue進展排隊。在ide_rwide_queuedisk沒有開頭讀寫,則喚起disk讀寫。(141~142行145~146進展輪詢等待讀寫進程的完成。輪詢中并不是盲sleep當前進程,等待進程完成是被喚起。ide_start_requestbufb進程懇求發(fā)送到磁盤。當進程完成時,磁盤將發(fā)出完成的硬件中斷。ide_intr則是相應此中斷的過程。ide_intr106~108行去除狀態(tài),并喚醒等待此bufide_queue有后繼進程,則啟動此進程。第八章對稱多處理〔SMP/MultiCore〕支持概述本章將給出xv6多處理器支持的實現(xiàn)概貌。讀者將學習以下一些內容:SMP系統(tǒng)?什么是PIC,LAPIC,IOAPIC?xv6CPU的?xv6CPU之間的中斷信息傳遞的?xv6如何初始化主處理器〔BP〕和從處理器
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 《農村留守老人心理健康及生命質量狀況調查及對策研究》
- 2024年建筑防水工程勞務合同
- 2024-2030年版中國生產(chǎn)性服務產(chǎn)業(yè)發(fā)展創(chuàng)新模式及投資戰(zhàn)略分析報告
- 2024-2030年版中國林業(yè)市場發(fā)展規(guī)模及投資戰(zhàn)略分析報告
- 2024-2030年版中國人類輔助生殖行業(yè)市場動態(tài)分析及發(fā)展策略研究報告
- 2024年度消防水箱系統(tǒng)升級與改造合同
- 2024-2030年林可霉素利多卡因搬遷改造項目可行性研究報告
- 2024-2030年新版中國銅鎳礦項目可行性研究報告
- 2024-2030年新版中國塑膠表面處理項目可行性研究報告
- 2024-2030年全球及中國高碳鉻鐵行業(yè)需求現(xiàn)狀及前景趨勢預測報告
- 大學軍事理論課教程第四章現(xiàn)代戰(zhàn)爭第二節(jié) 新軍事革命
- 職業(yè)生涯規(guī)劃-自我認知-價值觀
- 安徽省蕪湖市2023年七年級上學期語文期末試卷(附答案)
- 上肢康復機器人說明書
- 市政道路改造工程 投標方案(技術標)
- (1.28)-法律的含義及歷史發(fā)展
- 如何撰寫和發(fā)表高水平的科研論文-good ppt
- 企業(yè)參保人員基本養(yǎng)老金申領表
- 測量血壓的正確方法-PPT
- ICH指南指導原則Q8(R2)藥品研發(fā)
- 2022玻璃棧道工程技術規(guī)程
評論
0/150
提交評論