首先對於任何一個操做系統, 系統內核必須應該明確一種獲取進程信息的辦法, pkzd所使用的是一個全局數組struct proc proc[NPROC]。java
其中struct proc爲進程結構的結構體, NPROC是一個用來肯定當前能同時存在的進程的最大數目的宏。struct proc結構的具體代碼以下:數組
struct proc{ int p_exit; uint p_stat; uint p_flag; uint p_sig; uint p_esp; uint p_lesp; pid_t p_pid; pid_t p_ppid; pid_t p_pgrp; uid_t p_uid; uid_t p_ruid; gid_t p_gid; gid_t p_rgid; uint p_cpu; int p_pri; int p_nice; time_t p_time; uint p_error; uint *p_stack; uint *p_pgdir; void *p_wchan; void *p_ttyp; int p_signal[NSIG]; void *p_cdir; void *p_rdir; uint p_start; uint p_end; uint p_brk; uint p_send; void *p_ofile[NOFILE]; };
操做系統的進程有各類各樣的信息, 好比進程id, 打開的文件信息等。有的信息對內核而言不是必須的,而有的則是必須的。函數
我以進程id和文件描述符表爲例作個對比:ui
p_pid做爲每一個進程的惟一標識必須一直常駐在系統內核空間,若是設計時將其放在用戶空間,那麼就會存在進程的pid可能被換出到交換空間的狀況,一旦如此那麼內核將沒法辨別進程。spa
p_ofile爲進程打開的文件描述符表, 每一個進程的文件描述符表理論上不須要常駐內核空間。理由是隻有當前進程纔會去讀寫文件, 一個沒有運行的進程是不會存在讀取文件的狀況的。操作系統
進程id必須存在內核空間的理由有不少,我舉一個例子:好比當前進程執行exit系統調用後內核要向當前進程的父進程發送一個信號或者喚醒正在等待子進程終止的父進程, 而若是此時父進程的p_pid已經被換出, 那麼內核將無所適從。.net
pkzd將進程的全部信息都存放在struct proc中,而不去區分信息是否必要常駐內核(這是一種偷懶的方式)。
unix系統的通常設計都會將只對當前進程有用的信息(好比文件描述符表)放在用戶空間中, 這個空間通常稱爲u區。設計u區的最重要的理由是爲了節省內存, 而現現在的機器已經都有很是充裕的內存了,因此已經不須要特別明確的把全部能夠放在u區的信息都放在u區,個人作法
更是直接省去了u區的實現,固然這是偷懶的。
最後pkzd所使用的語言爲c,之因此採用c而非其餘語言,首先c和彙編的契合度很高(c中能夠調用匯編函數,彙編中又可調用c)。最重要的理由是c對 資源的有力控制,而通常的面向對象的語言並不能作到。另外使用c的理由並不是是由於不少人理解的c能操控硬件(通常控制硬件的代碼仍是用匯編完成的,雖然也 有使用c的例子),根本的理由是c不會像java這樣的面向對象的語言肆意的自動分配內存而致使操做系統內核對資源的失控(我的編寫系統後的看法)。設計
我編寫的操做系統的源代碼的連接:https://sourceforge.net/projects/pkzd/unix