]>
Commit | Line | Data |
---|---|---|
26e8964b KZ |
1 | /* |
2 | * Please, don't add this file to libcommon because timers requires | |
3 | * -lrt on systems with old libc (and probably also -lpthread for static | |
4 | * build). | |
5 | */ | |
6 | #include <time.h> | |
7 | #include <signal.h> | |
26e8964b KZ |
8 | #include <sys/time.h> |
9 | ||
10 | #include "c.h" | |
11 | #include "timer.h" | |
12 | ||
dc9a23fe KZ |
13 | /* |
14 | * Note the timeout is used for the first signal, then the signal is send | |
15 | * repeatedly in interval ~1% of the original timeout to avoid race in signal | |
16 | * handling -- for example you want to use timer to define timeout for a | |
17 | * syscall: | |
18 | * | |
19 | * setup_timer() | |
20 | * syscall() | |
21 | * cancel_timer() | |
22 | * | |
23 | * if the timeout is too short than it's possible that the signal is delivered | |
24 | * before application enter the syscall function. For this reason timer send | |
25 | * the signal repeatedly. | |
26 | * | |
27 | * The applications need to ensure that they can tolerate multiple signal | |
28 | * deliveries. | |
29 | */ | |
6df5acf9 KZ |
30 | #ifdef HAVE_TIMER_CREATE |
31 | int setup_timer(struct ul_timer *timer, | |
32 | struct itimerval *timeout, | |
26e8964b KZ |
33 | void (*timeout_handler)(int, siginfo_t *, void *)) |
34 | { | |
e2cd1072 RV |
35 | time_t sec = timeout->it_value.tv_sec; |
36 | long usec = timeout->it_value.tv_usec; | |
26e8964b KZ |
37 | struct sigaction sig_a; |
38 | static struct sigevent sig_e = { | |
39 | .sigev_notify = SIGEV_SIGNAL, | |
40 | .sigev_signo = SIGALRM | |
41 | }; | |
42 | struct itimerspec val = { | |
e2cd1072 RV |
43 | .it_value.tv_sec = sec, |
44 | .it_value.tv_nsec = usec * 1000, | |
45 | .it_interval.tv_sec = sec / 100, | |
46 | .it_interval.tv_nsec = (sec ? sec % 100 : 1) * 10*1000*1000 | |
26e8964b KZ |
47 | }; |
48 | ||
49 | if (sigemptyset(&sig_a.sa_mask)) | |
50 | return 1; | |
51 | ||
52 | sig_a.sa_flags = SA_SIGINFO; | |
53 | sig_a.sa_sigaction = timeout_handler; | |
54 | ||
87918040 | 55 | if (sigaction(SIGALRM, &sig_a, NULL)) |
26e8964b | 56 | return 1; |
6df5acf9 | 57 | if (timer_create(CLOCK_MONOTONIC, &sig_e, &timer->t_id)) |
26e8964b | 58 | return 1; |
6df5acf9 | 59 | if (timer_settime(timer->t_id, 0, &val, NULL)) |
26e8964b KZ |
60 | return 1; |
61 | return 0; | |
62 | } | |
6df5acf9 KZ |
63 | void cancel_timer(struct ul_timer *timer) |
64 | { | |
65 | timer_delete(timer->t_id); | |
66 | } | |
67 | ||
68 | #else /* !HAVE_TIMER_CREATE */ | |
69 | ||
70 | int setup_timer(struct ul_timer *timer, | |
71 | struct itimerval *timeout, | |
72 | void (*timeout_handler)(int, siginfo_t *, void *)) | |
73 | { | |
74 | struct sigaction sa; | |
75 | ||
76 | memset(&sa, 0, sizeof sa); | |
77 | memset(timer, 0, sizeof(*timer)); | |
26e8964b | 78 | |
6df5acf9 KZ |
79 | sa.sa_flags = SA_SIGINFO | SA_RESETHAND; |
80 | sa.sa_sigaction = timeout_handler; | |
81 | ||
82 | if (sigaction(SIGALRM, &sa, &timer->old_sa)) | |
83 | return 1; | |
84 | if (setitimer(ITIMER_REAL, timeout, &timer->old_timer) != 0) | |
85 | return 1; | |
86 | return 0; | |
87 | } | |
88 | ||
89 | void cancel_timer(struct ul_timer *timer) | |
26e8964b | 90 | { |
6df5acf9 KZ |
91 | setitimer(ITIMER_REAL, &timer->old_timer, NULL); |
92 | sigaction(SIGALRM, &timer->old_sa, NULL); | |
93 | ||
26e8964b | 94 | } |
6df5acf9 | 95 | #endif /* !HAVE_TIMER_CREATE */ |