mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2024-11-26 15:32:05 +00:00
444b159963
Send a signal whose handler is no-op to a blocking thread to wake up the blocking syscall with either EINTR equivalent or partial success. Unlike the approach taken in the `dev/interrupt_block_insn` branch (that is, signal + longjmp similarly to `OS_ENABLE_HW_BOUND_CHECK`), this PR does not use longjmp because: * longjmp from signal handler doesn't work on nuttx refer to https://github.com/apache/nuttx/issues/10326 * the singal+longjmp approach may be too difficult for average programmers who might implement host functions to deal with See also https://github.com/bytecodealliance/wasm-micro-runtime/issues/1910
93 lines
2.3 KiB
C
93 lines
2.3 KiB
C
/*
|
|
* Copyright (C) 2023 Midokura Japan KK. All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
*/
|
|
|
|
#include "wasm_runtime_common.h"
|
|
|
|
#include "bh_platform.h"
|
|
#include "bh_common.h"
|
|
#include "bh_assert.h"
|
|
|
|
#if WASM_ENABLE_THREAD_MGR != 0 && defined(OS_ENABLE_WAKEUP_BLOCKING_OP)
|
|
|
|
#define LOCK(env) WASM_SUSPEND_FLAGS_LOCK((env)->wait_lock)
|
|
#define UNLOCK(env) WASM_SUSPEND_FLAGS_UNLOCK((env)->wait_lock)
|
|
|
|
#define ISSET(env, bit) \
|
|
((WASM_SUSPEND_FLAGS_GET((env)->suspend_flags) & WASM_SUSPEND_FLAG_##bit) \
|
|
!= 0)
|
|
#define SET(env, bit) \
|
|
WASM_SUSPEND_FLAGS_FETCH_OR((env)->suspend_flags, WASM_SUSPEND_FLAG_##bit)
|
|
#define CLR(env, bit) \
|
|
WASM_SUSPEND_FLAGS_FETCH_AND((env)->suspend_flags, ~WASM_SUSPEND_FLAG_##bit)
|
|
|
|
bool
|
|
wasm_runtime_begin_blocking_op(wasm_exec_env_t env)
|
|
{
|
|
LOCK(env);
|
|
bh_assert(!ISSET(env, BLOCKING));
|
|
SET(env, BLOCKING);
|
|
if (ISSET(env, TERMINATE)) {
|
|
CLR(env, BLOCKING);
|
|
UNLOCK(env);
|
|
return false;
|
|
}
|
|
UNLOCK(env);
|
|
os_begin_blocking_op();
|
|
return true;
|
|
}
|
|
|
|
void
|
|
wasm_runtime_end_blocking_op(wasm_exec_env_t env)
|
|
{
|
|
int saved_errno = errno;
|
|
LOCK(env);
|
|
bh_assert(ISSET(env, BLOCKING));
|
|
CLR(env, BLOCKING);
|
|
UNLOCK(env);
|
|
os_end_blocking_op();
|
|
errno = saved_errno;
|
|
}
|
|
|
|
void
|
|
wasm_runtime_interrupt_blocking_op(wasm_exec_env_t env)
|
|
{
|
|
/*
|
|
* ISSET(BLOCKING) here means that the target thread
|
|
* is in somewhere between wasm_begin_blocking_op and
|
|
* wasm_end_blocking_op.
|
|
* keep waking it up until it reaches wasm_end_blocking_op,
|
|
* which clears the BLOCKING bit.
|
|
*
|
|
* this dumb loop is necessary because posix doesn't provide
|
|
* a way to unmask signal and block atomically.
|
|
*/
|
|
|
|
LOCK(env);
|
|
SET(env, TERMINATE);
|
|
while (ISSET(env, BLOCKING)) {
|
|
UNLOCK(env);
|
|
os_wakeup_blocking_op(env->handle);
|
|
|
|
/* relax a bit */
|
|
os_usleep(50 * 1000);
|
|
LOCK(env);
|
|
}
|
|
UNLOCK(env);
|
|
}
|
|
|
|
#else /* WASM_ENABLE_THREAD_MGR && OS_ENABLE_WAKEUP_BLOCKING_OP */
|
|
|
|
bool
|
|
wasm_runtime_begin_blocking_op(wasm_exec_env_t env)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void
|
|
wasm_runtime_end_blocking_op(wasm_exec_env_t env)
|
|
{}
|
|
|
|
#endif /* WASM_ENABLE_THREAD_MGR && OS_ENABLE_WAKEUP_BLOCKING_OP */
|