我們知道 Linux 是 multi-tasking 的環境,同時可以有很多人執行很多的程序。這是從 user 的觀點來看的。如果就 kernel 的觀點來看,是沒有所謂的 multi-tasking 的。在 kernel 裡,只有 single-thread。也就是說,如果你的 kernel code 正在執行,那系統裡只有那部分在執行。不會有另一部分的 kernel code 也在運作。當然,這是指 single processor 的情況下,如果是 SMP 的話,那我就不清楚了。我想很多人都在 Windows 3.1 下寫過程序,在那種環境下寫程序,每一個程序都必須適當的將 CPU 讓給別的程序使用。如果有個程序裡面有一個 while (1); 的話,那保證系統就停在那裡了。這種的多任務叫做 non-preemptive。它多任務的特性是由各個程序相互合作而造成的。在 Linux 的 user space 下,則是所謂的 preemptive,各個 process 喜歡執行什麼就執行什麼,就算你在你的程序裡加上 while(1); 這一行也不會影響系統的運作。反正時間到了,系統自動就會將你的程序停住,讓別的程序去執行。這是在 user space 的情況下,在 kernel 這方面,就跟 Windows 3.1 程序是一樣的。在 kernel 裡,你必須適當的將 CPU 的執行權釋放出來。如果你在 kernel裡加入 while(1); 這一行。那系統就會跟 Windows 3.1 一樣。卡在那裡。當然啦,我是沒試過這樣去改 kernel,有興趣的人可以去試試看,如果有不同的結果,請記得告訴我。
假設我們在 kernel 裡產生一個 buffer,user 可以經由 read,write 等 system call 來讀取或寫資料到這個 buffer 裡。如果有一個 user 寫資料到 buffer 時,此時 buffer 已經滿了。那請問你要如何去處理這種情形呢 ? 第一種,傳給 user 一個錯誤訊息,說 buffer 已經滿了,不能再寫入。第二種,將 user 的要求 block 住,等有人將 buffer 內容讀走,留出空位時,再讓 user 寫入資料。但問題來了,你要怎麼將 user 的要求 block 住。
struct wait_queue *wq = NULL; /* global variable */
while ( is_full ) {
interruptible_sleep_on( &wq );
}
write_to_buffer();
interruptible_sleep_on( &wq ) 是用來將目前的 process,也就是要求寫資料到 buffer 的 process放到 wq 這個 wait_queue 裡。在 interruptible_sleep_on 裡,則是最後會呼叫 schedule() 來做 schedule 的動作,也就是去找另一個 process 來執行以維持系統的運作。當執行完 interruptible_sleep_on 之後,要求 write 的 process 就會被 block 住。那什麼時候會恢復執行呢 ? 這個 process 之所以會被 block 住是因為 buffer 的空間滿了,無法寫入。但是如果有人將 buffer 的資料讀取掉,則 buffer 就有空間可以讓人寫入。所以,有關於叫醒 process 的動作應該是在 read buffer 這方面的程序代碼做的。
extern struct wait_queue *wq;
if ( !is_empty ) {
read_from_buffer();
wake_up_interruptible( &wq );
}
以上的程序代碼應該要放在 read buffer 這部分的程序代碼裡,當 buffer 有多余的空間時,我們就呼叫 wake_up_interruptible( &wq ) 來將掛在 wq 上的所有 process 叫醒。請記得,我是說將 wq 上的所有 process 叫醒,所以,如果如果有10個 process 掛在 wq 上的話,那這 10 個都會被叫醒。之後,至於誰先執行。則是要看 schedule 是怎麼做的。就是因為這 10 個都會被叫醒。如果 A 先執行,而且萬一很不湊巧的,A 又把 buffer 寫滿了,那其它 9 個 process 要怎麼辦呢? 所以在 write buffer 的部分,需要用一個 while 來檢查 buffer 目前是否滿了.如果是的話,那就繼續掛在 wq 上面.