程序此時不僅是在執行而已,它可以隨時被中斷,可以在中斷處理程式完成之後被恢復。程序此時已經有了兩種狀態:執行和睡眠。我們已經具備了處理多個程序的能力,只需要讓其中乙個程序處在執行態,其餘程序處在睡眠態就可以了。
在main.c中程序a的**的下面新增程序b:
void testb()列印的字母換成了b,i的初始值被設成了0x1000.}
讓我們來回憶一下當初準備第乙個程序時還做了哪些工作。程序不外乎4個要素:程序表、程序體、gdt、tss。
minix系統中定義了乙個陣列叫做tasktab。這個陣列的每一項定義好乙個任務(「任何」和「程序」可以互換)的開始位址、堆疊等,在初始化的時候,只要用乙個for迴圈依次讀取每一項,然後填充到相應的程序表項中就可以了。
首先在proc.h中:
typedef struct s_task task;乙個程序只要有乙個程序體和堆疊就可以執行了,所以這個陣列只要有前兩個成員其實就已經夠了。這裡我們還定義了name,以便給每個程序起乙個名字。
public task task_table[nr_tasks] = ,別忘了在global.h中:};
extern task task_table;記得把nr_tasks的值修改為2.還有stack_size_testb:
/* number of tasks */下面來做程序表的初始化工作。現在可以用for迴圈來做程序表的初始化工作了。#define nr_tasks 2
/* stacks of tasks */
#define stack_size_testa 0x8000
#define stack_size_testb 0x8000
#define stack_size_total (stack_size_testa + \
stack_size_testb)
請看main.c的kernel_main()函式。在我們這個簡單的例子中,程序之間區別真的不大。每一次迴圈的不同在於,從task結構中讀取不同的任務入口位址、堆疊棧頂和程序名,然後賦給相應的程序表項。需要注意兩點:
1.由於堆疊是從高位址往低位址生長的,所以在給每乙個程序分配堆疊空間的時候也是從高位址往低位址進行。
2.我們為每乙個程序都在gdt中分配乙個描述符用來對應程序的ldt。我們在task_table中定義了幾個任務,通過上文的for迴圈中的**,gdt中就會有幾個描述符被初始化,它們列在selector_ldt_first之後。
此外,p_name和pid目前並沒有什麼實際的作用。
每乙個程序都會在gdt中對應乙個ldt描述符。可是ldt選擇子僅僅是解決了where問題,通過它,我們能在gdt中找到相應的描述符,但描述符的具體內容是什麼,what問題還沒解決。
在protect.c中的init_prot函式也使用乙個迴圈:
// 填充 gdt 中程序的 ldt 的描述符,如下:int i;
process* p_proc = proc_table;
u16 selector_ldt = index_ldt_first << 3;
for(i=0;i>3],
vir2phys(seg2phys(selector_kernel_ds),
proc_table[i].ldts),
ldt_size * sizeof(descriptor) - 1,
da_ldt);
p_proc++;
selector_ldt += 1 << 3;
}
lldt [esp + p_ldt_sel]接下來修改中斷處理程式來切換程序。
在任務切換過程中,首先,處理器中各暫存器的當前值被自動儲存到tr(任務暫存器)所指定的tss中;然後,下一任務的tss的選擇子被裝入tr;最後,從tr所指定的tss中取出各暫存器的值送到處理器的各暫存器中。
要想恢復不同的程序,只需要將esp指向不同的程序表就可以了,全域性變數p_proc_ready是指向程序表結構的指標,我們只需要在下面這一句執行之前把它賦予不同的值就可以了。
mov esp, [p_proc_ready] ; 離開核心棧我們再來學習一下minix,建立乙個clock.c。
public void clock_handler(int irq)在時鐘中斷例程中呼叫這個函式。
下面該程序切換了:
public void clock_handler(int irq)在上面**中,每一次我們讓p_proc_ready指向程序表中的下乙個表項,如果切換前已經到達程序表結尾則回到第乙個表項。執行結果如下,我們看到了交替出現的「a」和「b」,還有各自不斷增加的數字,實現了多程序:
【原始碼
】
作業系統開發系列 13 h 延時操作
計數器的工作原理是這樣的 它有乙個輸入頻率,在pc上是1193180hz。在每乙個時鐘週期 clk cycle 計數器值會減1,當減到0時,就會觸發乙個輸出。由於計數器是16位的,所以最大值是65535,因此,預設的時鐘中斷的發生頻率就是1193180 65536約等於18.2hz。我們可以通過程式...
作業系統開發 Hello OS 開始作業系統開發
在開發作業系統之前 我們需要知道從按下電源開機鍵開始 cpu 都做了什麼 第一步 按下電源鍵 cpu重置,開始工作 第二步 從記憶體位址為 0xfffffff0 的位置開始 讀取指令並執行 而這個位址對應的就是 bios basic input output system 第三步 bios 的pos...
BEAR作業系統開發 1
從今天開始,我將開發作業系統了。我將她取名為 bear 小熊的意思,因為我的乙個朋友喜歡小熊,所以就用它了。其實 bear 還有另外乙個意思,就是 忍受 忍受學習的壓力和痛苦,這樣才會有所收穫。我模仿的linux0.11的核心源 現在主要將它的string標頭檔案移植到x86系統上面。今天完成了7個...