From 79d5412fe6c9e3666a88b85af2ed1e615b4d8f6a Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Thu, 5 Jun 2025 00:45:40 -0500 Subject: [PATCH] massively simplify loop logic --- .cell/cell.toml | 2 +- prosperon/prosperon.ce | 4 +- prosperon/sdl_video.ce | 1 + scripts/engine.cm | 8 +- scripts/os.cm | 2 - source/cell.c | 386 ++++++++++++++++++++--------------------- source/cell.h | 6 +- source/qjs_actor.c | 14 +- source/qjs_fd.c | 2 - source/qjs_os.c | 9 - source/qjs_sdl_input.c | 10 -- source/qjs_sdl_input.h | 8 +- tests/delay.ce | 1 + tests/modules.ce | 3 +- 14 files changed, 207 insertions(+), 249 deletions(-) diff --git a/.cell/cell.toml b/.cell/cell.toml index 6190029a..6cb2505c 100644 --- a/.cell/cell.toml +++ b/.cell/cell.toml @@ -10,4 +10,4 @@ actor_max = "10_000" stack_max = 0 [actors] [actors.prosperon/sdl_video] -main = true \ No newline at end of file +main = true diff --git a/prosperon/prosperon.ce b/prosperon/prosperon.ce index f27ae36f..a8e3a8d3 100644 --- a/prosperon/prosperon.ce +++ b/prosperon/prosperon.ce @@ -12,6 +12,7 @@ $_.start(e => { video = e.actor graphics = use('graphics', video) send(video, {kind:"window", op:"makeRenderer"}, e => { + log.console("MADE A WINDOW! so now renderer") $_.start(e => { if (gameactor) return gameactor = e.actor @@ -24,9 +25,6 @@ $_.start(e => { height:500 }) -var input = use('input') - -input.watch($_) var geometry = use('geometry') diff --git a/prosperon/sdl_video.ce b/prosperon/sdl_video.ce index 5b7fa297..6b4c0602 100644 --- a/prosperon/sdl_video.ce +++ b/prosperon/sdl_video.ce @@ -200,6 +200,7 @@ function handle_window(msg) { return {success: true}; case 'makeRenderer': + log.console("MAKE RENDERER") if (ren) return {reason: "Already made a renderer"} ren = win.make_renderer() diff --git a/scripts/engine.cm b/scripts/engine.cm index f4363a11..f092d126 100644 --- a/scripts/engine.cm +++ b/scripts/engine.cm @@ -86,8 +86,6 @@ var nota = hidden.nota // Strip hidden from cell so nothing else can access it delete cell.hidden -var os = use_embed('os') - function disrupt(err) { if (overling) { @@ -97,10 +95,12 @@ function disrupt(err) log.error(err) + log.console("DISRUPTING") + actor_mod.disrupt() } -os.on(disrupt) +actor_mod.on_exception(disrupt) var js = use_embed('js') @@ -688,7 +688,7 @@ function destroyself() { if (overling) report_to_overling({type:'stop'}) - actor_mod.destroy() + actor_mod.disrupt() } function handle_actor_disconnect(id) { diff --git a/scripts/os.cm b/scripts/os.cm index f5c5906a..c22fc805 100644 --- a/scripts/os.cm +++ b/scripts/os.cm @@ -7,12 +7,10 @@ os.freemem[cell.DOC] = "Return the amount of free system RAM in bytes, if known. os.hostname[cell.DOC] = "Return the system's hostname, or an empty string if not available." os.version[cell.DOC] = "Return the OS or kernel version string, if the platform provides it." -os.exit[cell.DOC] = "Exit the application with the specified exit code." os.now[cell.DOC] = "Return current time (in seconds as a float) with high resolution." os.power_state[cell.DOC] = "Return a string describing power status: 'on battery', 'charging', 'charged', etc." -os.on[cell.DOC] = "Register a global callback for certain engine-wide or system-level events." os.rusage[cell.DOC] = "Return resource usage stats for this process, if the platform supports it." os.mallinfo[cell.DOC] = "Return detailed memory allocation info (arena size, free blocks, etc.) on some platforms." diff --git a/source/cell.c b/source/cell.c index 92c387dc..4ba30373 100644 --- a/source/cell.c +++ b/source/cell.c @@ -45,7 +45,7 @@ int tracy_profiling_enabled = 0; static cell_rt **ready_queue = NULL; static cell_rt **main_ready_queue = NULL; -static SDL_Mutex *queue_mutex = NULL; +static SDL_Mutex *queue_mutex = NULL; // for the ready queue static SDL_Condition *queue_cond = NULL; static SDL_Mutex *actors_mutex = NULL; static struct { char *key; cell_rt *value; } *actors = NULL; @@ -56,106 +56,117 @@ cell_rt *root_cell = NULL; static SDL_AtomicInt engine_shutdown; static SDL_Thread **runners = NULL; -// TIMERS -struct timer_entry { uint64_t when_ns; cell_rt *actor; uint32_t id; }; -static struct timer_entry *timers = NULL; -static uint32_t timer_counter = 1; -static SDL_Mutex *timer_mutex = NULL; // protects access to timers +// ───────────────────────────────────────────────────────────────────────────── +// TIMER “SDL_AddTimerNS”–replacement +// ───────────────────────────────────────────────────────────────────────────── -static inline uint64_t now_ns() -{ - return SDL_GetTicksNS(); +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; +static SDL_Condition *timer_cond = 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; } -// Add a message into each actor's event queue for expired timers -static void process_due_timers(void) -{ - uint64_t tnow = now_ns(); +// 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); - while (arrlen(timers) && timers[0].when_ns <= tnow) { - struct timer_entry te = timers[0]; - arrdel(timers, 0); - SDL_UnlockMutex(timer_mutex); - - /* Marshal callback into actor mailbox. */ - SDL_LockMutex(te.actor->msg_mutex); - int idx = hmgeti(te.actor->timers, te.id); - if (idx != -1) { - JSValue cb = te.actor->timers[idx].value; /* already duped when stored */ - hmdel(te.actor->timers, te.id); - - letter l; - l.type = LETTER_CALLBACK; - l.callback = cb; - arrput(te.actor->letters, l); - } - SDL_UnlockMutex(te.actor->msg_mutex); - set_actor_state(te.actor); - - SDL_LockMutex(timer_mutex); - } + arrput(timers, t); + SDL_SignalCondition(timer_cond); SDL_UnlockMutex(timer_mutex); + return t.id; } -static uint64_t next_timeout_ns(void) -{ +// Cancel (remove) a pending timer by its ID. If not found, does nothing. +void remove_timer(Uint32 id) { SDL_LockMutex(timer_mutex); - uint64_t timeout = arrlen(timers) ? (timers[0].when_ns - now_ns()) : UINT64_MAX; - SDL_UnlockMutex(timer_mutex); - return timeout; -} - -static void timer_insert(struct timer_entry te) -{ - SDL_LockMutex(timer_mutex); - size_t n = arrlen(timers); - arrput(timers, te); - for (size_t i = n; i > 0 && timers[i].when_ns < timers[i-1].when_ns; --i) { - struct timer_entry tmp = timers[i]; - timers[i] = timers[i-1]; - timers[i-1] = tmp; - } - SDL_UnlockMutex(timer_mutex); -} - -/* Public API used by JS glue (replaces SDL_AddTimer). */ -uint32_t scheduler_add_timer(cell_rt *actor, double seconds, JSValue cb) -{ - uint32_t id = SDL_AtomicIncRef((SDL_AtomicInt*)&timer_counter); - uint64_t deadline = now_ns() + (uint64_t)(seconds * 1e9); - - SDL_LockMutex(timer_mutex); - timer_insert((struct timer_entry){ deadline, actor, id }); - SDL_UnlockMutex(timer_mutex); - - /* Stash in actor map so removal/GC works. Duplicated to hold ref. */ - SDL_LockMutex(actor->msg_mutex); - hmput(actor->timers, id, JS_DupValue(actor->context, cb)); - SDL_UnlockMutex(actor->msg_mutex); - - /* Wake a sleeper if this timer is sooner than the current next. */ - SDL_SignalCondition(queue_cond); - return id; -} - -void scheduler_remove_timer(cell_rt *actor, uint32_t id) -{ - SDL_LockMutex(timer_mutex); - for (int i = 0; i < arrlen(timers); ++i) { + for (int i = 0; i < arrlen(timers); i++) { if (timers[i].id == id) { arrdel(timers, i); break; } } SDL_UnlockMutex(timer_mutex); +} - SDL_LockMutex(actor->msg_mutex); - int idx = hmgeti(actor->timers, id); - if (idx != -1) { - JS_FreeValue(actor->context, actor->timers[idx].value); - hmdel(actor->timers, id); +// 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(actor->msg_mutex); + 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(); } static void exit_handler(void) @@ -196,7 +207,6 @@ void actor_free(cell_rt *actor) SDL_UnlockMutex(queue_mutex); // Do not go forward with actor destruction until the actor is completely free - SDL_LockMutex(actor->mutex); SDL_LockMutex(actor->msg_mutex); SDL_LockMutex(actor->mutex); @@ -208,19 +218,10 @@ void actor_free(cell_rt *actor) JS_FreeValue(js, actor->unneeded); JS_FreeAtom(js, actor->actor_sym); - SDL_RemoveTimer(actor->ar); + remove_timer(actor->ar); for (int i = 0; i < arrlen(actor->js_swapchains); i++) JS_FreeValue(js, actor->js_swapchains[i]); - /* Remove all timers for this actor from the global timer queue */ - SDL_LockMutex(timer_mutex); - for (int i = arrlen(timers) - 1; i >= 0; i--) { - if (timers[i].actor == actor) { - arrdel(timers, i); - } - } - SDL_UnlockMutex(timer_mutex); - /* Free timer callbacks stored in actor */ for (int i = 0; i < hmlen(actor->timers); i++) { JS_FreeValue(js, actor->timers[i].value); @@ -251,25 +252,19 @@ void actor_free(cell_rt *actor) SDL_DestroyMutex(actor->mutex); SDL_UnlockMutex(actor->msg_mutex); SDL_DestroyMutex(actor->msg_mutex); - SDL_UnlockMutex(actor->mutex); - SDL_DestroyMutex(actor->mutex); free(actor); - if (actor == root_cell) + SDL_LockMutex(actors_mutex); + if (shlen(actors) == 0) exit(0); -// exit_handler(); + SDL_UnlockMutex(actors_mutex); } JSValue js_actor_remove_cb(JSContext *js, JSValue this_val, int argc, JSValue *argv) { cell_rt *actor = JS_GetContextOpaque(js); - if (actor->need_stop) { - actor_free(actor); - return JS_UNDEFINED; - } - if (JS_IsUndefined(actor->unneeded)) actor_free(actor); else { @@ -497,7 +492,7 @@ const char *send_message(const char *id, void *msg) SDL_LockMutex(target->msg_mutex); arrput(target->letters, l); if (target->ar) { - SDL_RemoveTimer(target->ar); + remove_timer(target->ar); target->ar = 0; } SDL_UnlockMutex(target->msg_mutex); @@ -507,58 +502,69 @@ const char *send_message(const char *id, void *msg) return NULL; } -/* - set_actor_state should check if any letters are pending. - -*/ -void set_actor_state(cell_rt *actor) +static Uint32 actor_remove_cb(Uint32 id, Uint32 interval, cell_rt *actor) +{ + if (!JS_IsUndefined(actor->unneeded)) { + SDL_LockMutex(actor->mutex); + JSValue ret = JS_Call(actor->context, actor->unneeded, JS_UNDEFINED, 0, NULL); + uncaught_exception(actor->context, ret); + SDL_UnlockMutex(actor->mutex); + } + actor_free(actor); + return 0; +} + +/* Timer callback adds an event to the queue under evt_mutex. */ +Uint32 actor_delay_cb(SDL_TimerID id, Uint32 interval, cell_rt *actor) { SDL_LockMutex(actor->msg_mutex); - if (actor->need_stop) { - if (!actor->ar) { - JSValue remove_cb = JS_NewCFunction(actor->context, js_actor_remove_cb, "actor_remove", 0); - actor->ar = scheduler_add_timer(actor, 0, remove_cb); - JS_FreeValue(actor->context, remove_cb); - } - SDL_UnlockMutex(actor->msg_mutex); - return; - } - - int has_letters = arrlen(actor->letters); - int has_upcoming = hmlen(actor->timers); - - if (actor->state == ACTOR_RUNNING) - actor->state = ACTOR_IDLE; + int idx = hmgeti(actor->timers, id); + if (idx == -1) goto END; - switch(actor->state) { - case ACTOR_IDLE: - if (has_letters) { - actor->state = ACTOR_READY; - SDL_LockMutex(queue_mutex); - if (actor->main_thread_only) { - arrput(main_ready_queue, actor); - } else { - SDL_SignalCondition(queue_cond); - arrput(ready_queue, actor); - } - SDL_UnlockMutex(queue_mutex); - goto END; - } - break; - - case ACTOR_READY: - if (!has_letters) { - actor->state = ACTOR_IDLE; - goto END; - } - break; - } + JSValue cb = actor->timers[idx].value; + hmdel(actor->timers, id); + letter l ={0}; + l.type = LETTER_CALLBACK; + l.callback = cb; + arrput(actor->letters, l); + set_actor_state(actor); END: - if (actor->state == ACTOR_IDLE && !actor->ar && !has_upcoming) { - JSValue remove_cb = JS_NewCFunction(actor->context, js_actor_remove_cb, "actor_remove", 0); - actor->ar = scheduler_add_timer(actor, actor->ar_secs, remove_cb); - JS_FreeValue(actor->context, remove_cb); + SDL_UnlockMutex(actor->msg_mutex); + return 0; +} + +void set_actor_state(cell_rt *actor) +{ + if (actor->disrupt) { + actor_free(actor); + return; + } + SDL_LockMutex(actor->msg_mutex); + + switch(actor->state) { + case ACTOR_RUNNING: + case ACTOR_READY: + if (actor->ar) { + remove_timer(actor->ar); + actor->ar = 0; + } + break; + + case ACTOR_IDLE: + if (arrlen(actor->letters)) { + actor->state = ACTOR_READY; + SDL_LockMutex(queue_mutex); + if (actor->main_thread_only) + arrput(main_ready_queue, actor); + else + arrput(ready_queue, actor); + SDL_SignalCondition(queue_cond); + SDL_UnlockMutex(queue_mutex); + + } else if (!arrlen(actor->letters) && !hmlen(actor->timers)) + actor->ar = add_timer_ns(actor->ar_secs*1e9, actor_remove_cb, actor); + break; } SDL_UnlockMutex(actor->msg_mutex); @@ -594,6 +600,9 @@ void actor_turn(cell_rt *actor) JS_FreeValue(actor->context, l.callback); } + // now idle + actor->state = ACTOR_IDLE; + SDL_UnlockMutex(actor->mutex); #ifdef TRACY_ENABLE @@ -604,7 +613,6 @@ void actor_turn(cell_rt *actor) set_actor_state(actor); } - /* JS function that schedules a timer. */ JSValue js_actor_delay(JSContext *js, JSValue self, int argc, JSValue *argv) { @@ -623,13 +631,11 @@ JSValue js_actor_delay(JSContext *js, JSValue self, int argc, JSValue *argv) SDL_UnlockMutex(actor->msg_mutex); return JS_NewInt32(js, -1); } - uint32_t id = scheduler_add_timer(actor, seconds, argv[0]); + uint32_t id = add_timer_ns(seconds*1e9, actor_delay_cb, actor); SDL_LockMutex(actor->msg_mutex); - if (actor->ar) { - SDL_RemoveTimer(actor->ar); - actor->ar = 0; - } + JSValue cb = JS_DupValue(js, argv[0]); + hmput(actor->timers, id, cb); SDL_UnlockMutex(actor->msg_mutex); return JS_NewUint32(js, id); @@ -640,9 +646,21 @@ JSValue js_actor_removetimer(JSContext *js, JSValue self, int argc, JSValue *arg cell_rt *actor = JS_GetContextOpaque(js); uint32_t timer_id; JS_ToUint32(js, &timer_id, argv[0]); - if (timer_id == (uint32_t)-1) return JS_UNDEFINED; + if (timer_id == -1) return JS_UNDEFINED; - scheduler_remove_timer(actor, timer_id); + remove_timer(timer_id); + + JSValue cb = JS_UNDEFINED; + + SDL_LockMutex(actor->msg_mutex); + int id = hmgeti(actor->timers, timer_id); + if (id != -1) { + cb = actor->timers[id].value; + hmdel(actor->timers, timer_id); + } + SDL_UnlockMutex(actor->msg_mutex); + + JS_FreeValue(js,cb); return JS_UNDEFINED; } @@ -706,14 +724,11 @@ void tracy_end_hook(JSContext *js, JSValue fn) void actor_disrupt(cell_rt *crt) { crt->disrupt = 1; - crt->need_stop = 1; } static int actor_interrupt_cb(JSRuntime *rt, cell_rt *crt) { - if (crt->disrupt) - return 1; - return 0; + return crt->disrupt; } void script_startup(cell_rt *prt) @@ -745,9 +760,6 @@ void script_startup(cell_rt *prt) JS_AddIntrinsicJSON(js); JS_AddIntrinsicMapSet(js); JS_AddIntrinsicProxy(js); -// JS_AddIntrinsicTypedArrays(js); -// JS_AddIntrinsicDate(js); -// JS_AddIntrinsicPromise(js); JS_SetContextOpaque(js, prt); prt->context = js; @@ -765,7 +777,6 @@ void script_startup(cell_rt *prt) PHYSFS_close(eng); data[stat.filesize] = 0; - /* Called with actor->mutex locked by create_actor(). */ JSValue v = JS_Eval(js, data, (size_t)stat.filesize, ENGINE, JS_EVAL_FLAG_STRICT); uncaught_exception(js, v); } @@ -790,29 +801,7 @@ int uncaught_exception(JSContext *js, JSValue v) return 0; } -void script_evalf(JSContext *js, const char *format, ...) -{ - cell_rt *rt = JS_GetContextOpaque(js); - SDL_LockMutex(rt->mutex); - - va_list args; - va_start(args, format); - int len = vsnprintf(NULL, 0, format, args); - va_end(args); - - char *eval = malloc(len + 1); - va_start(args, format); - vsnprintf(eval, len + 1, format, args); - va_end(args); - - JSValue obj = JS_Eval(js, eval, len, "C eval", JS_EVAL_FLAG_STRICT); - free(eval); - uncaught_exception(js, obj); - - SDL_UnlockMutex(rt->mutex); -} - -static int crank_actor(void *data) +static int actor_runner(void *data) { while (!SDL_GetAtomicInt(&engine_shutdown)) { SDL_LockMutex(queue_mutex); @@ -848,7 +837,6 @@ static void signal_handler(int sig) exit_handler(); } - int main(int argc, char **argv) { int profile_enabled = 0; @@ -926,6 +914,7 @@ int main(int argc, char **argv) queue_cond = SDL_CreateCondition(); actors_mutex = SDL_CreateMutex(); timer_mutex = SDL_CreateMutex(); + timer_cond = SDL_CreateCondition(); /* Create the initial actor from the command line */ int actor_argc = argc - script_start; @@ -946,7 +935,7 @@ int main(int argc, char **argv) for (int i = 0; i < cores-1; i++) { // -1 to keep the main thread free char threadname[128]; snprintf(threadname, sizeof(threadname), "actor runner %d", i); - SDL_Thread *thread = SDL_CreateThread(crank_actor, threadname, NULL); + SDL_Thread *thread = SDL_CreateThread(actor_runner, threadname, NULL); arrput(runners, thread); } @@ -975,8 +964,10 @@ int main(int argc, char **argv) uint64_t to_ns = next_timeout_ns(); if (to_ns == UINT64_MAX) { - // No timers pending, wait indefinitely - pselect(0, NULL, NULL, NULL, NULL, NULL); + SDL_LockMutex(timer_mutex); + SDL_WaitCondition(timer_cond, timer_mutex); + SDL_UnlockMutex(timer_mutex); + continue; } else { struct timespec timeout = { .tv_sec = to_ns / 1000000000, @@ -1000,7 +991,7 @@ int actor_exists(const char *id) return 1; } -/*int JS_ArrayLength(JSContext *js, JSValue a) +int JS_ArrayLength(JSContext *js, JSValue a) { JSValue length = JS_GetPropertyStr(js, a, "length"); int len; @@ -1008,4 +999,3 @@ int actor_exists(const char *id) JS_FreeValue(js,length); return len; } -*/ \ No newline at end of file diff --git a/source/cell.h b/source/cell.h index 51148ae3..3888cee2 100644 --- a/source/cell.h +++ b/source/cell.h @@ -58,7 +58,7 @@ typedef struct cell_rt { /* Protects JSContext usage */ SDL_Mutex *mutex; /* for access to the JSContext */ - SDL_Mutex *msg_mutex; /* For messages queue only */ + SDL_Mutex *msg_mutex; /* For message queue and timers */ char *id; MTRand mrand; @@ -68,7 +68,6 @@ typedef struct cell_rt { /* The “mailbox” for incoming messages + a dedicated lock for it: */ struct letter *letters; - /* CHANGED FOR EVENTS: a separate lock for the actor->events queue */ struct { Uint32 key; JSValue value; } *timers; @@ -77,7 +76,6 @@ typedef struct cell_rt { double ar_secs; // time for unneeded JSValue unneeded; // fn to call before unneeded - int need_stop; int disrupt; int main_thread_only; @@ -99,8 +97,6 @@ Uint32 actor_timer_cb(cell_rt *actor, SDL_TimerID id, Uint32 interval); JSValue js_actor_delay(JSContext *js, JSValue self, int argc, JSValue *argv); JSValue js_actor_removetimer(JSContext *js, JSValue self, int argc, JSValue *argv); void script_startup(cell_rt *rt); -void script_evalf(JSContext *js, const char *format, ...); -JSValue script_eval(JSContext *js, const char *file, const char *script); int uncaught_exception(JSContext *js, JSValue v); int actor_exists(const char *id); cell_rt *get_actor(char *id); diff --git a/source/qjs_actor.c b/source/qjs_actor.c index 4d564c67..a9e5d712 100644 --- a/source/qjs_actor.c +++ b/source/qjs_actor.c @@ -139,12 +139,6 @@ JSC_CCALL(os_unneeded, SDL_UnlockMutex(actor->msg_mutex); ) -JSC_CCALL(os_destroy, - cell_rt *rt = JS_GetContextOpaque(js); - rt->need_stop = 1; - set_actor_state(rt); -) - JSC_CCALL(actor_disrupt, cell_rt *crt = JS_GetContextOpaque(js); actor_disrupt(crt); @@ -160,6 +154,12 @@ JSC_CCALL(actor_testfn, printf("actor? %p\n", crt); ) +JSC_CCALL(actor_on_exception, + cell_rt *rt = JS_GetContextOpaque(js); + JS_FreeValue(js, rt->on_exception); + rt->on_exception = JS_DupValue(js,argv[0]); +) + static const JSCFunctionListEntry js_actor_funcs[] = { MIST_FUNC_DEF(os, createactor, 1), MIST_FUNC_DEF(os, mailbox_push, 2), @@ -168,10 +168,10 @@ static const JSCFunctionListEntry js_actor_funcs[] = { MIST_FUNC_DEF(actor, removetimer, 1), MIST_FUNC_DEF(os, register_actor, 4), MIST_FUNC_DEF(os, unneeded, 2), - MIST_FUNC_DEF(os, destroy, 0), MIST_FUNC_DEF(actor, disrupt, 0), MIST_FUNC_DEF(actor, setname, 1), MIST_FUNC_DEF(actor, testfn, 1), + MIST_FUNC_DEF(actor, on_exception, 1), }; JSValue js_actor_use(JSContext *js) { diff --git a/source/qjs_fd.c b/source/qjs_fd.c index 0d1c9ff7..9e7ceebf 100644 --- a/source/qjs_fd.c +++ b/source/qjs_fd.c @@ -7,11 +7,9 @@ #include #include #include -#include #include #include #include -#include "wildmatch.h" // File descriptor wrapper structure typedef struct { diff --git a/source/qjs_os.c b/source/qjs_os.c index 8a3bdbcf..d5452f6d 100644 --- a/source/qjs_os.c +++ b/source/qjs_os.c @@ -28,7 +28,6 @@ #endif #endif -JSC_CCALL(os_exit, exit(js2number(js,argv[0]));) JSC_CCALL(os_now, return number2js(js, (double)SDL_GetTicksNS()/1000000000.0)) JSC_CCALL(os_sleep, @@ -169,12 +168,6 @@ static JSValue js_os_version(JSContext *js, JSValue self, int argc, JSValue *arg return ret; } -JSC_CCALL(os_on, - cell_rt *rt = JS_GetContextOpaque(js); - JS_FreeValue(js, rt->on_exception); - rt->on_exception = JS_DupValue(js,argv[0]); -) - JSC_CCALL(os_buffer2string, if (argc < 1) { return JS_ThrowTypeError(js, "buffer2string expects an ArrayBuffer"); @@ -289,10 +282,8 @@ static const JSCFunctionListEntry js_os_funcs[] = { MIST_FUNC_DEF(os, freemem, 0), MIST_FUNC_DEF(os, hostname, 0), MIST_FUNC_DEF(os, version, 0), - MIST_FUNC_DEF(os, exit, 1), MIST_FUNC_DEF(os, now, 0), MIST_FUNC_DEF(os, power_state, 0), - MIST_FUNC_DEF(os, on, 1), MIST_FUNC_DEF(os, rusage, 0), MIST_FUNC_DEF(os, mallinfo, 0), MIST_FUNC_DEF(os, buffer2string, 1), diff --git a/source/qjs_sdl_input.c b/source/qjs_sdl_input.c index 1e81eeb9..8f7d22d1 100644 --- a/source/qjs_sdl_input.c +++ b/source/qjs_sdl_input.c @@ -9,16 +9,6 @@ #include -void input_system_init(void) -{ - // No initialization needed for simplified system -} - -void input_system_cleanup(void) -{ - // No cleanup needed for simplified system -} - // Internal keymod function for input module static JSValue js_keymod(JSContext *js) { diff --git a/source/qjs_sdl_input.h b/source/qjs_sdl_input.h index d7eb749a..8eb369c1 100644 --- a/source/qjs_sdl_input.h +++ b/source/qjs_sdl_input.h @@ -2,14 +2,8 @@ #define QJS_SDL_INPUT_H #include -#include -// Initialization and cleanup functions -void input_system_init(void); -void input_system_cleanup(void); - -// Event conversion functions -const char* event_type_to_string(Uint32 event_type); +const char* event_type_to_string(uint32_t event_type); const char* mouse_button_to_string(int mouse); // JavaScript module entry point diff --git a/tests/delay.ce b/tests/delay.ce index c9784ef1..a33ba2bd 100644 --- a/tests/delay.ce +++ b/tests/delay.ce @@ -1,3 +1,4 @@ + var count = 0 function loop() { diff --git a/tests/modules.ce b/tests/modules.ce index e426702a..d9233532 100644 --- a/tests/modules.ce +++ b/tests/modules.ce @@ -2,6 +2,7 @@ var io = use('io') var shop = use('shop') +var time = use('time') log.console("=== Testing Module System ===") @@ -26,7 +27,7 @@ log.console("✓ TOML parser working") // Test 2: Shop initialization log.console("\n2. Testing shop initialization...") -var test_dir = "module_test_" + Date.now() +var test_dir = "module_test_" + time.number() io.mkdir(test_dir) var old_cwd = io.basedir()