-
Notifications
You must be signed in to change notification settings - Fork 708
chore: For WASI builds only, use fatalError in all .wait() calls. Recommend using .get() instead. #3421
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
base: main
Are you sure you want to change the base?
Conversation
…existing blocking call in wait() will cause wasm executables to trap with an ambiguous message. This improves the message to help developers understand and correct the issue.
|
@MaxDesiatov @kateinoigakukun Would love to have your thoughts on this. Open to other solutions. But from what I've experienced so far, having this change could be very helpful for developers newly adopting swift nio into their WASI builds. |
| // calling wait here results in the following runtime crash: | ||
| // | ||
| // ``` | ||
| // SomeExecutable.wasm:0x123456 Uncaught (in promise) RuntimeError: Atomics.wait cannot be called in this 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.
Does this also happen with multi-threaded Swift SDKs for WASI? If not, we should only make this conditional on multi-threading availability.
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.
It's not an SDK limitation, but the browser's limitation. They don't allow exeucting memory.atomic.wait32 instruction on the main thread regardless of the SDK variants. On multi-threading context, the opt-in busy-wait mode in wasi-libc (WebAssembly/wasi-libc#562) might make sense under some conditions, though.
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.
Is the limitation only on the main thread? If so, we could plausibly detect specifically that condition on WASI.
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.
Correct, this is a limitation only applied to the main thread.
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.
Ok, my recommendation then would be that we try to only diagnose this on the main thread. Can that be detected in WASI?
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, it would be really nice to be able to restrict this to just the main thread. Unfortunately from what I'm seeing I don't think that Thread.isMain compiles in Swift for WebAssembly. @MaxDesiatov are you aware of any other solutions that might work well here?
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.
Hmm, I don't think we have a good way other than recording the main thread handle in a ctor and comparing with it later.
static pthread_t main_thread;
__attribute__((constructor))
void init_main_thread() {
main_thread = pthread_self();
}
bool is_main_thread() {
return pthread_equal(pthread_self(), main_thread);
}But I think we can unlock Thread.isMainThread in foundation using this approach.
Use fatalError in all .wait() calls for WASI builds only, and point developers towards .get() instead.
Motivation:
While working to adopt NIO in some wasm code, I've commonly ran into issues any time code calls
.wait()during wasm runtime. Typically the executable either traps or crashes any time.wait()is called with an ambiguous error:Uncaught (in promise) RuntimeError: Atomics.wait cannot be called in this context. The error occurs because it is forbidden to block the main thread for a wasm executable, and the current implementation of.wait()blocks the calling thread.The fix is straight forward, all calls to
.wait()need refactor to.get(), which sometimes involves some Swift Concurrency adoption (eg.async) in the process. That change avoids blocking the main thread.Modifications:
Added
fatalErrorwith a descriptive error message to help developers identify the issue easier.Result:
For WASI builds only, changes the trap error message
Uncaught (in promise) RuntimeError: Atomics.wait cannot be called in this contextinto the following error message instead:Alternatives considered
.wait()completely out of nio for WASI builds, to turn runtime errors into compiler errors. That makes detection of this issue easier, but forces a refactor and breaking change, and somewhat precludes the possibility that WASI might support this down the road with a future change.Context
This PR is part of a larger effort by PassiveLogic to move Swift for WebAssembly support forward in a large number of dependencies.