Changing the signal screen word of a process can block selected signals or unblock them, and using this technique can protect code critical sections that do not want to be interrupted by a signal.
What if you want to unblock a signal and then pause to wait for a previously blocked signal to occur? Assuming that the signal is SIGINT, a way to achieve this
The incorrect method is:
sigset_t Newmask,oldmask;
Sigemptyset (&newmask);
Sigaddset (&newmask, SIGINT);
if (Sigprocmask (Sig_block, &newmask, &oldmask) < 0) {
perror (sigprocmask);
return-1;
}
Perform additional operations
if (Sigprocmask (Sig_setmask &oldmask, NULL) < 0) {
perror (sigprocmask);
return-1;
}
Pause ();
If it is sent to the process when the signal is blocked, the signal's delivery is deferred until it is unblocked. For the application, the signal appears to be lifted
Between blocking and pause for SIGINT, if this happens, the latter if there is a real signal between the unblocking moment and pause, then there is
Problem, we may not see the signal again, so that pause is blocked forever.
To correct this problem, you need to restore the signal mask word in an atomic operation and then hibernate the process. This functionality is provided by the Sigsuspend function.
#include <signal.h>
int sigsuspend (const sigset_t *sigmask); The return value is-1, and the errno is set to Eintr.
Sets the signal screen character of the process to the value pointed to by Sigmask. The process is suspended until a signal is captured or a signal is signaled to terminate the process.
If a signal is captured and returned from the signal processing sequence, the sigsuspend is returned and the signal screen word of the process is set to call Sigsuspend
Before the value.
Practice:
#include <stdio.h> #include <signal.h> static void sig_int (int);
int main (void) {sigset_t newmask,oldmask,waitmask;
printf ("program start.\n");
if (Signal (SIGUSR1, sig_int) = = Sig_err) {perror ("signal");
return-1;
} if (Signal (SIGUSR2, sig_int) = = Sig_err) {perror ("signal");
return-1;
} sigemptyset (&waitmask);
Sigaddset (&waitmask, SIGUSR1);
Sigemptyset (&newmask);
Sigaddset (&newmask, SIGUSR2);
if (Sigprocmask (Sig_block, &newmask, &oldmask) < 0) {perror ("Sigprocmask");
return-1;
} printf ("In Critical region.\n");
Sigsuspend (&waitmask);
if (Sigprocmask (Sig_setmask, &oldmask, NULL) < 0) {perror ("Sigprocmask");
return-1;
} printf ("Program exit.\n");
return 0; } statIC void sig_int (int signo) {printf ("int sig_int:%d.\n", signo);} Operation Result:
[ROOT@YANPC apue]#./a.out &
[1] 16802
Program start.
In the critical region.
[ROOT@YANPC apue]# KILL-SIGUSR1 16802
[ROOT@YANPC apue]# KILL-SIGUSR2 16802
int Sig_int:12.
int sig_int:10.
Program exit.
The SIGUSR2 is blocked at the beginning, and when the program executes Sigsuspend, the waitmask is used, which is to block the SIGUSR1, SIGUSR2
unblocked, so after sending SIGUSR1 to the process, there is no response, after sending SIGUSR2 to the process, the Sig_int function is executed, the Sigsuspend function returns,
And the mask is set to the state before the call to Sigsuspend, that is, the SIGUSR1 is not blocked, so the Sig_int function is executed.