Files
cell/source/timer.c

98 lines
2.2 KiB
C

#include "timer.h"
#include <time.h>
#include <limits.h>
#include "stb_ds.h"
/* External variables from cell.c */
extern SDL_Condition *mainqueue_cond;
/* Global timer state */
static timer_t *timers = NULL;
static Uint32 next_timer_id = 1;
static SDL_Mutex *timer_mutex = NULL;
void timer_init(void)
{
if (!timer_mutex) {
timer_mutex = SDL_CreateMutex();
}
}
uint64_t get_time_ns(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000000000ull + ts.tv_nsec;
}
Uint32 add_timer_ns(uint64_t delay_ns, TimerCallback callback, void *param)
{
timer_t t;
t.id = next_timer_id++;
t.interval_ns = delay_ns;
t.due_ns = get_time_ns() + delay_ns;
t.callback = callback;
t.param = param;
SDL_LockMutex(timer_mutex);
arrput(timers, t);
SDL_UnlockMutex(timer_mutex);
SDL_SignalCondition(mainqueue_cond);
return t.id;
}
void remove_timer(Uint32 id)
{
SDL_LockMutex(timer_mutex);
for (int i = 0; i < arrlen(timers); i++) {
if (timers[i].id == id) {
arrdel(timers, i);
break;
}
}
SDL_UnlockMutex(timer_mutex);
}
void process_due_timers(void)
{
uint64_t now = get_time_ns();
SDL_LockMutex(timer_mutex);
for (int i = 0; i < arrlen(timers); i++) {
if (timers[i].due_ns <= now) {
timer_t t = timers[i];
arrdel(timers, i);
SDL_UnlockMutex(timer_mutex);
/* Convert interval_ns back to milliseconds for the callback */
Uint32 next_ms = t.callback(t.id, t.interval_ns, t.param);
if (next_ms > 0) {
uint64_t next_ns = (uint64_t)next_ms * 1000000ull;
add_timer_ns(next_ns, t.callback, t.param);
}
/* restart scan because array may have shifted */
SDL_LockMutex(timer_mutex);
i = -1;
continue;
}
}
SDL_UnlockMutex(timer_mutex);
}
uint64_t next_timeout_ns(void)
{
SDL_LockMutex(timer_mutex);
if (!timers || arrlen(timers) == 0) {
SDL_UnlockMutex(timer_mutex);
return UINT64_MAX;
}
uint64_t now = get_time_ns();
uint64_t min_due = timers[0].due_ns;
for (int i = 1; i < arrlen(timers); i++) {
if (timers[i].due_ns < min_due)
min_due = timers[i].due_ns;
}
SDL_UnlockMutex(timer_mutex);
if (min_due <= now)
return 0;
return min_due - now;
}