Problem in Timers and signal

17,369

Solution 1

Will this work for you? (Modified the code from example in timer_create man page.)

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>

#define CLOCKID CLOCK_REALTIME
#define SIG SIGUSR1
timer_t timerid;


static void handler(int sig, siginfo_t *si, void *uc)
{
    if(si->si_value.sival_ptr != &timerid){
        printf("Stray signal\n");
    } else {
        printf("Caught signal %d from timer\n", sig);
    }
}

int main(int argc, char *argv[])
{
    struct sigevent sev;
    struct itimerspec its;
    long long freq_nanosecs;
    sigset_t mask;
    struct sigaction sa;

    printf("Establishing handler for signal %d\n", SIG);
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    sigaction(SIG, &sa, NULL);

    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIG;
    sev.sigev_value.sival_ptr = &timerid;
    timer_create(CLOCKID, &sev, &timerid);
    /* Start the timer */

    its.it_value.tv_sec = 10;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = its.it_value.tv_sec;
    its.it_interval.tv_nsec = its.it_value.tv_nsec;

    timer_settime(timerid, 0, &its, NULL);
    sleep(100);
    exit(EXIT_SUCCESS);
}

When signal from timer is caught Caught signal 10 from timer will be displayed. Otherwise Stray signal will be displayed.

Solution 2

The question is whether you really need to use signals. You may think of using callback that will be called when the timer expires:

void cbf(union sigval);
struct sigevent sev;
timer_t timer;

sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = cbf; //this function will be called when timer expires
sev.sigev_value.sival_ptr = (void*) arg;//this argument will be passed to cbf
timer_create(CLOCK_MONOTONIC, &sev, &timer);

The callback function will be called in a new thread.

Solution 3

No, there is no easy way. Why don't you use SIGUSR2 instead for your timers if you have something else generating SIGUSR1 together with your timer. If that is not enough, use one of the real time signals for your application.

If it must be able to handle the same signal from the timer and some other source, then depending on how fast, how many, what system, etc etc you could try setting a timestamp before registering a timer on when the timer will approximately exit, and then in the signal handler try to deduce if it was within time margin. I would strongly advise not to use this approach, but instead redesign what you are doing.

Solution 4

Use another RT signals. See answers on Is there any way to create a user defined signal in Linux?

Share:
17,369
RajSanpui
Author by

RajSanpui

Around 9+ years experience into development C, C++, and Linux domain. Also understand Core-Java and consider it as a secondary skill. Currently, in addition to the developer responsibilities, i am also serving the role of DevOps engineer.

Updated on June 07, 2022

Comments

  • RajSanpui
    RajSanpui about 2 years

    I have implemented a POSIX timer using timer_create( ) API, and this will generate SIGUSR1 when the timer expires for which i have put a handler code. Now the problem is, if this program receives another SIGUSR1, then the same signal handler will be invoked and caught.

    Is there any way to prevent this, so that the handler can catch signals only generated by the timer?

  • RajSanpui
    RajSanpui about 13 years
    No, we can't use SIGEV_THREAD, because our library does not support that. Also, SIGEV_THREAD creates useless threads which in turn cause memory leaks.
  • RajSanpui
    RajSanpui about 13 years
    One of the real-time signals? Can you please elaborate? What if the test code also generates a real time signal? Won't the same handler catch it?
  • Milan
    Milan about 13 years
    Yes, the handler will catch the signal. The point with real time signals is that they should be used within your own application where you know what happens. Scroll down to real time signals on the man page and read more linux.die.net/man/7/signal
  • RajSanpui
    RajSanpui about 13 years
    Extremely sorry, i saw your post late. You have given an excellent solution. Bravo!!!! And also loads and loads of thanks :)
  • Viet
    Viet about 12 years
    +1 Great thanks! It turned out that timer ins UNIX is simple, just a bit confusing
  • mihirj
    mihirj over 10 years
    what if i have to use multiple timers using this API? I tried but after executing handler once, the program exits. is there any way?
  • Mawg says reinstate Monica
    Mawg says reinstate Monica almost 8 years
    Sure, you just change struct sigaction sa; to make it an array (and you rename all of those variables to meaningful, maintainable, names ;-)
  • Mawg says reinstate Monica
    Mawg says reinstate Monica almost 8 years
    In what way do threads created by system calls cause memeory leaks? Have you reported this?
  • Mawg says reinstate Monica
    Mawg says reinstate Monica almost 8 years
    While I do like this (+1), as it is much clearer than the solution using signals, I have to ask - if you cancel the timer before expiry, will the callback association also be cancelled?