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. I.MX6 bq27441 driver hacking

    /************************************************************************* * I.MX6 bq27441 driver ha ...

  2. RMAN数据库异机迁移

    本文讲述如何用rman将一个库迁移到另一个服务器上. 服务器A:linux es4 + oracle9204 (源)服务器B:linux es4 + oracle9204 (目标) 一.创建目录 为了 ...

  3. java vm args

    这个问题主要还是由这个问题 java.lang.OutOfMemoryError: Java heap space 引起的.第一次出现这样的的问题以后,引发了其他的问题.在网上一查可能是JAVA的堆栈 ...

  4. Hibernate4.x之Session

    Hibernate Session概述 Session接口是Hibernate向应用程序提供的操纵数据库的最主要的接口,它提供了基本的保存.更新.删除和加载Java对象的方法. Session具有一个 ...

  5. http://www.cnblogs.com/youfan/articles/3216816.html

    我对 CodeFirst 的理解,与之对应的有 ModelFirst与 DatabaseFirst ,三者各有千秋,依项目实际情况自行选择. 1.开发过程中先行设计数据库并依此在项目中生成 *.dbm ...

  6. codeforces 401D (数位DP)

    思路:很明显的数位dp,设dp[i][j] 表示选取数字的状态为i,模m等于j的数的个数,那么最后的答案就是dp[(1<<n)-1][0].状态转移方程就是,dp[i|(1<< ...

  7. 转:maven项目添加jar包.

    很多新手都不知道如何在maven项目里添加jar包. 以前我还没接触maven的时候下载过一个demo,是maven项目. 我居然是照着他的pom.xml文件一个一个的写!!! 很多人认为理所当然的东 ...

  8. [原]Links

    [Date]2014-04-19 [Author]wintys (wintys@gmail.com) http://wintys.cnblogs.com [Content]: 1.Android 1. ...

  9. leetcode—Palindrome 解题报告

    1.题目描述 Given a string s, partition s such that every substring of the partition is a palindrome. Ret ...

  10. [C++]VS与第三方工具下载

    名称:Qt 5.1.1 (商业版与开放源码许可GPL/LGPL) 说明:Qt是一个1991年由奇趣科技开发的跨平台C++图形用户界面应用程序开发框架 下载:http://www.qt.io/downl ...