2018-2019-1 20189221 《Linux核心原理與分析》第六週作業
2018-2019-1 20189221 《Linux核心原理與分析》第六週作業
實驗五
實驗過程
將Fork函式移植到Linux的MenuOS
fork()函式通過系統呼叫建立一個與原來程序幾乎完全相同的程序。在fork函式執行完畢後,如果建立新程序成功,則出現兩個程序,一個是子程序,一個是父程序。在子程序中,fork函式返回0,在父程序中,fork返回新建立子程序的程序ID。通過fork返回的值來判斷當前程序是子程序還是父程序。
啟動MenuOS:
在test.c中新增程式碼如下:
int Fork(int argc, char *argv[]) { pid_t fpid; int count = 0; fpid = fork(); if (fpid < 0) printf("error in fork!"); else if (fpid == 0) { printf("i am the child process, my process id is %d\n",getpid()); count++; } else { printf("i am the parent process, my process id is %d\n",getpid()); count++; } printf("count: %d\n",count); return 0; } int main() { PrintMenuOS(); SetPrompt("MenuOS>>"); MenuConfig("version","MenuOS V1.0(Based on Linux 3.18.6)",NULL); MenuConfig("quit","Quit from MenuOS",Quit); MenuConfig("fork","fork a child process",Fork); ExecuteMenu(); }
執行結果:
sys_call過程分析
gdb除錯:
由於實驗樓多次卡頓,十分浪費時間
除錯程式碼:
$ gdb
(gdb) file linux-3.18.6/vmlinux
(gdb) target remote:1234
(gdb) continue
在sys_fork設定斷點,在qemu中輸入fork-asm命令,可以看到停在了sys_fork()函式中。
然後s單步執行,finish返回do_fork函式,返回值$2=866,即分配了pid=866的子程序。繼續單步,到了schedule()中,此時發生了程序排程。finish後schedule返回。
再次單步執行,出現Cannot find bounds of current function。此時gdb已無法跟蹤。
gdb中輸入c繼續執行,看到qemu中輸出fid = 866,即子程序的pid為866。
system_call的程式碼:
ENTRY(system_call) RING0_INT_FRAME ASM_CLAC pushl_cfi %eax //儲存系統呼叫號; SAVE_ALL //可以用到的所有CPU暫存器儲存到棧中 GET_THREAD_INFO(%ebp) //ebp用於存放當前程序thread_info結構的地址 testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) jnz syscall_trace_entry cmpl $(nr_syscalls), %eax //檢查系統呼叫號(系統呼叫號應小於NR_syscalls), jae syscall_badsys //不合法,跳入到異常處理 syscall_call: call *sys_call_table(,%eax,4) //合法,對照系統呼叫號在系統呼叫表中尋找相應服務例程 movl %eax,PT_EAX(%esp) //儲存返回值到棧中 syscall_exit: testl $_TIF_ALLWORK_MASK, %ecx //檢查是否需要處理訊號 jne syscall_exit_work //需要,進入 syscall_exit_work restore_all: TRACE_IRQS_IRET //不需要,執行restore_all恢復,返回使用者態 irq_return: INTERRUPT_RETURN //相當於iret
system_call流程:
實驗總結
系統呼叫是特殊的中斷函式,是多種中斷處理過程的集合
系統呼叫的過程其實是另一種上下文切換的實現:
首先SAVE ALL儲存上下文
根據IDT呼叫核心函式
執行RESTORE_ALL並返回使用者模式
系統呼叫與中斷的共同之處
儲存現場
在系統呼叫時,用SAVE_ALL來儲存系統呼叫時的上下文。
中斷處理的第一步也是要儲存中斷程式現場。
中斷處理完之後,可以返回到原來被中斷的地方,在原有的執行環境下繼續正確的執行下去。確定中斷資訊
在系統呼叫中,需要將系統呼叫號通過eax傳入,通過sys_call_table查詢到呼叫的系統呼叫,然後跳轉到相應的程式進行處理。
中斷處理時系統也需要有一箇中斷號,通過檢索中斷向量表,瞭解中斷的型別和裝置。處理中斷
跳轉到相應的中斷處理程式後,對中斷進行處理。
返回
系統呼叫時最後要restore_all恢復系統呼叫時的現場,並用iret返回使用者態。
同樣,執行完中斷處理程式,核心也要執行特定指令序列,恢復中斷時現場,並使得程序回到使用者態。
系統呼叫與一般函式的不同之處
不是通過“CALL”指令而是通過“INT”指令發起呼叫;
不是通過“RET”指令,而是通過“IRET”指令完成呼叫返回;
當到達核心態後,作業系統需要嚴格檢查系統呼叫傳遞的引數,確保不破壞整個系統的安全性;
執行系統呼叫可導致程序等待某事件發生,從而可引起程序切換;