lib/timer: add fallback if timer_create() not available

* add struct ul_timer as API abstraction to hide differences between
timer_create() and setitimer()

* add setitimer() detection to ./configure.ac

* add fallback code to use setitimer() if timer_create() not available
  (for example on OSX)

Addresses: https://github.com/karelzak/util-linux/issues/584
Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2018-10-24 12:28:13 +02:00
parent 9a558f9cf6
commit 6df5acf970
5 changed files with 62 additions and 13 deletions

View File

@ -558,6 +558,10 @@ AC_CHECK_FUNCS([timer_create],
AC_SUBST([REALTIME_LIBS]) AC_SUBST([REALTIME_LIBS])
AS_IF([test x"$have_timer" = xno], [
AC_CHECK_FUNCS([setitimer], [have_timer="yes"], [have_timer="no"])
])
AC_CHECK_LIB([rtas], [rtas_get_sysparm], [ AC_CHECK_LIB([rtas], [rtas_get_sysparm], [
RTAS_LIBS="-lrtas" RTAS_LIBS="-lrtas"

View File

@ -4,8 +4,19 @@
#include <signal.h> #include <signal.h>
#include <sys/time.h> #include <sys/time.h>
extern int setup_timer(timer_t * t_id, struct itimerval *timeout, #ifdef HAVE_TIMER_CREATE
struct ul_timer {
timer_t t_id;
};
#else
struct ul_timer {
struct itimerval old_timer;
struct sigaction old_sa;
};
#endif
extern int setup_timer(struct ul_timer *timer, struct itimerval *timeout,
void (*timeout_handler)(int, siginfo_t *, void *)); void (*timeout_handler)(int, siginfo_t *, void *));
extern void cancel_timer(timer_t * t_id); extern void cancel_timer(struct ul_timer *timer);
#endif /* UTIL_LINUX_TIMER_H */ #endif /* UTIL_LINUX_TIMER_H */

View File

@ -27,7 +27,9 @@
* The applications need to ensure that they can tolerate multiple signal * The applications need to ensure that they can tolerate multiple signal
* deliveries. * deliveries.
*/ */
int setup_timer(timer_t * t_id, struct itimerval *timeout, #ifdef HAVE_TIMER_CREATE
int setup_timer(struct ul_timer *timer,
struct itimerval *timeout,
void (*timeout_handler)(int, siginfo_t *, void *)) void (*timeout_handler)(int, siginfo_t *, void *))
{ {
time_t sec = timeout->it_value.tv_sec; time_t sec = timeout->it_value.tv_sec;
@ -52,14 +54,42 @@ int setup_timer(timer_t * t_id, struct itimerval *timeout,
if (sigaction(SIGALRM, &sig_a, NULL)) if (sigaction(SIGALRM, &sig_a, NULL))
return 1; return 1;
if (timer_create(CLOCK_MONOTONIC, &sig_e, t_id)) if (timer_create(CLOCK_MONOTONIC, &sig_e, &timer->t_id))
return 1; return 1;
if (timer_settime(*t_id, 0, &val, NULL)) 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 1;
return 0; return 0;
} }
void cancel_timer(timer_t *t_id) void cancel_timer(struct ul_timer *timer)
{ {
timer_delete(*t_id); setitimer(ITIMER_REAL, &timer->old_timer, NULL);
sigaction(SIGALRM, &timer->old_sa, NULL);
} }
#endif /* !HAVE_TIMER_CREATE */

View File

@ -298,7 +298,9 @@ static void timeout_handler(int sig __attribute__((__unused__)),
siginfo_t * info, siginfo_t * info,
void *context __attribute__((__unused__))) void *context __attribute__((__unused__)))
{ {
#ifdef HAVE_TIMER_CREATE
if (info->si_code == SI_TIMER) if (info->si_code == SI_TIMER)
#endif
errx(EXIT_FAILURE, _("timed out")); errx(EXIT_FAILURE, _("timed out"));
} }
@ -327,18 +329,18 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
if (!uuidd_cxt->no_sock) /* no_sock implies no_fork and no_pid */ if (!uuidd_cxt->no_sock) /* no_sock implies no_fork and no_pid */
#endif #endif
{ {
static timer_t t_id; struct ul_timer timer;
struct itimerval timeout; struct itimerval timeout;
memset(&timeout, 0, sizeof timeout); memset(&timeout, 0, sizeof timeout);
timeout.it_value.tv_sec = 30; timeout.it_value.tv_sec = 30;
if (setup_timer(&t_id, &timeout, &timeout_handler)) if (setup_timer(&timer, &timeout, &timeout_handler))
err(EXIT_FAILURE, _("cannot set up timer")); err(EXIT_FAILURE, _("cannot set up timer"));
if (pidfile_path) if (pidfile_path)
fd_pidfile = create_pidfile(uuidd_cxt, pidfile_path); fd_pidfile = create_pidfile(uuidd_cxt, pidfile_path);
ret = call_daemon(socket_path, UUIDD_OP_GETPID, reply_buf, ret = call_daemon(socket_path, UUIDD_OP_GETPID, reply_buf,
sizeof(reply_buf), 0, NULL); sizeof(reply_buf), 0, NULL);
cancel_timer(&t_id); cancel_timer(&timer);
if (ret > 0) { if (ret > 0) {
if (!uuidd_cxt->quiet) if (!uuidd_cxt->quiet)
warnx(_("uuidd daemon is already running at pid %s"), warnx(_("uuidd daemon is already running at pid %s"),

View File

@ -81,7 +81,9 @@ static void timeout_handler(int sig __attribute__((__unused__)),
siginfo_t *info, siginfo_t *info,
void *context __attribute__((__unused__))) void *context __attribute__((__unused__)))
{ {
#ifdef HAVE_TIMER_CREATE
if (info->si_code == SI_TIMER) if (info->si_code == SI_TIMER)
#endif
timeout_expired = 1; timeout_expired = 1;
} }
@ -124,7 +126,7 @@ static void __attribute__((__noreturn__)) run_program(char **cmd_argv)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
static timer_t t_id; struct ul_timer timer;
struct itimerval timeout; struct itimerval timeout;
int have_timeout = 0; int have_timeout = 0;
int type = LOCK_EX; int type = LOCK_EX;
@ -268,7 +270,7 @@ int main(int argc, char *argv[])
have_timeout = 0; have_timeout = 0;
block = LOCK_NB; block = LOCK_NB;
} else } else
if (setup_timer(&t_id, &timeout, &timeout_handler)) if (setup_timer(&timer, &timeout, &timeout_handler))
err(EX_OSERR, _("cannot set up timer")); err(EX_OSERR, _("cannot set up timer"));
} }
@ -321,7 +323,7 @@ int main(int argc, char *argv[])
} }
if (have_timeout) if (have_timeout)
cancel_timer(&t_id); cancel_timer(&timer);
if (verbose) { if (verbose) {
struct timeval delta; struct timeval delta;