Skip to content

Commit 0f4edf9

Browse files
authored
Implement suspend flags as atomic variable (#2361)
We have observed a significant performance degradation after merging #1991 Instead of protecting suspend flags with a mutex, we implement the flags as atomic variable and only use mutex when atomics are not available on a given platform.
1 parent fbe072c commit 0f4edf9

8 files changed

Lines changed: 135 additions & 45 deletions

File tree

core/iwasm/common/wasm_exec_env.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define _WASM_EXEC_ENV_H
88

99
#include "bh_assert.h"
10+
#include "wasm_suspend_flags.h"
1011
#if WASM_ENABLE_INTERP != 0
1112
#include "../interpreter/wasm.h"
1213
#endif
@@ -57,15 +58,8 @@ typedef struct WASMExecEnv {
5758
exception. */
5859
uint8 *native_stack_boundary;
5960

60-
/* Used to terminate or suspend current thread
61-
bit 0: need to terminate
62-
bit 1: need to suspend
63-
bit 2: need to go into breakpoint
64-
bit 3: return from pthread_exit */
65-
union {
66-
uint32 flags;
67-
uintptr_t __padding__;
68-
} suspend_flags;
61+
/* Used to terminate or suspend current thread */
62+
WASMSuspendFlags suspend_flags;
6963

7064
/* Auxiliary stack boundary */
7165
union {
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (C) 2023 Amazon Inc. All rights reserved.
3+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
*/
5+
6+
#ifndef _WASM_SUSPEND_FLAGS_H
7+
#define _WASM_SUSPEND_FLAGS_H
8+
9+
#include "bh_platform.h"
10+
11+
#ifdef __cplusplus
12+
extern "C" {
13+
#endif
14+
15+
/* Need to terminate */
16+
#define WASM_SUSPEND_FLAG_TERMINATE 0x1
17+
/* Need to suspend */
18+
#define WASM_SUSPEND_FLAG_SUSPEND 0x2
19+
/* Need to go into breakpoint */
20+
#define WASM_SUSPEND_FLAG_BREAKPOINT 0x4
21+
/* Return from pthread_exit */
22+
#define WASM_SUSPEND_FLAG_EXIT 0x8
23+
24+
typedef union WASMSuspendFlags {
25+
uint32 flags;
26+
uintptr_t __padding__;
27+
} WASMSuspendFlags;
28+
29+
#if defined(__GNUC_PREREQ)
30+
#if __GNUC_PREREQ(4, 7)
31+
#define CLANG_GCC_HAS_ATOMIC_BUILTIN
32+
#endif
33+
#elif defined(__clang__)
34+
#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 0)
35+
#define CLANG_GCC_HAS_ATOMIC_BUILTIN
36+
#endif
37+
#endif
38+
39+
#if defined(CLANG_GCC_HAS_ATOMIC_BUILTIN)
40+
#define WASM_SUSPEND_FLAGS_IS_ATOMIC 1
41+
#define WASM_SUSPEND_FLAGS_GET(s_flags) \
42+
__atomic_load_n(&s_flags.flags, __ATOMIC_SEQ_CST)
43+
#define WASM_SUSPEND_FLAGS_FETCH_OR(s_flags, val) \
44+
__atomic_fetch_or(&s_flags.flags, val, __ATOMIC_SEQ_CST)
45+
#define WASM_SUSPEND_FLAGS_FETCH_AND(s_flags, val) \
46+
__atomic_fetch_and(&s_flags.flags, val, __ATOMIC_SEQ_CST)
47+
#else /* else of defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) */
48+
#define WASM_SUSPEND_FLAGS_GET(s_flags) (s_flags.flags)
49+
#define WASM_SUSPEND_FLAGS_FETCH_OR(s_flags, val) (s_flags.flags |= val)
50+
#define WASM_SUSPEND_FLAGS_FETCH_AND(s_flags, val) (s_flags.flags &= val)
51+
52+
/* The flag can be defined by the user if the platform
53+
supports atomic access to uint32 aligned memory. */
54+
#ifdef WASM_UINT32_IS_ATOMIC
55+
#define WASM_SUSPEND_FLAGS_IS_ATOMIC 1
56+
#else /* else of WASM_UINT32_IS_ATOMIC */
57+
#define WASM_SUSPEND_FLAGS_IS_ATOMIC 0
58+
#endif /* WASM_UINT32_IS_ATOMIC */
59+
60+
#endif
61+
62+
#if WASM_SUSPEND_FLAGS_IS_ATOMIC != 0
63+
#define WASM_SUSPEND_FLAGS_LOCK(lock) (void)0
64+
#define WASM_SUSPEND_FLAGS_UNLOCK(lock) (void)0
65+
#else /* else of WASM_SUSPEND_FLAGS_IS_ATOMIC */
66+
#define WASM_SUSPEND_FLAGS_LOCK(lock) os_mutex_lock(&lock)
67+
#define WASM_SUSPEND_FLAGS_UNLOCK(lock) os_mutex_unlock(&lock);
68+
#endif /* WASM_SUSPEND_FLAGS_IS_ATOMIC */
69+
70+
#ifdef __cplusplus
71+
}
72+
#endif
73+
74+
#endif /* end of _WASM_SUSPEND_FLAGS_H */

core/iwasm/interpreter/wasm_interp_classic.c

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,21 +1062,33 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
10621062
os_mutex_unlock(&exec_env->wait_lock); \
10631063
} while (0)
10641064
#else
1065-
#define CHECK_SUSPEND_FLAGS() \
1066-
do { \
1067-
os_mutex_lock(&exec_env->wait_lock); \
1068-
if (exec_env->suspend_flags.flags != 0) { \
1069-
if (exec_env->suspend_flags.flags & 0x01) { \
1070-
/* terminate current thread */ \
1071-
os_mutex_unlock(&exec_env->wait_lock); \
1072-
return; \
1073-
} \
1074-
while (exec_env->suspend_flags.flags & 0x02) { \
1075-
/* suspend current thread */ \
1076-
os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \
1077-
} \
1078-
} \
1079-
os_mutex_unlock(&exec_env->wait_lock); \
1065+
#if WASM_SUSPEND_FLAGS_IS_ATOMIC != 0
1066+
/* The lock is only needed when the suspend_flags is atomic; otherwise
1067+
the lock is already taken at the time when SUSPENSION_LOCK() is called. */
1068+
#define SUSPENSION_LOCK() os_mutex_lock(&exec_env->wait_lock);
1069+
#define SUSPENSION_UNLOCK() os_mutex_unlock(&exec_env->wait_lock);
1070+
#else
1071+
#define SUSPENSION_LOCK()
1072+
#define SUSPENSION_UNLOCK()
1073+
#endif
1074+
1075+
#define CHECK_SUSPEND_FLAGS() \
1076+
do { \
1077+
WASM_SUSPEND_FLAGS_LOCK(exec_env->wait_lock); \
1078+
if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) \
1079+
& WASM_SUSPEND_FLAG_TERMINATE) { \
1080+
/* terminate current thread */ \
1081+
WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \
1082+
return; \
1083+
} \
1084+
while (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) \
1085+
& WASM_SUSPEND_FLAG_SUSPEND) { \
1086+
/* suspend current thread */ \
1087+
SUSPENSION_LOCK() \
1088+
os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \
1089+
SUSPENSION_UNLOCK() \
1090+
} \
1091+
WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \
10801092
} while (0)
10811093
#endif /* WASM_ENABLE_DEBUG_INTERP */
10821094
#endif /* WASM_ENABLE_THREAD_MGR */
@@ -3783,7 +3795,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
37833795
HANDLE_OP(DEBUG_OP_BREAK)
37843796
{
37853797
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP);
3786-
exec_env->suspend_flags.flags |= 2;
3798+
WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
3799+
WASM_SUSPEND_FLAG_SUSPEND);
37873800
frame_ip--;
37883801
SYNC_ALL_TO_FRAME();
37893802
CHECK_SUSPEND_FLAGS();

core/iwasm/interpreter/wasm_interp_fast.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,18 +1065,17 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
10651065
#endif
10661066

10671067
#if WASM_ENABLE_THREAD_MGR != 0
1068-
#define CHECK_SUSPEND_FLAGS() \
1069-
do { \
1070-
os_mutex_lock(&exec_env->wait_lock); \
1071-
if (exec_env->suspend_flags.flags != 0) { \
1072-
if (exec_env->suspend_flags.flags & 0x01) { \
1073-
/* terminate current thread */ \
1074-
os_mutex_unlock(&exec_env->wait_lock); \
1075-
return; \
1076-
} \
1077-
/* TODO: support suspend and breakpoint */ \
1078-
} \
1079-
os_mutex_unlock(&exec_env->wait_lock); \
1068+
#define CHECK_SUSPEND_FLAGS() \
1069+
do { \
1070+
WASM_SUSPEND_FLAGS_LOCK(exec_env->wait_lock); \
1071+
if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) \
1072+
& WASM_SUSPEND_FLAG_TERMINATE) { \
1073+
/* terminate current thread */ \
1074+
WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \
1075+
return; \
1076+
} \
1077+
/* TODO: support suspend and breakpoint */ \
1078+
WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \
10801079
} while (0)
10811080
#endif
10821081

core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,8 @@ pthread_start_routine(void *arg)
531531
else {
532532
info_node->u.ret = (void *)(uintptr_t)argv[0];
533533
#ifdef OS_ENABLE_HW_BOUND_CHECK
534-
if (exec_env->suspend_flags.flags & 0x08)
534+
if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)
535+
& WASM_SUSPEND_FLAG_EXIT)
535536
/* argv[0] isn't set after longjmp(1) to
536537
invoke_native_with_hw_bound_check */
537538
info_node->u.ret = exec_env->thread_ret_value;

core/iwasm/libraries/thread-mgr/thread_manager.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,8 @@ thread_manager_start_routine(void *arg)
606606

607607
#ifdef OS_ENABLE_HW_BOUND_CHECK
608608
os_mutex_lock(&exec_env->wait_lock);
609-
if (exec_env->suspend_flags.flags & 0x08)
609+
if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)
610+
& WASM_SUSPEND_FLAG_EXIT)
610611
ret = exec_env->thread_ret_value;
611612
os_mutex_unlock(&exec_env->wait_lock);
612613
#endif
@@ -993,7 +994,9 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval)
993994
if (exec_env->jmpbuf_stack_top) {
994995
/* Store the return value in exec_env */
995996
exec_env->thread_ret_value = retval;
996-
exec_env->suspend_flags.flags |= 0x08;
997+
998+
WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
999+
WASM_SUSPEND_FLAG_EXIT);
9971000

9981001
#ifndef BH_PLATFORM_WINDOWS
9991002
/* Pop all jmpbuf_node except the last one */
@@ -1055,7 +1058,8 @@ set_thread_cancel_flags(WASMExecEnv *exec_env)
10551058
#if WASM_ENABLE_DEBUG_INTERP != 0
10561059
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
10571060
#endif
1058-
exec_env->suspend_flags.flags |= 0x01;
1061+
WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
1062+
WASM_SUSPEND_FLAG_TERMINATE);
10591063

10601064
os_mutex_unlock(&exec_env->wait_lock);
10611065
}
@@ -1178,7 +1182,8 @@ void
11781182
wasm_cluster_suspend_thread(WASMExecEnv *exec_env)
11791183
{
11801184
/* Set the suspend flag */
1181-
exec_env->suspend_flags.flags |= 0x02;
1185+
WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
1186+
WASM_SUSPEND_FLAG_SUSPEND);
11821187
}
11831188

11841189
static void
@@ -1214,7 +1219,8 @@ wasm_cluster_suspend_all_except_self(WASMCluster *cluster,
12141219
void
12151220
wasm_cluster_resume_thread(WASMExecEnv *exec_env)
12161221
{
1217-
exec_env->suspend_flags.flags &= ~0x02;
1222+
WASM_SUSPEND_FLAGS_FETCH_AND(exec_env->suspend_flags,
1223+
~WASM_SUSPEND_FLAG_SUSPEND);
12181224
os_cond_signal(&exec_env->wait_cond);
12191225
}
12201226

@@ -1343,8 +1349,10 @@ bool
13431349
wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env)
13441350
{
13451351
os_mutex_lock(&exec_env->wait_lock);
1346-
bool is_thread_terminated =
1347-
(exec_env->suspend_flags.flags & 0x01) ? true : false;
1352+
bool is_thread_terminated = (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)
1353+
& WASM_SUSPEND_FLAG_TERMINATE)
1354+
? true
1355+
: false;
13481356
os_mutex_unlock(&exec_env->wait_lock);
13491357

13501358
return is_thread_terminated;

core/shared/utils/bh_platform.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "bh_log.h"
1717
#include "bh_queue.h"
1818
#include "bh_vector.h"
19+
#include "gnuc.h"
1920
#include "runtime_timer.h"
2021

2122
/**

core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h renamed to core/shared/utils/gnuc.h

File renamed without changes.

0 commit comments

Comments
 (0)