From 1032aac60b351cc5e99a92ffda8159a5b43c5bf9 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Thu, 24 Nov 2022 21:26:18 +0900 Subject: [PATCH] Add wasm_runtime_get_wasi_exit_code (#1748) Refer to https://github.com/bytecodealliance/wasm-micro-runtime/issues/1738 --- core/iwasm/common/wasm_runtime_common.c | 20 +++++++---- core/iwasm/common/wasm_runtime_common.h | 10 +++++- core/iwasm/include/wasm_export.h | 12 +++++++ .../libc-uvwasi/libc_uvwasi_wrapper.c | 20 +++++++++-- .../libraries/libc-wasi/libc_wasi_wrapper.c | 3 ++ product-mini/platforms/posix/main.c | 33 ++++++++++++++----- product-mini/platforms/windows/main.c | 33 ++++++++++++++----- 7 files changed, 103 insertions(+), 28 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 0cbaaf5c..a6e552e9 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2675,17 +2675,18 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, char *argv[], uint32 argc, int stdinfd, int stdoutfd, int stderrfd, char *error_buf, uint32 error_buf_size) { - uvwasi_t *uvwasi = NULL; + WASIContext *ctx; + uvwasi_t *uvwasi; uvwasi_options_t init_options; const char **envp = NULL; uint64 total_size; uint32 i; bool ret = false; - uvwasi = runtime_malloc(sizeof(uvwasi_t), module_inst, error_buf, - error_buf_size); - if (!uvwasi) + ctx = runtime_malloc(sizeof(*ctx), module_inst, error_buf, error_buf_size); + if (!ctx) return false; + uvwasi = &ctx->uvwasi; /* Setup the initialization options */ uvwasi_options_init(&init_options); @@ -2733,7 +2734,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, goto fail; } - wasm_runtime_set_wasi_ctx(module_inst, uvwasi); + wasm_runtime_set_wasi_ctx(module_inst, ctx); ret = true; @@ -2863,12 +2864,19 @@ wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); if (wasi_ctx) { - uvwasi_destroy(wasi_ctx); + uvwasi_destroy(&wasi_ctx->uvwasi); wasm_runtime_free(wasi_ctx); } } #endif +uint32_t +wasm_runtime_get_wasi_exit_code(WASMModuleInstanceCommon *module_inst) +{ + WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); + return wasi_ctx->exit_code; +} + WASIContext * wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst_comm) { diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 418d4352..bcfa05cb 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -369,9 +369,13 @@ typedef struct WASIContext { char **argv_list; char *env_buf; char **env_list; + uint32_t exit_code; } WASIContext; #else -typedef uvwasi_t WASIContext; +typedef struct WASIContext { + uvwasi_t uvwasi; + uint32_t exit_code; +} WASIContext; #endif #endif @@ -768,6 +772,10 @@ wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst); WASM_RUNTIME_API_EXTERN WASMFunctionInstanceCommon * wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32_t +wasm_runtime_get_wasi_exit_code(WASMModuleInstanceCommon *module_inst); + bool wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *dir_list[], uint32 dir_count, diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index a8aa1611..182c5753 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -450,6 +450,18 @@ wasm_runtime_is_wasi_mode(wasm_module_inst_t module_inst); WASM_RUNTIME_API_EXTERN wasm_function_inst_t wasm_runtime_lookup_wasi_start_function(wasm_module_inst_t module_inst); +/** + * Get WASI exit code. + * + * After a WASI command completed its execution, an embedder can + * call this function to get its exit code. (that is, the value given + * to proc_exit.) + * + * @param module_inst the module instance + */ +WASM_RUNTIME_API_EXTERN uint32_t +wasm_runtime_get_wasi_exit_code(wasm_module_inst_t module_inst); + /** * Lookup an exported function in the WASM module instance. * diff --git a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c index 187693ea..504ff7f9 100644 --- a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c +++ b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c @@ -11,9 +11,6 @@ #define get_module_inst(exec_env) \ wasm_runtime_get_module_inst(exec_env) -#define get_wasi_ctx(module_inst) \ - wasm_runtime_get_wasi_ctx(module_inst) - #define validate_app_addr(offset, size) \ wasm_runtime_validate_app_addr(module_inst, offset, size) @@ -72,9 +69,24 @@ typedef struct iovec_app { uint32 buf_len; } iovec_app_t; +typedef struct WASIContext { + uvwasi_t uvwasi; + uint32_t exit_code; +} WASIContext; + void * wasm_runtime_get_wasi_ctx(wasm_module_inst_t module_inst); +static uvwasi_t * +get_wasi_ctx(wasm_module_inst_t module_inst) +{ + WASIContext *ctx = wasm_runtime_get_wasi_ctx(module_inst); + if (ctx == NULL) { + return NULL; + } + return &ctx->uvwasi; +} + static wasi_errno_t wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf) { @@ -924,10 +936,12 @@ static void wasi_proc_exit(wasm_exec_env_t exec_env, wasi_exitcode_t rval) { wasm_module_inst_t module_inst = get_module_inst(exec_env); + WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); /* Here throwing exception is just to let wasm app exit, the upper layer should clear the exception and return as normal */ wasm_runtime_set_exception(module_inst, "wasi proc exit"); + wasi_ctx->exit_code = rval; } static wasi_errno_t diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index d9eea055..a6a448b5 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -57,6 +57,7 @@ typedef struct WASIContext { char **argv_list; char *env_buf; char **env_list; + uint32_t exit_code; } * wasi_ctx_t; wasi_ctx_t @@ -980,10 +981,12 @@ static void wasi_proc_exit(wasm_exec_env_t exec_env, wasi_exitcode_t rval) { wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); /* Here throwing exception is just to let wasm app exit, the upper layer should clear the exception and return as normal */ wasm_runtime_set_exception(module_inst, "wasi proc exit"); + wasi_ctx->exit_code = rval; } static wasi_errno_t diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index e58bbf3d..147e7386 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -86,7 +86,7 @@ app_instance_main(wasm_module_inst_t module_inst) wasm_application_execute_main(module_inst, app_argc, app_argv); if ((exception = wasm_runtime_get_exception(module_inst))) printf("%s\n", exception); - return NULL; + return exception; } static void * @@ -96,7 +96,7 @@ app_instance_func(wasm_module_inst_t module_inst, const char *func_name) app_argv + 1); /* The result of wasm function or exception info was output inside wasm_application_execute_func(), here we don't output them again. */ - return NULL; + return wasm_runtime_get_exception(module_inst); } /** @@ -643,14 +643,29 @@ main(int argc, char *argv[]) } #endif - if (is_repl_mode) - app_instance_repl(wasm_module_inst); - else if (func_name) - app_instance_func(wasm_module_inst, func_name); - else - app_instance_main(wasm_module_inst); - ret = 0; + if (is_repl_mode) { + app_instance_repl(wasm_module_inst); + } + else if (func_name) { + if (app_instance_func(wasm_module_inst, func_name)) { + /* got an exception */ + ret = 1; + } + } + else { + if (app_instance_main(wasm_module_inst)) { + /* got an exception */ + ret = 1; + } + } + +#if WASM_ENABLE_LIBC_WASI != 0 + if (ret == 0) { + /* propagate wasi exit code. */ + ret = wasm_runtime_get_wasi_exit_code(wasm_module_inst); + } +#endif #if WASM_ENABLE_DEBUG_INTERP != 0 fail4: diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index 1042763d..8b1d6057 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -63,7 +63,7 @@ app_instance_main(wasm_module_inst_t module_inst) wasm_application_execute_main(module_inst, app_argc, app_argv); if ((exception = wasm_runtime_get_exception(module_inst))) printf("%s\n", exception); - return NULL; + return exception; } static void * @@ -73,7 +73,7 @@ app_instance_func(wasm_module_inst_t module_inst, const char *func_name) app_argv + 1); /* The result of wasm function or exception info was output inside wasm_application_execute_func(), here we don't output them again. */ - return NULL; + return wasm_runtime_get_exception(module_inst); } /** @@ -451,14 +451,29 @@ main(int argc, char *argv[]) } #endif - if (is_repl_mode) - app_instance_repl(wasm_module_inst); - else if (func_name) - app_instance_func(wasm_module_inst, func_name); - else - app_instance_main(wasm_module_inst); - ret = 0; + if (is_repl_mode) { + app_instance_repl(wasm_module_inst); + } + else if (func_name) { + if (app_instance_func(wasm_module_inst, func_name)) { + /* got an exception */ + ret = 1; + } + } + else { + if (app_instance_main(wasm_module_inst)) { + /* got an exception */ + ret = 1; + } + } + +#if WASM_ENABLE_LIBC_WASI != 0 + if (ret == 0) { + /* propagate wasi exit code. */ + ret = wasm_runtime_get_wasi_exit_code(wasm_module_inst); + } +#endif #if WASM_ENABLE_DEBUG_INTERP != 0 fail4: