diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2024-10-10 10:20:11 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2024-10-10 11:18:06 -0400 |
commit | 881d590d23730fff6bf8f37e10d998226180cd65 (patch) | |
tree | dd962f8c2f84d312c845781ddbceb35e23b9b207 /src | |
parent | 2889537ee68dacbdd9c8ea4e2053e03e86219c24 (diff) | |
download | bfs-881d590d23730fff6bf8f37e10d998226180cd65.tar.xz |
xtime: Add a wrapper for timer_create()/setitimer()
setitimer() is obsolescent in POSIX 2008 and removed from POSIX 2024.
However, at least macOS doesn't implement the new timer_create() API, so
we still need the setitimer() fallback.
Diffstat (limited to 'src')
-rw-r--r-- | src/xtime.c | 97 | ||||
-rw-r--r-- | src/xtime.h | 23 |
2 files changed, 120 insertions, 0 deletions
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 |