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.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;

View File

@ -1,9 +1,9 @@
#ifndef EVENTS_H_
#define EVENTS_H_
#include <time.h>
#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;

2
main.c
View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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_ */

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_ */