From d3a3217e88dee3b16e13f95abd3e885436c27517 Mon Sep 17 00:00:00 2001 From: Vftdan Date: Wed, 14 Aug 2024 13:47:55 +0200 Subject: [PATCH] Add newtypes for absolute and relative time --- events.c | 13 ++---- events.h | 4 +- main.c | 2 +- nodes/getchar.c | 2 +- nodes/print.c | 2 +- processing.c | 97 +++++++++++++--------------------------- processing.h | 10 ++--- time.h | 116 ++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 160 insertions(+), 86 deletions(-) create mode 100644 time.h diff --git a/events.c b/events.c index 5190349..27572cb 100644 --- a/events.c +++ b/events.c @@ -37,20 +37,15 @@ event_create(const EventData * content) event->data = *content; event->data.modifiers = modifier_set_copy(content->modifiers); } else { - clock_gettime(CLOCK_MONOTONIC, &event->data.time); + event->data.time = get_current_time(); } - struct timespec self_time = event->data.time; + AbsoluteTime self_time = event->data.time; EventNode ** list_pos = &LAST_EVENT; FOREACH_EVENT_DESC(other) { - struct timespec other_time = other->data.time; - if (self_time.tv_sec > other_time.tv_sec) { + AbsoluteTime other_time = other->data.time; + if (absolute_time_cmp(self_time, other_time) >= 0) { break; } - if (self_time.tv_sec == other_time.tv_sec) { - if (self_time.tv_nsec >= other_time.tv_nsec) { - break; - } - } list_pos = &other->next->prev; } EventNode * prev = *list_pos; diff --git a/events.h b/events.h index 5e847d6..3e2217a 100644 --- a/events.h +++ b/events.h @@ -1,9 +1,9 @@ #ifndef EVENTS_H_ #define EVENTS_H_ -#include #include "defs.h" #include "modifiers.h" +#include "time.h" typedef uint32_t EventNamespace; @@ -18,7 +18,7 @@ typedef struct { int32_t priority; int64_t payload; ModifierSet modifiers; - struct timespec time; + AbsoluteTime time; } EventData; typedef struct event_position_base EventPositionBase; diff --git a/main.c b/main.c index 2832591..a7d0002 100644 --- a/main.c +++ b/main.c @@ -10,8 +10,8 @@ main(int argc, char ** argv) ProcessingState state = (ProcessingState) { .wait_delay = NULL, + .reached_time = get_current_time(), }; - clock_gettime(CLOCK_MONOTONIC, &state.reached_time); io_subscription_list_init(&state.wait_input, 5); io_subscription_list_init(&state.wait_output, 5); diff --git a/nodes/getchar.c b/nodes/getchar.c index f738d11..90e5d85 100644 --- a/nodes/getchar.c +++ b/nodes/getchar.c @@ -28,8 +28,8 @@ handle_io(EventPositionBase * self, int fd, bool is_output) .priority = 10, .payload = buf[0], .modifiers = EMPTY_MODIFIER_SET, + .time = get_current_time(), }; - clock_gettime(CLOCK_MONOTONIC, &data.time); if (status == 0) { node->subscription.enabled = false; data.code.value = 2; diff --git a/nodes/print.c b/nodes/print.c index 88cb9ac..9bd2632 100644 --- a/nodes/print.c +++ b/nodes/print.c @@ -18,7 +18,7 @@ handle_event(EventPositionBase * self, EventNode * event) printf("%02x", data.modifiers.bits[i]); } printf("\n"); - printf("time = %ld.%09ld\n", data.time.tv_sec, data.time.tv_nsec); + printf("time.absolute = %ld.%09ld\n", data.time.absolute.tv_sec, data.time.absolute.tv_nsec); printf("---\n\n"); event_destroy(event); return true; diff --git a/processing.c b/processing.c index 734195e..1138250 100644 --- a/processing.c +++ b/processing.c @@ -117,7 +117,7 @@ run_io_handlers(fd_set * fds, IOSubscriptionList * subs, bool arg) } bool -process_io(ProcessingState * state, const struct timespec * timeout) +process_io(ProcessingState * state, const RelativeTime * timeout) { int max_fd = 0; fd_set readfds, writefds; @@ -126,7 +126,7 @@ process_io(ProcessingState * state, const struct timespec * timeout) max_fd = populate_fd_set(&writefds, &state->wait_output, max_fd); ++max_fd; - int ready = pselect(max_fd, &readfds, &writefds, NULL, timeout, NULL); + int ready = pselect(max_fd, &readfds, &writefds, NULL, &timeout->relative, NULL); if (ready < 0) { FD_ZERO(&readfds); @@ -143,19 +143,14 @@ process_io(ProcessingState * state, const struct timespec * timeout) } bool -schedule_delay(ProcessingState * state, EventPositionBase * target, void (*callback) (EventPositionBase*, void*, const struct timespec*), const struct timespec * time) +schedule_delay(ProcessingState * state, EventPositionBase * target, void (*callback) (EventPositionBase*, void*, const AbsoluteTime*), const AbsoluteTime * time) { DelayList **next = &state->wait_delay; while (*next) { - struct timespec next_time = (*next)->time; - if (next_time.tv_sec > time->tv_sec) { + AbsoluteTime next_time = (*next)->time; + if (absolute_time_cmp(next_time, *time) > 0) { break; } - if (next_time.tv_sec == time->tv_sec) { - if (next_time.tv_nsec > time->tv_nsec) { - break; - } - } next = &((*next)->next); } @@ -174,33 +169,22 @@ schedule_delay(ProcessingState * state, EventPositionBase * target, void (*callb return true; } -static const struct timespec ZERO_TS = { - .tv_sec = 0, - .tv_nsec = 0, +static const RelativeTime ZERO_TO = { + .relative ={ + .tv_sec = 0, + .tv_nsec = 0, + } }; -inline static void -fix_nsec(struct timespec * ts) -{ - if (ts->tv_nsec < 0) { - ts->tv_nsec += 1000000000; - ts->tv_sec -= 1; - } -} - static bool -process_single_scheduled(ProcessingState * state, const struct timespec extern_time) +process_single_scheduled(ProcessingState * state, const AbsoluteTime extern_time) { if (!state->wait_delay) { return false; } - struct timespec next_scheduled_time = state->wait_delay->time; // abs - if (next_scheduled_time.tv_sec > extern_time.tv_sec) { + AbsoluteTime next_scheduled_time = state->wait_delay->time; + if (absolute_time_cmp(next_scheduled_time, extern_time) > 0) { return false; - } else if (next_scheduled_time.tv_sec == extern_time.tv_sec) { - if (next_scheduled_time.tv_nsec > extern_time.tv_nsec) { - return false; - } } DelayList next_scheduled = *state->wait_delay; free(state->wait_delay); @@ -217,7 +201,7 @@ process_single_scheduled(ProcessingState * state, const struct timespec extern_t } static bool -process_events_until(ProcessingState * state, const struct timespec * max_time) +process_events_until(ProcessingState * state, const AbsoluteTime * max_time) { bool stable = true; int32_t next_priority = INT32_MIN; @@ -225,17 +209,11 @@ process_events_until(ProcessingState * state, const struct timespec * max_time) FOREACH_EVENT(ev) { if (max_time) { - struct timespec ev_time = ev->data.time; - if (ev_time.tv_sec > max_time->tv_sec) { + AbsoluteTime ev_time = ev->data.time; + if (absolute_time_cmp(ev_time, *max_time) > 0) { // stable = false; state->has_future_events = true; break; - } else if (ev_time.tv_sec == max_time->tv_sec) { - if (ev_time.tv_nsec > max_time->tv_nsec) { - // stable = false; - state->has_future_events = true; - break; - } } } @@ -270,15 +248,10 @@ process_events_until(ProcessingState * state, const struct timespec * max_time) } if (max_time) { - struct timespec ev_time = ev->data.time; - if (ev_time.tv_sec > max_time->tv_sec) { + AbsoluteTime ev_time = ev->data.time; + if (absolute_time_cmp(ev_time, *max_time) > 0) { state->has_future_events = true; break; - } else if (ev_time.tv_sec == max_time->tv_sec) { - if (ev_time.tv_nsec > max_time->tv_nsec) { - state->has_future_events = true; - break; - } } } @@ -304,28 +277,21 @@ process_events_until(ProcessingState * state, const struct timespec * max_time) void process_iteration(ProcessingState * state) { - struct timespec extern_time; - if (clock_gettime(CLOCK_MONOTONIC, &extern_time) < 0) { - perror("Failed to get time"); - exit(1); - } + AbsoluteTime extern_time = get_current_time(); // late_by.tv_sec = extern_time.tv_sec - state->reached_time.tv_sec; // late_by.tv_nsec = extern_time.tv_nsec - state->reached_time.tv_nsec; // fix_nsec(&late_by); - struct timespec next_scheduled_delay; - const struct timespec *max_io_timeout = NULL; + RelativeTime next_scheduled_delay; + const RelativeTime *max_io_timeout = NULL; if (state->has_future_events) { - max_io_timeout = &ZERO_TS; + max_io_timeout = &ZERO_TO; } else { if (state->wait_delay) { - next_scheduled_delay = state->wait_delay->time; // abs - next_scheduled_delay.tv_sec -= extern_time.tv_sec; - next_scheduled_delay.tv_nsec -= extern_time.tv_nsec; - fix_nsec(&next_scheduled_delay); - if (next_scheduled_delay.tv_sec < 0) { - max_io_timeout = &ZERO_TS; + next_scheduled_delay = absolute_time_sub_absolute(state->wait_delay->time, extern_time); + if (relative_time_cmp(next_scheduled_delay, ZERO_TO) < 0) { + max_io_timeout = &ZERO_TO; } else { max_io_timeout = &next_scheduled_delay; } @@ -334,19 +300,16 @@ process_iteration(ProcessingState * state) // FIXME reason about timeouts process_io(state, max_io_timeout); - // process_io(state, &ZERO_TS); + // process_io(state, &ZERO_TO); while (true) { bool had_scheduled = process_single_scheduled(state, extern_time); - const struct timespec *max_event_time = &extern_time; + const AbsoluteTime *max_event_time = &extern_time; if (state->wait_delay) { - struct timespec next_scheduled_time = state->wait_delay->time; + AbsoluteTime next_scheduled_time = state->wait_delay->time; bool use_scheduled = false; if (!use_scheduled) { - use_scheduled = next_scheduled_time.tv_sec > extern_time.tv_sec; - } - if (!use_scheduled) { - use_scheduled = next_scheduled_time.tv_nsec > extern_time.tv_nsec; + use_scheduled = absolute_time_cmp(next_scheduled_time, extern_time) > 0; } if (use_scheduled) { max_event_time = &state->wait_delay->time; @@ -356,6 +319,6 @@ process_iteration(ProcessingState * state) if (!had_scheduled && !had_events) { break; } - process_io(state, &ZERO_TS); + process_io(state, &ZERO_TO); } } diff --git a/processing.h b/processing.h index 8452dc8..9debce9 100644 --- a/processing.h +++ b/processing.h @@ -23,17 +23,17 @@ typedef struct { typedef struct delay_list DelayList; struct delay_list { - void (*callback) (EventPositionBase * target, void * closure, const struct timespec * time); + void (*callback) (EventPositionBase * target, void * closure, const AbsoluteTime * time); EventPositionBase *target; void *closure; DelayList *next; - struct timespec time; + AbsoluteTime time; }; typedef struct { IOSubscriptionList wait_input, wait_output; DelayList *wait_delay; - struct timespec reached_time; + AbsoluteTime reached_time; int32_t pass_priority; bool has_future_events; } ProcessingState; @@ -42,8 +42,8 @@ void io_subscription_list_init(IOSubscriptionList * lst, size_t capacity); void io_subscription_list_deinit(IOSubscriptionList * lst); void io_subscription_list_add(IOSubscriptionList * lst, int fd, IOHandling *subscriber); -bool schedule_delay(ProcessingState * state, EventPositionBase * target, void (*callback) (EventPositionBase*, void*, const struct timespec*), const struct timespec * time); -bool process_io(ProcessingState * state, const struct timespec * timeout); +bool schedule_delay(ProcessingState * state, EventPositionBase * target, void (*callback) (EventPositionBase*, void*, const AbsoluteTime*), const AbsoluteTime * time); +bool process_io(ProcessingState * state, const RelativeTime * timeout); void process_iteration(ProcessingState * state); #endif /* end of include guard: PROCESSING_H_ */ diff --git a/time.h b/time.h new file mode 100644 index 0000000..ef627ab --- /dev/null +++ b/time.h @@ -0,0 +1,116 @@ +#ifndef TIME_H_ +#define TIME_H_ + +#include +#define NANOSECONDS_IN_SECOND 1000000000 + +typedef struct { + struct timespec absolute; +} AbsoluteTime; + +typedef struct { + struct timespec relative; +} RelativeTime; + +__attribute__((unused)) inline static void +timespec_add(struct timespec *accum, const struct timespec *item) +{ + accum->tv_sec += item->tv_sec; + accum->tv_nsec += item->tv_nsec; + while (accum->tv_nsec >= NANOSECONDS_IN_SECOND) { + ++(accum->tv_sec); + accum->tv_nsec -= NANOSECONDS_IN_SECOND; + } +} + +__attribute__((unused)) inline static void +timespec_sub(struct timespec *accum, const struct timespec *item) +{ + accum->tv_sec -= item->tv_sec; + accum->tv_nsec -= item->tv_nsec; + while (accum->tv_nsec < 0) { + --(accum->tv_sec); + accum->tv_nsec += NANOSECONDS_IN_SECOND; + } +} + +__attribute__((unused)) inline static int +timespec_cmp(const struct timespec *lhs, const struct timespec *rhs) +{ + if (lhs->tv_sec > rhs->tv_sec) { + return 1; + } + if (lhs->tv_sec < rhs->tv_sec) { + return -1; + } + if (lhs->tv_nsec > rhs->tv_nsec) { + return 1; + } + if (lhs->tv_nsec < rhs->tv_nsec) { + return -1; + } + return 0; +} + +__attribute__((unused)) inline static AbsoluteTime +get_current_time() +{ + AbsoluteTime time; + if (clock_gettime(CLOCK_MONOTONIC, &time.absolute) < 0) { + time.absolute.tv_sec = 0; + time.absolute.tv_nsec = 0; + } + return time; +} + +__attribute__((unused)) inline static AbsoluteTime +absolute_time_add_relative(AbsoluteTime lhs, RelativeTime rhs) +{ + timespec_add(&lhs.absolute, &rhs.relative); + return lhs; +} + +__attribute__((unused)) inline static AbsoluteTime +absolute_time_sub_relative(AbsoluteTime lhs, RelativeTime rhs) +{ + timespec_sub(&lhs.absolute, &rhs.relative); + return lhs; +} + +__attribute__((unused)) inline static RelativeTime +absolute_time_sub_absolute(AbsoluteTime lhs, AbsoluteTime rhs) +{ + RelativeTime result = { + .relative = lhs.absolute, + }; + timespec_sub(&result.relative, &rhs.absolute); + return result; +} + +__attribute__((unused)) inline static RelativeTime +relative_time_add(RelativeTime lhs, RelativeTime rhs) +{ + timespec_add(&lhs.relative, &rhs.relative); + return lhs; +} + +__attribute__((unused)) inline static RelativeTime +relative_time_sub(RelativeTime lhs, RelativeTime rhs) +{ + timespec_sub(&lhs.relative, &rhs.relative); + return lhs; +} + +__attribute__((unused)) inline static int +absolute_time_cmp(AbsoluteTime lhs, AbsoluteTime rhs) +{ + return timespec_cmp(&lhs.absolute, &rhs.absolute); +} + +__attribute__((unused)) inline static int +relative_time_cmp(RelativeTime lhs, RelativeTime rhs) +{ + return timespec_cmp(&lhs.relative, &rhs.relative); +} + +#endif /* end of include guard: TIME_H_ */