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函数的更多相关文章

  1. 关于linux下system()函数的总结

    导读 曾经的曾经,被system()函数折磨过,之所以这样,是因为对system()函数了解不够深入.这里必须要搞懂system()函数,因为有时你不得不面对它. 先来看一下system()函数的简单 ...

  2. system函数遇到的问题

     这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数中调用的命令也都一切正常.就没理这个bug,以 ...

  3. [转载]关于linux下system()函数的总结

    1.曾经的曾经,被system()函数折磨过,之所以这样,是因为对system()函数了解不够深入.这里必须要搞懂system()函数,因为有时你不得不面对它. 2.先来看一下system()函数的简 ...

  4. 二十六、Linux 进程与信号---system 函数 和进程状态切换

    26.1 system 函数 26.1.1 函数说明 system(执行shell 命令)相关函数 fork,execve,waitpid,popen #include <stdlib.h> ...

  5. 一、进程与信号之exec函数system函数

    exec函数: 子进程调用exec函数执行另一个程序,exec函数进程完全由新程序代替,替换原有程序正文,数据,堆,栈段 #include <unistd.h> extern char * ...

  6. Linux system函数详解

    system 功能:system()函数调用"/bin/sh -c command"执行特定的命令,阻塞当前进程直到command命令执行完毕 原型 int system(cons ...

  7. system 函数

    相关函数:fork, execve, waitpid, popen 头文件:#include <stdlib.h> 定义函数:int system(const char * string) ...

  8. system函数

    system两层含义: 1.正确退出后.还需要再判断,操作成功或者操作失败. 2.错误退出. #include <stdio.h> #include <stdlib.h> #i ...

  9. [转]system函数返回值探究

    对于system这个函数的功能早就有一定了解,读书期间,就学习了UNIX系统编程这本书,后来买了APUE.我这个人总是有好读书不求甚解的毛病.对于system函数只知其一,不知其二.后来被人问起相关的 ...

随机推荐

  1. Spring3中用注解直接注入properties中的值

    在bean(可是controller, service, dao等了)中,使用@Value注解: @Service public class TestService{ @Value("${s ...

  2. mysql中php生成唯一ID

    <?php //uniqid官方手册 function create_guid($namespace = '') { static $guid = ''; $uid = uniqid(" ...

  3. windows2003远程桌面退出后系统自动注销的解决方法

    最近公司有一个奇怪的需求,意思是有一个网页,要时时的打开着.现在只有把这个网页在服务器上打开. 这样才能满足需求.但我在应用中遇见了个问题.我在服务器上打开网页后,关掉远程,过一会网页的运行效果就没有 ...

  4. 剑指Offer:找出数组中出现次数超过一半的元素

    题目:找出数组中出现次数超过一半的元素 解法:每次删除数组中两个不同的元素,删除后,要查找的那个元素的个数仍然超过删除后的元素总数的一半 #include <stdio.h> int ha ...

  5. jquery在线引用的地址

    1. 很多网站都是使用这种方式引入,客户的浏览器可能已经缓存过了 jquery.可以直接调用本地的,速度更快… 2. Google code 使用了 cdn 技术在很多地方有节点服务器,加载 jque ...

  6. 【转】经典SQL语句大全

    原博客地址:http://www.cnblogs.com/yubinfeng/archive/2010/11/02/1867386.html (超级纳闷为啥没有转载的功能) 一.基础 1.说明:创建数 ...

  7. [Bhatia.Matrix Analysis.Solutions to Exercises and Problems]ExI.2.6

    If $\sen{A}<1$, then $I-A$ is invertible, and $$\bex (I-A)^{-1}=I+A+A^2+\cdots, \eex$$ aa converg ...

  8. NGUI如何创建自己的精灵图集

    说实话其实很简单,但是在不知道的情况下真的不好弄啊. 1. 选择你要制作精灵图集的图片,可以选择多张 2. 提倡使用快捷键Alt + Shift + M 会有如下窗口弹出,也可以NGUI --> ...

  9. opencv 在工业中的应用:blob分析

    在工业中经常要检测一副图像中物体的数量,位置,大小,面积等信息,这就要用到BLOB分析,我用OPENCV做了个BLOB分析的DEMO. (1)打开一幅图像 (2)进行参数设置,设定二值化阙值,并选择是 ...

  10. 导入showb时候出错--2015-12-4

    [root@cache-02 ~]# /opt/coreseek/csftweb-bash: /opt/coreseek/csftweb: is a directory[root@cache-02 ~ ...