Changing the signal screen word of a process can block the selected signal or unblock them. Use this technique to protect code critical sections that you 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? An incorrect way to achieve this is to assume that the signal is SIGINT:
sigset_t Newmask, Oldmask;
Sigemptyset (&newmask);
Sigaddset (&newmask, SIGINT);
/* Block SIGINT and save current signal mask */if (Sigprocmask (Sig_block, &newmask, &oldmask) < 0)
Err_sys ("Sig_block error");
/* Critical Region of code */if (Sigprocmask (Sig_setmask, &oldmask, NULL) < 0)
Err_sys ("Sig_setmask error");
/* window is open */
Pause (); /* Wait for signal to occur */
/* Continue processing */
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 between the unblocking of the SIGINT and the pause . If this happens, or if a signal does occur between the time of unblocking and pause , then a problem arises. Since we may not see the signal again, in this sense, The signal that occurs in this time window (between unblocking and pause) is lost so that pause is blocked forever.
To correct this problem, you need to first 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);
return value:-1, and set errno 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 handler, sigsuspend returns and sets the signal screen word of the process to the value before the call to sigsuspend .
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void handler (int sig)// Signal Processing program
{
if (sig = = SIGINT)
printf ("SIGINT sig");
else if (sig = = Sigquit)
printf ("Sigquit sig");
Else
printf ("SIGUSR1 sig");
}
int main ()
{
sigset_t new,old,wait; three set of signals
struct Sigaction Act;
Act.sa_handler = handler;
Sigemptyset (&act.sa_mask);
act.sa_flags = 0;
Sigaction (SIGINT, &act, 0); The following three signals can be captured:sigint/sigquit/sigusr1
Sigaction (sigquit, &act, 0);
Sigaction (SIGUSR1, &act, 0);
Sigemptyset (&new);
Sigaddset (&new, SIGINT); SIGINT Signal added to the new signal set
Sigemptyset (&wait);
Sigaddset (&wait, SIGUSR1); SIGUSR1 signal Join wait
Sigprocmask (Sig_block, &new, &old); block SIGINT , save current signal set to old
critical section Code execution
if (Sigsuspend (&wait)! =-1)//program hangs here; replace the new signal set with the wait signal set . That is: Come over SIGUSR1 letter , block out, the program continues to hang; other signals, such as SIGINT, Wake the program. Performs Atomic operations on Sigsuspend. Note: If "Sigaddset (&wait, SIGUSR1);" This does not block any signal here, that is, any signal will wake up the program.
printf ("Sigsuspend error");
printf ("After Sigsuspend");
Sigprocmask (Sig_setmask, &old, NULL);
return 0;
}
the atomic operation of the Sigsuspend is:
(1 Span style= "Font-family:times New Roman" >mask blocking current process ( wait replace new SIGUSR1 signal )
(2 SIGUSR1 signal, block, program continues to hang, receive other signals, restore original mask ( sigint signal "
(3 ( If you first come to SIGUSR1 signal, then come over sigint signal, the signal processing function will be called two times to print different content. First print sigint, second print SIGUSR1 SIGUSR1 front blocked "
(4) when the signal processing function returns,sigsuspend returns. (sigsuspend integrates the capture signal and signal processing functions together )
Linux C Programming: Signal (v) sigsuspend