unix 环境高级编程之 system函数

#include  <sys/wait.h>
#include  <erron.h>
#include  <signal.h>
#include  <unistd.h>
int system(const char* cmdstring)
{ 
   pid_t pid;
   int status;
   struct sigaction ignore,saveintr,savequit;
   sigset_t chldmask,savemask;
   if(cmdstring==NULL)
       return 1;
   ignore.sa_handler=SIG_IGN;
   if(sigaction(SIGINT,&ignore,&saveintr)<0)
       return -1;
   if(sigaction(SIGQUIT,&ignore,&savequit)<0)
       return -1;
   sigemptyset(&chldmask);
   sigaddset(&chldmask,SIGCHLD);
   if(sigpromask(SIG_BOLCK,&chllmask,&savemask)
     return -1;
   if((pid=fork())<0)
       status=-1;
   else if(pid==0)
    {
       sigaction(SIGINT,&saveintr,NULL);
       sigaction(SIGQUIT,&savequit,NULL);
       sigpromask(SIG_SETMASK,&savemask,NULL);
       execl("/bin/sh","sh","-c",cmdstring,(char*)0);
       _exit(127);
     }
    else {
    while(waitpid(pid,&status,0)<0)
      {
         if(errno!=EINTR)
            {
               status=-1;
               break;
               }
      }
    if(sigaction(SIGINT,&saveintr,NULL)<0)
      return -1;
    if(sigaction(SIGQUIT,&savequit,NULL)<0)
      return -1;
    if(sigpromask(SIG_SETMASK,&savemask,NULL)<0)
      return -1;
     return status;
     }

    上面的是apue中对system函数加信号处理函数的实现,其中调用进程忽略了SIGINT和SIGQUIT信号,以及阻塞了SIGCHLD信号,并且书上举了一个ed编辑器的例子来说明system函数的用法,这里需要注意的第一点就是调用进程通过fork创建的进程的函数是/bin/sh这个子shell,然后又因为ed不是shell的内建命令,从而又是fork调用创建了一个新的进程,这个进程的函数才是ed,这里所说的就是system设置的是调用进程和/bin/sh这两个进程对信号的不同处理方式。但是我在这里一直存在着一个疑问,那就是在if(pid==0) 之后的那两行,我记得apuep242上面说到当exec函数时,exec函数会将原先设置为要捕捉的信号更改为它们的默认动作,其他信号的状态不变。 如果是这样的话,那么这两行有什么用呢?

 下面说说为什么要对SIGCHLD加上阻塞:

          apue的p277上面这么说:如果父进程正在捕捉SIGCHLD信号,那么正在执行system函数的时候,应当阻塞对父进程递送SIGCHLD信号.否则,当system创建的子进程结束的时候,system的调用者可能错误的认为,它自己的一个子进程结束了.于是,调用者将会调用一种wait函数以获得子进程的终止状态,这样就阻止了system函数获得子进程的终止状态,并将其作为返回值。

         上面的话我是有些听得不是很懂,所以自己就往里面加了点东西,首先是父进程设置了捕捉SIGCHLD信号的处理函数,并且处理函数中调用waipid函数来获得子进程的结束状态。如果调用 者进程没有将SIGCHLD信号设置为阻塞位,也就是上面的system函数中没有设置(或者是采用类似于第八章的未加信号处理的system函数),则当system创建的子进程结束的时候,也就是ed编译器进程结束的时候,调用者进程的SIGCHLD信号处理函数会捕捉到这个信号,然后waitpid获得子进程的终止状态,然后再为子进程收尸。。当执行完这个信号处理程序之后,会继续执行调用者进程的其余部分,显然这个时候调用者进程被停止在waitpid的地方,但是这个时候pid对应的子进程的终止状态在信号处理函数中已经被处理了,这里再等下去也没什么意思,就会返回错误了,所以我们需要阻塞在调用者进程中阻塞对SIGCHLD信号的处理,只有当调用者进程waitpid获得子进程的状态之后,再接触对该信号的阻塞,这个时候信号处理函数才能起作用,但是这个时候信号处理函数中的waitpid也会出错。注意的是ed编译器进程结束的时候,会向所以的前台进程组成员发信号(当然同属于唯一的一个前台进程组),这个时候调用者进程是阻塞,shell子进程是忽略,因为有execl的复位操作。

      apue上面的对于SIGINT和SIGSTOP信号的处理为什么是忽略我不是很了解,p278上面的解释也没明白,希望大神求踩。。

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值