Add newtypes for absolute and relative time

This commit is contained in:
Vftdan 2024-08-14 13:47:55 +02:00
parent d0bcd6b20c
commit d3a3217e88
8 changed files with 160 additions and 86 deletions

View File

@ -37,20 +37,15 @@ event_create(const EventData * content)
event->data = *content; event->data = *content;
event->data.modifiers = modifier_set_copy(content->modifiers); event->data.modifiers = modifier_set_copy(content->modifiers);
} else { } 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; EventNode ** list_pos = &LAST_EVENT;
FOREACH_EVENT_DESC(other) { FOREACH_EVENT_DESC(other) {
struct timespec other_time = other->data.time; AbsoluteTime other_time = other->data.time;
if (self_time.tv_sec > other_time.tv_sec) { if (absolute_time_cmp(self_time, other_time) >= 0) {
break; 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; list_pos = &other->next->prev;
} }
EventNode * prev = *list_pos; EventNode * prev = *list_pos;

View File

@ -1,9 +1,9 @@
#ifndef EVENTS_H_ #ifndef EVENTS_H_
#define EVENTS_H_ #define EVENTS_H_
#include <time.h>
#include "defs.h" #include "defs.h"
#include "modifiers.h" #include "modifiers.h"
#include "time.h"
typedef uint32_t EventNamespace; typedef uint32_t EventNamespace;
@ -18,7 +18,7 @@ typedef struct {
int32_t priority; int32_t priority;
int64_t payload; int64_t payload;
ModifierSet modifiers; ModifierSet modifiers;
struct timespec time; AbsoluteTime time;
} EventData; } EventData;
typedef struct event_position_base EventPositionBase; typedef struct event_position_base EventPositionBase;

2
main.c
View File

@ -10,8 +10,8 @@ main(int argc, char ** argv)
ProcessingState state = (ProcessingState) { ProcessingState state = (ProcessingState) {
.wait_delay = NULL, .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_input, 5);
io_subscription_list_init(&state.wait_output, 5); io_subscription_list_init(&state.wait_output, 5);

View File

@ -28,8 +28,8 @@ handle_io(EventPositionBase * self, int fd, bool is_output)
.priority = 10, .priority = 10,
.payload = buf[0], .payload = buf[0],
.modifiers = EMPTY_MODIFIER_SET, .modifiers = EMPTY_MODIFIER_SET,
.time = get_current_time(),
}; };
clock_gettime(CLOCK_MONOTONIC, &data.time);
if (status == 0) { if (status == 0) {
node->subscription.enabled = false; node->subscription.enabled = false;
data.code.value = 2; data.code.value = 2;

View File

@ -18,7 +18,7 @@ handle_event(EventPositionBase * self, EventNode * event)
printf("%02x", data.modifiers.bits[i]); printf("%02x", data.modifiers.bits[i]);
} }
printf("\n"); 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"); printf("---\n\n");
event_destroy(event); event_destroy(event);
return true; return true;

View File

@ -117,7 +117,7 @@ run_io_handlers(fd_set * fds, IOSubscriptionList * subs, bool arg)
} }
bool bool
process_io(ProcessingState * state, const struct timespec * timeout) process_io(ProcessingState * state, const RelativeTime * timeout)
{ {
int max_fd = 0; int max_fd = 0;
fd_set readfds, writefds; 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 = populate_fd_set(&writefds, &state->wait_output, max_fd);
++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) { if (ready < 0) {
FD_ZERO(&readfds); FD_ZERO(&readfds);
@ -143,19 +143,14 @@ process_io(ProcessingState * state, const struct timespec * timeout)
} }
bool 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; DelayList **next = &state->wait_delay;
while (*next) { while (*next) {
struct timespec next_time = (*next)->time; AbsoluteTime next_time = (*next)->time;
if (next_time.tv_sec > time->tv_sec) { if (absolute_time_cmp(next_time, *time) > 0) {
break; break;
} }
if (next_time.tv_sec == time->tv_sec) {
if (next_time.tv_nsec > time->tv_nsec) {
break;
}
}
next = &((*next)->next); next = &((*next)->next);
} }
@ -174,33 +169,22 @@ schedule_delay(ProcessingState * state, EventPositionBase * target, void (*callb
return true; return true;
} }
static const struct timespec ZERO_TS = { static const RelativeTime ZERO_TO = {
.tv_sec = 0, .relative ={
.tv_nsec = 0, .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 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) { if (!state->wait_delay) {
return false; return false;
} }
struct timespec next_scheduled_time = state->wait_delay->time; // abs AbsoluteTime next_scheduled_time = state->wait_delay->time;
if (next_scheduled_time.tv_sec > extern_time.tv_sec) { if (absolute_time_cmp(next_scheduled_time, extern_time) > 0) {
return false; 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; DelayList next_scheduled = *state->wait_delay;
free(state->wait_delay); free(state->wait_delay);
@ -217,7 +201,7 @@ process_single_scheduled(ProcessingState * state, const struct timespec extern_t
} }
static bool static bool
process_events_until(ProcessingState * state, const struct timespec * max_time) process_events_until(ProcessingState * state, const AbsoluteTime * max_time)
{ {
bool stable = true; bool stable = true;
int32_t next_priority = INT32_MIN; int32_t next_priority = INT32_MIN;
@ -225,17 +209,11 @@ process_events_until(ProcessingState * state, const struct timespec * max_time)
FOREACH_EVENT(ev) { FOREACH_EVENT(ev) {
if (max_time) { if (max_time) {
struct timespec ev_time = ev->data.time; AbsoluteTime ev_time = ev->data.time;
if (ev_time.tv_sec > max_time->tv_sec) { if (absolute_time_cmp(ev_time, *max_time) > 0) {
// stable = false; // stable = false;
state->has_future_events = true; state->has_future_events = true;
break; 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) { if (max_time) {
struct timespec ev_time = ev->data.time; AbsoluteTime ev_time = ev->data.time;
if (ev_time.tv_sec > max_time->tv_sec) { if (absolute_time_cmp(ev_time, *max_time) > 0) {
state->has_future_events = true; state->has_future_events = true;
break; 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 void
process_iteration(ProcessingState * state) process_iteration(ProcessingState * state)
{ {
struct timespec extern_time; AbsoluteTime extern_time = get_current_time();
if (clock_gettime(CLOCK_MONOTONIC, &extern_time) < 0) {
perror("Failed to get time");
exit(1);
}
// late_by.tv_sec = extern_time.tv_sec - state->reached_time.tv_sec; // 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; // late_by.tv_nsec = extern_time.tv_nsec - state->reached_time.tv_nsec;
// fix_nsec(&late_by); // fix_nsec(&late_by);
struct timespec next_scheduled_delay; RelativeTime next_scheduled_delay;
const struct timespec *max_io_timeout = NULL; const RelativeTime *max_io_timeout = NULL;
if (state->has_future_events) { if (state->has_future_events) {
max_io_timeout = &ZERO_TS; max_io_timeout = &ZERO_TO;
} else { } else {
if (state->wait_delay) { if (state->wait_delay) {
next_scheduled_delay = state->wait_delay->time; // abs next_scheduled_delay = absolute_time_sub_absolute(state->wait_delay->time, extern_time);
next_scheduled_delay.tv_sec -= extern_time.tv_sec; if (relative_time_cmp(next_scheduled_delay, ZERO_TO) < 0) {
next_scheduled_delay.tv_nsec -= extern_time.tv_nsec; max_io_timeout = &ZERO_TO;
fix_nsec(&next_scheduled_delay);
if (next_scheduled_delay.tv_sec < 0) {
max_io_timeout = &ZERO_TS;
} else { } else {
max_io_timeout = &next_scheduled_delay; max_io_timeout = &next_scheduled_delay;
} }
@ -334,19 +300,16 @@ process_iteration(ProcessingState * state)
// FIXME reason about timeouts // FIXME reason about timeouts
process_io(state, max_io_timeout); process_io(state, max_io_timeout);
// process_io(state, &ZERO_TS); // process_io(state, &ZERO_TO);
while (true) { while (true) {
bool had_scheduled = process_single_scheduled(state, extern_time); 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) { 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; bool use_scheduled = false;
if (!use_scheduled) { if (!use_scheduled) {
use_scheduled = next_scheduled_time.tv_sec > extern_time.tv_sec; use_scheduled = absolute_time_cmp(next_scheduled_time, extern_time) > 0;
}
if (!use_scheduled) {
use_scheduled = next_scheduled_time.tv_nsec > extern_time.tv_nsec;
} }
if (use_scheduled) { if (use_scheduled) {
max_event_time = &state->wait_delay->time; max_event_time = &state->wait_delay->time;
@ -356,6 +319,6 @@ process_iteration(ProcessingState * state)
if (!had_scheduled && !had_events) { if (!had_scheduled && !had_events) {
break; break;
} }
process_io(state, &ZERO_TS); process_io(state, &ZERO_TO);
} }
} }

View File

@ -23,17 +23,17 @@ typedef struct {
typedef struct delay_list DelayList; typedef struct delay_list DelayList;
struct delay_list { struct delay_list {
void (*callback) (EventPositionBase * target, void * closure, const struct timespec * time); void (*callback) (EventPositionBase * target, void * closure, const AbsoluteTime * time);
EventPositionBase *target; EventPositionBase *target;
void *closure; void *closure;
DelayList *next; DelayList *next;
struct timespec time; AbsoluteTime time;
}; };
typedef struct { typedef struct {
IOSubscriptionList wait_input, wait_output; IOSubscriptionList wait_input, wait_output;
DelayList *wait_delay; DelayList *wait_delay;
struct timespec reached_time; AbsoluteTime reached_time;
int32_t pass_priority; int32_t pass_priority;
bool has_future_events; bool has_future_events;
} ProcessingState; } 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_deinit(IOSubscriptionList * lst);
void io_subscription_list_add(IOSubscriptionList * lst, int fd, IOHandling *subscriber); 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 schedule_delay(ProcessingState * state, EventPositionBase * target, void (*callback) (EventPositionBase*, void*, const AbsoluteTime*), const AbsoluteTime * time);
bool process_io(ProcessingState * state, const struct timespec * timeout); bool process_io(ProcessingState * state, const RelativeTime * timeout);
void process_iteration(ProcessingState * state); void process_iteration(ProcessingState * state);
#endif /* end of include guard: PROCESSING_H_ */ #endif /* end of include guard: PROCESSING_H_ */

116
time.h Normal file
View File

@ -0,0 +1,116 @@
#ifndef TIME_H_
#define TIME_H_
#include <time.h>
#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_ */