I want to start a timer and have a function called when it expires.
Googling finds lots of examples, including the example in the manual, all of which use sigaction()
to set a signal handler.
However, @Patryk says in this question that we can just
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);
which is shorter, simpler, cleaner, more maintainable ...
What gives? Is this correct? Is it just a wrapper for sigaction()
? Why do the examples explicitly set a signal handler?
Also, if I start a timer either by this method, or by timer_settime
and a signal handler, will cancelling the timer casue the system to remove the association between that timer and the callback, or do I have to do that explicitly?
[Update] You can choose either signals or the method I show in my answer below (or both, but that seems silly). It is a matter of taste. Singals might offer a little more functionality, at the cost of complification.
If all you want to do is start a timer and be notified when it expires, the method in my answer is simplest.
It seems that I do not have to use a signal handler and can make the code much simpler, as shown here:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
static unsigned int pass_value_by_pointer = 42;
void Timer_has_expired(union sigval timer_data)
{
printf("Timer expiration handler function; %d\n", *(int *) timer_data.sival_ptr);
}
int main(void)
{
struct sigevent timer_signal_event;
timer_t timer;
struct itimerspec timer_period;
printf("Create timer\n");
timer_signal_event.sigev_notify = SIGEV_THREAD;
timer_signal_event.sigev_notify_function = Timer_has_expired; // This function will be called when timer expires
// Note that the following is a union. Assign one or the other (preferably by pointer)
//timer_signal_event.sigev_value.sival_int = 38; // This argument will be passed to the function
timer_signal_event.sigev_value.sival_ptr = (void *) &pass_value_by_pointer; // as will this (both in a structure)
timer_signal_event.sigev_notify_attributes = NULL;
timer_create(CLOCK_MONOTONIC, &timer_signal_event, &timer);
printf("Start timer\n");
timer_period.it_value.tv_sec = 1; // 1 second timer
timer_period.it_value.tv_nsec = 0; // no nano-seconds
timer_period.it_interval.tv_sec = 0; // non-repeating timer
timer_period.it_interval.tv_nsec = 0;
timer_settime(timer, 0, &timer_period, NULL);
sleep(2);
printf("----------------------------\n");
printf("Start timer a second time\n");
timer_settime(timer, 0, &timer_period, NULL);
sleep(2);
printf("----------------------------\n");
printf("Start timer a third time\n");
timer_settime(timer, 0, &timer_period, NULL);
printf("Cancel timer\n");
timer_delete(timer);
sleep(2);
printf("The timer expiration handler function should not have been called\n");
return EXIT_SUCCESS;
}
when run, it gives this output:
Create timer
Start timer
Timer expiration handler function; 42
----------------------------
Start timer a second time
Timer expiration handler function; 42
----------------------------
Start timer a third time
Cancel timer
The timer expiration handler function should not have been called