/* * Please, don't add this file to libcommon because timers requires * -lrt on systems with old libc (and probably also -lpthread for static * build). */ #include #include #include #include "c.h" #include "timer.h" /* * Note the timeout is used for the first signal, then the signal is send * repeatedly in interval ~1% of the original timeout to avoid race in signal * handling -- for example you want to use timer to define timeout for a * syscall: * * setup_timer() * syscall() * cancel_timer() * * if the timeout is too short than it's possible that the signal is delivered * before application enter the syscall function. For this reason timer send * the signal repeatedly. * * The applications need to ensure that they can tolerate multiple signal * deliveries. */ #ifdef HAVE_TIMER_CREATE int setup_timer(struct ul_timer *timer, struct itimerval *timeout, void (*timeout_handler)(int, siginfo_t *, void *)) { time_t sec = timeout->it_value.tv_sec; long usec = timeout->it_value.tv_usec; struct sigaction sig_a; static struct sigevent sig_e = { .sigev_notify = SIGEV_SIGNAL, .sigev_signo = SIGALRM }; struct itimerspec val = { .it_value.tv_sec = sec, .it_value.tv_nsec = usec * 1000, .it_interval.tv_sec = sec / 100, .it_interval.tv_nsec = (sec ? sec % 100 : 1) * 10*1000*1000 }; if (sigemptyset(&sig_a.sa_mask)) return 1; sig_a.sa_flags = SA_SIGINFO; sig_a.sa_sigaction = timeout_handler; if (sigaction(SIGALRM, &sig_a, NULL)) return 1; if (timer_create(CLOCK_MONOTONIC, &sig_e, &timer->t_id)) return 1; if (timer_settime(timer->t_id, 0, &val, NULL)) return 1; return 0; } void cancel_timer(struct ul_timer *timer) { timer_delete(timer->t_id); } #else /* !HAVE_TIMER_CREATE */ int setup_timer(struct ul_timer *timer, struct itimerval *timeout, void (*timeout_handler)(int, siginfo_t *, void *)) { struct sigaction sa; memset(&sa, 0, sizeof sa); memset(timer, 0, sizeof(*timer)); sa.sa_flags = SA_SIGINFO | SA_RESETHAND; sa.sa_sigaction = timeout_handler; if (sigaction(SIGALRM, &sa, &timer->old_sa)) return 1; if (setitimer(ITIMER_REAL, timeout, &timer->old_timer) != 0) return 1; return 0; } void cancel_timer(struct ul_timer *timer) { setitimer(ITIMER_REAL, &timer->old_timer, NULL); sigaction(SIGALRM, &timer->old_sa, NULL); } #endif /* !HAVE_TIMER_CREATE */