1. 適用範圍
SylixOS是一款爲大型嵌入式系統設計的硬實時系統,支持使用system調用執行命令。SylixOS爲了保證明時性在system的實現上和Linux有所差異,本文着重介紹SylixOS如何實現system和在使用system時須要注意的事項。shell
2. 原理介紹
SylixOS爲保證系統的實時性因此沒有實現fork功能,Linux下system是使用fork實現的。而SylixOS則經過使用內核的shell線程實現system功能。app
2.1 Linux的system功能淺析
Linux下system會調用fork產生子進程,由子進程execve調用/bin/sh-c string來執行參數string字符串所表明的命令,此命令執行完後隨即返回原調用的進程。異步
由於Linux下是經過fork實現system,因此被執行的命令繼承父系的一些資源(好比文件描述符,父系的工做路徑等)。同時可以實現異步執行和同步執行,同步執行即父系等待system調用運行結束(包括system調用的命令執行結束);異步即不等待,父系繼續運行。函數
2.2 SylixOS的system原理介紹
#include <stdlib.h>spa int system(const char *command);線程 |
函數成功返回 0,失敗返回-1,並設置錯誤碼。設計
SylixOS的system是先建立一個內核的shell線程,而後經過內核的shell線程執行system須要執行的命令。繼承
若是使用system調用執行一個進程,則同時啓動一個內核線程來join等待清除該進程。若是使用system調用執行一個shell命令,則直接由內核線程t_tshell負責清除。如圖 2‑1所示,由open(pid=5)調用system執行hellow(pid=6),而內核建立一個hellow(pid=0)的內核線程join等待。進程
圖 2‑1 system調用現象ci
2.3 SylixOS的system功能
SylixOS 的system實現原理和Linux不一樣,功能上和Linux的基本相同。
1. SylixOS實現system基礎功能,調用執行命令;
2. SylixOS 的system執行命令可設置爲同步執行和異步執行。
3. SylixOS的system繼承父系進程的工做空間;
4. SylixOS中由system啓動的進程繼承內核線程的棧空間大小;
5.Linux的system調用的三者有血緣關係,因此被system調用的進程繼承父系的資源(包括文件描述符),而SylixOS的system調用的三者之間沒有血緣關係,因此不可以繼承父系的資源。因此SylixOS在使用system時須要注意,在技術實現章節會介紹如何實現system的這個功能。
3. 技術實現
在移植Linux應用程序時,在某些特定的場景上Linux用戶會在A進程經過system調用B進程,同時經過傳參把一些文件描述符傳遞到B進程。由於Linux下B進程繼承A進程的文件描述符,因此B進程便能使用A進程的文件描述符進行操做。
使用場景如程序清單 3‑1和程序清單 3‑2所示。
程序清單 3‑1 A進程代碼
#include <stdio.h> #include <stdlib.h>
#define PATH_LEN 20 /* 路徑長度 */ #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) /* 建立文件的權限 */
int main(int argc, char **argv) { int iFd1; int iFd2; char cBuf[PATH_LEN] = {0};
iFd1 = open("test1", O_CREAT | O_WRONLY, FILE_MODE); /* 打開文件 */ iFd2 = open("test2", O_CREAT | O_WRONLY, FILE_MODE);
printf("open readfd %d writefd %d\n", iFd1, iFd2); /* * 構建system命令字符串 */ sprintf(cBuf, "%s %d:%d", "/apps/hellow/hellow", iFd1, iFd2);
system(cBuf); /* 調用system執行 */
close(iFd1); close(iFd2); printf("after system!\n"); return 0; } |
程序清單 3‑2 B進程代碼
#include <stdio.h> int main (int argc, char **argv) { int readfd; int writefd;
sscanf (argv[1], "%d:%d", &readfd, &writefd); /* 解析參數,得到文件描述符 */ printf("hellow readfd %d writefd %d\n", readfd, writefd);
if (!write(writefd, "SylixOS", sizeof("SylixOS"))) { perror("write"); return -1; } return (0); } |
在SylixOS運行結果如所示,B進程沒有繼承A進程的文件描述符致使報錯。
圖 3‑1 SylixOS運行結果
遇到這種狀況,能夠經過使用posix_spawn來替換system。posix_spawn函數建立子進程並繼承父系的文件描述符,因此能夠經過posix_spawn替換system實現。如程序清單 3‑3所示,只需修改A進程,B進程不用修改。
程序清單 3‑3 A進程修改後源碼
#include <stdio.h> #include <stdlib.h> #include <spawn.h>
#define PATH_LEN 20 /* 路徑長度 */ #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) /* 建立文件的權限 */
int main(int argc, char **argv) { int iFd1; int iFd2; char cBuf[PATH_LEN] = {0};
iFd1 = open("test1", O_CREAT | O_WRONLY, FILE_MODE); /* 打開文件 */ iFd2 = open("test2", O_CREAT | O_WRONLY, FILE_MODE);
printf("open readfd %d writefd %d\n", iFd1, iFd2); #ifndef SYLIXOS /* * 構建system命令字符串 */ sprintf(cBuf, "%s %d:%d", "/apps/hellow/hellow", iFd1, iFd2); system(cBuf); /* 調用system執行 */ #else char *pcArgv[5] = { "/apps/hellow/hellow", "SylixOS", (char *)0 }; int iRet; pid_t iPid;
sprintf(pcArgv[1], "%d:%d", iFd1, iFd2); /* 構建system命令字符串 */ iRet = posix_spawn(&iPid, /* 啓動進程 */ "/apps/hellow/hellow", NULL, NULL, pcArgv, NULL); if (iRet != 0) { close(iFd1); close(iFd2); return (-3); } #endif waitpid(iPid, NULL, 0); close(iFd1); close(iFd2); printf("after system!\n"); return 0; } |
運行結果如圖 3‑2所示,運行正確。
圖 3‑2 修改後運行結果
4. 參考資料
《 SylixOS 應用開發手冊》
《TN0015_fork函數替換爲SylixOS進程技術筆記》