Advanced Programming in UNIX Environment Episode 44

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

sigsuspend Function

We have seen how we can change the signal mask for a process to block and unblock selected signals. We can use this technique to protect critical regions of code that we don’t want interrupted by a signal.

To correct this problem, we need a way to both restore the signal mask and put the process to sleep in a single atomic operation. This feature is provided by the sigsuspend function.

#include <signal.h>

int sigsuspend(const sigset_t *signmask);

The signal mask of the process is set to the value pointed to by sigmask. Then the process is suspended until a signal is caught or until a signal occurs that terminates the process. If a signal is caught and if the signal handler returns, then sigsuspend returns, and the signal mask of the process is set to its value before the call to sigsuspend.

Note that there is no successful return from this function. If it returns to the caller, it always returns −1 with errno set to EINTR (indicating an interrupted system call).

#include "apue.h"

static void sig_int(int);

int main(void)
{
    sigset_t newmask, oldmask, waitmask;

    pr_mask("program start: ");
    if(signal(SIGINT,sig_int)==SIG_ERR)
        err_sys("signal(SIGINT) error");

    sigemptyset(&waitmask);
    sigaddset(&waitmask,SIGUSR1);
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGINT);

    if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)
        err_sys("SIG_BLOCK error");
    
    pr_mask("in critical regiion: ");

    if(sigsuspend(&waitmask)!=-1)
        err_sys("sigsuspend error");
    pr_mask("after return from sigsuspend");

    if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)
        err_sys("SIG_SETMASK error");
    
    pr_mask("program exit: ");
    return 0;
}

static void sig_int(int signo)
{
    pr_mask("\nin sig_int: ");
}

Protecting a critical region from a signal

#include "apue.h"

volatile sig_atomic_t quitflag;

static void sig_int(int signo)
{
    if(signo==SIGINT)
        printf("\ninterrupt\n");
    else if(signo==SIGQUIT)
        quitflag=1;
}

int main(void)
{
    sigset_t newmask,oldmask,zeromask;

    if(signal(SIGINT,sig_int)==SIG_ERR)
        err_sys("signal(SIGINT) error");
    if(signal(SIGQUIT,sig_int)==SIG_ERR)
        err_sys("signal(SIGQUIT) error");
    
    sigemptyset(&zeromask);
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGQUIT);

    if(sigprocmask(SIG_BLOCK, &newmask, &oldmask)<0)
        err_sys("SIG_BLOCK error");
    
    while(quitflag==0)
        sigsuspend(&zeromask);

    quitflag=0;

    if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)
        err_sys("SIG_SETMASK error");
    
    return 0;
}

Using sigsuspend to wait for a global variable to be set

For portability between non-POSIX systems that support ISO C and POSIX.1 systems, the only thing we should do within a signal handler is assign a value to a variable of type sig_atomic_t—nothing else. POSIX.1 goes further and specifies a list of functions that are safe to call from within a signal handler, but if we do this, our code may not run correctly on non-POSIX systems.

猜你喜欢

转载自blog.csdn.net/myfather103/article/details/79763682