#include #include #include #include #include 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; 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); } static inline int _slot_set_interval(hexagram_schedule *schedule, size_t i) { return _set_interval(schedule, _slot_interval_ns(schedule, i)); } static void _ev_notify(hexagram_schedule *schedule) { time_t last = -1; while (schedule->current < schedule->count) { hexagram_schedule_slot *slot = _slot(schedule, schedule->current); time_t delay = slot->interval_us; if (slot->handler(&slot->frame, schedule->ctx) < 0) { schedule->error = errno; break; } schedule->current++; if (last >= 0 && last != delay) { _slot_set_interval(schedule, schedule->current); return; } last = delay; } schedule->current = 0; _slot_set_interval(schedule, schedule->current); } static int _schedule_init(hexagram_schedule *schedule, hexagram_schedule_slot *table, size_t count, void *ctx) { size_t i; memset(schedule, '\0', sizeof(*schedule)); schedule->current = 0; schedule->error = 0; schedule->count = count; schedule->ctx = ctx; schedule->ev.sigev_notify = SIGEV_THREAD; schedule->ev.sigev_notify_function = _ev_notify; schedule->ev.sigev_value.sival_ptr = schedule; if (timer_create(CLOCK_REALTIME, &schedule->ev, &schedule->timer) < 0) { goto error_timer_create; } for (i=0; iframe.data, '\0', sizeof(*(slot->frame.data))); memcpy(slot, &table[i], sizeof(hexagram_schedule_slot)); } qsort(schedule + 1, count, sizeof(hexagram_schedule_slot), _slot_cmp); return 0; error_timer_create: return -1; } hexagram_schedule *hexagram_schedule_create(hexagram_schedule_slot *table, size_t count, void *ctx) { hexagram_schedule *schedule; if ((schedule = malloc(sizeof(*schedule) + count * sizeof(hexagram_schedule_slot))) == 0) { goto error_malloc_schedule; } _schedule_init(schedule, table, count, ctx); return schedule; error_malloc_schedule: return NULL; } void hexagram_schedule_destroy(hexagram_schedule *schedule) { if (schedule->timer) { timer_delete(schedule->timer); } free(schedule); } 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; return _slot_set_interval(schedule, schedule->current); } int hexagram_schedule_stop(hexagram_schedule *schedule) { return _set_interval(schedule, 0); } int hexagram_schedule_error(hexagram_schedule *schedule) { return schedule->error; }