[RFC][Draft] Separate the runtime context within runtime instances. #4035
Description
Background
The primary purpose of this feature is to prevent the use of global variables in the C language for storing runtime arguments and context.
This requirement has emerged from several embedded platforms where there is no POSIX-like process isolation. On these platforms, when multiple tasks or threads execute wasm_runtime_full_init()
with various RuntimeInitArgs
, such as using different MemAllocOption
to execute different allocation strategies, conflicts arise. This is because the incoming RuntimeInitArgs
are stored in global variables, which are actually shared among tasks or threads.
All tasks and threads are required to share the same runtime configuration. This encompasses a range of settings, including but not limited to: memory allocation strategy, running mode, gc heap size, JIT policy, WASI context, registered native functions, logging levels, error information, and more. This is not the solution that many products anticipate.
Design choice
let's refer to the outcome of wasm_runtime_full_init()
as a runtime instance,
Smallest unit
The first question we need to address is whether we allow multiple runtime instances within a single task or thread. In other words, what is the smallest execution unit for a runtime instance? The concept of "nanoprocesses" comes to mind. If tasks or threads are the smallest unit, then Thread Local Storage (TLS) might be an option for storing the runtime context. However, if we agree that the smallest unit is smaller than a task or thread, or if it should not be tied to the current process/task/thread concepts(may let embedding decide), then creating a new runtime instance structure becomes necessary.
Global variables
Examine the global variables within the libvm.so library carefully. $ readelf -s --wide --demangle libvmlib.a | grep OBJECT
.
LLVM ORC JIT
The LLVM environment should be initialized just once per process. It is permissible to create multiple LLJIT instances for different target machines. Each LLJIT instance can include multiple passes with varying optimization levels and size requirements for the generated binary. Every LLJIT instance possesses its own thread-safe module to house jitted functions and its own JITDyLib to manage symbols, which helps prevent symbols from being accessed unexpectedly. Thus, it appears to be acceptable for each runtime instance to create its own LLJIT instances, generate jitted code, and execute it.
The remaining issue to address is the potential consequences of calling LLVMInitializeXXX()
multiple times within a single process.
ASM JIT
to be continued
Consts
Some global variables are used as .rodata and can be shared across multiple runtime-instances. Below is a brief list of such variables:
aot_stack_xxx
handle_table
in interpretersinvokeNative_XXX
exception_msgs
for conversion from exception ids to stringsMEMORY_PAGE_SIZE
andwasm_limits_max_default
in wasm_c_api.hquick_aot_entries
native_symbols_xxx
andnative_globals_xxx
valid_xxx
,bit_cnt_llvm_intrinsic
,block_name_xxx
,target_sym_map
,g_intrinsic_xxx
,section_ids
for aot and llvm jit- more
Variables
Other global variables should be converted into field members of a runtime instance and will be utilized in various ways across multiple runtime instances.
aot_error
g_shared_memory_lock
,wait_map
for shared-memory featureexternref_xxx
for externref recordingreader
,destroyer
,register_module_xxx
,loading_module_xxx
for multi-module feature.
It appears correct that all runtime instances share the content of loaded module files(untouch) while maintaining their own linking resources (instances).runtime_ref_count
,runtime_lock
. These are utilized to create a singleton runtime instance, which may no longer be necessary. Plussingleton_engine
andengine_lock
in wasm_c_api.cruntime_running_mode
llvm_jit_options
jit_options
for fast-jitg_context_dtors
,g_wasi_context_keys
g_native_symbols_list
global_pool_size
,free_fuc
,realloc_func
,malloc_func
,enlarge_memory_error_used_data
,enlarge_memory_error_cb
,pool_allocator
,memory_mode
from wasm_memory.total_time_ms
,last_time_ms
,log_verbose_level
from bh_logprev_sig_act_XXX
from pthread_managerg_blocking_op_xxx
from posix_blocking_opsRuntimeInitArgs
- more