




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、1. 宏總結(jié):Ø /threads/thread.h#define MachineStateSize 18#define StackSize(4 * 1024)Ø /threads/thread.cc#define STACK_FENCEPOST 0xdeadbeefØ /userprog/addrspace.h#define UserStackSize1024Ø /userprog/bitmap.h#define BitsInByte 8#define BitsInWord 32Ø /userprog/syscall.h#define SC_
2、Halt0#define SC_Exit1#define SC_Exec2#define SC_Join3#define SC_Create4#define SC_Open5#define SC_Read6#define SC_Write7#define SC_Close8#define SC_Fork9#define SC_Yield10 #define ConsoleInput0 #define ConsoleOutput1 Ø /machine/disk.h#define SectorSize 128/ number of bytes per disk sector#defin
3、e SectorsPerTrack 32/ number of sectors per disk track #define NumTracks 32/ number of tracks per disk#define NumSectors (SectorsPerTrack * NumTracks)/ total # of sectors per diskØ /machine/disk.cc#define MagicNumber 0x456789ab#define MagicSize sizeof(int)#define DiskSize (MagicSize + (NumSecto
4、rs * SectorSize)Ø /machine/machine.h#define PageSize SectorSize / set the page size equal to the disk sector size, for simplicity#define NumPhysPages 32#define MemorySize (NumPhysPages * PageSize)#define StackReg29/ User's stack pointer#define RetAddrReg31/ Holds return address for procedur
5、e calls#define NumGPRegs32/ 32 general purpose registers on MIPS#define HiReg32/ Double register to hold multiply result#define LoReg33#define PCReg34/ Current program counter#define NextPCReg35/ Next program counter (for branch delay) #define PrevPCReg36/ Previous program counter (for debugging)#de
6、fine LoadReg37/ The register target of a delayed load.#define LoadValueReg 38/ The value to be loaded by a delayed load.#define BadVAddrReg39/ The failing virtual address on an exception#define NumTotalRegs 40Ø /machine/mipssim.h#define OP_?Ø /filesys/directory.h#define FileNameMaxLen 9/ f
7、or simplicity, we assume file names are <= 9 characters longØ /filesys/filehdr.h#define NumDirect (SectorSize - 2 * sizeof(int) / sizeof(int)#define MaxFileSize (NumDirect * SectorSize)Ø /filesys/filesys.cc#define FreeMapSector 0#define DirectorySector 1#define FreeMapFileSize (NumSecto
8、rs / BitsInByte)#define NumDirEntries 10#define DirectoryFileSize (sizeof(DirectoryEntry) * NumDirEntries)#define TransferSize 10 / make it small, just to be difficultØ /filesys/fstest.cc#define TransferSize 10 / make it small, just to be difficult2. /nachos-3.4/code/A. Makefile.dep:GNU-Makefil
9、e的一部分,指定了Makefile系統(tǒng)環(huán)境中相互依賴的部分,還指定了平臺,此處為Linux;# also, LinuxHOST = -DHOST_i386LDFLAGS =B. Mmon:1) 包含了nachos提供的所有的基本程序(baseline code),無論何時需要添加 .h 和 .cc 文件,都需要在相應(yīng)的_H、_C和_O列表中修改;2) 任務(wù)的依賴關(guān)系有:a) threads在所有程序之前;b) userprog在vm之前運行;c) userprog可在filesys之前或之后運行,但是如果先運行userprog,必須定義filesys_stub;3) 當(dāng)修改程序的架構(gòu)時,應(yīng)該在
10、相應(yīng)的子文件夾下執(zhí)行make depend,程序會自動修改Makefile并更新依賴性;4) CFLAGS = -g -Wall -Wshadow $(INCPATH) $(DEFINES) $(HOST) DCHANGED:-g:在可執(zhí)行程序中包含標(biāo)準(zhǔn)調(diào)試信息;-Wall:允許發(fā)出Gcc提供的所有有用的報警信息;-Wshadow:當(dāng)局部變量遮蔽(shadow)了參數(shù)、全局變量或其他局部變量時,該選項會給我們警告信息;-DCHANGED?:5) Depend函數(shù)?:6) DTHREADS:Dthreads is an efficient deterministic multithre
11、ading system for unmodified C/C+ applications that replaces the pthreads library.C. Makefile:1) Lpr:將檔案或是由標(biāo)準(zhǔn)輸入送進(jìn)來的資料送到打印機(jī)貯列之中,打印機(jī)管理程序 lpd 會在稍后將這個檔案送給適當(dāng)?shù)某绦蚧蜓b置處理。lpr 可以用來將料資送給本地或是遠(yuǎn)端的主機(jī)來處理。;2) Make nachos:D.3. /nachos-3.4/code/threads/A. Makefile:和線程任務(wù)有關(guān)的Makefile,首先必須完成線程任務(wù)。B. Utility.cc:調(diào)試代碼,通過命令行參數(shù)允許
12、用戶控制是否打印調(diào)試信息;1) DebugInit():只能打印flaglist的調(diào)試信息,即確定打印調(diào)試信息的部分;2) Debug():打印調(diào)試信息;C. Main.cc:初始化操作系統(tǒng)內(nèi)核的引導(dǎo)程序代碼。允許直接調(diào)用內(nèi)部的操作系統(tǒng)函數(shù)來簡化調(diào)試和測試。實際上,這些引導(dǎo)程序代碼只是初始化數(shù)據(jù)結(jié)構(gòu),然后開啟一個用戶線程來打印注冊提示。1) 相關(guān)編譯選項: nachos -d <debugflags> -rs <random seed #>-s -x <nachos file> -c <consoleIn> <consoleOut>-
13、f -cp <unix file> <nachos file>-p <nachos file> -r <nachos file> -l -D -t -n <network reliability> -m <machine id> -o <other machine id> -z -d causes certain debugging messages to be printed (cf. utility.h) -rs causes Yield to occur at random (but repeatable
14、) spots -z prints the copyright message USER_PROGRAM -s causes user programs to be executed in single-step mode -x runs a user program -c tests the console FILESYS -f causes the physical disk to be formatted -cp copies a file from UNIX to Nachos -p prints a Nachos file to stdout -r removes a Nachos
15、file from the file system -l lists the contents of the Nachos directory -D prints the contents of the entire file system -t tests the performance of the Nachos file system NETWORK -n sets the network reliability -m sets this machine's host id (needed for the network)-o runs a simple test of the
16、Nachos network software備注:直到完成相關(guān)任務(wù)時這些選項才會起作用2) Main():操作系統(tǒng)內(nèi)核的啟動代碼,工作有檢查命令行參數(shù),初始化數(shù)據(jù)結(jié)構(gòu),以及選擇性地調(diào)用測試程序Case “q”?;3) Main()函數(shù)最后調(diào)用CurrentThread->Finish()函數(shù),是因為nachos相對于宿主機(jī)來說只是一個程序,直接exit(0)會導(dǎo)致nachos退出,但是nachos系統(tǒng)中可能有等待線程,所以我們切換到這些線程告訴它們主線程已經(jīng)結(jié)束,防止它們返回是說main退出,但是這些線程會在宿主機(jī)繼續(xù)運行甚至返回結(jié)果嗎?。D. system.h:定義了nachos所用
17、的全局變量;E. system.cc:1) 定義了所有的全局?jǐn)?shù)據(jù)結(jié)構(gòu),并進(jìn)行初始化和分配空間;Thread *currentThread;/ the thread we are running nowThread *threadToBeDestroyed; / the thread that just finishedScheduler *scheduler;/ the ready listInterrupt *interrupt;/ interrupt statusStatistics *stats;/ performance metricsTimer *timer;/ the hardwa
18、re timer device,/ for invoking context switches2) 定義了Nachos兩個函數(shù):Initialize()和Cleanup();a) Initialize():初始化nachos的全局?jǐn)?shù)據(jù)結(jié)構(gòu),詮釋命令行參數(shù);b) Cleanup():終止nachos,釋放全局?jǐn)?shù)據(jù)結(jié)構(gòu);3) TimerInterruptHandler():Timer device周期性(每個TimerTicks一次)中斷CPU,然后每次會調(diào)用此函數(shù),同時關(guān)閉中斷。直接調(diào)用Yield()會掛起interrupt handler,而不是被中斷的線程。不同的是,我們設(shè)置一個flag,所
19、以當(dāng)完成interrupt handler時,看起來就像是被中斷的線程在中斷時刻調(diào)用了Yield()。參數(shù)Int dummy(虛擬/假的)是因為interrupt handler都需要一個參數(shù),無論是否需要;F. thread.cc(h):1) 管理線程的數(shù)據(jù)結(jié)構(gòu),一個現(xiàn)場的狀態(tài)包括pc、寄存器和執(zhí)行棧;a) 為每個棧分配固定的空間,所以要防止棧溢出,動態(tài)分配數(shù)據(jù)結(jié)構(gòu)空間;b) 調(diào)試是否是棧空間太小導(dǎo)致segmentation fault,可以增加占空間ThreadStackSize;c) Fork一個線程包括:先分配一個數(shù)據(jù)結(jié)構(gòu)空間,然后調(diào)用fork()函數(shù);2) 線程狀態(tài)(ThreadSt
20、atus)包括:剛創(chuàng)建、運行中、準(zhǔn)備好、阻塞;3) 線程控制塊(class Thread):表示一個線程的執(zhí)行狀況,包括:a) 一個執(zhí)行棧,用來保存活躍記錄,以及不運行的時候保存CPU寄存器;b) 某些用戶線程包括一個用戶地址空間,內(nèi)核線程的地址空間為NULL;c) 基本操作包括:Fork(調(diào)用內(nèi)置函數(shù)stackAllocate()、Yield、Sleep、Finish、CheckOverflow、setStatus、getName、Print;d) 用戶線程包括兩套CPU寄存器,分別保存執(zhí)行用戶和內(nèi)核代碼的狀態(tài)用戶線程(a thread running a user program)vs運行
21、用戶代碼的線程(execute );4) Thread():初始化一個線程控制塊,之后就可以調(diào)用Fork函數(shù),參數(shù)為線程名字,是一個任意字符串,用來調(diào)試;5) Thread():釋放一個線程空間,參數(shù)是線程名字。但是current線程不能直接刪除自己,因為它運行在我們將要刪除的??臻g。同時主線程不能刪除??臻g,因為主線程空間是我們自動獲取的,它是啟動nachos的一部分;6) Fork():調(diào)用(*func)(arg),使得caller和callee可以并發(fā)執(zhí)行。雖然arg只是一個int型變量,但是可以把想要傳遞的參數(shù)打包成一個數(shù)據(jù)結(jié)構(gòu),然后把它的指針作為int參數(shù)。執(zhí)行步驟包括:a) 分配棧
22、空間;b) 初始化棧使得switch函數(shù)可以運行此程序;c) 將線程放入就緒隊列;7) CheckOverflow():nachos不會捕獲所有的溢出情況,所以程序仍然可能因為溢出掛掉。8) Finish():當(dāng)一個fork線程執(zhí)行完畢被ThreadRoot調(diào)用。但是我們沒有立即釋放線程數(shù)據(jù)結(jié)構(gòu)空間,因為該線程仍在運行切還在其??臻g。相反,我們設(shè)置“threadToBeDestroyed”,使得我們在不同的線程上下文環(huán)境時,調(diào)度器可以調(diào)用析構(gòu)函數(shù)。我們關(guān)閉中斷,使得設(shè)置“threToBeDestroyed”和sleep之間沒有時間片;9) Yield():當(dāng)有其它就緒線程時刻放棄CPU資源,并
23、把當(dāng)前線程放入就緒隊列隊首使得可以被再次調(diào)度。如果沒有就緒隊列則立即返回。關(guān)閉中斷,使得檢查就緒線程隊列和切換上下文可以原子操作完成。返回之后,立即設(shè)置中斷到之前狀態(tài),以免被其他中斷操作影響;10) Sleep():等待一個同步變量而掛起并讓出CPU。最后,某個線程會喚醒此線程,并放入就緒隊列可以被再次調(diào)度。沒有就緒線程則調(diào)用Interrupt:Idle函數(shù),表明CPU空閑,直到IO中斷使得某個線程再次運行。關(guān)閉中斷保證取出就緒隊列線程和切換上下文是原子操作;11) ThreadFinish、InterruptEnable和ThreadPrint函數(shù)都是偽函數(shù),因為C+不允許指針指向成員函數(shù)。
24、所以,創(chuàng)建偽C函數(shù)可以使用指針調(diào)用成員函數(shù);12) StackAllocate():分配和初始化執(zhí)行棧,為ThreadRoot函數(shù)的??蚣?,使得可以開中斷、調(diào)用(*func)(arg)以及調(diào)用Thread:Finish函數(shù);13) SaveUserState/RestoreUserState:在上下文切換時保護(hù)/恢復(fù)CPU狀態(tài);G. Threadtest.cc:工作機(jī)制是創(chuàng)建兩個線程,通過調(diào)用Yield()函數(shù)頻繁切換上下文,顯示內(nèi)部線程的工作過程;1) SimpleThread():循環(huán)5次,讓出CPU給其它準(zhǔn)備好的線程,參數(shù)int which是為了調(diào)試用;2) ThreadTest1():
25、在兩個線程之間設(shè)置ping-pong,fork一個線程調(diào)用SimpleThread()函數(shù),再自己調(diào)用SimpThread()函數(shù);3) ThreadTest():通過檢查參數(shù)int testnum是否是1決定是否調(diào)用測試代碼,即調(diào)用ThreadTest1()函數(shù);H. Scheduler.h:線程分發(fā)器和調(diào)度器的數(shù)據(jù)結(jié)構(gòu),包括一個就緒隊列;I. Scheduler.cc:選擇下一個要運行的線程,并且調(diào)度該線程。這些代碼假設(shè)中斷已關(guān)來實現(xiàn)互斥。在這里我們不能使用鎖來提供互斥機(jī)制,因為我們需要等待一個鎖,而且這個鎖是被占用的,我們最后會調(diào)用FindNextToRun(),這會使我們進(jìn)入一個無限的
26、循環(huán)。1) Scheduler():初始化就緒隊列為空;2) scheduler():刪除就緒線程隊列;3) ReadyToRun():標(biāo)記一個線程為ready,放入就緒隊列末尾;4) FindNextToRun():返回下一個將要運行的線程,沒有則返回NULL,同時從就緒隊列刪除該線程;5) Run():把CPU分發(fā)給下一個運行線程。調(diào)用switch代碼以保存舊線程狀態(tài),同時加載新線程狀態(tài);a) 保存當(dāng)前線程指針為oldThread;b) 如果是用戶程序,則保存用戶的CPU寄存器;c) 檢查oldThread是否棧溢出(因為不是時刻檢查棧段溢出,所以這時線程的運行可能已經(jīng)出錯);d) 當(dāng)前線
27、程置為傳進(jìn)來的參數(shù)nextThread;e) 當(dāng)先線程狀態(tài)設(shè)為Running;f) 調(diào)用switch,切換新舊線程的狀態(tài)(之前運城在當(dāng)先線程的??臻g,之后運行在nextThread的??臻g);g) 如果舊線程因為結(jié)束放棄運行,即被賦給threadToBeDestroyed,則刪除舊線程;h) 如果是用戶程序,則恢復(fù)當(dāng)前線程的地址空間;6) Print():打印調(diào)度器的狀態(tài),即就緒隊列的內(nèi)容,用于調(diào)試;J. Switch.s:與機(jī)器有關(guān)的上下文切換代碼。說是機(jī)器相關(guān)的,是因為需要保存的寄存器、設(shè)置初始的調(diào)用函數(shù)??臻g等對于每一個處理器架構(gòu)都是特別的。此處為每種架構(gòu)設(shè)計了兩段代碼:1) Threa
28、dRoot(InitialPC, InitialArg, WhenDonePC, StartupPC):a) InitialPC:將要運行的線程的入口函數(shù)的地址;b) InitialArg:入口函數(shù)的參數(shù);c) WhenDonePC:當(dāng)該線程運行結(jié)束時要調(diào)用的代碼;d) StartupPC:運行該線程需要調(diào)用的代碼,即要做的一些初始化工作;e) 在nachos源代碼中,沒有函數(shù)和方法顯式調(diào)用此函數(shù),ThreadRoot函數(shù)只有在線程切換時才被調(diào)用。線程在初始化的最后準(zhǔn)備工作要調(diào)用StackAllocate方法,該方法設(shè)置了幾個寄存器的值,該線程第一次被切換時調(diào)用的就是ThreadRoot函數(shù)。
29、其工作流程為:1. 清除幀指針;2. 調(diào)用StartupPC函數(shù);3. 設(shè)置InitialArg參數(shù),調(diào)用InitialPC函數(shù),主程序;4. 調(diào)用WhenDonePC函數(shù),結(jié)束時調(diào)用clean up程序;f) 由此,ThreadRoot入口可以轉(zhuǎn)而運行線程所要運行的函數(shù),從而生成一個新的線程;2) SWITCH(oldThread, newThread):a) oldThread:當(dāng)前運行的線程,需要保存其CPU寄存器狀態(tài);b) newThread:將要運行的線程,需要加載其CPU寄存器狀態(tài);c) 在Makefile.dep下定義了HOST = -DHOST_i386,所以只需看最下面的匯編
30、代碼;d) 工作流程是:1. 保存當(dāng)前線程的狀態(tài):棧指針、被調(diào)用者保存的寄存器、幀指針、返回地址;2. 加載將要運行的線程狀態(tài):棧指針、被調(diào)用者保存的寄存器、幀指針、返回地址;3. 跳轉(zhuǎn)到新運行的線程的??臻g運行新線程;K. Synch.h:同步線程的數(shù)據(jù)結(jié)構(gòu)。這里定義了三種類型:信號量、鎖和條件變量。已經(jīng)實現(xiàn)了信號量,且給出了鎖和條件變量的接口。此處每個同步對象都有一個name便于調(diào)試。1) Class Semaphore:定義了一個非負(fù)整數(shù)value,包括一個在P處的等待隊列queue。還有一個函數(shù)bool isHeldByCurrentThread(),檢查如果是currentThrea
31、d持有該鎖則返回true,用于檢查Release時用。只有兩個原子操作P和V:a) P():等待直到value>0。然后減1;b) V():加1,喚醒一個正在P()等待的線程;此處不允許直接讀信號量的值,即使讀也是舊的值,不知道最新的值是多少,因為從寄存器讀取時,可能發(fā)生了上下文切換,也可能有其它線程修改了信號量的值。2) Class Lock:鎖機(jī)制是線程進(jìn)入臨界區(qū)的工具。一個鎖有busy和free兩種狀態(tài),當(dāng)鎖處于free時,線程可以申請取得鎖進(jìn)入臨界區(qū),執(zhí)行完臨界區(qū)代碼后釋放鎖;當(dāng)鎖處于busy時,需申請該鎖的線程進(jìn)入睡眠態(tài),等到鎖為free時再申請取得鎖。包含兩個原子操作Acqu
32、ire和Release,而且只有得到鎖的線程才可以釋放它:a) Acquire():鎖為busy時進(jìn)入睡眠等待;鎖為free時,線程獲得鎖設(shè)置為busy繼續(xù)運行;b) Release():設(shè)置鎖為free,如有等待線程,喚醒其中一個線程進(jìn)入就緒態(tài);和信號量類似,不允許直接讀鎖的值value,因為讀過之后馬上就可能改變。另外,在這里可以添加需要實現(xiàn)鎖自定義的變量。3) Class Condition:條件變量沒有值,當(dāng)一個線程需要的某種條件沒有滿足時,可作為一個等待條件變量的線程插入所有等待該條件變量的隊列,只要條件滿足就會被喚醒繼續(xù)運行。條件變量總是和鎖機(jī)制一同使用,在條件變量上有三個操作(所
33、有這些操作必須在currentThread持有一個鎖的前提下,且所有對一個條件變量進(jìn)行的操作必須建立在同一個鎖的前提下,保證訪問該條件變量的線程之間的互斥):a) Wait():釋放鎖,放棄CPU進(jìn)入睡眠等待直到接收到信號,然后再次申請鎖。其中,釋放鎖和進(jìn)入睡眠都是原子操作;b) Signal():喚醒一個等待該條件變量的線程(如果存在);c) Broadcast():喚醒所有等待該條件變量的線程(如果存在);在nachos中,所有的條件變量默認(rèn)是遵循Mesa規(guī)范當(dāng)調(diào)用Signal或者Broadcast喚醒一個線程時,該線程置于等待鏈表,該線程調(diào)用Wait等待再次獲得鎖。不同于Hoare規(guī)范發(fā)
34、送信號的線程放棄鎖和CPU給喚醒的線程,喚醒的線程立即運行,然后在運行至臨界區(qū)之外時將鎖給先前發(fā)送信號的線程。使用Mesa規(guī)范導(dǎo)致在被喚醒的線程得到機(jī)會運行之前,可能有其它線程得到這個鎖并且改變數(shù)據(jù)結(jié)構(gòu)。L. Synch.cc:線程同步的代碼。關(guān)于同步代碼的實現(xiàn)需要一些原語的原子操作。我們假定nachos運行在單處理器上,因此原子操作可以通過關(guān)中斷來實現(xiàn)。關(guān)閉中斷后,沒有上下文切換,currentThread確保一直占用CPU,直到中斷打開。一些代碼調(diào)用時中斷可能已關(guān)閉(比如信號量的V操作),?我們直接重設(shè)中斷狀態(tài)到它原來的狀態(tài),而不是在原子操作的最后打開中斷。1) Class Semapho
35、re:a) Semaphore(char* debugName, int initialValue):構(gòu)造函數(shù),初始化一個信號量;b) Semaphore():當(dāng)沒有線程等待該信號量時,刪除該信號量;c) P():關(guān)中斷,循環(huán)判斷value的值,如果等于0則插入該信號量的等待隊列queue,然后調(diào)用sleep進(jìn)入睡眠狀態(tài)并切換到其它線程運行,喚醒之后繼續(xù)檢查value的值。檢查到value>0,則跳出循環(huán)將value減1,然后恢復(fù)中斷至原來的狀態(tài);d) V():關(guān)中斷,如果線程等待隊列中有等待該信號量的線程,取出隊首線程,不為空則設(shè)為ready準(zhǔn)備運行,然后立即將value加1,最后恢復(fù)
36、中斷狀態(tài);2) 關(guān)于Lock和Condition的函數(shù)需要后面完善;M. Synchlist.h:定義了對一個鏈表同時訪問時的數(shù)據(jù)結(jié)構(gòu)。通過在抽象鏈表數(shù)據(jù)結(jié)構(gòu)前后添加同步代碼來完善。Class SynchList定義了同步的鏈表,該鏈表滿足約束條件:1) 試圖從鏈表刪除一個元素,必須等待鏈表中含有一個元素;2) 每個時刻只有一個線程可以訪問鏈表數(shù)據(jù)結(jié)構(gòu);私有變量包括list鏈表(一個未同步的鏈表)、lock鎖(保證對鏈表的互斥訪問)、listEmpty條件變量(鏈表為空時在Remove處等待)。N. Synchlist.cc:用管程monitor的方式實現(xiàn)每個程序都用一個鎖的獲得和釋放對維護(hù),
37、同時利用條件變量的Signal和Wait來同步。1) SynchList():為一個同步鏈表分配和初始化一個數(shù)據(jù)結(jié)構(gòu),初始鏈表為空;2) SynchList():刪除為一個同步鏈表分配的資源;3) Append():在鏈表末尾添加一個元素item,并喚醒所以等待添加元素的線程,item是將要放進(jìn)鏈表的東西,也可以是一個指針。執(zhí)行過程是嘗試申請取得鎖(保證互斥訪問)->添加元素item->喚醒等待的線程->釋放鎖;4) Remove():刪除鏈表的開頭元素,若鏈表為空等待,最后返回刪除的元素。執(zhí)行過程為嘗試申請取得鎖->循環(huán)檢查鏈表為空則等待->鏈表不為空,則刪除開
38、頭元素->釋放鎖->返回該元素;5) Mapcar():將函數(shù)應(yīng)用于鏈表的每個元素,遵循互斥的限制。執(zhí)行過程為嘗試申請取得鎖->調(diào)用List類的Mapcar->釋放鎖;O.4. /nachos-3.4/code/machine:A. Timer.h:定義了模擬硬件時鐘的數(shù)據(jù)結(jié)構(gòu)。一個硬件時鐘每x毫秒,這可以用來給時間分片,或者讓一個線程睡眠一定長的時間段。此處模擬硬件時鐘的思路是每次TimerTicks使得變量stats->totalTicks增加就產(chǎn)生一個終端。為了在時間分片上產(chǎn)生一定的隨機(jī)性,可以設(shè)置變量doRandom,然后在隨機(jī)的ticks之后產(chǎn)生中斷。不
39、能改編代碼,因為這是機(jī)器模擬的一部分。Timer.cc:只是為了模擬一個nachos運行的硬件,并不是nachos系統(tǒng)的部分。所以不要改變:1) static void TimerHandler(int arg):偽處理中斷的函數(shù);a) 在Timer的初始化函數(shù)中,調(diào)用此內(nèi)部函數(shù);b) 不直接使用初始化函數(shù)中的timeHandler參數(shù)作為中斷處理函數(shù)的原因:如果直接使用timeHandler作為時鐘中斷處理函數(shù), interrupt->Schedule(TimerHandler, (int) this, TimeOfNextInterrupt(),TimerInt)是將一個時鐘中斷插入
40、等待處理中斷隊列,一旦中斷時刻到來則立即處理中斷,處理結(jié)束后沒有機(jī)會將下一個時鐘中斷插入等待處理的中斷隊列。而時鐘中斷時刻到來,調(diào)用TimerHandler內(nèi)部函數(shù),TimerHandler則調(diào)用TimerExpired成員函數(shù),該函數(shù)可以將新的中斷插入到等待處理的中斷隊列,然后再調(diào)用真正的時鐘中斷處理函數(shù);c) 不講TimerExpired函數(shù)作為時鐘中斷在Timer的初始化函數(shù)中調(diào)用的原因:C+不能直接引用一個類成員函數(shù)的指針,所以借用TimerHandler內(nèi)部函數(shù),也因此將TimerExpired設(shè)置為public屬性;2) Timer:初始化一個硬件時鐘設(shè)備,每次中斷,保存要調(diào)用的地
41、址,然后安排時鐘開始產(chǎn)生中斷;3) TimerExpired():模擬產(chǎn)生中斷的代碼。調(diào)度下一次中斷,并且調(diào)用中斷處理函數(shù);4) TimeOfNextInterrupt():返回下一次時鐘中斷的時間。如果設(shè)置了隨機(jī)查宿,則產(chǎn)生一個偽隨機(jī)的延遲;B. Interrupt.h:定義模擬底層中斷硬件的數(shù)據(jù)結(jié)構(gòu)。硬件提供了代碼來開關(guān)中斷,可以設(shè)置SetLevel。為了模擬硬件,我們需要記錄硬件設(shè)備將要產(chǎn)生的中斷,以及它們什么時候應(yīng)該產(chǎn)生。這個模塊也要記錄模擬時間。只有一下三種情況才會增加時間:Ø 再次開中斷;Ø 執(zhí)行一條用戶指令;Ø 就緒隊列為空;因此,不同于真實的硬件,
42、中斷不能在關(guān)閉中斷的代碼中產(chǎn)生。這意味著不正確的同步代碼可能在硬件模擬器上正常工作,但是在真實的硬件上則不然。不能改變此處的代碼,這是機(jī)器模擬的一部分。1) IntStatus:枚舉變量,包括開/關(guān)中斷;2) MachineStatus:枚舉變量,包括空閑/系統(tǒng)/用戶模式;3) IntType:枚舉變量,記錄了產(chǎn)生中斷的硬件設(shè)備,包括時鐘、磁盤、控制臺、網(wǎng)絡(luò)接收和發(fā)送;4) PendingInterrupt:類定義了未來要產(chǎn)生的中斷,內(nèi)部數(shù)據(jù)結(jié)構(gòu)均為public屬性,便于操作,包括產(chǎn)生中斷時要調(diào)用的函數(shù)指針、傳遞的參數(shù)、產(chǎn)生的中斷時間,以及初始化中斷的函數(shù);5) Interrupt:類定義了模
43、擬硬件中斷的數(shù)據(jù)結(jié)構(gòu)。記錄中斷是否打開,以及未來所以的硬件中斷;Interrupt.cc:1) PendingInterrupt:PendingInterrupt():初始化未來要調(diào)度的硬件設(shè)備中斷;2) Interrupt:Interrupt():初始化硬件設(shè)備中斷,即中斷關(guān)閉,清楚inHandler標(biāo)志,初始為系統(tǒng)態(tài),同時初始化等待處理的中斷隊列;3) Interrupt: Interrupt():刪除模擬中斷所需的數(shù)據(jù)結(jié)構(gòu),循環(huán)釋放等待處理的中斷隊列中每個中斷占用的空間資源;4) Interrupt:ChangeLevel():改變中斷類型為開/關(guān),同時模擬時間不能增加,是一個內(nèi)置函數(shù);
44、5) Interrupt:SetLevel():設(shè)置中斷為開/關(guān),而且如果設(shè)置打開中斷,通過調(diào)用OneTick()使得模擬時間增加。最后返回之前的中斷開/關(guān)狀態(tài)Assert的用意?;6) Interrupt:Enable():打開中斷,不關(guān)心之前的狀態(tài),在ThreadRoot中用于啟動一個線程時打開中斷;7) Interrupt:OneTick():模擬時間增加一個單位,根據(jù)當(dāng)前狀態(tài)為用戶態(tài)/系統(tǒng)態(tài)時鐘分別前進(jìn)一個用戶態(tài)時間單位/系統(tǒng)態(tài)時間單位,并更新nachos用戶態(tài)和系統(tǒng)態(tài)運行的時間,同時檢查當(dāng)前是否還有中斷發(fā)生,有則進(jìn)行處理。有兩種情況會調(diào)用此函數(shù):Ø 再次打開中斷;Ø
45、; 執(zhí)行一條用戶指令;執(zhí)行的過程如下:a) 保存舊狀態(tài);b) 前進(jìn)和前進(jìn)時間單位;c) 關(guān)中斷;d) 等待將要發(fā)生的中斷;e) 如果yieldOnReturn為true,表示要切換上下文,則切換到內(nèi)核模式,當(dāng)前線程調(diào)用Yield()函數(shù)讓出CPU;8) Interrupt:YieldOnReturn():在一個中斷處理程序內(nèi)部被調(diào)用,返回時在被中斷的線程引發(fā)一個上下文切換。在這里不能切換上下文,否則會置換掉中斷處理函數(shù),而我們想要置換被中斷的線程?。此函數(shù)內(nèi)部設(shè)置yieldOnReturn標(biāo)志;9) Interrupt:Idle():就緒隊列為空調(diào)用的代碼。檢查當(dāng)前等待處理的中斷隊列是否有待處
46、理的中斷,如果有將系統(tǒng)時鐘前進(jìn)到下一個被調(diào)度的中斷進(jìn)處理。然后處理在新的時刻其他需要發(fā)送的中斷?多次調(diào)用CheckIfDue()。如果沒有等待的中斷,則無事可做,調(diào)用Halt()停止;10) Interrupt:Halt():關(guān)掉nachos系統(tǒng),打印性能數(shù)據(jù),最后調(diào)用cleanup()函數(shù);11) Interrupt:Schedule():安排CPU在某個模擬的時刻被中斷,nachos的內(nèi)核不能直接調(diào)用,只有硬件設(shè)備模擬可以調(diào)用此代碼;12) Interrupt:CheckIfDue(bool advanceClock):檢查一個中斷是否要被調(diào)度發(fā)生,如果是,則發(fā)射中斷,并返回true;參數(shù)
47、advanceClock是時鐘前進(jìn)標(biāo)志,為true表示就緒隊列為空,系統(tǒng)處于Idle狀態(tài),我們應(yīng)該增加時間到下一個要發(fā)射的中斷。如果要發(fā)生的中斷為時間片守護(hù)進(jìn)程,則系統(tǒng)退出:a) 保存舊的狀態(tài);b) 確保中斷關(guān)閉,以調(diào)用中斷處理程序;c) 尋找下一個要發(fā)生的中斷;d) 如果沒有要發(fā)生的中斷,返回false;e) 設(shè)置了advanceClock,時鐘前進(jìn)到要發(fā)生的中斷的時刻;f) 未設(shè)置advanceClock,不能前進(jìn)時鐘,則取出的中斷放回原處,返回false;g) 當(dāng)前為空閑模式,要發(fā)生的為時鐘中斷,且等待中斷隊列沒有其他類型的中斷,則將該中斷放回原處等待一會處理,返回false;h) 發(fā)生
48、中斷:1. InHandler設(shè)置為true,表示正在進(jìn)行中斷處理程序;2. Status設(shè)置成系統(tǒng)態(tài),說明中斷處理程序是系統(tǒng)態(tài)的;3. 進(jìn)行中斷處理程序的處理,直到處理結(jié)束;4. 恢復(fù)機(jī)器狀態(tài),即恢復(fù)inHandler和status標(biāo)志;5. 返回true;13) PrintPending():打印一個將被調(diào)度的中斷的相關(guān)信息,包括時間、地點和原因(類型);14) Interrupt:DumpState():打印完整的中斷狀況,包括狀態(tài)和將要發(fā)生的C. Machine.h:1) 模擬運行在nachos上的用戶程序的數(shù)據(jù)結(jié)構(gòu)。用戶程序被加載到主存在nachos看來,類似于一個byte數(shù)組。Na
49、chos的內(nèi)核也在主存中,但是在現(xiàn)在的很多機(jī)器上,內(nèi)核被加載到一個和用戶程序不同的一塊內(nèi)存,而且對內(nèi)核的訪問也不翻譯或者分頁。2) 在nachos,用戶程序一次執(zhí)行一條指令。每次對內(nèi)存的訪問都會被翻譯和查錯。3) Machine類用來模擬計算機(jī)主機(jī)。它提供的功能有:讀寫寄存器。讀寫主存、運行一條用戶程序的匯編指令、運行用戶程序、單步調(diào)試用戶程序、顯示主存和寄存器狀態(tài)、將虛擬內(nèi)存地址轉(zhuǎn)換為物理內(nèi)存地址、陷入 Nachos 內(nèi)核等等。4) Machine類實現(xiàn)方法是在宿主機(jī)上分配兩塊內(nèi)存分別作為虛擬機(jī)的寄存器和物理內(nèi)存。運行用戶程序時,先將用戶程序從 Nachos 文件系統(tǒng)中讀出,寫入模擬的物理內(nèi)
50、存中,然后調(diào)用指令模擬模塊對每一條用戶指令解釋執(zhí)行。將用戶程序的讀寫內(nèi)存要求,轉(zhuǎn)變?yōu)閷ξ锢韮?nèi)存地址的讀寫。Machine類提供了單步調(diào)試用戶程序的功能,執(zhí)行一條指令后會自動停下來,讓用戶查看系統(tǒng)狀態(tài),不過這里的單步調(diào)試是匯編指令級的,需要讀者對R2/3000指令比較熟悉。如果用戶程序想使用操作系統(tǒng)提供的功能或者發(fā)出異常信號時,Machine調(diào)用系統(tǒng)異常陷入功能,進(jìn)入Nachos的核心部分。5) Nachos寄存器組模擬了全部32個MIPS機(jī)(R2/3000)的寄存器,同時加上有關(guān)Nachos系統(tǒng)調(diào)試用的8個寄存器,以期讓模擬更加真實化并易于調(diào)試。6) class Instruction:模擬機(jī)
51、的機(jī)器指令由操作代碼和操作數(shù)組成的;class Machine: 定義Machine類的目的是為了執(zhí)行用戶程序,如同許多其它系統(tǒng)一樣,用戶程序不直接使用內(nèi)存的物理地址,而是使用自己的邏輯地址,在用戶程序邏輯地址和實際物理地址之間,就需要一次轉(zhuǎn)換,系統(tǒng)提供了兩種轉(zhuǎn)換方法的接口:線性頁面地址轉(zhuǎn)換方法和TLB頁面地址轉(zhuǎn)換方法。enum ExceptionType: 在用戶程序運行過程中,會有很多系統(tǒng)陷入核心的情況。系統(tǒng)陷入有兩大類原因:進(jìn)行系統(tǒng)調(diào)用陷入和系統(tǒng)出錯陷入。系統(tǒng)調(diào)用陷入在用戶程序進(jìn)行系統(tǒng)調(diào)用時發(fā)生。系統(tǒng)調(diào)用可以看作是軟件指令,它們有效地彌補了機(jī)器硬件指令不足;系統(tǒng)出錯陷入在系統(tǒng)發(fā)生錯誤時發(fā)
52、生,比如用戶程序使用了非法指令以及用戶程序邏輯地址同實際的物理地址映射出錯等情況。不同的出錯陷入會有不同的處理,比如用戶程序邏輯地址映射出錯會引起頁面的重新調(diào)入,而用戶程序使用了非法指令則需要向用戶報告等等。7) 另外,由于Nachos可以在多種平臺上運行,各種運行平臺的數(shù)據(jù)表達(dá)方式不完全一樣,有的是高位在前,有的是高位在后。為了解決跨平臺的問題,特地給出了四個函數(shù)作數(shù)據(jù)轉(zhuǎn)換,它們是WordToHost、ShortToHost、WordToMachine和ShortToMachine。D. Machine.cc:1) Machine:初始化用戶程序執(zhí)行的模擬(此處實現(xiàn)tlb和linear pa
53、ge table不可同時使用);2) Machine:釋放數(shù)據(jù)空間,包括maimMemory和tlb;3) Static void CheckEndian:檢查宿主機(jī)是大端以便存儲(nachos是大端存儲);4) Machine:RaiseException:由于用戶程序的系統(tǒng)調(diào)用或者發(fā)生異常,將控制從用戶模式轉(zhuǎn)換到nachos的內(nèi)核模式。當(dāng)系統(tǒng)檢查到出錯陷入時調(diào)用,通過調(diào)用ExceptionHandler來處理陷入。(見exception.cc)ExceptionHandler目前對所有的陷入都不進(jìn)行處理,需要進(jìn)一步加強(qiáng)。如上面提到的,如果使用TLB表時,應(yīng)該對PageFaultError作
54、出處理;5) Machine:Debugger:用戶程序的調(diào)試工具。注意不可以用gdb,因為gdb沒有運行在nachos上。這里主要是允許單步運行,然后打印內(nèi)存的內(nèi)容;6) Machine:DumpState:打印用戶的CPU狀態(tài)。但是打印主存的內(nèi)容殺傷力比較大主存東西比較多,打印會比較費時;7) Machine:ReadRegister/ WriteRegister:讀取或者寫用戶程序寄存器的內(nèi)容;E. Mipssim.h:1) 內(nèi)部的模擬MIPS指令集的數(shù)據(jù)結(jié)構(gòu)。opCode的名字直接取自MIPS手冊,除了OP_UNIMP(該指令合法但是還未被執(zhí)行),OP_RES(保留的opcode,體系
55、不支持);2) struct OpInfo:包括opCode和format,包括I、J、R;3) opTable:確定指令的opCode和format;4) specialTable:結(jié)合opCode翻譯funct域;5) struct OpString:為了調(diào)試打印每條指令的信息;F. Mipssim.cc:1) 模擬了MIPS R2/3000 進(jìn)程。這段代碼摘自O(shè)usterhout的MIPSSIM包。字節(jié)排列是小端法,所以和Dec的RISC系統(tǒng)兼容;2) Machine:Run:模擬nachos上用戶級程序的執(zhí)行,當(dāng)程序開始的時候被內(nèi)核調(diào)用,從不返回。這段代碼是可重入的,因為它可以被同時多
56、次調(diào)用,然后每個線程執(zhí)行各自的用戶代碼;3) static int TypeToReg:檢索一條指令的寄存器編號;4) Machine:OneInstruction:執(zhí)行用戶級程序的一條指令;5) Machine:DelayedLoad:模擬執(zhí)行一次延遲載入的效果。注意RaiseException和CheckInterrupts必須調(diào)用此函數(shù),因為任何延遲的載入都必須在我們陷入內(nèi)核前申請;Instruction:Decode:對一條MIPS指令譯碼;6) static void Mult:模擬R2000的乘法,指針hiPtr和loPtr在保存double長度的結(jié)果時被重寫;G. Transla
57、te.h:1) 管理虛擬頁號到物理頁號的翻譯,代表頁號程序管理物理內(nèi)存。且此處的數(shù)據(jù)結(jié)構(gòu)既用于page table,又用于tlb,條目的格式是<虛擬頁號,物理頁號>。2) class TranslationEntry:無論是線性頁面地址轉(zhuǎn)換還是TLB頁面地址轉(zhuǎn)換,都需要一張地址轉(zhuǎn)換表,地址轉(zhuǎn)換表是由若干個表項(Entry)組成的。每個表項記錄程序邏輯頁到內(nèi)存實頁的映射關(guān)系,和實頁的使用狀態(tài)、訪問權(quán)限信息。H. Translate.cc:1) 此處支持兩種翻譯linear page table, Translation lookaside buffer2) linear page table:虛擬頁號用于到此表的索引,用于查找物理頁號;3) Translation loo
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 各類建筑工程施工方案設(shè)計
- 垃圾填埋場項目可行性研究報告
- 做東南亞跨境電商平臺
- 肉鴨養(yǎng)殖項目可行性研究報告
- 大數(shù)據(jù)時代企業(yè)數(shù)據(jù)安全管理制度手冊
- 動力電池再生利用
- 三農(nóng)村電氣化工程作業(yè)指導(dǎo)書
- 高職護(hù)理婦產(chǎn)科復(fù)習(xí)測試卷附答案
- 附件3醫(yī)院護(hù)類人員年終理論考試500題練習(xí)試題附答案
- 智能環(huán)保與資源利用作業(yè)指導(dǎo)書
- 眼科學(xué)基礎(chǔ)本科
- 小沈陽《四大才子》歡樂喜劇人臺詞
- 交通安全設(shè)施作業(yè)指導(dǎo)書
- 優(yōu)秀員工榮譽證書模板
- 神奇的電家長課堂
- 城南舊事讀書匯報教學(xué)課件
- 不銹鋼容器制造通用標(biāo)準(zhǔn)工藝守則
- 校園環(huán)境衛(wèi)生檢查及記錄表
- 合同能源管理合同范本模板
- Q∕SY 05006-2016 在役油氣管道 第三方施工管理規(guī)范
- 數(shù)值分析 第二章 代數(shù)插值解析
評論
0/150
提交評論