Advanced Programming in UNIX Environment Episode 46

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/myfather103/article/details/79766045

system Function

In Section 8.13, we showed an implementation of the system function. That version, however, did not do any signal handling. POSIX.1 requires that system ignore SIGINT and SIGQUIT and block SIGCHLD. Before showing a version that handles these signals correctly, let’s see why we need to worry about signal handling.

#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");
    return 0;
}

Using system to invoke the ed editor

#include <sys/wait.h>
#include <errno.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;
    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);
    sigaddset(&chldmask);
    if(sigprocmask(SIG_BLOCK,&chldmask,&savemask)<0)
        return -1;
    
    if((pid=fork())<0)
    {
        status=-1;
    }
    else if(pid==0)
    {
        sigaction(SIGINT,&saveintr, NULL);
        sigaction(SIGQIT,&savequit,NULL);
        sigprocmaask(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(sigprocmask(SIG_SETMASK,&savemask, NULL)<0)
        return -1;

    return status;
}

Correct POSIX.1 implementation of system function

If we link the program in Figure 10.26 with this implementation of the system function, the resulting binary differs from the last (flawed) one in the following ways.

1.No signal is sent to the calling process when we type the interrupt or quit character.
2.When the ed command exits, SIGCHLD is not sent to the calling process. Instead, it is blocked until we unblock it in the last call to sigprocmask, after the system function retrieves the child’s termination status by calling waitpid.

POSIX.1 states that if wait or waitpid returns the status of a child process while SIGCHLD is pending, then SIGCHLD should not be delivered to the process unless the status of another child process is also available. FreeBSD 8.0, Mac OS X 10.6.8, and Solaris 10 all implement this semantic. Linux 3.2.0, however, doesn’t —SIGCHLD remains pending after the system function calls waitpid; when the signal is unblocked, it is delivered to the caller.

Here, we can see that the return value from system reports an abnormal termination only when the shell itself terminates abnormally.

Other shells behave differently when handling terminal-generated signals, such as SIGINT and SIGQUIT. With bash and dash, for example, pressing the interrupt or quit key will result in an exit status indicating abnormal termination with the corresponding signal number. However, if we find our process executing sleep and send it a signal directly, so that the signal goes only to the individual process instead of the entire foreground process group, we will find that these shells behave like the Bourne shell and exit with a normal termination status of 128 plus the signal number.

猜你喜欢

转载自blog.csdn.net/myfather103/article/details/79766045
今日推荐