網(wǎng)站建設 個人服務器怎么做網(wǎng)頁
[272頁]
第7章 初始化程序
1、main.c主要內(nèi)核初始化工作。
2、如果能完全理解這里調(diào)用的所有程序,那么看完這張內(nèi)容后應該對Linux內(nèi)核有了大致的了解。
3、 有一定的C語言知識
4、 需要GNU gcc手冊在身邊作為參考,因為在內(nèi)核代碼很多地方使用gcc的擴展特性。
例如內(nèi)聯(lián)(inline)函數(shù)、內(nèi)聯(lián)(內(nèi)嵌)匯編語句等。
7-1 main.c程序
7-1-1 功能描述
1、
(a)main.c程序首先利用前面setup.s程序取得的系統(tǒng)參數(shù)設置、系統(tǒng)的根文件設備
以及一些內(nèi)存全局變量。這些內(nèi)存變量指明了主內(nèi)存的開始地址、系統(tǒng)所擁有的內(nèi)存容量
和作為高速緩沖區(qū)內(nèi)存的末端地址。
如果還定義了虛擬盤,則主內(nèi)存將適當減少。
整個內(nèi)存的映像示意圖如圖7-1所示
內(nèi)核程序+高速緩沖+虛擬盤+主內(nèi)存區(qū)。
(b)高速緩沖部分還要扣除被顯示和ROM BIOS占用的部分。
高速緩沖區(qū)是用于磁盤等塊設備臨時存放數(shù)據(jù)的地方,
以1K(1024)字節(jié)為一個數(shù)據(jù)塊單位。
?主內(nèi)存區(qū)域的內(nèi)存由內(nèi)存管理模塊mm通過分頁機制進行管理分配,
以4K字節(jié)為一個內(nèi)存頁面單位。
(d)內(nèi)核程序可以自由訪問高速緩沖中的數(shù)據(jù),但需要通過mm才能使用分配到內(nèi)存頁面。
2、main.c進行所有方面的硬件初始化工作
包括陷阱門、塊設備、字符設備和tty,還包括人工設置第一個任務task 0。
待所有初始化工作完成后程序就設置中斷允許標志以開啟中斷,
并切換到任務0中運行。
作者建議深入的看,遇到看不懂暫時先放一放。
3、整個內(nèi)核完成初始化后,內(nèi)核將執(zhí)行權切換到用戶模式(任務0),即CPU從0特權級
切換到了第3特權級。此時main.c的主程序就工作在任務0中。然后系統(tǒng)第一次調(diào)用進程創(chuàng)建
函數(shù)fork(),創(chuàng)建出一個用于運行init()的子進程(通常被稱為init進程)。
4、 系統(tǒng)整個初始化過程如圖7-2所示
看作者
(a)main.c程序首先確定如何分配使用系統(tǒng)物理內(nèi)存
(b)調(diào)用內(nèi)核各部分的初始化函數(shù)分別對內(nèi)存管理、中斷處理、塊設備和字符設備、進程管理以及硬盤和軟盤等硬件進行初始化處理。
?程序把自己"手工"移動到任務0(進程0)中運行,并使用fork()調(diào)用首次創(chuàng)建出進程1(init進程),
(d)init()函數(shù)將繼續(xù)進行應用環(huán)境的初始化并執(zhí)行shell登陸程序。
(e)而原進程0則會在系統(tǒng)空閑時被調(diào)度執(zhí)行,因此進程0通常也被稱為idle進程。
5、 init()函數(shù)可分為4個部分:安裝根文件系統(tǒng)、顯示系統(tǒng)信息、
運行系統(tǒng)初始資源配置文件rc中的命令、執(zhí)行用戶登陸shell程序。
(a)代碼首先調(diào)用系統(tǒng)調(diào)用setup((void *) &drive_info);用來收集硬盤設備分區(qū)表信息并安裝根文件系統(tǒng)。
在安裝根文件系統(tǒng)之前,系統(tǒng)會先判斷是否需要建立虛擬盤。若編譯內(nèi)核時設置了虛擬盤的大小,
并在前面內(nèi)核初始化過程中已經(jīng)開辟了一塊內(nèi)存用在虛擬盤,則內(nèi)核就會首先嘗試把根文件系統(tǒng)加載到內(nèi)存的虛擬盤區(qū)中。
(b)打開一個終端設備tty0,并復制其文件描述符以產(chǎn)生標準輸入stdin、標準輸出stdout和錯誤輸出stderr設備。
內(nèi)核隨后利用這些描述符在終端上顯示一些系統(tǒng)信息,例如高速緩沖區(qū)中緩沖塊總數(shù)、注內(nèi)存區(qū)空閑內(nèi)存總字節(jié)等。
?新建一個進程2,并在其中為建立用戶交互使用環(huán)境而執(zhí)行一些初始配置操作,即在用戶可以使用shell命令行環(huán)境之前,
內(nèi)核調(diào)用/bin/sh程序運行了配置文件etc/rc中設置的命令。rc文件的作業(yè)與DOS系統(tǒng)根目錄中的AUTOEXEC.BAT文件類似。
這段代碼首先通過關閉文件描述符0,并立刻打開文件/etc/rc,從而把標志輸入stdin定向到/etc/rc文件上。
這樣,所有的標準輸入數(shù)據(jù)都將從該文件中讀取。然后內(nèi)核以非交互形式執(zhí)行/bin/sh,從而實現(xiàn)執(zhí)行/etc/rc文件中的命令。
當該文件中的命令執(zhí)行完畢后,/bin/sh就會立刻退出。因此進程2也就隨之結束。
(d)init()函數(shù)的最后一部分,等待進程2退出,創(chuàng)建新的進程,執(zhí)行參數(shù)_exit(execve(“/bin/sh”,argv,envp));等待新進程退出,如此循環(huán)。
帶有’-'標志會在/bin/sh執(zhí)行時通知它這不是一次普通的運行,而是作為登陸shell運行/bin/sh的。
6、fork()是內(nèi)聯(lián)函數(shù),因為創(chuàng)建進程1之前,要求進程0的用戶堆棧干凈,所以fork()不能以函數(shù)形式進行調(diào)用。
作者展開代碼,且解釋。
static inline int fork(void)
{
long __res;
asm volatile(“int $0x80”:“=a”(__res):“0”(__NR_fork));
if (__res>=0)
return (int)__res;
errno = -__res;
return -1;
}
進程init和進程0實際上同時使用著內(nèi)核代碼區(qū)內(nèi)(小于1MB的物理內(nèi)存)相同的代碼和數(shù)據(jù)物理內(nèi)存頁面(640KB),
只是執(zhí)行的代碼不在一處。當進程init操作用戶堆棧時,內(nèi)核才會分配內(nèi)存頁給進程init。
當進程init或進程2執(zhí)行過execve()調(diào)用后,進程2的代碼和數(shù)據(jù)區(qū)位于系統(tǒng)的主內(nèi)存。
7-1-2 代碼注釋
佩服趙老師保姆式注釋,如果學不會只能怪您自己了。!!!(-:
/** linux/init/main.c** (C) 1991 Linus Torvalds*/
//是為了包括定義在unistd.h中的內(nèi)嵌匯編代碼等信息。
#define __LIBRARY__
//*.h頭文件所在的默認目錄是include/,則在代碼中就不必明確指明其位置。如果不是UNIX的
//標準頭文件,則需要指明所在的目錄,并用雙引號括住。unistd.h是標準符號常數(shù)與類型文件。
//其中定義了各種符號常數(shù)和類型,并聲明了各種函數(shù)。如果還定義了符號__LIBRARY__,則還會
//包含系統(tǒng)調(diào)用號和內(nèi)嵌匯編代碼syscall0()等。
#include <unistd.h>
#include <time.h>//時間類型頭文件。其中主要定義了tm結構和一些有關時間的函數(shù)原形。/*
我們需要下面這些內(nèi)嵌語句-從內(nèi)核空間創(chuàng)建進程將導致沒有寫時復制(COPY ON WRITE)!!!
知道執(zhí)行一個execve調(diào)用。這對堆??赡軒韱栴}。處理方法是在fork()調(diào)用后不讓main()
使用任何堆棧。因此就不能由函數(shù)調(diào)用-這意味著fork也要使用內(nèi)嵌的代碼,否則我們在從
fork()退出時就要使用堆棧了。實際上只要pause和fork需要使用內(nèi)嵌方式,以保證從main()中不會弄亂堆棧,但是我們同時還
定義了其他一些函數(shù)。
*/
//fork()展開后
static inline _syscall0(int,fork)
//pause()系統(tǒng)調(diào)用;暫停進程的執(zhí)行,直到收到一個信號。
static inline _syscall0(int,pause)
//setup(void *BIOS)系統(tǒng)調(diào)用,僅用于linux初始化(僅在這個程序中被調(diào)用)。
static inline _syscall1(int,setup,void *,BIOS)
//sync()系統(tǒng)調(diào)用:更新文件系統(tǒng)。
static inline _syscall0(int,sync)#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/head.h>
#include <asm/system.h>
#include <asm/io.h>#include <stddef.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>#include <linux/fs.h>#include <string.h>static char printbuf[1024];//靜態(tài)字符串數(shù)組,用作內(nèi)核顯示信息的緩存。extern char *strcpy();
extern int vsprintf();//送格式化輸出到一字符串中
extern void init(void);//函數(shù)原形,初始化
extern void blk_dev_init(void);//塊設備初始化子程序
extern void chr_dev_init(void);//字符設備初始化
extern void hd_init(void);//硬盤初始化程序
extern void floppy_init(void);//軟驅初始化程序
extern void mem_init(long start, long end);//內(nèi)存管理初始化
extern long rd_init(long mem_start, int length);//虛擬盤初始化
extern long kernel_mktime(struct tm * tm);//計算系統(tǒng)開機啟動時間(秒)。
//內(nèi)核專用sprintf()函數(shù)。該函數(shù)用于產(chǎn)生格式化信息并輸出到指定緩沖區(qū)str中。參數(shù)'*fmt'
//指定輸出將采用的格式,參見標志C語言書籍。該子程序正好是vsprintf如何使用的一個簡單
//例子。函數(shù)使用vsprintf()將格式化字符串放入str緩沖區(qū),參見第179行上的printf()函數(shù)。
static int sprintf(char * str, const char *fmt, ...)
{va_list args;int i;va_start(args, fmt);i = vsprintf(str, fmt, args);va_end(args);return i;
}/** 以下這些數(shù)據(jù)是在內(nèi)核引導期間由setup.s程序設置的。*///下面三行分別將指定的線性地址強行轉換為給定數(shù)據(jù)類型的指針,并獲取指針所指內(nèi)容。由于內(nèi)核代碼//被映射到從物理地址零開始的地方,因此這些線性地址正好也是對應的物理地址。//這些指定地址處內(nèi)存值的含義請參見表6-3(setup程序讀取并保存的參數(shù))。//drive_info結構請參見下面第125行。
#define EXT_MEM_K (*(unsigned short *)0x90002)//1MB以后的擴展內(nèi)存大小KB
#define CON_ROWS ((*(unsigned short *)0x9000e) & 0xff)//選的的控制臺屏幕行、列數(shù)。
#define CON_COLS (((*(unsigned short *)0x9000e) & 0xff00) >> 8)//
#define DRIVE_INFO (*(struct drive_info *)0x90080)//硬盤參數(shù)表32字節(jié)內(nèi)容。
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)//根文件系統(tǒng)所在設備號。
#define ORIG_SWAP_DEV (*(unsigned short *)0x901FA)//交換文件所在設備號。/*
是啊,是啊,下面這段程序很差勁,但我不知道如何正確地實現(xiàn),而且好像
它還能運行。如果有關于實時時鐘更多資料,那我很感興趣。這些都是試探
出來的,另外還看了一些bios程序,呵!*/
//這段宏讀取CMOS實時時鐘信息。outb_p和inb_p是include/asm/io.h中定義的端口輸入輸出宏。
#define CMOS_READ(addr) ({ \
outb_p(0x80|addr,0x70); \ //0x70是寫地址端口號。
inb_p(0x71); \ //0x71是讀數(shù)據(jù)端口號。
})
//定義宏。將BCD碼轉換二進制數(shù)據(jù)值。
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)//該函數(shù)取CMOS時鐘信息作為開機時間,保存到全局變量startup_time(秒)中。參見后面
//CMOS內(nèi)存列表說明。其中調(diào)用的函數(shù)kernel_mktime()用于計算從1970年1月1日0時起到
//開機當日經(jīng)過的秒數(shù),作為開機時間。
static void time_init(void)
{struct tm time;do {time.tm_sec = CMOS_READ(0);time.tm_min = CMOS_READ(2);time.tm_hour = CMOS_READ(4);time.tm_mday = CMOS_READ(7);time.tm_mon = CMOS_READ(8);time.tm_year = CMOS_READ(9);} while (time.tm_sec != CMOS_READ(0));BCD_TO_BIN(time.tm_sec);BCD_TO_BIN(time.tm_min);BCD_TO_BIN(time.tm_hour);BCD_TO_BIN(time.tm_mday);BCD_TO_BIN(time.tm_mon);BCD_TO_BIN(time.tm_year);time.tm_mon--;startup_time = kernel_mktime(&time);
}
//下面定義一些局部變量。
static long memory_end = 0; //機器具有的物理內(nèi)存容量(字節(jié)數(shù))。
static long buffer_memory_end = 0; //告訴緩沖區(qū)末端地址。
static long main_memory_start = 0; //主內(nèi)存(將用于分頁)開始的位置。
static char term[32]; //終端設置字符串(環(huán)境參數(shù))。//讀取并執(zhí)行/etc/rc文件時所使用的命令行參數(shù)和環(huán)境參數(shù)。
static char * argv_rc[] = { "/bin/sh", NULL };
static char * envp_rc[] = { "HOME=/", NULL ,NULL };
//運行登陸shell時所使用的命令行參數(shù)和環(huán)境參數(shù)。
//"-"是傳遞給shell程序sh的一個標志。通過識別該標志,sh程序
//會作為登陸shell執(zhí)行。其執(zhí)行過程與在shell提示符下執(zhí)行sh不一樣。
static char * argv[] = { "-/bin/sh",NULL };
static char * envp[] = { "HOME=/usr/root", NULL, NULL };struct drive_info { char dummy[32]; } drive_info;//用于存放硬盤參數(shù)表信息。//內(nèi)核初始化主程序。初始化結束后將以任務0(idle任務即空閑任務)的身份運行。
void main(void) /* 這里確實是void,沒錯。 */
{ /* 在startup程序(head.s)中就是這樣假設的 */
/*
此時中斷仍被禁止著,做完必要的設置后就將其開啟。*/
//首先保存根文件系統(tǒng)設備號和交換文件設備號,并根據(jù)setup.s程序中獲取的信息設置控制臺終端
//屏幕行、列數(shù)環(huán)境變量TERM,并用其設置初始init進程中執(zhí)行etc/rc文件和shell程序使用的
//環(huán)境變量,以及復制內(nèi)存0x90080處的硬盤參數(shù)表。
//其中ROOT_DEV已在前面包含進的include/linux/fs.h文件第206行上被聲明為extern int,
//而SWAP_DEV在include/linux/mm.h文件內(nèi)也作了相同聲明。這里mm.h文件并沒有顯示地列在
//本程序前面,因為前面包含進的include/linux/sched.h文件中已經(jīng)包含有它。 ROOT_DEV = ORIG_ROOT_DEV;//聲明在fs/super.c 定義在bootsetup.sSWAP_DEV = ORIG_SWAP_DEV;//聲明在mm/swap.c 定義在bootsetup.ssprintf(term, "TERM=con%dx%d", CON_COLS, CON_ROWS);envp[1] = term; envp_rc[1] = term;drive_info = DRIVE_INFO;//復制內(nèi)存0x90080處的硬盤參數(shù)表。
//接著根據(jù)機器物理內(nèi)存容量設置高速緩沖區(qū)和主內(nèi)存區(qū)的位置和范圍。
//高速緩存末端地址->buffer_memory_end;機器內(nèi)存容量->memory_end;
//主內(nèi)存開始地址->main_memory_start;memory_end = (1<<20) + (EXT_MEM_K<<10);//內(nèi)存大小=1MB+擴展內(nèi)存(k)*1024字節(jié)。memory_end &= 0xfffff000;//忽略不到4KB(1頁)的內(nèi)存數(shù)。if (memory_end > 16*1024*1024)//如果內(nèi)存量超過16MB,則按16MB計。memory_end = 16*1024*1024;if (memory_end > 12*1024*1024) //如果內(nèi)存>12MB,則設置緩沖區(qū)末端=4MBbuffer_memory_end = 4*1024*1024;else if (memory_end > 6*1024*1024)//如果內(nèi)存>6MB,則設置緩沖區(qū)末端=2MBbuffer_memory_end = 2*1024*1024;else//否則設置緩沖區(qū)末端=1MBbuffer_memory_end = 1*1024*1024;main_memory_start = buffer_memory_end;//主內(nèi)存起始位置=緩沖區(qū)末端。//如果在Makefile文件中定義了內(nèi)存虛擬盤符號RAMDISK,則初始化虛擬盤。此時主內(nèi)存將減少。
//參見kernel/blk_drv_ramdisk.c。
#ifdef RAMDISKmain_memory_start += rd_init(main_memory_start, RAMDISK*1024);
#endif
//以下是內(nèi)核進行所有方面的初始化工作。閱讀時最好跟著調(diào)用的程序深入進去看,
//若實在看不下去了,就先放一放,繼續(xù)看下一個初始化調(diào)用。--作者保姆式的注釋和關系。mem_init(main_memory_start,memory_end);//主內(nèi)存區(qū)初始化。trap_init();//陷阱門(硬件中斷量)初始化。blk_dev_init();//塊設備初始化。chr_dev_init();//字符設備初始化。tty_init();//tty初始化。time_init();//設置開機啟動時間。sched_init();//調(diào)度程序初始化buffer_init(buffer_memory_end);//緩沖管理初始化,建內(nèi)存鏈表等。hd_init();//硬盤初始化。floppy_init();//軟驅動初始化sti();//所有初始化工作都完了,于是開啟中斷。
//下面過程通過在堆棧中設置的參數(shù),利用中斷返回指令啟動任務0執(zhí)行。 move_to_user_mode();//移到用戶模式下執(zhí)行。if (!fork()) { /* 在新建的子進程(任務1即init進程)中執(zhí)行。 */init();}
//下面代碼開始以任務0的身份運行。
/*
注意!!對于任何其他的任務,'pause()'將意味著我們必須等待收到一個信號才會返回就緒態(tài),但
任務0(task0)是唯一例外情況,因為任務0在任何空閑時間里都會被激活,
因此對于任務0'pause()'僅意味著我們返回來查看是否有其他任務可以運行,如果沒有的話我們就回到合理,
一直循環(huán)執(zhí)行'pause()'*/for(;;)__asm__("int $0x80"::"a" (__NR_pause):"ax");
}//下面函數(shù)產(chǎn)生格式化信息并輸出到標準輸出設備stdout(1),這里是指屏幕上顯示。參數(shù)'*fmt'
//指定輸出將采用的格式,參見標準C語言書籍。該子程序正好是vsprintf如何使用的一個簡單
//例子。該程序使用vsprintf()將格式化的字符串放入printbuf緩沖區(qū),然后用write()將緩沖
//去的內(nèi)容輸出到標準設備(1--stdout)。vsprintf()函數(shù)的實現(xiàn)建kernel/vsprintf.c
static int printf(const char *fmt, ...)
{va_list args;int i;va_start(args, fmt);write(1,printbuf,i=vsprintf(printbuf, fmt, args));va_end(args);return i;
}
//在main()中已經(jīng)進行了系統(tǒng)初始化,包括內(nèi)存管理、各種硬件設備和驅動程序。init()函數(shù)
//運行在任務0第1次創(chuàng)建的子進程(任務1)中。它首先對第一個將要執(zhí)行的程序(shell)
//的環(huán)境進行初始化,然后以登陸shell方式加載該程序并執(zhí)行之。
void init(void)
{int pid,i;
//setup()是一個系統(tǒng)調(diào)用。用于讀取硬盤參數(shù)包括分區(qū)表信息并加載虛擬盤(若存在的話)和
//安裝根文件系統(tǒng)設備。該函數(shù)用25行上的宏定義,對應函數(shù)時sys_setup(),在塊設備子目錄
//kernel/blk_drv/hd.c,74行。setup((void *) &drive_info);
//下面以讀寫訪問方式打開設備"/dev/tty0",它對應終端控制臺。由于這是第一次打開文件
//操作,因此產(chǎn)生的文件句柄號(文件描述符)肯定是0.該句柄是UNIX類操作系統(tǒng)默認的控制
//臺標志輸入句柄stdin。這里再把它以讀和寫的方式分別打開是為了復制產(chǎn)生標準輸出(寫)
//句柄stdou和標志出差輸出句柄stderr。函數(shù)前面的"(void)"前綴用于表示強制函數(shù)無需返回值。(void) open("/dev/tty1",O_RDWR,0);(void) dup(0);//復制句柄,產(chǎn)生句柄1號--stdout標準輸出設備。(void) dup(0);//復制句柄,產(chǎn)生句柄2號--stderr標志出錯輸出設備。//下面打印緩沖區(qū)塊數(shù)和總字節(jié)數(shù),每塊1024字節(jié),以及主內(nèi)存區(qū)空閑內(nèi)存字節(jié)數(shù)。 printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,NR_BUFFERS*BLOCK_SIZE);printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);//函數(shù)_exit()退出時的出錯碼 1-操作未允許;2--文件或目錄不存在。if (!(pid=fork())) {//if語句里面是task2//關閉句柄0(stdin)并立刻打開/etc/rc文件的作業(yè)是把標志輸入stdin重定向到/etc/rc文件。//這樣shell程序/bin/sh就可以運行rc文件中的設置的命令。close(0);if (open("/etc/rc",O_RDONLY,0))_exit(1);//若打開文件失敗,則退出。execve("/bin/sh",argv_rc,envp_rc);//替換成/bin/sh程序并執(zhí)行。_exit(2);//若execve()執(zhí)行失敗則退出。}//下面還是父進程(1)執(zhí)行語句。wait()等待子進程停止或終止,返回值應是子進程的進程號//(pid)。這三局的作用是父進程等待子進程的結束。&i是存放返回狀態(tài)信息的位置。//如果wait()返回值不等于子進程號,則繼續(xù)等待。if (pid>0)while (pid != wait(&i))/* nothing */;//如果執(zhí)行到這里,說明剛創(chuàng)建的子進程的執(zhí)行已停止或終止了。下面循環(huán)中首先再創(chuàng)建一個子進程,
//如果出錯,則顯示"初始化程序創(chuàng)建子進程失敗"信息并繼續(xù)執(zhí)行。對于所創(chuàng)建的子進程將關閉所有
//以前還遺留的句柄(stdin,stdou,stderr),新創(chuàng)建一個會后并設置進程組號,
//然后重新打開/dev/tty0作為stdin,并復制成stdou和stderr。再次執(zhí)行系統(tǒng)解釋程序/bin/sh。但這
//次執(zhí)行所選用的參數(shù)和環(huán)境數(shù)組另選了一套。然后父進程再次運行wait()等待。
//如果子進程又停止了執(zhí)行,則在標準輸出上顯示出錯信息"子進程pid停止了運行,返回碼時i",
//然后繼續(xù)重試下……,形成"大"死循環(huán)。while (1) {if ((pid=fork())<0) {printf("Fork failed in init\r\n");continue;}if (!pid) {//新的子進程。close(0);close(1);close(2);setsid();//創(chuàng)建新的會話期,見后面說明。(void) open("/dev/tty1",O_RDWR,0);(void) dup(0);(void) dup(0);_exit(execve("/bin/sh",argv,envp));}while (1)if (pid == wait(&i))break;printf("\n\rchild %d died with code %04x\n\r",pid,i);sync();//同步操作,刷新緩沖區(qū)。}_exit(0); /* 注意! 是_exit(),非exit() *///_exit()和exit()都用于正常終止一個函數(shù)。但_exit()直接是一個sys_exit系統(tǒng)調(diào)用,而//exit()則通常是普通函數(shù)庫中的一個函數(shù)。它會先執(zhí)行一些清除操作,例如調(diào)用執(zhí)行各終止處理程序、//關閉所有標準IO等,然后調(diào)用sys_exit。
}
7-1-3 其他信息
1、 CMOS信息
(a)0x70是地址端口,0x71是數(shù)據(jù)端口。
(b)表7-1 CMOS 64字節(jié)信息簡表
2、 調(diào)用fork()創(chuàng)建新進程
(a)fork是創(chuàng)建新進程,但需要用exec()簇函數(shù)取執(zhí)行其他不同的程序。
(b)子進程pid=0,父進程pid=子進程的pid號。
?當程序執(zhí)行完或有必要終止時就可以調(diào)用exit()來退出,
而父進程則可以使用wait()調(diào)用來查看或等待子進程的退出,并獲取被終止進程的退出狀態(tài)信息。
3、 關于會話期的概念
_不理解進程組和會話期。