Signal Handler to stop Timer in C
Solution 1
Just set it_interval
to zero, and you'll get a one-shot timer. You don't need to do anything with it in your handler.
For instance, with this:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#define INTERVAL 2 // number of seconds to go off
void TimerStop(int signum) {
printf("Timer ran out! Stopping timer\n");
}
void TimerSet(int interval) {
printf("starting timer\n");
struct itimerval it_val;
it_val.it_value.tv_sec = interval;
it_val.it_value.tv_usec = 0;
it_val.it_interval.tv_sec = 0;
it_val.it_interval.tv_usec = 0;
if (signal(SIGALRM, TimerStop) == SIG_ERR) {
perror("Unable to catch SIGALRM");
exit(1);
}
if (setitimer(ITIMER_REAL, &it_val, NULL) == -1) {
perror("error calling setitimer()");
exit(1);
}
}
int main(int argc, char *argv[]) {
TimerSet(INTERVAL);
while (1) {
// do stuff
}
return 0;
}
the message "Timer ran out! Stopping timer"
will appear only once, and your timer will stop without you doing anything.
Note that you need to fill in the tv_usec
members of your struct itimerval
, which your current code does not do. If you don't, it_interval
is highly unlikely to be zero, and your timer will never stop.
printf()
, along with the other standard IO functions, is not really safe to call from a signal handler, although in this particular case it won't cause you any problems, since the main code is just sitting in a loop and not doing anything.
Also, presume you're calling signal()
on purpose - sigaction()
is the recommended way for setting handlers. setitimer()
is also obsolete, now, and timer_settime()
is recommended.
Solution 2
According to manual:
Timers decrement from it_value to zero, generate a signal, and reset to
it_interval. A timer which is set to zero (it_value is zero or the timer
expires and it_interval is zero) stops.
Both tv_sec and tv_usec are significant in determining the duration of a
timer.
So timer can be set to run only once if interval is set to zero before setitimer() call (thanks to Duck's comment).
Olivier
Updated on August 21, 2022Comments
-
Olivier over 1 year
I am trying to have a signal handler stop a timer without exiting my program. How should I go about. I want StopTimer to handle the signal to stop the timer
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <sys/time.h> #include <signal.h> #include <unistd.h> #define INTERVAL 2 // number of seconds to go off int main(int argc, char* argv[]) { TimerSet(INTERVAL); while(1) { // do stuff } return 0; } void TimerSet(int interval) { printf("starting timer\n"); struct itimerval it_val; // interval value it_val.it_value.tv_sec = interval; it_val.it_interval = it_val.it_value; // on SIGALRM, close window if (signal(SIGALRM, TimerStop) == SIG_ERR) { perror("Unable to catch SIGALRM"); exit(1); } // set interval timer, returns SIGALRM on expiration if (setitimer(ITIMER_REAL, &it_val, NULL) == -1) { perror("error calling setitimer()"); exit(1); } } void TimerStop(int signum) { printf("Timer ran out! Stopping timer\n"); exit(signum); }
I tried to set the setitimer interval to 0, but I am not sure how to use the same timer within the TimerStop signal handler function
-
Olivier over 10 yearsI am getting this error: error calling setitimer(): Invalid argument. When trying to stop the timer. ALso when I set the interval to 0, it does not stop the timer
-
Duck over 10 years
setitimer
isn't safe to call from w/i a signal handler. I think OP just wants to shut down the timer. All he needs to do is zero out the interval values when he creates the timer. -
Michael over 10 years@Olihoops I fixed my answer. As mentioned in man (and as Duck recommends) - it also possible to set interval to zero before starting timer.
-
Olivier over 10 yearsI want to have my timer run again at some time later in the program. I tried making the interval global and have a function change the interval so that my timer starts again. However, the timer only runs once now.
-
Olivier over 10 yearsI want to have my timer run later at some point in my program. I made it_val global, and have a function that changes the interval. However, the timer stops forever. How can I make the timer go ON and OFF when I want it to? setitimer can only be run once.
-
Crowman over 10 yearsWhat makes you think
setitimer()
can only be run once? You make it go off by callingsetitimer()
with everything zero, and make it go on by calling it with something else. -
Olivier over 10 yearsYou are correct, I must have done something wrong earlier. THis works. Thank you