Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use sigsuspend

Tags:

c

I have this code, and i have to make the program block repeatedly waiting for a signal. My teacher wants us to use the sigsuspend and masks instead of pause or sleep. I'm not familiar with the sigsuspend or mask, i know that sigsuspend() temporarily replaces the signal mask of the calling process with the mask given by mask and then suspends the process until delivery of a signal whose action is to invoke a signal handler or to terminate a process. But how do I implement it.

#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

unsigned Conta = 0;

void mypause(int sign)
{
    switch (sign)
    {
        case SIGINT:
            printf("You've pressed ctrl-C\n");
            printf("I'm running waiting for a signal...\n");
            Conta++;
            break;

        case SIGQUIT:
            printf("You've pressd ctrl-\\n");
            printf("Number of times you've pressed CTRL-C: %d", Conta); 
            exit(0);
            break;
    }
}

int main()
{
    alarm(3);
    printf("I'm Alive\n");

    signal(SIGINT, mypause);
    signal(SIGQUIT, mypause);
    printf("I'm running, waiting for a signal...\n");
    while (1)
    {
    }

    return (0);
}
like image 311
Luis Quesado Avatar asked Apr 16 '13 16:04

Luis Quesado


2 Answers

The simple way to get started is to just call sigsuspend with an empty mask (i.e., any signal can wake up the program):

sigset_t myset;
(void) sigemptyset(&myset);
while (1) {
    (void) printf("I'm running, waiting for a signal...\n");
    (void) sigsuspend(&myset);
}

The next step would be to use sigprocmask to disable your two handled signals (SIGINT and SIGQUIT) from occurring other than when you're waiting from them in sigsuspend. Then you would use the “old mask” obtained from sigprocmask instead of the empty mask when suspending.

like image 63
Arkku Avatar answered Oct 08 '22 18:10

Arkku


The GNU libc manual description seems clear and thorough:

Function: int sigsuspend (const sigset_t *set)

This function replaces the process's signal mask with set and then suspends the process until a signal is delivered whose action is either to terminate the process or invoke a signal handling function. In other words, the program is effectively suspended until one of the signals that is not a member of set arrives.

If the process is woken up by delivery of a signal that invokes a handler function, and the handler function returns, then sigsuspend also returns.

The mask remains set only as long as sigsuspend is waiting. The function sigsuspend always restores the previous signal mask when it returns.

The return value and error conditions are the same as for pause.

With sigsuspend, you can replace the pause or sleep loop in the previous section with something completely reliable:

 sigset_t mask, oldmask;

 ...

 /* Set up the mask of signals to temporarily block. */
 sigemptyset (&mask);
 sigaddset (&mask, SIGUSR1);

 ...

 /* Wait for a signal to arrive. */
 sigprocmask (SIG_BLOCK, &mask, &oldmask);
 while (!usr_interrupt)
   sigsuspend (&oldmask);
 sigprocmask (SIG_UNBLOCK, &mask, NULL);

This last piece of code is a little tricky. The key point to remember here is that when sigsuspend returns, it resets the process's signal mask to the original value, the value from before the call to sigsuspend—in this case, the SIGUSR1 signal is once again blocked. The second call to sigprocmask is necessary to explicitly unblock this signal.

One other point: you may be wondering why the while loop is necessary at all, since the program is apparently only waiting for one SIGUSR1 signal. The answer is that the mask passed to sigsuspend permits the process to be woken up by the delivery of other kinds of signals, as well—for example, job control signals. If the process is woken up by a signal that doesn't set usr_interrupt, it just suspends itself again until the “right” kind of signal eventually arrives.

This technique takes a few more lines of preparation, but that is needed just once for each kind of wait criterion you want to use. The code that actually waits is just four lines.

like image 9
Matt Phillips Avatar answered Oct 08 '22 19:10

Matt Phillips