Implement async termination of blocking thread (#2516)
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
This commit is contained in:
69
core/shared/platform/common/posix/posix_blocking_op.c
Normal file
69
core/shared/platform/common/posix/posix_blocking_op.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Midokura Japan KK. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "platform_api_extension.h"
|
||||
|
||||
#ifdef OS_ENABLE_WAKEUP_BLOCKING_OP
|
||||
|
||||
static bool g_blocking_op_inited = false;
|
||||
static int g_blocking_op_signo = SIGUSR1;
|
||||
static sigset_t g_blocking_op_sigmask;
|
||||
|
||||
static void
|
||||
blocking_op_sighandler(int signo)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
void
|
||||
os_set_signal_number_for_blocking_op(int signo)
|
||||
{
|
||||
g_blocking_op_signo = signo;
|
||||
}
|
||||
|
||||
int
|
||||
os_blocking_op_init()
|
||||
{
|
||||
if (g_blocking_op_inited) {
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
sigemptyset(&g_blocking_op_sigmask);
|
||||
sigaddset(&g_blocking_op_sigmask, g_blocking_op_signo);
|
||||
|
||||
struct sigaction sa;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = blocking_op_sighandler;
|
||||
if (sigaction(g_blocking_op_signo, &sa, NULL)) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
g_blocking_op_inited = true;
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
void
|
||||
os_begin_blocking_op()
|
||||
{
|
||||
pthread_sigmask(SIG_UNBLOCK, &g_blocking_op_sigmask, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
os_end_blocking_op()
|
||||
{
|
||||
pthread_sigmask(SIG_BLOCK, &g_blocking_op_sigmask, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
os_wakeup_blocking_op(korp_tid tid)
|
||||
{
|
||||
int ret = pthread_kill(tid, g_blocking_op_signo);
|
||||
if (ret != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
#endif /* OS_ENABLE_WAKEUP_BLOCKING_OP */
|
||||
@ -39,6 +39,9 @@ os_thread_wrapper(void *arg)
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
if (os_thread_signal_init(handler) != 0)
|
||||
return NULL;
|
||||
#endif
|
||||
#ifdef OS_ENABLE_WAKEUP_BLOCKING_OP
|
||||
os_end_blocking_op();
|
||||
#endif
|
||||
start_func(thread_arg);
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
|
||||
@ -102,6 +102,12 @@ os_sigreturn();
|
||||
#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64/RISCV64 */
|
||||
#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */
|
||||
|
||||
#if WASM_DISABLE_WAKEUP_BLOCKING_OP != 0
|
||||
#define OS_ENABLE_WAKEUP_BLOCKING_OP
|
||||
#endif
|
||||
void
|
||||
os_set_signal_number_for_blocking_op(int signo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -101,6 +101,12 @@ os_sigreturn();
|
||||
#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64/RISCV64 */
|
||||
#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */
|
||||
|
||||
#if WASM_DISABLE_WAKEUP_BLOCKING_OP != 0
|
||||
#define OS_ENABLE_WAKEUP_BLOCKING_OP
|
||||
#endif
|
||||
void
|
||||
os_set_signal_number_for_blocking_op(int signo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -323,6 +323,34 @@ os_sem_getvalue(korp_sem *sem, int *sval);
|
||||
int
|
||||
os_sem_unlink(const char *name);
|
||||
|
||||
/**
|
||||
* Initialize process-global state for os_wakeup_blocking_op.
|
||||
*/
|
||||
int
|
||||
os_blocking_op_init();
|
||||
|
||||
/**
|
||||
* Start accepting os_wakeup_blocking_op requests for the calling thread.
|
||||
*/
|
||||
void
|
||||
os_begin_blocking_op();
|
||||
|
||||
/**
|
||||
* Stop accepting os_wakeup_blocking_op requests for the calling thread.
|
||||
*/
|
||||
void
|
||||
os_end_blocking_op();
|
||||
|
||||
/**
|
||||
* Wake up the specified thread.
|
||||
*
|
||||
* For example, on posix-like platforms, this can be implemented by
|
||||
* sending a signal (w/o SA_RESTART) which interrupts a blocking
|
||||
* system call.
|
||||
*/
|
||||
int
|
||||
os_wakeup_blocking_op(korp_tid tid);
|
||||
|
||||
/****************************************************
|
||||
* Section 2 *
|
||||
* Socket support *
|
||||
|
||||
@ -115,6 +115,12 @@ os_sigreturn();
|
||||
#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64/RISCV64 */
|
||||
#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */
|
||||
|
||||
#if WASM_DISABLE_WAKEUP_BLOCKING_OP != 0
|
||||
#define OS_ENABLE_WAKEUP_BLOCKING_OP
|
||||
#endif
|
||||
void
|
||||
os_set_signal_number_for_blocking_op(int signo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -123,6 +123,12 @@ utimensat(int fd, const char *path, const struct timespec ts[2], int flag);
|
||||
DIR *
|
||||
fdopendir(int fd);
|
||||
|
||||
#if WASM_DISABLE_WAKEUP_BLOCKING_OP != 0
|
||||
#define OS_ENABLE_WAKEUP_BLOCKING_OP
|
||||
#endif
|
||||
void
|
||||
os_set_signal_number_for_blocking_op(int signo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user