作者:追梦and寻梦 | 来源:互联网 | 2023-10-15 18:49
1. 适用范围
SylixOS是一款为大型嵌入式系统设计的硬实时系统,支持使用system调用执行命令。SylixOS为了保证实时性在system的实现上和Linux有所差别,本文着重介绍SylixOS如何实现system和在使用system时需要注意的事项。
2. 原理介绍
SylixOS为保证系统的实时性所以没有实现fork功能,Linux下system是使用fork实现的。而SylixOS则通过使用内核的shell线程实现system功能。
2.1 Linux的system功能浅析
Linux下system会调用fork产生子进程,由子进程execve调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。
因为Linux下是通过fork实现system,所以被执行的命令继承父系的一些资源(比如文件描述符,父系的工作路径等)。同时能够实现异步执行和同步执行,同步执行即父系等待system调用运行结束(包括system调用的命令执行结束);异步即不等待,父系继续运行。
2.2
SylixOS的system原理介绍
#include
intsystem(constchar *command);
|
函数成功返回 0,失败返回-1,并设置错误码。
SylixOS的system是先创建一个内核的shell线程,然后通过内核的shell线程执行system需要执行的命令。
如果使用system调用执行一个进程,则同时启动一个内核线程来join等待清除该进程。如果使用system调用执行一个shell命令,则直接由内核线程t_tshell负责清除。如图 21所示,由open(pid=5)调用system执行hellow(pid=6),而内核创建一个hellow(pid=0)的内核线程join等待。
图 21 system调用现象
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进程的文件描述符进行操作。
使用场景如程序清单 31和程序清单 32所示。
程序清单 31 A进程代码
#include
#include
#define PATH_LEN 20 /* 路径长度 */
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) /* 创建文件的权限 */
intmain(intargc, 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;
}
|
程序清单 32 B进程代码
#include
intmain (intargc, char **argv)
{
intreadfd;
intwritefd;
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进程的文件描述符导致报错。
图 31 SylixOS运行结果
遇到这种情况,可以通过使用posix_spawn来替换system。posix_spawn函数创建子进程并继承父系的文件描述符,所以可以通过posix_spawn替换system实现。如程序清单 33所示,只需修改A进程,B进程不用修改。
程序清单 33 A进程修改后源码
#include
#include
#include
#define PATH_LEN 20 /* 路径长度 */
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
/* 创建文件的权限 */
intmain(intargc, 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_tiPid;
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;
}
|
运行结果如图 32所示,运行正确。
图 32 修改后运行结果
#
:http://www.linuxidc.com/Linux/2017-06/144762.htm