文章随机晒最新文章关照最多的

jiayi Rss

signal sigaction

| Posted in APUE |

4

As people say, the old signal() had number of problems:1. The disposition for a signal was automatically reset to its defualt each time the signal occured. So we had to reestablish the handler on catching the signal. 2.There is, however, another subtle problem after reestablish the handler: There is a window of time –after the signal has occured,but before the call to signal in the signal handler. If the same signal occured int the window of time, it would cause the default action to occur and the handler would never fetch it. 3.It couldn’t control the blocking stat of signal. And so on

Fortunately, the new signal() implemented by sigaction() has fixed those problems. So the following will take us look into the new signal() (My environment is Linux 2.6.25)

C code


#include<stdio.h>

#include<stdlib.h>
#include<signal.h>
#include<errno.h>

sigset_t newmask,oldmask,pendmask;

void sig_int(int signo);
int main()
{
    if(signal(SIGINT,sig_int)==SIG_ERR) {
        perror("SIGNAL");
        exit(1);
    }

    sigemptyset(&newmask);
    sigaddset(&newmask,SIGCONT);
    if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0) {
        perror("SIGPROCMASK");
        exit(2);
    }
   
    sleep(10);
    printf("\nNo SIGINT be blocked and return to main(). \n");     /* 中断系统调用后,没有自动restart it */

    /* Reset signal mask which unblocks SIGINT */
    if (sigprocmask(SIG_SETMASK,&oldmask,NULL)<0) {
        perror("SIGPROCMASK");
        exit(3);
    } else {
        if(sigismember(&oldmask,SIGCONT))
            printf("Out of the handler, SIGCONT blocked——————————-\n");
        else
            printf("Out of the handler, SIGCONT unblocked———————————-\n");

        if(sigismember(&oldmask,SIGINT))
            printf("Out of the handler, SIGINT blocked———————————-\n");
        else
            printf("Out of the handler, SIGINT unblocked———————————-\n");
    }

    printf("Sleeping in main()…\n");
    sleep(10);
    exit(0);
}

void sig_int(int signo)
{
    printf("nncaught SIGINT\n");

    if(sigprocmask(SIG_BLOCK,NULL,&newmask)<0) {
        perror("SIGPENDING");
        exit(3);
    }

    if(sigismember(&newmask,SIGINT))
        printf("SIGINT blocked\n");
    else
        printf("SIGINT unblocked\n");

    if(sigismember(&newmask,SIGCONT))
        printf("SIGCONT blocked\n");
    else
        printf("SIGCONT unblocked\n");

    printf("Sleeping…\n");
    sleep(5);
}

jiayi:/home/jiayi/apue # ./queue0
^C                    #SIGINT wasn’t be blocked. It was caught immediately on its occurence

caught SIGINT     # In the signal handler
SIGINT blocked   # SIGINT was automatically blocked by signal() in its own handler,
SIGCONT blocked   # SIGCONT was blocked out of the signal handler manually
Sleeping…            # signal handler sleeping
^C^C^C^C^C        # SIGINT was blocked…

caught SIGINT     # When the last signal handler return, the delivery mask was reset to its previous value. So the blocked SIGINT was delivered to the signal handler again. We send SIGINT 5 times, but signal handler merely caught it once. Because SIGINT isn’t a reliable signal and it can’t be queued.
SIGINT blocked   # Be blocked again…
SIGCONT blocked   # Still be blocked…
Sleeping…            # Sleep in the signal handler

No SIGINT be blocked and return to main().
Out of the handler, SIGCONT unblocked———————————-  # As we set the delivery mask to its old value, SIGCONT wasn’t blocked
Out of the handler, SIGINT unblocked———————————-
Sleeping in main()
^C

caught SIGINT   # Caught SIGINT immediately
SIGINT blocked # Automatically be blocked
SIGCONT unblocked
Sleeping…
^C^C^C^C^C

caught SIGINT
SIGINT blocked
SIGCONT unblocked
Sleeping…

The output above tells us:
1.We needn’t  reestablish the handler on catching the signal.There is no window of time. It’s reliable.
2.SIGXXX automatically be blocked in its own handler
3.The process would block until signal handler absolutely return(ie, there is no blocked signal in the handler)

Now, show a implemention of signal() with sigaction()

C code


typedef
void Sigfunc(int);

Sigfunc *signal(int signo, Sigfunc *func)
{
    struct sigaction    act, oact;

    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if (signo == SIGALRM) {
#ifdef  SA_INTERRUPT
        act.sa_flags |= SA_INTERRUPT;
#endif
    } else {
#ifdef  SA_RESTART
        act.sa_flags |= SA_RESTART;
#endif
    }  
    if (sigaction(signo, &act, &oact) < 0)
        return(SIG_ERR);
    return(oact.sa_handler);
}

If we don’t want the signal which triggered the handler to be automatically blocked, the SA_NODEFER flag should be set as the following code added
        act.sa_flags |= SA_NODEFER

Comments (4)

这个就有点伤脑筋了

能把代码的背景颜色改一下吗,厄,我也只能提这种建议了~~

好的,有空调一下~
其实早就想调了。。。

路过回复 呵呵

Write a comment

You must be logged in to post a comment.