move timer to its own file
This commit is contained in:
@@ -295,7 +295,7 @@ src += [
|
||||
'anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c',
|
||||
'render.c','simplex.c','spline.c', 'transform.c','cell.c', 'wildmatch.c',
|
||||
'sprite.c', 'rtree.c', 'qjs_nota.c', 'qjs_soloud.c', 'qjs_sdl.c', 'qjs_sdl_input.c', 'qjs_sdl_video.c', 'qjs_sdl_surface.c', 'qjs_math.c', 'qjs_geometry.c', 'qjs_transform.c', 'qjs_sprite.c', 'qjs_io.c', 'qjs_fd.c', 'qjs_os.c', 'qjs_actor.c',
|
||||
'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c', 'qjs_spline.c', 'qjs_js.c', 'qjs_debug.c', 'picohttpparser.c', 'qjs_miniz.c'
|
||||
'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c', 'qjs_spline.c', 'qjs_js.c', 'qjs_debug.c', 'picohttpparser.c', 'qjs_miniz.c', 'timer.c'
|
||||
]
|
||||
# quirc src
|
||||
src += [
|
||||
|
||||
111
source/cell.c
111
source/cell.c
@@ -28,6 +28,7 @@
|
||||
#include "stb_ds.h"
|
||||
#include "jsffi.h"
|
||||
#include "cell.h"
|
||||
#include "timer.h"
|
||||
|
||||
#ifdef TRACY_ENABLE
|
||||
#include <tracy/TracyC.h>
|
||||
@@ -55,7 +56,7 @@ static cell_rt **main_ready_queue = NULL;
|
||||
static SDL_Mutex *queue_mutex = NULL; // for the ready queue
|
||||
static SDL_Condition *queue_cond = NULL;
|
||||
static SDL_Mutex *mainqueue_mutex = NULL;
|
||||
static SDL_Condition *mainqueue_cond = NULL;
|
||||
SDL_Condition *mainqueue_cond = NULL;
|
||||
static SDL_Mutex *actors_mutex = NULL;
|
||||
static struct { char *key; cell_rt *value; } *actors = NULL;
|
||||
static unsigned char *zip_buffer_global = NULL;
|
||||
@@ -64,113 +65,6 @@ cell_rt *root_cell = NULL;
|
||||
|
||||
static SDL_Thread **runners = NULL;
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// TIMER “SDL_AddTimerNS”–replacement
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
typedef Uint32 (*TimerCallback)(Uint32 timer_id, Uint32 interval, void *param);
|
||||
|
||||
typedef struct {
|
||||
Uint32 id;
|
||||
uint64_t due_ns;
|
||||
uint64_t interval_ns;
|
||||
TimerCallback callback;
|
||||
void *param;
|
||||
} timer_t;
|
||||
|
||||
// stb_ds array of timer_t
|
||||
static timer_t *timers = NULL;
|
||||
static Uint32 next_timer_id = 1;
|
||||
|
||||
// Must be initialized exactly once (e.g. in main after SDL_Init)
|
||||
static SDL_Mutex *timer_mutex = NULL;
|
||||
|
||||
// Return monotonic time in nanoseconds
|
||||
static uint64_t get_time_ns(void) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (uint64_t)ts.tv_sec * 1000000000ull + ts.tv_nsec;
|
||||
}
|
||||
|
||||
// Schedule a new timer to fire after `delay_ns` nanoseconds.
|
||||
// Returns a Uint32 timer ID. When it fires, `callback(interval_ms,param)` is invoked.
|
||||
// If `callback` returns nonzero (in ms), the timer is rescheduled with that
|
||||
// new interval; otherwise it is removed permanently.
|
||||
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;
|
||||
}
|
||||
|
||||
// Cancel (remove) a pending timer by its ID. If not found, does nothing.
|
||||
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);
|
||||
}
|
||||
|
||||
// Scan the global `timers[]` array and invoke any timer whose due_ns <= now.
|
||||
// For each such timer:
|
||||
// 1) pop it out of the `timers` array
|
||||
// 2) call `callback(interval_ms,param)`
|
||||
// 3) if callback returns nonzero "next_ms", re-insert it with new due_ns = now + next_ms*1e6
|
||||
// This must be called once per iteration of your main loop (before polling).
|
||||
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;
|
||||
}
|
||||
|
||||
static inline uint64_t now_ns()
|
||||
{
|
||||
return SDL_GetTicksNS();
|
||||
@@ -863,7 +757,6 @@ queue_cond = SDL_CreateCondition();
|
||||
mainqueue_mutex = SDL_CreateMutex();
|
||||
mainqueue_cond = SDL_CreateCondition();
|
||||
actors_mutex = SDL_CreateMutex();
|
||||
timer_mutex = SDL_CreateMutex();
|
||||
|
||||
add_runners(SDL_GetNumLogicalCPUCores()-1);
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ typedef struct cell_rt {
|
||||
|
||||
int disrupt;
|
||||
int main_thread_only;
|
||||
int affinity;
|
||||
|
||||
JSAtom actor_sym;
|
||||
|
||||
|
||||
98
source/timer.c
Normal file
98
source/timer.c
Normal file
@@ -0,0 +1,98 @@
|
||||
#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;
|
||||
}
|
||||
35
source/timer.h
Normal file
35
source/timer.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
typedef Uint32 (*TimerCallback)(Uint32 timer_id, Uint32 interval, void *param);
|
||||
|
||||
typedef struct {
|
||||
Uint32 id;
|
||||
uint64_t due_ns;
|
||||
uint64_t interval_ns;
|
||||
TimerCallback callback;
|
||||
void *param;
|
||||
} timer_t;
|
||||
|
||||
/* Initialize timer system - must be called once */
|
||||
void timer_init(void);
|
||||
|
||||
/* Schedule a new timer to fire after delay_ns nanoseconds */
|
||||
Uint32 add_timer_ns(uint64_t delay_ns, TimerCallback callback, void *param);
|
||||
|
||||
/* Cancel a pending timer by its ID */
|
||||
void remove_timer(Uint32 id);
|
||||
|
||||
/* Process due timers - call once per main loop iteration */
|
||||
void process_due_timers(void);
|
||||
|
||||
/* Get time until next timer expires (in nanoseconds) */
|
||||
uint64_t next_timeout_ns(void);
|
||||
|
||||
/* Get current monotonic time in nanoseconds */
|
||||
uint64_t get_time_ns(void);
|
||||
|
||||
#endif /* TIMER_H */
|
||||
Reference in New Issue
Block a user