信号之system函数
在http://www.cnblogs.com/nufangrensheng/p/3512291.html中已经有了一个system函数的实现,但是该版本并不执行任何信号处理。POSIX.1要求system忽略SIGINT和SIGQUIT,阻塞SIGCHLD。
实例
程序清单10-19使用http://www.cnblogs.com/nufangrensheng/p/3512291.html中的system版本,用其调用ed(1)编辑器。(ed很久以来就是UNIX的组成部分。在这里调用它的原因是:它是捕捉中断和退出信号的交互式程序。若 从shell调用ed,并键入中断字符,则它捕捉中断信号并打印问号。它还将对退出符的处理方式设置为忽略。
程序清单10-19 用system调用ed编辑器
#include "apue.h" static void
sig_int(int signo)
{
printf("caught SIGINT\n");
} static void
sig_chld(int signo)
{
printf("caught SIGCHLD\n");
} int
main(void)
{
if(signal(SIGINT, sig_int) == SIG_ERR)
err_sys("signal(SIGINT) error");
if(signal(SIGCHLD, sig_chld) == SIG_ERR)
err_sys("signal(SIGCHLD) error"); if(system("/bin/ed") < 0)
err_sys("system() error");
exit(0);
}
程序清单10-19用于捕捉SIGINT和SIGCHLD信号。若调用它则可得:
当编辑器终止时,系统向父进程(a.out进程)发送SIGCHLD信号。父进程捕捉它,然后从信号处理程序返回。但是若父进程正在捕捉SIGCHLD信号(因为它创建了子进程,所以应当这样做以便了解它的子进程在何时终止),那么正在执行system函数时,应当阻塞对父进程递送SIGCHLD信号。实际上,这就是POSIX.1所说明的。否则,当system创建的子进程结束时,system的调用者可能错误地认为,它自己的一个子进程结束了。于是,调用者将会调用一种wait函数以获得子进程的终止状态,这样就阻止了system函数获得子进程的终止状态,并将其作为它的返回值。
如果再次执行该程序,在这次运行时将一个中断信号传送给编辑器,则可得:
键入中断字符可使中断信号传送给前台进程组中的所有进程。编辑程序正在运行时的各个进程的关系:
登录shell ---fork/exec---> a.out ---fork/exec---> /bin/sh ---fork/exec---> /bin/ed
后台进程组 前台进程组
a.out ---fork/exec---> /bin/sh 是由a.out中调用system函数引起的:http://www.cnblogs.com/nufangrensheng/p/3512291.html
/bin/sh ---fork/exec---> /bin/ed 可参考类shell程序的简化实现程序清单1-5:http://www.cnblogs.com/nufangrensheng/p/3495129.html
在这一实例中,SIGINT被送给三个前台进程(shell进程忽略此信号)。从输出中可见a.out进程和ed进程捕捉该信号。但是,当用system运行另一程序(例如ed)时,不应使父子进程两者都捕捉中断产生的两个信号:中断和退出。这两个信号只应送给正在运行的程序:子进程。因为由system执行的命令可能是交互式命令(例如本例中的ed程序),以及因为system的调用者在程序执行时放弃了控制,等待该执行程序的结束,所以system的调用者就不应接收这两个终端产生的信号。这就是为什么POSIX.1规定system的调用者应当忽略这两个信号的原因。(糊里糊涂的感觉)
实例
程序清单10-20 system函数的POSIX.1正确实现
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h> int
system(const char *cmdstring) /* with appropriate signal handling */
{
pid_t pid;
int status;
struct sigaction ignore, saveintr, savequit;
sigset_t chldmask, savemask; if(cmdstring == NULL)
return(1); /* always a command processor with UNIX */ ignore.sa_handler = SIG_IGN; /* ignore SIGINT and SIGQUIT */
sigemptyset(&ignore.sa_mask);
ignore.sa_flags = 0;
if(sigaction(SIGINT, &ignore, &saveintr) < 0)
return(-1);
if(sigaction(SIGQUIT, &ignore, &savequit) < 0)
return(-1);
sigemptyset(&chldmask); /* now block SIGCHLD */
sigaddset(&chldmask, SIGCHLD);
if(sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0)
return(-1); if((pid = fork()) < 0)
{
status = -1; /* probably out of processes */
}
else if(pid == 0)
{
/* restore previous signal actions & reset signal mask */
sigaction(SIGINT, &saveintr, NULL);
sigaction(SIGQUIT, &savequit, NULL);
sigprocmask(SIG_SETMASK, &savemask, NULL); /* 在父进程中忽略SIGINT,SIGQUIT,阻塞SIGCHLD,在子进程中恢复 */ execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127); /* exec error */
}
else
{
while(waitpid(pid, &status, 0) < 0)
if(errno != EINTR)
{
status = -1; /* error other than EINTR from waitpid() */
break;
}
} /* restore previous signal actions & reset signal mask */
if(sigaction(SIGINT, &saveintr, NULL) < 0)
return(-1);
if(sigaction(SIGQUIT, &savequit, NULL) < 0)
return(-1);
if(sigprocmask(SIG_SETMASK, &savemask, NULL) < 0)
return(-1); /* 子进程退出后,父进程才恢复SIGINT,SIGQUIT和SIGCHLD */ return(status);
}
如果链接程序清单10-19与system函数的这一实现,那么所产生的二进制代码与上一个有缺陷的程序相比较,存在如下差别:
(1)当我们键入中断或退出字符时,不向调用者进程发送信号。
(2)当ed命令终止时,不向调用进程发送SIGCHLD信号。作为替代,在程序末尾的sigprocmask调用对SIGCHLD信号解除阻塞之前,SIGCHLD信号一直被阻塞。而对sigprocmask函数的这一次调用是在system函数调用waitpid取到子进程的终止状态之后。
system的返回值
注意system的返回值,它是shell的终止状态,但shell的终止状态并不总是执行命令字符串进程的终止状态。
Bourne shell有一个在其文档中没有说清楚的特性:当用一个信号终止了正在执行的命令时,其终止状态是128加上一个信号编号。
用交互方式使用shell可以看到这一点:
在所使用的系统中,SIGINT的值为2,SIGQUIT的值为3,于是给出shell终止状态130、131.
仅当shell本身异常终止时,system的返回值才报告一个异常终止。
在编写使用system函数的程序时,一定要正确地解释返回值。如果直接调用fork、exec和wait,则终止状态与调用system是不同的。
本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/。
信号之system函数的更多相关文章
- 关于linux下system()函数的总结
导读 曾经的曾经,被system()函数折磨过,之所以这样,是因为对system()函数了解不够深入.这里必须要搞懂system()函数,因为有时你不得不面对它. 先来看一下system()函数的简单 ...
- system函数遇到的问题
这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数中调用的命令也都一切正常.就没理这个bug,以 ...
- [转载]关于linux下system()函数的总结
1.曾经的曾经,被system()函数折磨过,之所以这样,是因为对system()函数了解不够深入.这里必须要搞懂system()函数,因为有时你不得不面对它. 2.先来看一下system()函数的简 ...
- 二十六、Linux 进程与信号---system 函数 和进程状态切换
26.1 system 函数 26.1.1 函数说明 system(执行shell 命令)相关函数 fork,execve,waitpid,popen #include <stdlib.h> ...
- 一、进程与信号之exec函数system函数
exec函数: 子进程调用exec函数执行另一个程序,exec函数进程完全由新程序代替,替换原有程序正文,数据,堆,栈段 #include <unistd.h> extern char * ...
- Linux system函数详解
system 功能:system()函数调用"/bin/sh -c command"执行特定的命令,阻塞当前进程直到command命令执行完毕 原型 int system(cons ...
- system 函数
相关函数:fork, execve, waitpid, popen 头文件:#include <stdlib.h> 定义函数:int system(const char * string) ...
- system函数
system两层含义: 1.正确退出后.还需要再判断,操作成功或者操作失败. 2.错误退出. #include <stdio.h> #include <stdlib.h> #i ...
- [转]system函数返回值探究
对于system这个函数的功能早就有一定了解,读书期间,就学习了UNIX系统编程这本书,后来买了APUE.我这个人总是有好读书不求甚解的毛病.对于system函数只知其一,不知其二.后来被人问起相关的 ...
随机推荐
- POJ 1637 Sightseeing tour ★混合图欧拉回路
[题目大意]混合图欧拉回路(1 <= N <= 200, 1 <= M <= 1000) [建模方法] 把该图的无向边随便定向,计算每个点的入度和出度.如果有某个点出入度之差为 ...
- OK335xS Qt network hacking
/********************************************************************** * OK335xS Qt network hacking ...
- apache开源项目--PDFBox
PDFBox是Java实现的PDF文档协作类库,提供PDF文档的创建.处理以及文档内容提取功能,也包含了一些命令行实用工具. 主要特性包括: 从PDF提取文本 合并PDF文档 PDF 文档加密与解密 ...
- 从ramdisk根文件系统启动Linux成功,及使用initramfs启动linux
下面两篇文章是ARM9论坛上的讲解ramdisk文件系统的很不错的文章 今天做了个试验,让Linux2.6.29.4从ramdisk根文件系统启动成功,总结一下. 其中涉及的内容较多,很多东西不再详述 ...
- Android中Bitmap和Drawable,等相关内容
一.相关概念 1.Drawable就是一个可画的对象,其可能是一张位图(BitmapDrawable),也可能是一个图形(ShapeDrawable),还有可能是一个图层(LayerDrawable) ...
- [原]AngularJS iframe打开不同域的内容时报错误
<iframe id="myFrame" ng-src="{{url}}" width="100%" height="100 ...
- bzoj 1034 [ZJOI2008]泡泡堂BNB(贪心)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1034 [题意] 给两个序列以任意顺序比较,求出最大和最小得分. [思路] 排序后使用贪 ...
- NOIP2004 合并石子
二.合并果子 (fruit.pas/dpr/c/cpp) [问题描述] 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多 ...
- STL(pair map set vector priority_queue) poj 3297
POJ 3297 算法竞赛初级杂烩包 题意:学生选课,没个学生只能选一门课.大写字符是课的名字,小写是人名.如果课程后面有多个相同名字算一个,如果一个人选多门课,则他选不上课,输出课和每门课选课人数 ...
- PHP与MySQL动态网站开发1
PHP内嵌在HTML中,置于 <?php ?> 标签内 一般php文件扩展名.php 在body结算标签之前 对于远程服务器,可以用ftp工具传程序 打印语句 echo'Hello Wor ...