Add newtypes for absolute and relative time
This commit is contained in:
parent
d0bcd6b20c
commit
d3a3217e88
13
events.c
13
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;
|
||||
|
|
4
events.h
4
events.h
|
@ -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
2
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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
97
processing.c
97
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);
|
||||
}
|
||||
}
|
||||
|
|
10
processing.h
10
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_ */
|
||||
|
|
|
@ -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_ */
|
Loading…
Reference in New Issue