mirror of https://github.com/yandex/odyssey.git
149 lines
3.1 KiB
C
149 lines
3.1 KiB
C
|
|
/*
|
|
* machinarium.
|
|
*
|
|
* cooperative multitasking engine.
|
|
*/
|
|
|
|
#include <machinarium.h>
|
|
#include <machinarium_private.h>
|
|
|
|
static int
|
|
mm_clock_cmp(const void *a_ptr, const void *b_ptr)
|
|
{
|
|
mm_timer_t *a = *(mm_timer_t**)a_ptr;
|
|
mm_timer_t *b = *(mm_timer_t**)b_ptr;
|
|
if (a->timeout == b->timeout) {
|
|
return (a->seq > b->seq) ? 1 : -1;
|
|
} else
|
|
if (a->timeout > b->timeout) {
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void mm_clock_init(mm_clock_t *clock)
|
|
{
|
|
mm_buf_init(&clock->timers);
|
|
clock->timers_count = 0;
|
|
clock->timers_seq = 0;
|
|
clock->time = 0;
|
|
clock->time_us = 0;
|
|
}
|
|
|
|
void mm_clock_free(mm_clock_t *clock)
|
|
{
|
|
mm_buf_free(&clock->timers);
|
|
}
|
|
|
|
int mm_clock_timer_add(mm_clock_t *clock, mm_timer_t *timer)
|
|
{
|
|
int count = clock->timers_count + 1;
|
|
int rc;
|
|
rc = mm_buf_ensure(&clock->timers, count * sizeof(mm_timer_t*));
|
|
if (rc == -1)
|
|
return -1;
|
|
mm_timer_t **list;
|
|
list = (mm_timer_t**)clock->timers.start;
|
|
list[count - 1] = timer;
|
|
mm_buf_advance(&clock->timers, sizeof(mm_timer_t*));
|
|
timer->seq = clock->timers_seq++;
|
|
timer->timeout = clock->time + timer->interval;
|
|
timer->active = 1;
|
|
timer->clock = clock;
|
|
qsort(list, count, sizeof(mm_timer_t*),
|
|
mm_clock_cmp);
|
|
clock->timers_count = count;
|
|
return 0;
|
|
}
|
|
|
|
int mm_clock_timer_del(mm_clock_t *clock, mm_timer_t *timer)
|
|
{
|
|
if (! timer->active)
|
|
return -1;
|
|
assert(clock->timers_count >= 1);
|
|
mm_timer_t **list;
|
|
list = (mm_timer_t**)clock->timers.start;
|
|
int i = 0;
|
|
int j = 0;
|
|
for (; i < clock->timers_count; i++) {
|
|
if (list[i] == timer)
|
|
continue;
|
|
list[j] = list[i];
|
|
j++;
|
|
}
|
|
timer->active = 0;
|
|
clock->timers.pos -= sizeof(mm_timer_t*);
|
|
clock->timers_count -= 1;
|
|
qsort(list, clock->timers_count, sizeof(mm_timer_t*),
|
|
mm_clock_cmp);
|
|
return 0;
|
|
}
|
|
|
|
mm_timer_t*
|
|
mm_clock_timer_min(mm_clock_t *clock)
|
|
{
|
|
if (clock->timers_count == 0)
|
|
return NULL;
|
|
mm_timer_t **list;
|
|
list = (mm_timer_t**)clock->timers.start;
|
|
return list[0];
|
|
}
|
|
|
|
int mm_clock_step(mm_clock_t *clock)
|
|
{
|
|
if (clock->timers_count == 0)
|
|
return 0;
|
|
mm_timer_t **list;
|
|
list = (mm_timer_t**)clock->timers.start;
|
|
int timers_hit = 0;
|
|
int i = 0;
|
|
int j = 0;
|
|
for (; i < clock->timers_count; i++) {
|
|
mm_timer_t *timer = list[i];
|
|
if (timer->timeout > clock->time)
|
|
break;
|
|
timer->callback(timer);
|
|
timer->active = 0;
|
|
timers_hit++;
|
|
list[i] = NULL;
|
|
}
|
|
if (! timers_hit)
|
|
return 0;
|
|
int timers_left = clock->timers_count - timers_hit;
|
|
if (timers_left == 0) {
|
|
mm_buf_reset(&clock->timers);
|
|
clock->timers_count = 0;
|
|
return timers_hit;
|
|
}
|
|
i = 0;
|
|
for (; i < clock->timers_count; i++) {
|
|
if (list[i] == NULL)
|
|
continue;
|
|
list[j] = list[i];
|
|
j++;
|
|
}
|
|
clock->timers.pos -= sizeof(mm_timer_t*) * timers_hit;
|
|
clock->timers_count -= timers_hit;
|
|
qsort(list, clock->timers_count, sizeof(mm_timer_t*),
|
|
mm_clock_cmp);
|
|
return timers_hit;
|
|
}
|
|
|
|
static uint64_t
|
|
mm_clock_gettime(void)
|
|
{
|
|
struct timespec t;
|
|
clock_gettime(CLOCK_MONOTONIC, &t);
|
|
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
|
|
}
|
|
|
|
void mm_clock_update(mm_clock_t *clock)
|
|
{
|
|
uint64_t time;
|
|
time = mm_clock_gettime();
|
|
/* set current time in millisecond precision */
|
|
clock->time = time / 1000000;
|
|
clock->time_us = time / 1000;
|
|
}
|