summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2024-10-10 10:20:11 -0400
committerTavian Barnes <tavianator@tavianator.com>2024-10-10 11:18:06 -0400
commit881d590d23730fff6bf8f37e10d998226180cd65 (patch)
treedd962f8c2f84d312c845781ddbceb35e23b9b207 /src
parent2889537ee68dacbdd9c8ea4e2053e03e86219c24 (diff)
downloadbfs-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.c97
-rw-r--r--src/xtime.h23
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