Skip to content

Commit

Permalink
Refactor interrupting blocking threads (#1948)
Browse files Browse the repository at this point in the history
- Disable the feature by default, use `cmake -DWAMR_BUILD_INTERRUPT_BLOCK_INSN` to enable it
- Reuse the original signal handler
- Move kill threads to be after notifying atomic waiting threads
- Add os_thread_set_interruptible to control whether a thread can be interrupted
- Fix some issues and refine the code
  • Loading branch information
wenyongh authored Feb 13, 2023
1 parent 753712f commit ed98d88
Show file tree
Hide file tree
Showing 17 changed files with 373 additions and 175 deletions.
6 changes: 3 additions & 3 deletions build-scripts/config_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,9 @@ else ()
add_definitions (-DWASM_DISABLE_STACK_HW_BOUND_CHECK=0)
endif ()
endif ()
if (WAMR_DISABLE_BLOCK_INSN_INTERRUPT EQUAL 1)
add_definitions (-DWASM_DISABLE_BLOCK_INSN_INTERRUPT=1)
message (" Interruption of blocking instructions disabled")
if (WAMR_BUILD_INTERRUPT_BLOCK_INSN EQUAL 1)
add_definitions (-DWASM_ENABLE_INTERRUPT_BLOCK_INSN=1)
message (" Interruption of blocking instructions enabled")
endif ()
if (WAMR_BUILD_SIMD EQUAL 1)
if (NOT WAMR_BUILD_TARGET MATCHES "RISCV64.*")
Expand Down
6 changes: 3 additions & 3 deletions core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,11 @@
#define WASM_DISABLE_STACK_HW_BOUND_CHECK 0
#endif

/* Disable the capability of interrupting blocking instructions
/* Enable the capability of interrupting blocking instructions
* (e.g. atomic.wait, sleep) when an exception (e.g. trap, proc_exit) is raised
*/
#ifndef WASM_DISABLE_BLOCK_INSN_INTERRUPT
#define WASM_DISABLE_BLOCK_INSN_INTERRUPT 0
#ifndef WASM_ENABLE_INTERRUPT_BLOCK_INSN
#define WASM_ENABLE_INTERRUPT_BLOCK_INSN 0
#endif

/* Disable SIMD unless it is manualy enabled somewhere */
Expand Down
40 changes: 32 additions & 8 deletions core/iwasm/aot/aot_runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -1276,10 +1276,16 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
return false;
}

#ifdef OS_ENABLE_INTERRUPT_BLOCK_INSN
exec_env->canjump = 0;
#endif
wasm_exec_env_push_jmpbuf(exec_env, &jmpbuf_node);

wasm_runtime_set_exec_env_tls(exec_env);

if (os_setjmp(jmpbuf_node.jmpbuf) == 0) {
#ifdef OS_ENABLE_INTERRUPT_BLOCK_INSN
exec_env->canjump = 1;
#endif
/* Quick call with func_ptr if the function signature is simple */
if (!signature && param_count == 1 && types[0] == VALUE_TYPE_I32) {
if (result_count == 0) {
Expand Down Expand Up @@ -1321,6 +1327,10 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
ret = false;
}

#ifdef OS_ENABLE_INTERRUPT_BLOCK_INSN
exec_env->canjump = 0;
#endif

jmpbuf_node_pop = wasm_exec_env_pop_jmpbuf(exec_env);
bh_assert(&jmpbuf_node == jmpbuf_node_pop);
if (!exec_env->jmpbuf_stack_top) {
Expand All @@ -1330,20 +1340,24 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
os_sigreturn();
os_signal_unmask();
}

#ifdef OS_ENABLE_INTERRUPT_BLOCK_INSN
exec_env->canjump = 1;
#endif
(void)jmpbuf_node_pop;
return ret;
}
#endif /* end of OS_ENABLE_HW_BOUND_CHECK */

#ifndef OS_ENABLE_BLOCK_INSN_INTERRUPT
#ifndef OS_ENABLE_INTERRUPT_BLOCK_INSN

#ifdef OS_ENABLE_HW_BOUND_CHECK
#define invoke_native_internal invoke_native_with_hw_bound_check
#else
#define invoke_native_internal wasm_runtime_invoke_native
#endif

#else /* else of OS_ENABLE_BLOCK_INSN_INTERRUPT */
#else /* else of OS_ENABLE_INTERRUPT_BLOCK_INSN */

#ifdef OS_ENABLE_HW_BOUND_CHECK
#define invoke_native_block_insn_interrupt invoke_native_with_hw_bound_check
Expand All @@ -1357,29 +1371,39 @@ invoke_native_internal(WASMExecEnv *exec_env, void *func_ptr,
void *attachment, uint32 *argv, uint32 argc,
uint32 *argv_ret)
{
int ret = false;
bool ret;
WASMJmpBuf jmpbuf_node = { 0 }, *jmpbuf_node_pop;

exec_env->canjump = 0;
wasm_exec_env_push_jmpbuf(exec_env, &jmpbuf_node);
wasm_runtime_set_exec_env_tls(exec_env);

if (os_setjmp(jmpbuf_node.jmpbuf) == 0) {
wasm_exec_env_push_jmpbuf(exec_env, &jmpbuf_node);
exec_env->canjump = 1;
ret = invoke_native_block_insn_interrupt(exec_env, func_ptr, func_type,
signature, attachment, argv,
argc, argv_ret);
}
else {
/* Exception has been set in signal handler before calling longjmp */
ret = false;
}

exec_env->canjump = 0;
jmpbuf_node_pop = wasm_exec_env_pop_jmpbuf(exec_env);
bh_assert(&jmpbuf_node == jmpbuf_node_pop);
if (!exec_env->jmpbuf_stack_top) {
wasm_runtime_set_exec_env_tls(NULL);
}

if (!ret) {
os_sigreturn();
os_signal_unmask();
}
exec_env->canjump = 1;
(void)jmpbuf_node_pop;
return ret;
}
#endif /* end of OS_ENABLE_BLOCK_INSN_INTERRUPT */
#endif /* end of OS_ENABLE_INTERRUPT_BLOCK_INSN */

bool
aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
Expand Down Expand Up @@ -1536,7 +1560,7 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst,
WASMExecEnv *exec_env = NULL, *existing_exec_env = NULL;
bool ret;

#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_BLOCK_INSN_INTERRUPT)
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
existing_exec_env = exec_env = wasm_runtime_get_exec_env_tls();
#elif WASM_ENABLE_THREAD_MGR != 0
existing_exec_env = exec_env =
Expand Down
2 changes: 1 addition & 1 deletion core/iwasm/common/wasm_exec_env.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg)
}
#endif

#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_BLOCK_INSN_INTERRUPT)
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
void
wasm_exec_env_push_jmpbuf(WASMExecEnv *exec_env, WASMJmpBuf *jmpbuf)
{
Expand Down
12 changes: 9 additions & 3 deletions core/iwasm/common/wasm_exec_env.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ typedef struct WASMCurrentEnvStatus WASMCurrentEnvStatus;
#endif
#endif

#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_BLOCK_INSN_INTERRUPT)
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
typedef struct WASMJmpBuf {
struct WASMJmpBuf *prev;
korp_jmpbuf jmpbuf;
Expand Down Expand Up @@ -120,6 +120,12 @@ typedef struct WASMExecEnv {

/* whether current thread is detached */
bool thread_is_detached;

#ifdef OS_ENABLE_INTERRUPT_BLOCK_INSN
/* Whether the signal handler of interrupting blocking instruction
feature can longjmp to the place of setjmp */
volatile sig_atomic_t canjump;
#endif
#endif

#if WASM_ENABLE_DEBUG_INTERP != 0
Expand All @@ -141,7 +147,7 @@ typedef struct WASMExecEnv {
BlockAddr block_addr_cache[BLOCK_ADDR_CACHE_SIZE][BLOCK_ADDR_CONFLICT_SIZE];
#endif

#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_BLOCK_INSN_INTERRUPT)
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
WASMJmpBuf *jmpbuf_stack_top;
#endif
#ifdef OS_ENABLE_HW_BOUND_CHECK
Expand Down Expand Up @@ -303,7 +309,7 @@ void
wasm_exec_env_set_thread_arg(WASMExecEnv *exec_env, void *thread_arg);
#endif

#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_BLOCK_INSN_INTERRUPT)
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
void
wasm_exec_env_push_jmpbuf(WASMExecEnv *exec_env, WASMJmpBuf *jmpbuf);

Expand Down
88 changes: 52 additions & 36 deletions core/iwasm/common/wasm_runtime_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,17 @@ static LLVMJITOptions llvm_jit_options = { 3, 3 };

static RunningMode runtime_running_mode = Mode_Default;

#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_BLOCK_INSN_INTERRUPT)
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
/* The exec_env of thread local storage, set before calling function
and used in signal handler, as we cannot get it from the argument
of signal handler */
static os_thread_local_attribute WASMExecEnv *exec_env_tls = NULL;
#endif

#ifdef OS_ENABLE_HW_BOUND_CHECK
#ifndef BH_PLATFORM_WINDOWS

#ifdef OS_ENABLE_HW_BOUND_CHECK
static void
runtime_signal_handler(void *sig_addr)
hw_bound_check_sig_handler(void *sig_addr)
{
WASMModuleInstance *module_inst;
WASMMemoryInstance *memory_inst;
Expand Down Expand Up @@ -200,7 +200,38 @@ runtime_signal_handler(void *sig_addr)
}
}
}
#else
#endif /* end of OS_ENABLE_HW_BOUND_CHECK */

#ifdef OS_ENABLE_INTERRUPT_BLOCK_INSN
static void
interrupt_block_insn_sig_handler()
{
WASMJmpBuf *jmpbuf_node;

/* Check whether current thread is running wasm function */
if (exec_env_tls && exec_env_tls->handle == os_self_thread()
&& exec_env_tls->canjump
&& (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) {
os_longjmp(jmpbuf_node->jmpbuf, 1);
}
}
#endif /* end of OS_ENABLE_INTERRUPT_BLOCK_INSN */

static void
runtime_signal_handler(int sig, void *sig_addr)
{
#ifdef OS_ENABLE_HW_BOUND_CHECK
if (sig == OS_SIGSEGV || sig == OS_SIGBUS)
hw_bound_check_sig_handler(sig_addr);
#endif
#ifdef OS_ENABLE_INTERRUPT_BLOCK_INSN
if (sig == OS_SIGUSR1)
interrupt_block_insn_sig_handler();
#endif
}

#else /* else if BH_PLATFORM_WINDOWS */

static LONG
runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
{
Expand Down Expand Up @@ -284,6 +315,7 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
sig_addr);
return EXCEPTION_CONTINUE_SEARCH;
}

#endif /* end of BH_PLATFORM_WINDOWS */

static bool
Expand Down Expand Up @@ -311,9 +343,7 @@ runtime_signal_destroy()
#endif
os_thread_signal_destroy();
}
#endif /* end of OS_ENABLE_HW_BOUND_CHECK */

#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_BLOCK_INSN_INTERRUPT)
void
wasm_runtime_set_exec_env_tls(WASMExecEnv *exec_env)
{
Expand All @@ -325,20 +355,8 @@ wasm_runtime_get_exec_env_tls()
{
return exec_env_tls;
}
#endif

#ifdef OS_ENABLE_BLOCK_INSN_INTERRUPT
static void
interrupt_block_insn_sig_handler()
{
WASMJmpBuf *jmpbuf_node = exec_env_tls->jmpbuf_stack_top;
if (!jmpbuf_node) {
return;
}

os_longjmp(jmpbuf_node->jmpbuf, 1);
}
#endif /* OS_ENABLE_BLOCK_INSN_INTERRUPT */
#endif /* end of defined(OS_ENABLE_HW_BOUND_CHECK) || \
defined(OS_ENABLE_INTERRUPT_BLOCK_INSN) */

static bool
wasm_runtime_env_init()
Expand Down Expand Up @@ -371,12 +389,7 @@ wasm_runtime_env_init()
goto fail5;
}
#endif
#ifdef OS_ENABLE_BLOCK_INSN_INTERRUPT
if (!os_interrupt_block_insn_init(interrupt_block_insn_sig_handler)) {
goto fail6;
}
#endif
#ifdef OS_ENABLE_HW_BOUND_CHECK
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
if (!runtime_signal_init()) {
goto fail6;
}
Expand Down Expand Up @@ -431,10 +444,8 @@ wasm_runtime_env_init()
fail7:
#endif
#endif
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_BLOCK_INSN_INTERRUPT)
#ifdef OS_ENABLE_HW_BOUND_CHECK
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
runtime_signal_destroy();
#endif
fail6:
#endif
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_THREAD_MGR != 0)
Expand Down Expand Up @@ -494,7 +505,7 @@ wasm_runtime_destroy()
#endif
#endif

#ifdef OS_ENABLE_HW_BOUND_CHECK
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
runtime_signal_destroy();
#endif

Expand Down Expand Up @@ -1333,7 +1344,7 @@ wasm_runtime_init_thread_env(void)
return false;
#endif

#ifdef OS_ENABLE_HW_BOUND_CHECK
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
if (!runtime_signal_init()) {
#ifdef BH_PLATFORM_WINDOWS
os_thread_env_destroy();
Expand All @@ -1348,7 +1359,7 @@ wasm_runtime_init_thread_env(void)
void
wasm_runtime_destroy_thread_env(void)
{
#ifdef OS_ENABLE_HW_BOUND_CHECK
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
runtime_signal_destroy();
#endif

Expand All @@ -1365,11 +1376,9 @@ wasm_runtime_thread_env_inited(void)
return false;
#endif

#if WASM_ENABLE_AOT != 0
#ifdef OS_ENABLE_HW_BOUND_CHECK
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
if (!os_thread_signal_inited())
return false;
#endif
#endif
return true;
}
Expand Down Expand Up @@ -2346,6 +2355,13 @@ wasm_set_exception(WASMModuleInstance *module_inst, const char *exception)
(WASMModuleInstanceCommon *)module_inst);
}
#endif
#ifdef OS_ENABLE_INTERRUPT_BLOCK_INSN
if (exec_env) {
/* Kill the blocking threads after exception was spreaded and
atomic waiting nodes were notified */
wasm_cluster_kill_all_except_self(exec_env->cluster, exec_env);
}
#endif
#else
(void)exec_env;
#endif
Expand Down
2 changes: 1 addition & 1 deletion core/iwasm/common/wasm_runtime_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ typedef struct WASMSignalInfo {
} WASMSignalInfo;
#endif

#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_BLOCK_INSN_INTERRUPT)
#if defined(OS_ENABLE_HW_BOUND_CHECK) || defined(OS_ENABLE_INTERRUPT_BLOCK_INSN)
/* Set exec_env of thread local storage */
void
wasm_runtime_set_exec_env_tls(WASMExecEnv *exec_env);
Expand Down
Loading

0 comments on commit ed98d88

Please sign in to comment.