免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2017 | 回复: 4
打印 上一主题 下一主题

请教信号问题--system的一个实现(APUE) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-05-27 11:45 |只看该作者 |倒序浏览
有一个地方不解,程序如下(APUE 10.18),问题是,在(1)处已经阻塞的子进程结束信号的递送,
在(2)中,父进程还可以等待到子进程的结束信号吗?

谢谢!!



  1. #include <sys/types.h>

  2. #include <sys/wait.h>

  3. #include <errno.h>

  4. #include <signal.h>

  5. #include <unistd.h>



  6. int system(const char *cmdstring)

  7. {

  8.     pid_t             pid;

  9.     int               status;

  10.     struct sigaction  ignore, saveintr, savequit;

  11.     sigset_t          chldmask, savemask;

  12.    

  13.     if (cmdstring == NULL)

  14.        return (1);  //always a command processor with unix

  15.       

  16.     ignore.sa_handler = SIG_IGN; //ignore SIGINT and SIGQUIT

  17.     sigempty(&ignore.sa_mask);

  18.     ignore.sa_flags = 0;

  19.     if (sigaction(SIGINT, &ignore, &saveintr) < 0)

  20.        return (-1);

  21.     if (sigaction(SIGQUIT,&ignore, &savequit) < 0)

  22.        return (-1);

  23.       

  24.     sigemptyset(&chldmask);        //now block SIGCHLD

  25.     sigaddset(&chldmask, SIGCHLD);


  26. //---------- (1) -----------------
  27.     if (sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0)

  28.        return (-1);

  29.       

  30.     if ( (pid = fork()) < 0)

  31.     {

  32.          status = -1; //probably out of  processes

  33.     }

  34.     else if (pid == 0)

  35.     {

  36.          //restore previous signal actions & reset signal mask

  37.          sigaction(SIGINT, &saveintr, NULL);

  38.          sigaction(SIGQUIT, &savequit, NULL);

  39.          sigprocmask(SIG_SETMASK, &savemask, NULL);

  40.          

  41.          execl("/bin/sh", "sh", "-c", cmdstring, (char*)0);

  42.          _exit(127);      //exec error

  43.     }

  44.     else

  45.     {

  46. //---------- (2) -----------------
  47.         while (waitpid(pid, &status, 0) < 0)

  48.               if (errno != EINTR)

  49.               {

  50.                  status = -1; //error other than EINTR form waitpid()

  51.                  break;

  52.               }

  53.     }

  54.    

  55.     if (sigaction(SIGINT, &saveintr, NULL) < 0)

  56.        return (-1);

  57.     if (sigaction(SIGQUIT, &savequit, NULL) < 0)

  58.        return (-1);

  59.     if (sigprocmask(SIG_SETMASK, &savemask, NULL) < 0)

  60.        return (-1);

  61.       

  62.     return (status);

  63. }

  64.       
复制代码

[ 本帖最后由 rwen2012 于 2006-5-27 11:50 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2006-05-27 18:10 |只看该作者
不能

论坛徽章:
0
3 [报告]
发表于 2006-05-27 19:40 |只看该作者
自己测试了一下,发现sigprocmask()了SIGCHLD之后,此信号不能递送给该进程,
但是仍然可以被wait()/waitpid()检测到,使父进程从阻塞等待(wait())中返回。
如下: 在程序(3)处的语句如果被注释掉,则会产生僵死进程(子进程),可以用ps -aux 检测到该子进程为Z态。
          在程序(4)处的语句如果‘不’被注释掉,则先前阻塞的SIGCHLD信号将被递送,调用其处理例程。

如有理解错误,请指正,谢谢!!



  1. #include <signal.h>
  2. #include <unistd.h>

  3. void sig_chld(int signo)
  4. {
  5.         printf("int the SIGCHLD handler\n");
  6. }

  7. int main(void)
  8. {       
  9.         int pid;
  10.         sigset_t nset, oset;

  11.         sigemptyset(&oset);
  12.         sigemptyset(&nset);
  13.         sigaddset(&nset, SIGCHLD);

  14.         signal(SIGCHLD, sig_chld);

  15.         sigprocmask(SIG_BLOCK, &nset, &oset);

  16.         if ( (pid = fork()) < 0)
  17.                 perror("fork error\n");
  18.         else if (pid == 0) {
  19.                 printf("in the child\n");
  20.                 _exit(1);
  21.         }
  22.        
  23.         wait(NULL);                                                    // == (3) ==
  24.        
  25.         sigprocmask(SIG_SETMASK, &oset, NULL);     // ===(4)===
  26.        
  27.         pause();

  28.         return 0;
  29. }       
  30.        

复制代码

[ 本帖最后由 rwen2012 于 2006-5-27 19:43 编辑 ]

论坛徽章:
0
4 [报告]
发表于 2006-05-27 22:56 |只看该作者
原帖由 rwen2012 于 2006-5-27 11:45 发表
有一个地方不解,程序如下(APUE 10.1,问题是,在(1)处已经阻塞的子进程结束信号的递送,
在(2)中,父进程还可以等待到子进程的结束信号吗?

谢谢!!

[code]

#include <sys/types.h>

# ...


个人的理解:
1 阻塞SIGCHLD是必要的,如果调用system的进程设置了SIGCHLD的handler,则system()函数不能正确地返回其执行的cmdstring的返回状态.
2 父进程是否能从waitpid()获得已经结束的子进程的终止态与父进程是否阻塞了SIGCHLD无关.(SIGCHLD默认的动作是忽略)

论坛徽章:
0
5 [报告]
发表于 2006-05-28 01:34 |只看该作者
>>> 2 父进程是否能从waitpid()获得已经结束的子进程的终止态与父进程是否阻塞了SIGCHLD无关.(SIGCHLD默认的动作是忽略)

非常感谢楼上的回复,第1点可以理解。

关键在第2点,我的想法差不多也是这样。 Unix sysV 的waitpid()实现大概是父进程将自己TASK_INTERRUPTIBLE状态,然后(在一指定地址中睡眠)切换下一下进程,在子进程退出之时,会唤醒睡眠在该队列中的父进程,使其重新进入TASK_RUNNIG状态。好像用了和信号处理不同的数据结构,这样就和信号的屏蔽与否无关。

不知理解有没有正确,哪位大哥看过Linux waitpid()的实现的指正一下,非常感谢!!!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP