Chinaunix首页 | 论坛 | 博客
  • 博客访问: 969292
  • 博文数量: 200
  • 博客积分: 5011
  • 博客等级: 大校
  • 技术积分: 2479
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-27 15:07
文章分类

全部博文(200)

文章存档

2009年(12)

2008年(190)

我的朋友

分类:

2008-12-08 12:17:38

10.18 system function

Posix.1要求,调用system函数时要ignore SIGINTSIGQUIT,并且要block SIGCHLD。因为:

1System其实是启动一个sh,然后用这个shexec 一个程序,并且system本身父进程会waitpid生成的子进程

2SIGINTSIGQUIT如果用terminal device发送一般都是发送给一个process group的,所以调用system函数的caller进程和被执行的程序进程都回收到该信号。

2SIGINTSIGQUIT应该给被执行的程序,而不是调用systemcaller进程,所以caller进程应该忽略他们,由被执行的程序去处理他们。

3.由于在system函数内部,caller进程会waitpid被执行的程序子进程,所以他通过waitpid得到了sh的执行结果,并返回。如果该程序结束后,向父亲发送的SIGCHLD被捕获,父亲当作自己一个普通的孩子结束了,就有可能去调用waitpid,从而提前将该子进程的返回status破坏,这样system里面的waitpid就不能有效得到他了,system就不能返回正确的直了。

下面我们列举出posix.1system函数的实现代码:

Figure 10.28. Correct POSIX.1 implementation of system function

#include     

#include     

#include     

#include     

 

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) {          /* child */

        /* restore previous signal actions & reset signal mask */

        sigaction(SIGINT, &saveintr, NULL);

        sigaction(SIGQUIT, &savequit, NULL);

        sigprocmask(SIG_SETMASK, &savemask, NULL);

 

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

        _exit(127);     /* exec error */

    } else {                        /* parent */

       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);

 

    return(status);

}

 

我们分析一下有几个进程:

执行命令:./a.out “sleep 30”

1Shellfork出一个进程,紧接着execa.out,此时一个进程

2a.out执行到system调用,systemfork出一个进程,此时有2a.out进程

3.孩子a.out调用execl sh …变成一个sh进程,此时还是2个进程

4Sh进程此时有参数-c “sleep 30”,于是sh会再次fork出一个进程,一个sh,此时有3个进程

5.这个刚被fork出的进程会立马exec sleep 30,至此还是3个进程。

 

如果sleep异常中止,那么他的父亲sh会知道,sh会正常终止,system得到正常终止的结果。

如果sh异常中止,那么system 会得到异常中止的结果。

System的返回值是sh的返回值。

Note: linux suse上,我只看到了2个进程。一个是a.out,一个是sleep 30, 我并没有看到那个 中间的sh.

阅读(586) | 评论(0) | 转发(0) |
0

上一篇:10.17 abort function

下一篇:10.19 sleep function

给主人留下些什么吧!~~