sigsuspend and pause, both do the same work, they pause or temporarily stops the process until they receive some signal. These functions return, once the signal handling of the signal is complete.
A small difference between these functions is that, in sigsuspend, we can specify the signal mask to which the function should not listen. Suppose we implement the sigsuspend in the following manner
sigset_t tempmask;
sigemptyset(&tempmask);
sigaddset(&tempmask,SIGINT);
sigsuspend(&tempmask);
Now, in the above code, we have specified the sigsuspend function to listen for every signal except SIGINT.
When sigsuspend receives any other signal than SIGINT, it returns.
This was a small difference between sigsuspend and pause. We get to know the major difference between their ways of working, when we have a scenario, and we try to implement it by both.
Suppose my scenario is, I have a program with two critical regions. By critical regions, I mean to say that I don't want some signal to interrupt in between, while my critical section is executing. But, at the same time I want my second critical section to start, only if I get the confirmation, that some signal has been received.
This is a very natural scenario, and we may encounter this type of condition anytime in our programs. Suppose I have two processes, p1 and p2, p2 has two critical sections, and it wants to go ahead with its second critical section only if it receives, a signal from p1 or has already received a signal from p1, and at the same time it doesn't want the signal to disturb, during the execution of its critical sections.
Let's see, how we can implement this scenario using pause()
#include<stdio.h>
#include<signal.h>
static void rec(int signo)
{
printf("\ninterrupt received\n");
}
int main()
{
sigset_t mask1,mask2;
signal(SIGINT, rec);
sigemptyset(&mask1);
sigaddset(&mask1,SIGINT);
sigprocmask(SIG_BLOCK,&mask1,&mask2);
printf("\ncritical region 1\n");
sleep(5);
printf("\ncritical region 1 ends\n");
sigprocmask(SIG_SETMASK,&mask2,NULL);
pause();
sigprocmask(SIG_BLOCK,&mask1,&mask2);
printf("\ncritical region 2\n");
sleep(5);
printf("\ncritical region 2 ends\n");
sigprocmask(SIG_SETMASK,&mask2,NULL);
exit(0);
}
We are using only one process, and let's assume that SIGINT is the signal which should not be allowed to interrupt the process during execution of critical section. In the above program, we block SIGINT before starting of any critical section and unblock it when the criticel section is over.
The program also pauses for confirmation that SIGINT is received before proceeding towards second critical section.
We unblock the signal SIGINT once the critical section ends, in order to receive the SIGINT signal. The main problem with this program is that, there is a time window, between unblocking of signal and pause, in which the signal can be received. In this case, the process will go to an infinite pause.
To test this problem, send the SIGINT from the terminal before the critical section 1 ends, i.e. when the process is in sleep inside first critical section
sigprocmask(SIG_SETMASK,&mask2,NULL);
//window in which the signal could be received pause();
To solve this problem, we make use of sigsuspend. We will write another program implementing the same logic, but using sigsuspend.
#include<stdio.h>
#include<signal.h>
static void rec(int signo)
{
printf("\ninterrupt received\n");
}
int main()
{
sigset_t mask1,mask2;
signal(SIGINT, rec);
sigemptyset(&mask1);
sigaddset(&mask1,SIGINT);
sigprocmask(SIG_BLOCK,&mask1,&mask2);
printf("\ncritical region 1\n");
sleep(5);
printf("\ncritical region 1 ends\n");
sigsuspend(&mask2);
printf("\ncritical region 2\n");
sleep(5);
printf("\ncritical region 2 ends\n");
sigprocmask(SIG_SETMASK,&mask2,NULL);
exit(0);
}
The above program is not unblocking the SIGINT to receive it. Infact, it is using sigsuspend in place of it.
We are passing original process mask, which doesn't mask SIGINT, in sigsuspend function. sigsuspend pauses the process and can only return if any of the signal, which is not in mask2, is received and its signal handler is executed. So, sigsuspend will return upon receival of SIGINT . When sigsuspend returns it resets the sigmask for the process to the mask just before when sigsuspend executed. In this case the SIGINT will be blocked again before execution of second critical section starts.