signal sigaction
Posted by jiayi | Posted in APUE | Posted on 02-11-2008
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)
#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()
^Ccaught SIGINT # Caught SIGINT immediately
SIGINT blocked # Automatically be blocked
SIGCONT unblocked
Sleeping…
^C^C^C^C^Ccaught 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()
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

