-
Notifications
You must be signed in to change notification settings - Fork 724
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wasm2c runtime: add per-thread initialization/free entrypoint #2332
Conversation
abaad17
to
d2c5c41
Compare
Maybe wait for @keithw who might have more feedback.. |
93d0f69
to
f4dabb3
Compare
@shravanrn, any concerns before this goes in? I know you were the one initially concerned about thread safety in the runtime via #2046. The semantics are basically:
So what's new here is that wasm_rt_is_initialized() is going to start enforcing that there's an altstack in place if we're using signals to catch stack exhaustion, and people who run wasm2c-generated code with asserts on will hit that. If the embedder is installing its own signal handler, I'm assuming it's also installing its own altstack on each thread if it wants to catch stack-exhaustion segfaults. Hopefully that's acceptable to Firefox and anybody else using WASM_RT_SKIP_SIGNAL_RECOVERY...? |
Looking today. Sorry for the delay |
wasm2c/wasm-rt-impl.c
Outdated
#if WASM_RT_USE_STACK_DEPTH_COUNT || (!WASM_RT_INSTALL_SIGNAL_HANDLER) | ||
return NULL; | ||
#else | ||
return os_allocate_and_install_altstack(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A minor future proofing point: could we return a struct with this pointer instead of the pointer directly. This would allow us to easily add fields to thread specific context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can always do this when we have more fields to add; it's an opaque void*
either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On further review... I just made wasm_rt_init_thread
return void
for now. The OS is already keeping track of the altstack.
wasm2c/wasm-rt-impl.c
Outdated
static bool os_has_altstack_installed() { | ||
/* check for altstack already in place */ | ||
stack_t ss; | ||
if (sigaltstack(NULL, &ss) != 0) { | ||
perror("sigaltstack failed"); | ||
abort(); | ||
} | ||
|
||
return !(ss.ss_flags & SS_DISABLE); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't aware you could do this. Neat! One worry I had was that the man page (which is a bit tricky to follow) says this indicates whether the altstack is "disabled". Unfortunately, I am not clear on whether "disabled" means not installed. I did run a quick test and saw that this worked as expected on my Ubuntu machine. Out of curiosity, did you have a chance to test this on other POSIX flavors and Mac?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, we do CI on Mac (with asserts enabled, at least I'm pretty sure)... AFAIK this is sigaltstack's only way of indicating a lack of alternate stack. But that's all the non-Linux testing I've done. I think if there are other POSIXy platforms that care, it would be great to get them in the CI (not necessarily using GitHub Actions to do it).
wasm2c/wasm-rt-impl.c
Outdated
} | ||
#if !WASM_RT_USE_STACK_DEPTH_COUNT | ||
assert(!g_alt_stack); | ||
g_alt_stack = os_allocate_and_install_altstack(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: It may make sense to call wasm_rt_thread_init
within here, as logically what we are saying is that the main thread gets has any thread-specific instantiation performed by default. Same with wasm_rt_free
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah... I think in a world where wasm_rt_init
returns the pointer (and wasm_rt_free
takes it), that makes total sense. But if g_alt_stack
only exists if certain preprocessor macros are set a certain way, then wasm_rt_init
would have to condition the call to wasm_rt_thread_init
similarly, and that feels weird -- why aren't we doing a thread init if WASM_RT_USE_STACK_DEPTH_COUNT
is set?
So I think as long as g_alt_stack
exists, wasm_rt_init
has to take responsibility for knowing the details itself; it can't take advantage of the abstraction barrier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On further review... I got rid of g_alt_stack and just let the OS keep track of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On further further view... I think I found a way to do this to satisfy everybody. wasm_rt_init() calls wasm_rt_init_thread() as you propose. g_alt_stack
is still there but it's a thread-local mostly just used for safety (it gets cross-checked against the actual altstack).
Looks reasonable % comments. I am still thinking through the design choice of "main thread is special and the user doesn't have to call |
I was able to clean up the internals a little by letting the OS keep track of the altstack. |
9cfeb80
to
5c1cbd6
Compare
wasm2c/wasm-rt-impl.c
Outdated
return; | ||
} | ||
|
||
fprintf(stderr, "Warning: wasm2c altstack was modified unexpectedly\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you invert the check above and put this error in an early return.
Also, do we want this error string in release builds?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
wasm2c/wasm-rt-impl.c
Outdated
@@ -42,8 +42,6 @@ | |||
static bool g_signal_handler_installed = false; | |||
#ifdef _WIN32 | |||
static void* g_sig_handler_handle = 0; | |||
#else | |||
static char* g_alt_stack = 0; | |||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe too much of a pain but removing g_alt_stack now seems like a separable change, along with SS_DISABLE
stuff?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, let me try to split this out into a new PR... (And maybe we should keep track of it in a thread-local just for safety anyway.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
5c1cbd6
to
fe5780a
Compare
fe5780a
to
a7a02d6
Compare
ced0cfe
to
da016f8
Compare
a7a02d6
to
fe77127
Compare
This is ready for review again and is a lot smaller now that #2338 has been merged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love how much smaller this change is now! Thanks for splitting it up.
lgtm from my POV but maybe wait for @shravanrn too
fe77127
to
60c2c7e
Compare
65eb03a
to
321122d
Compare
321122d
to
2009930
Compare
This helps wasm2c-generated modules be usable in a multithreaded context on POSIX, by giving each thread a runtime API entrypoint to initialize and free the altstack, which is used to catch segfaults from stack exhaustion. On Windows, explicit counting of stack depth is used to control stack exhaustion.
Closes #2189. Closes #2046, in the sense that this finishes getting rid of global state in our distributed runtime that doesn't have a thread-safe way of using it.