?? fork.c
字號(hào):
/** linux/kernel/fork.c** (C) 1991 Linus Torvalds*//** 'fork.c' contains the help-routines for the 'fork' system call* (see also system_call.s), and some misc functions ('verify_area').* Fork is rather simple, once you get the hang of it, but the memory* management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'*//** 'fork.c'中含有系統(tǒng)調(diào)用'fork'的輔助子程序(參見system_call.s),以及一些其它函數(shù)* ('verify_area')。一旦你了解了fork,就會(huì)發(fā)現(xiàn)它是非常簡(jiǎn)單的,但內(nèi)存管理卻有些難度。* 參見'mm/mm.c'中的'copy_page_tables()'。*/#include <errno.h> // 錯(cuò)誤號(hào)頭文件。包含系統(tǒng)中各種出錯(cuò)號(hào)。(Linus 從minix 中引進(jìn)的)。#include <linux/sched.h> // 調(diào)度程序頭文件,定義了任務(wù)結(jié)構(gòu)task_struct、初始任務(wù)0 的數(shù)據(jù),// 還有一些有關(guān)描述符參數(shù)設(shè)置和獲取的嵌入式匯編函數(shù)宏語句。#include <linux/kernel.h> // 內(nèi)核頭文件。含有一些內(nèi)核常用函數(shù)的原形定義。#include <asm/segment.h> // 段操作頭文件。定義了有關(guān)段寄存器操作的嵌入式匯編函數(shù)。#include <asm/system.h> // 系統(tǒng)頭文件。定義了設(shè)置或修改描述符/中斷門等的嵌入式匯編宏。extern void write_verify (unsigned long address);long last_pid = 0;//// 進(jìn)程空間區(qū)域?qū)懬膀?yàn)證函數(shù)。// 對(duì)當(dāng)前進(jìn)程的地址addr 到addr+size 這一段進(jìn)程空間以頁為單位執(zhí)行寫操作前的檢測(cè)操作。// 若頁面是只讀的,則執(zhí)行共享檢驗(yàn)和復(fù)制頁面操作(寫時(shí)復(fù)制)。voidverify_area (void *addr, int size){ unsigned long start; start = (unsigned long) addr;// 將起始地址start 調(diào)整為其所在頁的左邊界開始位置,同時(shí)相應(yīng)地調(diào)整驗(yàn)證區(qū)域大小。// 此時(shí)start 是當(dāng)前進(jìn)程空間中的線性地址。 size += start & 0xfff; start &= 0xfffff000; start += get_base (current->ldt[2]); // 此時(shí)start 變成系統(tǒng)整個(gè)線性空間中的地址位置。 while (size > 0) { size -= 4096;// 寫頁面驗(yàn)證。若頁面不可寫,則復(fù)制頁面。(mm/memory.c,261 行) write_verify (start); start += 4096; }}// 設(shè)置新任務(wù)的代碼和數(shù)據(jù)段基址、限長(zhǎng)并復(fù)制頁表。// nr 為新任務(wù)號(hào);p 是新任務(wù)數(shù)據(jù)結(jié)構(gòu)的指針。intcopy_mem (int nr, struct task_struct *p){ unsigned long old_data_base, new_data_base, data_limit; unsigned long old_code_base, new_code_base, code_limit; code_limit = get_limit (0x0f); // 取局部描述符表中代碼段描述符項(xiàng)中段限長(zhǎng)。 data_limit = get_limit (0x17); // 取局部描述符表中數(shù)據(jù)段描述符項(xiàng)中段限長(zhǎng)。 old_code_base = get_base (current->ldt[1]); // 取原代碼段基址。 old_data_base = get_base (current->ldt[2]); // 取原數(shù)據(jù)段基址。 if (old_data_base != old_code_base) // 0.11 版不支持代碼和數(shù)據(jù)段分立的情況。 panic ("We don't support separate I&D"); if (data_limit < code_limit) // 如果數(shù)據(jù)段長(zhǎng)度 < 代碼段長(zhǎng)度也不對(duì)。 panic ("Bad data_limit"); new_data_base = new_code_base = nr * 0x4000000; // 新基址=任務(wù)號(hào)*64Mb(任務(wù)大小)。 p->start_code = new_code_base; set_base (p->ldt[1], new_code_base); // 設(shè)置代碼段描述符中基址域。 set_base (p->ldt[2], new_data_base); // 設(shè)置數(shù)據(jù)段描述符中基址域。 if (copy_page_tables (old_data_base, new_data_base, data_limit)) { // 復(fù)制代碼和數(shù)據(jù)段。 free_page_tables (new_data_base, data_limit); // 如果出錯(cuò)則釋放申請(qǐng)的內(nèi)存。 return -ENOMEM; } return 0;}/** Ok, this is the main fork-routine. It copies the system process* information (task[nr]) and sets up the necessary registers. It* also copies the data segment in it's entirety.*//** OK,下面是主要的fork 子程序。它復(fù)制系統(tǒng)進(jìn)程信息(task[n])并且設(shè)置必要的寄存器。* 它還整個(gè)地復(fù)制數(shù)據(jù)段。*/// 復(fù)制進(jìn)程。intcopy_process (int nr, long ebp, long edi, long esi, long gs, long none, long ebx, long ecx, long edx, long fs, long es, long ds, long eip, long cs, long eflags, long esp, long ss){ struct task_struct *p; int i; struct file *f; p = (struct task_struct *) get_free_page (); // 為新任務(wù)數(shù)據(jù)結(jié)構(gòu)分配內(nèi)存。 if (!p) // 如果內(nèi)存分配出錯(cuò),則返回出錯(cuò)碼并退出。 return -EAGAIN; task[nr] = p; // 將新任務(wù)結(jié)構(gòu)指針放入任務(wù)數(shù)組中。// 其中nr 為任務(wù)號(hào),由前面find_empty_process()返回。 *p = *current; /* NOTE! this doesn't copy the supervisor stack *//* 注意!這樣做不會(huì)復(fù)制超級(jí)用戶的堆棧 */ (只復(fù)制當(dāng)前進(jìn)程內(nèi)容)。 p->state = TASK_UNINTERRUPTIBLE; // 將新進(jìn)程的狀態(tài)先置為不可中斷等待狀態(tài)。 p->pid = last_pid; // 新進(jìn)程號(hào)。由前面調(diào)用find_empty_process()得到。 p->father = current->pid; // 設(shè)置父進(jìn)程號(hào)。 p->counter = p->priority; p->signal = 0; // 信號(hào)位圖置0。 p->alarm = 0; p->leader = 0; /* process leadership doesn't inherit *//* 進(jìn)程的領(lǐng)導(dǎo)權(quán)是不能繼承的 */ p->utime = p->stime = 0; // 初始化用戶態(tài)時(shí)間和核心態(tài)時(shí)間。 p->cutime = p->cstime = 0; // 初始化子進(jìn)程用戶態(tài)和核心態(tài)時(shí)間。 p->start_time = jiffies; // 當(dāng)前滴答數(shù)時(shí)間。// 以下設(shè)置任務(wù)狀態(tài)段TSS 所需的數(shù)據(jù)(參見列表后說明)。 p->tss.back_link = 0; p->tss.esp0 = PAGE_SIZE + (long) p; // 堆棧指針(由于是給任務(wù)結(jié)構(gòu)p 分配了1 頁// 新內(nèi)存,所以此時(shí)esp0 正好指向該頁頂端)。 p->tss.ss0 = 0x10; // 堆棧段選擇符(內(nèi)核數(shù)據(jù)段)[??]。 p->tss.eip = eip; // 指令代碼指針。 p->tss.eflags = eflags; // 標(biāo)志寄存器。 p->tss.eax = 0; p->tss.ecx = ecx; p->tss.edx = edx; p->tss.ebx = ebx; p->tss.esp = esp; p->tss.ebp = ebp; p->tss.esi = esi; p->tss.edi = edi; p->tss.es = es & 0xffff; // 段寄存器僅16 位有效。 p->tss.cs = cs & 0xffff; p->tss.ss = ss & 0xffff; p->tss.ds = ds & 0xffff; p->tss.fs = fs & 0xffff; p->tss.gs = gs & 0xffff; p->tss.ldt = _LDT (nr); // 該新任務(wù)nr 的局部描述符表選擇符(LDT 的描述符在GDT 中)。 p->tss.trace_bitmap = 0x80000000; (高16
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -