1、適用範圍
sylixos是一款為嵌入式系統設計的硬實時系統。為了保證系統的實時性,系統建立子程序時不做頁表切換(頁表切換很耗時間,不利於實時性的體現),即父子程序共享同乙個頁表,而對於linux下fork函式建立的父子程序是需要進行頁表複製和切換的。為了在sylixos下實現linux的fork函式功能,本文總結了如何使用posix標準的posix_spawn函式替換fork函式。
2、原理介紹
sylixos的posix_spawn函式是基於posix標準的,是fork函式和exec函式的功能合二為一,它只是建立乙個新程序並執行指定程式。
2.1、linux下fork函式功能**
由fork函式建立的子程序獲得父程序的堆疊、資料段和執行文字段的拷貝,實質上我們可以這樣理解:即子程序完全複製父程序的頁表(對於有寫時拷貝機制的fork函式我們也可以這麼理解)。
父子程序均可修改各自的棧資料、以及堆段中的變數,而不影響另一程序。程式可以通過fork函式的返回值來區別父子程序,在父程序中fork函式將返回子程序的程序id。鑑於父程序可能需要建立,進而追蹤多個子程序(通過wait函式或類似的方法)。fork函式在子程序中返回0,子程序可以通過getpid函式以獲得自身id,可以使用getppid函式獲得父程序的id。
父子程序之間檔案共享,子程序獲得父程序所有檔案描述符號的副本(副本的建立類似於dup函式的功能),且父子程序中對應的描述符均指向相同的檔案控制代碼(即公用乙個檔案結構和檔案節點),共享同乙個檔案控制代碼,這樣公用的檔案偏移量保證了父子程序寫同乙個檔案時不會覆蓋彼此寫入的內容(但是父子程序的輸出會隨意混雜在一起,可用程序間同步來規避)。
總的來說fork函式建立子程序,複製父程序的資訊可分為主要三個方面:
1、複製父程序的檔案描述符表;
2、複製父程序資料段;
3、複製父程序的環境變數。
對於sylixos系統來說不提供fork函式,也沒有提供與fork函式相同功能的函式。而sylixos提供乙個posix標準的posix_spawn函式,我們可以根據fork函式功能進行使用posix_spawn函式替換fork函式。
2.2、sylixos的posix_spawn函式原型介紹
#include
int posix_spawn(pid_t *pid,
const char *path,
constposix_spawn_file_actions_t *file_actions,
constposix_spawnattr_t *attrp,
char *const argv,
char *const envp);
函式成功返回 0,失敗返回-1 並設定錯誤碼。函式引數如表2-1函式引數對比: 表
2-1函式引數
專案
posix_spawn
程序號pid
新的程序號
檔案操作集file_actions
新程序啟動時需要處理的檔案操作集, 為 0 表示不進行任何檔案操作
新程序初始化屬性attrp
新程序初始化屬性,為 null 表示不設定
命令列引數字串陣列argv
命令列引數組成的字串陣列,陣列以可執行檔名開始以 null結束,為 null 表示不使用命令列引數最多64個
程序環境變數字串陣列envp
需要預先設定的程序環境變數字串陣列,陣列以 null 結束,為null 表示不需要設定環境變數不超過64個
可執行檔案路徑path
path是可執行檔案路徑
根據posix_spawn函式原型和功能可知,針對fork函式建立子程序時複製的主要三個方面有如下的方法替代:
1. 複製檔案描述符表:posix_spawn函式自身在建立子程序時也複製父程序所有的檔案描述符,父子程序的檔案描述符表指向同乙個檔案結構,這個和fork函式一樣;
2. 複製資料段:posix_spawn函式可以通過第五個引數指標陣列argv[ ]進行資料傳遞,對於對父程序的**段的複製只能通過再次編寫來解決;
3. 複製壞境變數:posix_spawn函式可以使用第六個引數數指標陣列envp[ ]來傳遞父程序的環境引數,並且可以認為設定envp[ ]引數來設定子程序的環境引數。
注:因為在sylixos父子程序因為是共享同一張頁表的,所以對於sylixos作業系統的父子程序天生就有共享記憶體(即共享同一張頁表位址),不過需要注意如果父子程序通過使用同一張頁表同乙個位址來傳遞資料很危險,需謹慎使用(比如子程序到共享頁表位址進行讀寫操作,不小心踩到父程序的堆疊空間會造成不可估量的危險)。
3、技術實現
3.1、檔案描述符
例程描述:
父程序建立子程序前已經開啟乙個檔案,父程序將檔案描述符值傳遞給子程序,父、子程序共同對同一檔案進行寫操作。
替換框圖如圖3-1所示:
圖
3-1檔案描述符
例程總結:
父程序在建立子程序時,子程序複製父程序的檔案描述符表,所以只需要通過傳參的方式把檔案描述符告知給子程序,子程序就能夠使用這個檔案描述符,深入了解後發現使用posix_spawn函式建立子程序,父子程序也是公用乙個檔案結構和檔案節點。posix_spawn函式也支援執行時關閉(close-on-exec) 標誌,即檔案描述符設定fd_cloexec標誌,在建立子程序時子程序不能複製該檔案描述符 。
3.2、全域性變數
例程描述:
父程序建立子程序時將全域性變數值傳遞給子程序,隨後父程序對全域性變數進行加1操作,子程序對接收到的全域性變數值也進行加1操作。
替換框圖如圖3-2所示:
圖
3-2全域性資料
例程總結:
父程序可通過傳遞引數的方式將子程序需要的資料傳遞給子程序,這樣父子程序都有自己的資料,且互不干擾。
3.3、守護程序
例程描述:
父程序建立子程序,子程序執行daemon函式將自己設為守護程序,父程序手動退出。
替換框圖如圖3-3所示:
圖
3-3守護程序
例程總結:
sylixos提供了設定守護程序daemon函式,該函式內部包含了部分fork函式建立守護程序的相關操作。
daemon原型介紹
sylixos提供api介面daemon函式,可以設定當前程序為守護程序。
#include
int daemon(int nochdir, int noclose);
函式 daemon 原型分析:
l此函式成功返回 0,失敗返回-1 並設定錯誤碼;
l引數 nochdir表示是否切換程序當前工作目錄到根目錄" /"。 0 表示切換, 其他表
示不切換;
l引數 noclose表示是否重定向標準輸入、標準輸出、標準錯誤輸出到" /dev/null"
檔案。 0 表示重定向, 其他表示不重定向
4、posix_spawn函式原始碼實現框圖
如圖4-1所示:
圖4-1 posix_spawn
函式中的流程實現
如圖4-2所示對於posix_spawn函式實現的核心步驟__processstart的實現流程:
圖4-2 __processstart
函式的實現流程
5、參考資料
《 sylixos 應用開發手冊》
1.在open函式開啟時設定標誌位:
ifd = open("./filetest", o_rdwr | o_creat | o_cloexec , file_mode);
加上這個標誌:o_cloexec
2.使用fcntl函式設定檔案描述符不可複製:
fcntl(ifd, f_setfd, 0);
注:0表示不設定標誌位,1表示設定標誌位
fork(三程序替換)
程序替換 exec指定乙個程式把全新的程式載入到子程序中,子程序將會指向新程序 exec每個函式都有返回值,只有出錯時返回值才會有效,正確時會被覆蓋掉,也就沒人接收了 exec可以不用判斷,拿到返回值就已經代表出錯,int execl char pathname,char ar 0,char ar ...
fork 函式 fork 函式的使用
fork的意思是個叉子,在unix及其衍生版linux中,用於建立子程序,現在看一下fork函式的基本用法。include includeint main printf c b fflush stdout fork printf c c fflush stdout 上圖的輸出是什麼呢?答案是 bab...
c 中的fork函式 FORK()函式
乙個程序,包括 資料和分配給程序的資源。fork 函式通過系統呼叫建立乙個與原來程序幾乎完全相同的程序,也就是兩個程序可以做完全相同的事,但如果初始引數或者傳入的變數不同,兩個程序也可以做不同的事。乙個程序呼叫fork 函式後,系統先給新的程序分配資源,例如儲存資料和 的空間。然後把原來的程序的所有...