The sigsuspend( ) system call puts the process in the task_interruptible state, after having blocked the standard signals specified by a bit mask array to which the mask parameter points. The process will wake up only when a nonignored, nonblocked signal is sent to it.
The corresponding sys_sigsuspend( ) service routine executes these statements:
mask &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));
spin lock irq(¤t->sigmask lock);
saveset = current->blocked;
spin unlock irq(¤t->sigmask lock);
current->state = TASK_INTERRUPTIBLE; schedule( );
if (do signal(regs, &saveset)) return -EINTR;
The schedule( ) function selects another process to run. When the process that issued the sigsuspend( ) system call is executed again, sys_sigsuspend( ) invokes the do_signal( ) function to deliver the signal that has woken up the process. If that function returns the value 1, the signal is not ignored. Therefore the system call terminates by returning the error code -EINTR.
The sigsuspend( ) system call may appear redundant, since the combined execution of sigprocmask( ) and sleep( ) apparently yields the same result. But this is not true: because of interleaving of process executions, one must be conscious that invoking a system call to perform action A followed by another system call to perform action B is not equivalent to invoking a single system call that performs action A and then action B.
In the particular case, sigprocmask( ) might unblock a signal that is delivered before invoking sleep( ). If this happens, the process might remain in a task_interruptible state forever, waiting for the signal that was already delivered. On the other hand, the sigsuspend( ) system call does not allow signals to be sent after unblocking and before the schedule( ) invocation because other processes cannot grab the CPU during that time interval.
Was this article helpful?