2023-12-24 00:11:00 -05:00
|
|
|
#include <stdlib.h>
|
2023-12-26 20:25:57 -05:00
|
|
|
#include <string.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <errno.h>
|
2023-12-24 00:11:00 -05:00
|
|
|
|
|
|
|
#include <hexagram/schedule.h>
|
|
|
|
|
2023-12-26 20:25:57 -05:00
|
|
|
static int _slot_cmp(const void *item_a, const void *item_b) {
|
|
|
|
hexagram_schedule_slot *a = (hexagram_schedule_slot *)item_a,
|
|
|
|
*b = (hexagram_schedule_slot *)item_b;
|
2023-12-24 00:11:00 -05:00
|
|
|
|
2023-12-26 20:25:57 -05:00
|
|
|
return a->interval_us < b->interval_us? -1:
|
|
|
|
a->interval_us > b->interval_us? 1: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline hexagram_schedule_slot *_slot(hexagram_schedule *schedule, size_t i) {
|
|
|
|
return &((hexagram_schedule_slot *)(schedule + 1))[i];
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline time_t _slot_interval_ns(hexagram_schedule *schedule, size_t i) {
|
|
|
|
return 1000 * _slot(schedule, i)->interval_us;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int _set_interval(hexagram_schedule *schedule,
|
|
|
|
time_t int_nsec) {
|
|
|
|
schedule->ts.it_value.tv_sec = 0;
|
|
|
|
schedule->ts.it_value.tv_nsec = int_nsec;
|
|
|
|
schedule->ts.it_interval.tv_sec = 0;
|
|
|
|
schedule->ts.it_interval.tv_nsec = int_nsec;
|
|
|
|
|
|
|
|
return timer_settime(schedule->timer, 0, &schedule->ts, NULL);
|
|
|
|
}
|
|
|
|
|
2023-12-27 00:44:33 -05:00
|
|
|
static inline int _slot_set_interval(hexagram_schedule *schedule, size_t i) {
|
2023-12-26 20:25:57 -05:00
|
|
|
return _set_interval(schedule, _slot_interval_ns(schedule, i));
|
|
|
|
}
|
|
|
|
|
2023-12-27 13:19:19 -05:00
|
|
|
static void _ev_notify(union sigval sv) {
|
|
|
|
hexagram_schedule *schedule = sv.sival_ptr;
|
2023-12-26 20:25:57 -05:00
|
|
|
time_t last = -1;
|
|
|
|
|
|
|
|
while (schedule->current < schedule->count) {
|
|
|
|
hexagram_schedule_slot *slot = _slot(schedule, schedule->current);
|
|
|
|
time_t delay = slot->interval_us;
|
|
|
|
|
2023-12-27 13:14:26 -05:00
|
|
|
if (slot->handler(&slot->frame, schedule->ctx) < 0) {
|
2023-12-26 20:25:57 -05:00
|
|
|
schedule->error = errno;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
schedule->current++;
|
|
|
|
|
|
|
|
if (last >= 0 && last != delay) {
|
2023-12-27 00:44:33 -05:00
|
|
|
_slot_set_interval(schedule, schedule->current);
|
2023-12-26 20:25:57 -05:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
last = delay;
|
2023-12-24 00:11:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
schedule->current = 0;
|
|
|
|
|
2023-12-27 00:44:33 -05:00
|
|
|
_slot_set_interval(schedule, schedule->current);
|
2023-12-26 20:25:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static int _schedule_init(hexagram_schedule *schedule,
|
2023-12-27 01:01:21 -05:00
|
|
|
hexagram_schedule_slot *table,
|
2023-12-27 13:14:26 -05:00
|
|
|
size_t count,
|
|
|
|
void *ctx) {
|
2023-12-26 20:25:57 -05:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
memset(schedule, '\0', sizeof(*schedule));
|
|
|
|
|
|
|
|
schedule->current = 0;
|
2023-12-27 13:14:26 -05:00
|
|
|
schedule->error = 0;
|
2023-12-26 20:25:57 -05:00
|
|
|
schedule->count = count;
|
2023-12-27 13:14:26 -05:00
|
|
|
schedule->ctx = ctx;
|
2023-12-26 20:25:57 -05:00
|
|
|
|
|
|
|
schedule->ev.sigev_notify = SIGEV_THREAD;
|
2023-12-27 00:44:33 -05:00
|
|
|
schedule->ev.sigev_notify_function = _ev_notify;
|
2023-12-26 20:25:57 -05:00
|
|
|
schedule->ev.sigev_value.sival_ptr = schedule;
|
|
|
|
|
|
|
|
if (timer_create(CLOCK_REALTIME,
|
|
|
|
&schedule->ev,
|
|
|
|
&schedule->timer) < 0) {
|
|
|
|
goto error_timer_create;
|
|
|
|
}
|
|
|
|
|
2023-12-24 00:11:00 -05:00
|
|
|
for (i=0; i<count; i++) {
|
|
|
|
hexagram_schedule_slot *slot = &((hexagram_schedule_slot *)(schedule + 1))[i];
|
|
|
|
|
2023-12-27 13:14:26 -05:00
|
|
|
memset(slot->frame.data, '\0', sizeof(*(slot->frame.data)));
|
2023-12-27 01:01:21 -05:00
|
|
|
memcpy(slot, &table[i], sizeof(hexagram_schedule_slot));
|
2023-12-24 00:11:00 -05:00
|
|
|
}
|
|
|
|
|
2023-12-26 20:25:57 -05:00
|
|
|
qsort(schedule + 1, count, sizeof(hexagram_schedule_slot), _slot_cmp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_timer_create:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-12-27 01:01:21 -05:00
|
|
|
hexagram_schedule *hexagram_schedule_create(hexagram_schedule_slot *table,
|
2023-12-27 13:14:26 -05:00
|
|
|
size_t count,
|
|
|
|
void *ctx) {
|
2023-12-26 20:25:57 -05:00
|
|
|
hexagram_schedule *schedule;
|
|
|
|
|
|
|
|
if ((schedule = malloc(sizeof(*schedule) + count * sizeof(hexagram_schedule_slot))) == 0) {
|
|
|
|
goto error_malloc_schedule;
|
|
|
|
}
|
|
|
|
|
2023-12-27 13:14:26 -05:00
|
|
|
_schedule_init(schedule, table, count, ctx);
|
2023-12-26 20:25:57 -05:00
|
|
|
|
2023-12-24 00:11:00 -05:00
|
|
|
return schedule;
|
|
|
|
|
|
|
|
error_malloc_schedule:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hexagram_schedule_destroy(hexagram_schedule *schedule) {
|
|
|
|
if (schedule->timer) {
|
|
|
|
timer_delete(schedule->timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(schedule);
|
|
|
|
}
|
2023-12-26 20:25:57 -05:00
|
|
|
|
|
|
|
void hexagram_schedule_reset(hexagram_schedule *schedule) {
|
|
|
|
schedule->current = 0;
|
|
|
|
schedule->error = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int hexagram_schedule_run(hexagram_schedule *schedule) {
|
|
|
|
schedule->current = 0;
|
|
|
|
schedule->error = 0;
|
|
|
|
|
2023-12-27 00:44:33 -05:00
|
|
|
return _slot_set_interval(schedule, schedule->current);
|
2023-12-26 20:25:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int hexagram_schedule_stop(hexagram_schedule *schedule) {
|
2023-12-27 00:44:33 -05:00
|
|
|
return _set_interval(schedule, 0);
|
2023-12-26 20:25:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int hexagram_schedule_error(hexagram_schedule *schedule) {
|
|
|
|
return schedule->error;
|
|
|
|
}
|