From 60e61eef76431b193cf49a20a6b0a17d7005efcf Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Tue, 10 Feb 2026 08:12:42 -0600 Subject: [PATCH] scheduler starts --- source/cell.c | 68 +++++++++++++++++++++++++++++++++++++----- source/cell_internal.h | 1 + source/scheduler.c | 29 +++++++++++++----- 3 files changed, 83 insertions(+), 15 deletions(-) diff --git a/source/cell.c b/source/cell.c index ea659b11..788335e8 100644 --- a/source/cell.c +++ b/source/cell.c @@ -298,6 +298,8 @@ int cell_init(int argc, char **argv) if (!find_cell_shop()) return 1; + actor_initialize(); + size_t boot_size; int boot_is_bin = 1; char *boot_data = load_core_file(BOOTSTRAP_MACH, &boot_size); @@ -310,26 +312,54 @@ int cell_init(int argc, char **argv) return 1; } - JSRuntime *rt = JS_NewRuntime(); - if (!rt) { + g_runtime = JS_NewRuntime(); + if (!g_runtime) { printf("Failed to create JS runtime\n"); free(boot_data); return 1; } - JSContext *ctx = JS_NewContextWithHeapSize(rt, 16 * 1024 * 1024); + JSContext *ctx = JS_NewContextWithHeapSize(g_runtime, 16 * 1024 * 1024); if (!ctx) { printf("Failed to create JS context\n"); - free(boot_data); JS_FreeRuntime(rt); + free(boot_data); JS_FreeRuntime(g_runtime); return 1; } + /* Create a cell_rt for the CLI context so JS-C bridge functions work */ + cell_rt *cli_rt = calloc(sizeof(*cli_rt), 1); + cli_rt->mutex = malloc(sizeof(pthread_mutex_t)); + pthread_mutexattr_t mattr; + pthread_mutexattr_init(&mattr); + pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(cli_rt->mutex, &mattr); + cli_rt->msg_mutex = malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(cli_rt->msg_mutex, &mattr); + pthread_mutexattr_destroy(&mattr); + + cli_rt->context = ctx; + JS_SetContextOpaque(ctx, cli_rt); + JS_SetInterruptHandler(ctx, (JSInterruptHandler *)actor_interrupt_cb, cli_rt); + + JS_AddGCRef(ctx, &cli_rt->idx_buffer_ref); + JS_AddGCRef(ctx, &cli_rt->on_exception_ref); + JS_AddGCRef(ctx, &cli_rt->message_handle_ref); + JS_AddGCRef(ctx, &cli_rt->unneeded_ref); + JS_AddGCRef(ctx, &cli_rt->actor_sym_ref); + cli_rt->idx_buffer_ref.val = JS_NULL; + cli_rt->on_exception_ref.val = JS_NULL; + cli_rt->message_handle_ref.val = JS_NULL; + cli_rt->unneeded_ref.val = JS_NULL; + cli_rt->actor_sym_ref.val = JS_NewObject(ctx); + + root_cell = cli_rt; + JS_FreeValue(ctx, js_blob_use(ctx)); JSValue hidden_env = JS_NewObject(ctx); JS_SetPropertyStr(ctx, hidden_env, "os", js_os_use(ctx)); JS_SetPropertyStr(ctx, hidden_env, "core_path", JS_NewString(ctx, core_path)); JS_SetPropertyStr(ctx, hidden_env, "use_mcode", JS_NewBool(ctx, use_mcode)); - JS_SetPropertyStr(ctx, hidden_env, "actorsym", JS_NewObject(ctx)); + JS_SetPropertyStr(ctx, hidden_env, "actorsym", JS_DupValue(ctx, cli_rt->actor_sym_ref.val)); JS_SetPropertyStr(ctx, hidden_env, "json", js_json_use(ctx)); JS_SetPropertyStr(ctx, hidden_env, "nota", js_nota_use(ctx)); JS_SetPropertyStr(ctx, hidden_env, "wota", js_wota_use(ctx)); @@ -349,7 +379,7 @@ int cell_init(int argc, char **argv) } else { cJSON *ast = cJSON_Parse(boot_data); free(boot_data); - if (!ast) { printf("Failed to parse bootstrap AST\n"); JS_FreeContext(ctx); JS_FreeRuntime(rt); return 1; } + if (!ast) { printf("Failed to parse bootstrap AST\n"); JS_FreeContext(ctx); JS_FreeRuntime(g_runtime); return 1; } result = JS_RunMachTree(ctx, ast, hidden_env); cJSON_Delete(ast); } @@ -366,8 +396,32 @@ int cell_init(int argc, char **argv) } } + if (scheduler_actor_count() > 0) { + actor_loop(); + exit_handler(); + return exit_code; + } + + /* No actors spawned — clean up CLI context */ + JS_DeleteGCRef(ctx, &cli_rt->idx_buffer_ref); + JS_DeleteGCRef(ctx, &cli_rt->on_exception_ref); + JS_DeleteGCRef(ctx, &cli_rt->message_handle_ref); + JS_DeleteGCRef(ctx, &cli_rt->unneeded_ref); + JS_DeleteGCRef(ctx, &cli_rt->actor_sym_ref); + JS_SetInterruptHandler(ctx, NULL, NULL); + + pthread_mutex_destroy(cli_rt->mutex); + free(cli_rt->mutex); + pthread_mutex_destroy(cli_rt->msg_mutex); + free(cli_rt->msg_mutex); + free(cli_rt); + root_cell = NULL; + JS_FreeContext(ctx); - JS_FreeRuntime(rt); + JS_FreeRuntime(g_runtime); + g_runtime = NULL; + + exit_handler(); return exit_code; } diff --git a/source/cell_internal.h b/source/cell_internal.h index 21c39589..38733d74 100644 --- a/source/cell_internal.h +++ b/source/cell_internal.h @@ -81,6 +81,7 @@ int actor_interrupt_cb(JSRuntime *rt, cell_rt *crt); void actor_loop(); void actor_initialize(void); void actor_free(cell_rt *actor); +int scheduler_actor_count(void); uint64_t cell_ns(); void cell_sleep(double seconds); diff --git a/source/scheduler.c b/source/scheduler.c index f2361f55..df0ed40e 100644 --- a/source/scheduler.c +++ b/source/scheduler.c @@ -303,14 +303,29 @@ void actor_free(cell_rt *actor) free(actor); int actor_count = lockless_shlen(actors); - if (actor_count == 0) exit(0); + if (actor_count == 0) { + pthread_mutex_lock(&engine.lock); + engine.shutting_down = 1; + pthread_cond_broadcast(&engine.wake_cond); + pthread_cond_broadcast(&engine.timer_cond); + pthread_cond_broadcast(&engine.main_cond); + pthread_mutex_unlock(&engine.lock); + } +} + +int scheduler_actor_count(void) { + return (int)lockless_shlen(actors); } void exit_handler(void) { + static int already_exiting = 0; + if (already_exiting) return; + already_exiting = 1; + pthread_mutex_lock(&engine.lock); engine.shutting_down = 1; - pthread_cond_broadcast(&engine.wake_cond); - pthread_cond_broadcast(&engine.timer_cond); + pthread_cond_broadcast(&engine.wake_cond); + pthread_cond_broadcast(&engine.timer_cond); pthread_cond_broadcast(&engine.main_cond); pthread_mutex_unlock(&engine.lock); @@ -319,19 +334,17 @@ void exit_handler(void) { for (int i=0; i < engine.num_workers; i++) { pthread_join(engine.worker_threads[i], NULL); } - + free(engine.worker_threads); pthread_mutex_destroy(&engine.lock); pthread_cond_destroy(&engine.wake_cond); pthread_cond_destroy(&engine.timer_cond); pthread_cond_destroy(&engine.main_cond); - + pthread_mutex_destroy(actors_mutex); free(actors_mutex); - + arrfree(timer_heap); - - exit(0); } int actor_exists(const char *id)