diff options
-rw-r--r-- | build/has/timer-create.c | 9 | ||||
-rw-r--r-- | build/header.mk | 1 | ||||
-rw-r--r-- | src/xtime.c | 97 | ||||
-rw-r--r-- | src/xtime.h | 23 |
4 files changed, 130 insertions, 0 deletions
diff --git a/build/has/timer-create.c b/build/has/timer-create.c new file mode 100644 index 0000000..d5354c3 --- /dev/null +++ b/build/has/timer-create.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes <tavianator@tavianator.com> +// SPDX-License-Identifier: 0BSD + +#include <time.h> + +int main(void) { + timer_t timer; + return timer_create(CLOCK_REALTIME, NULL, &timer); +} diff --git a/build/header.mk b/build/header.mk index abec00f..88a8986 100644 --- a/build/header.mk +++ b/build/header.mk @@ -52,6 +52,7 @@ HEADERS := \ gen/has/strtofflags.h \ gen/has/tcgetwinsize.h \ gen/has/timegm.h \ + gen/has/timer-create.h \ gen/has/tm-gmtoff.h \ gen/has/uselocale.h diff --git a/src/xtime.c b/src/xtime.c index dd9b60f..49d7c36 100644 --- a/src/xtime.c +++ b/src/xtime.c @@ -3,9 +3,11 @@ #include "xtime.h" +#include "alloc.h" #include "bfs.h" #include "bfstd.h" #include "diag.h" +#include "sanity.h" #include <errno.h> #include <limits.h> @@ -351,3 +353,98 @@ invalid: error: return -1; } + +#if defined(_POSIX_TIMERS) && BFS_HAS_TIMER_CREATE +# define BFS_POSIX_TIMERS _POSIX_TIMERS +#else +# define BFS_POSIX_TIMERS (-1) +#endif + +struct timer { +#if BFS_POSIX_TIMERS >= 0 + /** The POSIX timer. */ + timer_t timer; +#endif + /** Whether to use timer_create() or setitimer(). */ + bool legacy; +}; + +struct timer *xtimer_start(const struct timespec *interval) { + struct timer *timer = ALLOC(struct timer); + if (!timer) { + return NULL; + } + +#if BFS_POSIX_TIMERS >= 0 + if (sysoption(TIMERS)) { + clockid_t clock = CLOCK_REALTIME; + +#if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 + if (sysoption(MONOTONIC_CLOCK) > 0) { + clock = CLOCK_MONOTONIC; + } +#endif + + if (timer_create(clock, NULL, &timer->timer) != 0) { + goto fail; + } + + // https://github.com/llvm/llvm-project/issues/111847 + sanitize_init(&timer->timer); + + struct itimerspec spec = { + .it_value = *interval, + .it_interval = *interval, + }; + if (timer_settime(timer->timer, 0, &spec, NULL) != 0) { + timer_delete(timer->timer); + goto fail; + } + + timer->legacy = false; + return timer; + } +#endif + +#if BFS_POSIX_TIMERS <= 0 + struct timeval tv = { + .tv_sec = interval->tv_sec, + .tv_usec = (interval->tv_nsec + 999) / 1000, + }; + struct itimerval ival = { + .it_value = tv, + .it_interval = tv, + }; + if (setitimer(ITIMER_REAL, &ival, NULL) != 0) { + goto fail; + } + + timer->legacy = true; + return timer; +#endif + +fail: + free(timer); + return NULL; +} + +void xtimer_stop(struct timer *timer) { + if (!timer) { + return; + } + + if (timer->legacy) { +#if BFS_POSIX_TIMERS <= 0 + struct itimerval ival = {0}; + int ret = setitimer(ITIMER_REAL, &ival, NULL); + bfs_everify(ret == 0, "setitimer()"); +#endif + } else { +#if BFS_POSIX_TIMERS >= 0 + int ret = timer_delete(timer->timer); + bfs_everify(ret == 0, "timer_delete()"); +#endif + } + + free(timer); +} diff --git a/src/xtime.h b/src/xtime.h index 11f2bf9..2927a2e 100644 --- a/src/xtime.h +++ b/src/xtime.h @@ -46,4 +46,27 @@ int xtimegm(struct tm *tm, time_t *timep); */ int xgetdate(const char *str, struct timespec *result); +/** + * A timer. + */ +struct timer; + +/** + * Start a timer. + * + * @interval + * The regular interval at which to send SIGALRM. + * @return + * The new timer on success, otherwise NULL. + */ +struct timer *xtimer_start(const struct timespec *interval); + +/** + * Stop a timer. + * + * @timer + * The timer to stop. + */ +void xtimer_stop(struct timer *timer); + #endif // BFS_XTIME_H |