《作業系統真象還原》-閱讀筆記(中)
第七章
作業系統是由中斷驅動的。
中斷分為外部中斷和內部中斷。
外部中斷分為可遮蔽中斷和不可遮蔽中斷,內部中斷分為軟中斷和異常。
外部中斷
來自CPU外部的中斷。
可遮蔽中斷:通過INTR引腳進入CPU,外部裝置如硬碟、網絡卡、印表機等發出的中斷
CPU可以不理會,因為不會宕機。
Linux把中斷分為上半部和下半部分開處理,把中斷立即需要執行的部分劃分到上半部,不緊急的部分劃分到下半部。上半部是在關中斷的情況下執行的。
不可遮蔽中斷:通過NMI引腳進入CPU,它表示系統發生了致命的錯誤。
三種常見原因:1.記憶體讀寫錯誤 2電源掉電 3匯流排奇偶校驗錯誤
內部中斷
軟中斷
異常:指令執行期間CPU內部產生的錯誤引起的。
中斷描述符表(IDT)
IDT中有中斷描述符,還有任務門描述符和陷阱門描述符。
這些描述符都是門,門是通往另一段程式的入口。門描述符中添加了各種屬性,就是進門的條件。
中斷處理過程:
CPU外:
CPU內:
1.處理器根據中斷向量號定位中斷描述符
2.處理器進行特權級檢查
3執行中斷處理程式
如下圖:
這裡我突然想起個問題,訪問核心地址空間不需要經過頁表嗎?因為核心地址空間一般是連續的。
答案是也需要,不過是核心頁表。一旦CPU進入了保護模式,開啟分頁機制,不管在核心空間,還是使用者空間,都是使用虛擬地址進行定址了。
在32位的系統,核心頁表記錄核心對高階記憶體訪問而進行的對映關係。因為現代 CPU 的定址不能繞過 MMU。不過核心空間和使用者空間不同,它一般不做 swap,也就沒有 page fault,而且它一般不會把連續的虛擬地址空間對映成不連續的物理空間,一般只是做一個 offset。
8259A程式設計
一箇中斷控制器
8253程式設計
一個定時器,打節拍,最重要功能:定時向處理器發時間中斷
第八章
makefile編寫
略
實現ASSERT
因為要列印螢幕,所以最好關中斷
開中斷:原理是執行sti指令把eflags中的IF位置1
關中斷:原理是執行cli指令把eflags中的IF位置0
實現字串操作函式
包括memset、memcpy、strcpy、strlen、strcmp、strcat、strchr(從左到右查詢字串str中首次出現字元ch的地址)、strchrs(查詢在字串str中ch出現的次數)
點陣圖實現
略
記憶體管理
每個任務(核心和使用者)都要維護自己的虛擬地址池。
聲明瞭一個叫virtual_addr的結構體用來表示虛擬記憶體池,儲存一個位圖結構和虛擬地址起始地址。
實現了malloc_page函式,2個引數,一個是pf,用來指明記憶體池(核心還是使用者),一個是pg_cnt,用來指明頁數,此函式的功能是在pf指向的記憶體池中分配pg_cnt個頁,成功則返回虛擬地址,失敗則返回NULL。
此函式幹了三件事:
1.通過vaddr_get在虛擬記憶體池中申請虛擬地址
2.通過palloc在實體記憶體池中申請物理頁
3.通過page_table_add將上兩步得到的虛擬地址和實體地址在頁表中完成對映
tips
在ubuntu下用gcc編譯連結,出現錯誤
undefined reference to `__stack_chk_fail’
解決方法:
add -fno-stack-protector to your CFLAGS.
第九章
PCB
每個程序都有自己的PCB,所有PCB放到一張表格中維護,這就是程序表。排程器可以根據這張表選擇處理器執行的程序。
暫存器映像用來儲存程序的現場,用於程序切換。
PCB最頂端為執行緒在0特權級下所用的棧。
實現執行緒
兩種實現方式
1.使用者空間實現,執行緒表就在使用者程序中,使用者程序要專門寫個執行緒用作執行緒排程器。
優點:
排程演算法自己實現
執行緒切換不用陷入核心態裝載暫存器映像
缺點:
某個執行緒出現阻塞,整個程序都會阻塞(作業系統不知道程序中存線上程)
2.核心空間實現,執行緒表就在核心中,該執行緒由作業系統一排程,無論執行緒屬於核心還是使用者空間。
優點:
核心提供的執行緒相當於讓程序多佔用了處理器資源(因為一個程序有多個執行緒可以放上排程器),提速明顯。
程序中某一執行緒阻塞後,只會阻塞這一個執行緒,變相提速。
缺點:
會陷入核心態,增加了一些保護現場的操作,但比起提速可以忽略。
本文用第二種實現方法,Linux中嚴格來說,使用者空間是沒有Thread這個概念的,Thread的相關實現是gcc等提供的模擬thread, gcc是使用了clone這個系統呼叫,利用linux的輕量級程序實現了類似thread的庫。下面的連結有詳細介紹
http://www.360doc.com/content/13/1008/11/13047933_319789998.shtml
執行緒PCB由雙向連結串列串聯
任務排程
在 schedule 中要判斷當前執行緒是出於什麼原因才“淪落到”要被換下處理器
的地步 。 是執行緒的時間片到期了?還是執行緒時間片未到,但它被阻塞了,以至於不得不換下處理器?其實這就是檢視執行緒的狀態,如果執行緒的狀態為TASK RUNNING ,這說明時間片到期了,將其 ticks 重新賦值為它的優先順序 prio ,將其狀態由 TASK_RUNNING 置為 TASK_READY ,並將其加入到就緒佇列的末尾。如果狀態為其他,這不需要任何操作,因為排程器是從就緒佇列中取出下一個執行緒,而當前執行的錢程並不在就緒佇列中。
完整的排程需要三部分的配合:
1.時鐘中斷函式
2.排程器schedule
3.任務切換函式switch_to
第十章
出現GP錯誤原因:多個執行緒訪問游標暫存器,一個執行緒更新完高8位後被換下,另一個執行緒通知顯示卡馬上要寫來的是暫存器高8位,這時被換下,第一個執行緒繼續寫低8位,但顯示卡認為這是高8位。需要實現鎖來同步
訊號量
一個全域性共享變數,變數的加減必須是原子操作,需要關中斷來保證
鎖
本文的鎖是用二元訊號量實現的