如下關於fork()的描述來自於:jason314linux
首先,在Linux環境下,一個進程調用fork()函數後,系統先給新的進程分配資源,例如存儲數據和代碼的空間。而後把原來的進程的全部值都複製到新的新進程中,只有少數值與原來的進程的值不一樣。至關於克隆了一個本身。函數
fork調用的一個奇妙之處就是它僅僅被調用一次,卻可以返回兩次,它可能有三種不一樣的返回值:
1)在父進程中,fork返回新建立子進程的進程ID;
2)在子進程中,fork返回0;
3)若是出現錯誤(如系統資源不足),fork返回一個負值。spa
在fork函數執行完畢後,若是建立新進程成功,則出現兩個進程,一個是子進程,一個是父進程。在子進程中,fork函數返回0,在父進程中,fork返回新建立子進程的進程ID。咱們能夠經過fork返回的值來判斷當前進程是子進程仍是父進程。.net
如今,咱們來寫一段程序,使用API調用fork:指針
#include <stdio.h> #include <unistd.h> int main() { pid_t fpid; int count = 0; fpid = fork(); printf("Now pid = %d\n", fpid); 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("Now count = %d\n", count); return 0; }
在第八行執行完fork後,父進程中有count=0、fpid=子進程的pid;子進程中變量爲count=0、 fpid=0,這兩個進程的變量都是獨立的,存在不一樣的地址中,也不是共用的。能夠說,咱們就是經過fpid來識別和操做父子進程的。orm
在x86的系統中,%eax寄存器在進行系統調用前儲存系統調用號。另外,因爲六個及以上參數的系統調用並很少見,所以通常使用%ebx、%ecx、%edx、%esi和%edi依次存放前五個參數。若是出現六個以上參數的狀況,應該用一個單獨的寄存器存放指向全部這些參數在用戶空間地址的指針。當調用結束後,函數的返回值存放在%eax中。接口
下面,咱們將改寫fork.c,直接嵌入彙編語言進行系統調用:進程
#include <stdio.h> #include <unistd.h> int main() { pid_t fpid; int count = 0; asm volatile( "mov $0, %%ebx\n\t" "mov $0x2, %%eax\n\t" "int $0x80\n\t" "mov %%eax, %0\n\t" : "=m"(fpid) ); printf("Now pid = %d\n", fpid); 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("Now count = %d\n", count); return 0; }
程序的運行結果以下:資源
總結:API與系統調用並非一一對應的關係(Linux系統能夠參考syscalls),它爲程序提供了標準接口。而內核基本只與系統調用打交道;固然,咱們也能夠直接使用系統調用寫程序,但勢必會下降程序的可移植性。至於APIs如何進行系統調用,那就是Glibc等標準制定者的事了。
陳政/arc001 原創做品轉載請註明出處 《Linux內核分析》MOOC課程