一、適用範圍
SylixOS是一款爲嵌入式系統設計的硬實時系統。爲了保證系統的實時性,系統建立子進程時不作頁表切換(頁表切換很耗時間,不利於實時性的體現),即父子進程共享同一個頁表,而對於Linux下fork函數建立的父子進程是須要進行頁表複製和切換的。爲了在SylixOS下實現Linux的fork函數功能,本文總結了如何使用posix標準的posix_spawn函數替換fork函數。數組
-
原理介紹
SylixOS的posix_spawn函數是基於posix標準的,是fork函數和exec函數的功能合二爲一,它只是建立一個新進程並執行指定程序。函數
-
Linux下fork函數功能淺析
由fork函數建立的子進程得到父進程的堆棧、數據段和執行文本段的拷貝,實質上咱們能夠這樣理解:即子進程徹底複製父進程的頁表(對於有寫時拷貝機制的fork函數咱們也能夠這麼理解)。spa
父子進程都可修改各自的棧數據、以及堆段中的變量,而不影響另外一進程。程序能夠經過fork函數的返回值來區別父子進程,在父進程中fork函數將返回子進程的進程ID。鑑於父進程可能須要建立,進而追蹤多個子進程(經過wait函數或相似的方法)。fork函數在子進程中返回0,子進程能夠經過getpid函數以得到自身ID,可使用getppid函數得到父進程的ID。操作系統
父子進程之間文件共享,子進程得到父進程全部文件描述符號的副本(副本的建立相似於dup函數的功能),且父子進程中對應的描述符均指向相同的文件句柄(即公用一個文件結構和文件節點),共享同一個文件句柄,這樣公用的文件偏移量保證了父子進程寫同一個文件時不會覆蓋彼此寫入的內容(可是父子進程的輸出會隨意混雜在一塊兒,可用進程間同步來規避)。命令行
總的來講fork函數建立子進程,複製父進程的信息可分爲主要三個方面:設計
一、複製父進程的文件描述符表;指針
二、複製父進程數據段;接口
三、複製父進程的環境變量。進程
對於SylixOS系統來講不提供fork函數,也沒有提供與fork函數相同功能的函數。而SylixOS提供一個posix標準的posix_spawn函數,咱們能夠根據fork函數功能進行使用posix_spawn函數替換fork函數。內存
-
SylixOS的posix_spawn函數原型介紹
#include <spawn.h>
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 並設置錯誤碼。函數參數如表21函數參數對比:
表21函數參數
項目
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操做系統的父子進程天生就有共享內存(即共享同一張頁表地址),不過須要注意若是父子進程經過使用同一張頁表同一個地址來傳遞數據很危險,需謹慎使用(好比子進程到共享頁表地址進行讀寫操做,不當心踩到父進程的堆棧空間會形成不可估量的危險)。
-
技術實現
-
文件描述符
例程描述:
父進程建立子進程前已經打開一個文件,父進程將文件描述符值傳遞給子進程,父、子進程共同對同一文件進行寫操做。
替換框圖如圖31所示:
圖31文件描述符
例程總結:
父進程在建立子進程時,子進程複製父進程的文件描述符表,因此只須要經過傳參的方式把文件描述符告知給子進程,子進程就可以使用這個文件描述符,深刻了解後發現使用posix_spawn函數建立子進程,父子進程也是公用一個文件結構和文件節點。posix_spawn函數也支持執行時關閉(close-on-exec) 標誌,即文件描述符設置FD_CLOEXEC標誌,在建立子進程時子進程不能複製該文件描述符 。
注:close-on-exec標誌可經過fnctl函數對文件描述符設置,具體實現可參考附錄一。
-
全局變量
例程描述:
父進程建立子進程時將全局變量值傳遞給子進程,隨後父進程對全局變量進行加1操做,子進程對接收到的全局變量值也進行加1操做。
替換框圖如圖32所示:
圖32全局數據
例程總結:
父進程可經過傳遞參數的方式將子進程須要的數據傳遞給子進程,這樣父子進程都有本身的數據,且互不干擾。
-
守護進程
例程描述:
父進程建立子進程,子進程執行daemon函數將本身設爲守護進程,父進程手動退出。
替換框圖:
圖33守護進程
例程總結:
SylixOS提供了設置守護進程daemon函數,該函數內部包含了部分fork函數建立守護進程的相關操做。
daemon原型介紹
SylixOS提供API接口daemon函數,能夠設置當前進程爲守護進程。
#include <unistd.h>
int daemon(int nochdir, int noclose);
函數 daemon 原型分析:
l此函數成功返回 0,失敗返回-1 並設置錯誤碼;
l參數 nochdir表示是否切換進程當前工做目錄到根目錄" /"。 0 表示切換, 其餘表
示不切換;
l參數 noclose表示是否重定向標準輸入、標準輸出、標準錯誤輸出到" /dev/null"
文件。 0 表示重定向, 其餘表示不重定向 -
posix_spawn函數源碼實現框圖
如圖41所示:
圖41 posix_spawn函數中的流程實現
如圖42所示對於posix_spawn函數實現的核心步驟__processStart的實現流程:
圖42 __processStart函數的實現流程
-
參考資料
《 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表示設置標誌位