From 13f824cb41889c122d08c3d123ba2d38f33183dd Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Sat, 12 Jul 2025 09:03:55 +0200 Subject: [PATCH] Start with init:boot/1 Signed-off-by: Paul Guyot --- libs/estdlib/src/init.erl | 12 ++++++ src/libAtomVM/defaultatoms.def | 2 + src/libAtomVM/globalcontext.c | 37 +++++++++++++++++++ src/libAtomVM/globalcontext.h | 21 +++++++++++ src/platforms/emscripten/src/main.c | 13 ++----- .../avm_sys/include/platform_defaultatoms.def | 1 - src/platforms/esp32/main/main.c | 11 +----- src/platforms/generic_unix/main.c | 13 +------ src/platforms/rp2/src/main.c | 17 +-------- src/platforms/stm32/src/main.c | 15 +------- tests/libs/estdlib/test_net_kernel.erl | 8 ---- 11 files changed, 83 insertions(+), 67 deletions(-) diff --git a/libs/estdlib/src/init.erl b/libs/estdlib/src/init.erl index 7af53158d..73a8031b3 100644 --- a/libs/estdlib/src/init.erl +++ b/libs/estdlib/src/init.erl @@ -28,11 +28,23 @@ -module(init). -export([ + boot/1, get_argument/1, get_plain_arguments/0, notify_when_started/1 ]). +%%----------------------------------------------------------------------------- +%% @param Args command line arguments +%% @doc Entry point. +%% @end +%%----------------------------------------------------------------------------- +-spec boot([binary() | atom()]) -> any(). +boot([<<"-s">>, StartupModule]) when is_atom(StartupModule) -> + % Until we have boot scripts, we just start kernel application. + {ok, _KernelPid} = kernel:start(boot, []), + StartupModule:start(). + %%----------------------------------------------------------------------------- %% @param Flag flag to get values for %% @return `error' if no value is associated with provided flag or values in diff --git a/src/libAtomVM/defaultatoms.def b/src/libAtomVM/defaultatoms.def index fa5150a07..410d50fc6 100644 --- a/src/libAtomVM/defaultatoms.def +++ b/src/libAtomVM/defaultatoms.def @@ -188,3 +188,5 @@ X(BREAK_IGNORED_ATOM, "\xD", "break_ignored") X(SCOPE_ATOM, "\x5", "scope") X(NOMATCH_ATOM, "\x7", "nomatch") + +X(INIT_ATOM, "\x4", "init") diff --git a/src/libAtomVM/globalcontext.c b/src/libAtomVM/globalcontext.c index 38d9ea858..c8ba7f561 100644 --- a/src/libAtomVM/globalcontext.c +++ b/src/libAtomVM/globalcontext.c @@ -719,3 +719,40 @@ Module *globalcontext_get_module_by_index(GlobalContext *global, int index) SMP_RWLOCK_UNLOCK(global->modules_lock); return result; } + +enum RunResult globalcontext_run(GlobalContext *glb, Module *startup_module) +{ + Context *ctx = context_new(glb); + ctx->leader = 1; + Module *init_module = globalcontext_get_module(glb, INIT_ATOM_INDEX); + if (IS_NULL_PTR(init_module)) { + context_execute_loop(ctx, startup_module, "start", 0); + } else { + if (UNLIKELY(memory_ensure_free(ctx, term_binary_heap_size(2) + LIST_SIZE(2, 0)) != MEMORY_GC_OK)) { + fprintf(stderr, "Unable to allocate arguments.\n"); + return RUN_MEMORY_FAILURE; + } + term s_opt = term_from_literal_binary("-s", 2, &ctx->heap, glb); + term list = term_list_prepend(module_get_name(startup_module), term_nil(), &ctx->heap); + ctx->x[0] = term_list_prepend(s_opt, list, &ctx->heap); + + context_execute_loop(ctx, init_module, "boot", 1); + } + + term ret_value = ctx->x[0]; + fprintf(stderr, "Return value: "); + term_display(stderr, ret_value, ctx); + fprintf(stderr, "\n"); + + enum RunResult result; + // ok or 0. 0 is required for running tests for emscripten + if (ret_value == OK_ATOM || ret_value == term_from_int(0)) { + result = RUN_SUCCESS; + } else { + result = RUN_RESULT_NOT_OK; + } + + context_destroy(ctx); + + return result; +} diff --git a/src/libAtomVM/globalcontext.h b/src/libAtomVM/globalcontext.h index 00113be93..b02089f4d 100644 --- a/src/libAtomVM/globalcontext.h +++ b/src/libAtomVM/globalcontext.h @@ -90,6 +90,13 @@ struct RefcBinaryQueueItem struct RefcBinary *refc; }; +enum RunResult +{ + RUN_SUCCESS = 0, + RUN_MEMORY_FAILURE = 1, + RUN_RESULT_NOT_OK = 2, +}; + struct GlobalContext { struct ListHead ready_processes; @@ -512,6 +519,20 @@ Module *globalcontext_get_module(GlobalContext *global, atom_index_t module_name */ Module *globalcontext_load_module_from_avm(GlobalContext *global, const char *module_name); +/** + * @brief Run a given start module. + * + * @details This function will create a new context and call init:boot/1 + * to execute the passed start module. If init module is not found, it will + * fallback to calling start module:start/0 directly. It will also + * print the result to stdout. It will return RUN_SUCCESS if result is ok, + * an error code otherwise. + * @param global the global context + * @param start_module the start module + * @returns RUN_SUCCESS or an error code + */ +enum RunResult globalcontext_run(GlobalContext *global, Module *start_module); + #ifndef __cplusplus static inline uint64_t globalcontext_get_ref_ticks(GlobalContext *global) { diff --git a/src/platforms/emscripten/src/main.c b/src/platforms/emscripten/src/main.c index 3ecd15b00..e86dcb39d 100644 --- a/src/platforms/emscripten/src/main.c +++ b/src/platforms/emscripten/src/main.c @@ -95,23 +95,16 @@ static int start(void) fprintf(stderr, "main module not loaded\n"); return EXIT_FAILURE; } - Context *ctx = context_new(global); - ctx->leader = 1; - context_execute_loop(ctx, main_module, "start", 0); - term ret_value = ctx->x[0]; - fprintf(stdout, "Return value: "); - term_display(stdout, ret_value, ctx); - fprintf(stdout, "\n"); + + enum RunResult ret_value = globalcontext_run(global, main_module); int status; - if (ret_value == OK_ATOM || ret_value == term_from_int(0)) { + if (ret_value == RUN_SUCCESS) { status = EXIT_SUCCESS; } else { status = EXIT_FAILURE; } - context_destroy(ctx); - return status; } diff --git a/src/platforms/esp32/components/avm_sys/include/platform_defaultatoms.def b/src/platforms/esp32/components/avm_sys/include/platform_defaultatoms.def index c96024d50..a5dd2c768 100644 --- a/src/platforms/esp32/components/avm_sys/include/platform_defaultatoms.def +++ b/src/platforms/esp32/components/avm_sys/include/platform_defaultatoms.def @@ -49,7 +49,6 @@ X(BACKLOG_ATOM, "\x7", "backlog") X(ACCEPT_ATOM, "\x6", "accept") X(FD_ATOM, "\x2", "fd") -X(INIT_ATOM, "\x4", "init") X(GET_PORT_ATOM, "\x8", "get_port") X(SOCKNAME_ATOM, "\x8", "sockname") X(PEERNAME_ATOM, "\x8", "peername") diff --git a/src/platforms/esp32/main/main.c b/src/platforms/esp32/main/main.c index fd9f665aa..8a3daaddf 100644 --- a/src/platforms/esp32/main/main.c +++ b/src/platforms/esp32/main/main.c @@ -119,18 +119,11 @@ void app_main() AVM_ABORT(); } globalcontext_insert_module(glb, mod); - Context *ctx = context_new(glb); - ctx->leader = 1; ESP_LOGI(TAG, "Starting %s...", startup_module_name); fprintf(stdout, "---\n"); - context_execute_loop(ctx, mod, "start", 0); - term ret_value = ctx->x[0]; - - fprintf(stdout, "AtomVM finished with return value: "); - term_display(stdout, ret_value, ctx); - fprintf(stdout, "\n"); + enum RunResult result = globalcontext_run(glb, mod); bool reboot_on_not_ok = #if defined(CONFIG_REBOOT_ON_NOT_OK) @@ -138,7 +131,7 @@ void app_main() #else false; #endif - if (reboot_on_not_ok && ret_value != OK_ATOM) { + if (reboot_on_not_ok && result != RUN_SUCCESS) { ESP_LOGE(TAG, "AtomVM application terminated with non-ok return value. Rebooting ..."); esp_restart(); } else { diff --git a/src/platforms/generic_unix/main.c b/src/platforms/generic_unix/main.c index f2c96f53f..eb35f6794 100644 --- a/src/platforms/generic_unix/main.c +++ b/src/platforms/generic_unix/main.c @@ -146,24 +146,15 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - Context *ctx = context_new(glb); - ctx->leader = 1; - - context_execute_loop(ctx, startup_module, "start", 0); - - term ret_value = ctx->x[0]; - fprintf(stderr, "Return value: "); - term_display(stderr, ret_value, ctx); - fprintf(stderr, "\n"); + enum RunResult result = globalcontext_run(glb, startup_module); int status; - if (ret_value == OK_ATOM) { + if (result == RUN_SUCCESS) { status = EXIT_SUCCESS; } else { status = EXIT_FAILURE; } - context_destroy(ctx); globalcontext_destroy(glb); return status; diff --git a/src/platforms/rp2/src/main.c b/src/platforms/rp2/src/main.c index 8ac8639c7..8bd90515b 100644 --- a/src/platforms/rp2/src/main.c +++ b/src/platforms/rp2/src/main.c @@ -132,26 +132,13 @@ static int app_main() globalcontext_insert_module(glb, mod); mod->module_platform_data = NULL; - Context *ctx = context_new(glb); - ctx->leader = 1; - fprintf(stderr, "Starting %s...", startup_module_name); - fprintf(stdout, "---\n"); - - context_execute_loop(ctx, mod, "start", 0); - term ret_value = ctx->x[0]; - - fprintf(stdout, "AtomVM finished with return value: "); - term_display(stdout, ret_value, ctx); - fprintf(stdout, "\n"); - int result = ret_value != OK_ATOM; - - context_destroy(ctx); + enum RunResult result = globalcontext_run(glb, mod); nif_collection_destroy_all(glb); globalcontext_destroy(glb); - return result; + return (int) result; } static void exit_handler(bool reboot) diff --git a/src/platforms/stm32/src/main.c b/src/platforms/stm32/src/main.c index a57f4c1a7..ef79457b2 100644 --- a/src/platforms/stm32/src/main.c +++ b/src/platforms/stm32/src/main.c @@ -267,22 +267,11 @@ int main() Module *mod = module_new_from_iff_binary(glb, startup_beam, startup_beam_size); globalcontext_insert_module(glb, mod); - Context *ctx = context_new(glb); - ctx->leader = 1; AVM_LOGI(TAG, "Starting: %s...\n", startup_module_name); fprintf(stdout, "---\n"); - context_execute_loop(ctx, mod, "start", 0); - - term ret_value = ctx->x[0]; - char *ret_atom_string = interop_atom_to_string(ctx, ret_value); - if (ret_atom_string != NULL) { - AVM_LOGI(TAG, "Exited with return: %s", ret_atom_string); - } else { - AVM_LOGI(TAG, "Exited with return value: %lx", (long) term_to_int32(ret_value)); - } - free(ret_atom_string); + enum RunResult result = globalcontext_run(glb, mod); bool reboot_on_not_ok = #if defined(CONFIG_REBOOT_ON_NOT_OK) @@ -290,7 +279,7 @@ int main() #else false; #endif - if (reboot_on_not_ok && ret_value != OK_ATOM) { + if (reboot_on_not_ok && result != RUN_SUCCESS) { AVM_LOGE(TAG, "AtomVM application terminated with non-ok return value. Rebooting ..."); scb_reset_system(); } else { diff --git a/tests/libs/estdlib/test_net_kernel.erl b/tests/libs/estdlib/test_net_kernel.erl index 833878b50..3314096f0 100644 --- a/tests/libs/estdlib/test_net_kernel.erl +++ b/tests/libs/estdlib/test_net_kernel.erl @@ -30,7 +30,6 @@ test() -> case has_compatible_erl(Platform) andalso has_epmd(Platform) of true -> ok = ensure_epmd(Platform), - ok = setup(Platform), ok = test_ping_from_beam(Platform), ok = test_fail_with_wrong_cookie(Platform), ok = test_rpc_from_beam(Platform), @@ -459,13 +458,6 @@ test_is_alive(Platform) -> false = is_alive(), ok. -% On AtomVM, we need to start kernel. -setup("BEAM") -> - ok; -setup("ATOM") -> - {ok, _KernelPid} = kernel:start(normal, []), - ok. - execute_command("BEAM", Command) -> os:cmd(Command); execute_command("ATOM", Command) ->