Search code examples
cmultithreadingtimer

multiple timers delivering signal to separate threads


I am developing an application wherein I have created a timer using timer_create function which upon expiration delivers a signal to a thread. As of now I am able to implement delivering a timer signal to a particular thread. The problem that I am facing now is if there is an other timer, how to deliver the signal to another separate thread(basically 1st timer signal to thread A and second timer signal to thread B). This is what I have written so far

static void *
sig_threadproc(void *thrarg)
{
    sigset_t sigset;
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGALRM);

/* endless loop to wait for and handle a signal repeatedly */
for (;;) {
    int sig;
    int error;

    error = sigwait(&sigset, &sig);
    if (error == 0) {
        assert(sig == SIGALRM);
        printf("got SIGALRM\n");
    } else {
        perror("sigwait");
    }
}
return NULL;
}

static void
sig_alrm_handler(int signo)
{
    /**
     * dummy signal handler, 
     * the signal is actually handled in sig_threadproc() 
     **/
}


int
main(int argc, char *argv[])
{
    sigset_t sigset;
    struct sigaction sa;
    pthread_t sig_thread;
    struct itimerspec tspec;
    timer_t timer_id;

/* mask SIGALRM in all threads by default */
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);           
sigprocmask(SIG_BLOCK, &sigset, NULL);

/* we need a signal handler.
 * The default is to call abort() and 
 * setting SIG_IGN might cause the signal
 * to not be delivered at all.
 **/
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sig_alrm_handler;
sigaction(SIGALRM, &sa, NULL);

/* create SIGALRM looper thread */
pthread_create(&sig_thread, NULL, sig_threadproc, NULL);

/* setup timer */
tspec.it_interval.tv_sec = 1;
tspec.it_interval.tv_nsec = 0;
tspec.it_value.tv_sec = 1;
tspec.it_value.tv_nsec = 0;

timer_create(CLOCK_REALTIME, NULL, &timer_id);
timer_settime(timer_id, 0, &tspec, NULL);

/**
 * this might return early if usleep() is interrupted (by a signal)
 * It should not happen, since SIGALRM is blocked on the
 * main thread
 **/
usleep(10000000);

return 0;
    }

Solution

  • Do not use SIGALRM for real time timer, instead use SIGRTMIN. So you will create two timer, for the 1st one, set sigev_signo member of sevp argument to SIGRTMIN + 0, and set the the 2nd one's segev_signo to SIGRTMIN + 1. This means the when the 1st timer fires, your process will receive SIGRTMIN signal, when 2nd fires, you will receive SIGRTMIN + 1.

    Then call pthread_sigmask in the 2 threads of your program, mask signal SIGRTMIN in your thread B, and mask SIGRTMIN + 1 in your thread A.

    As a result, your thread A will only be notified when 1st timer fires, and thread B will get notification from 2nd timer.