Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Sources/NIOCore/EventLoopFuture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,26 @@ extension EventLoopFuture {
@preconcurrency
@inlinable
public func wait(file: StaticString = #file, line: UInt = #line) throws -> Value where Value: Sendable {
#if os(WASI)
// NOTE: As of July 22, 2025 `wait()` calling wait() is not supported on WASI platforms.
//
// This may change down the road if and when true multi-threading evolves. But right now
// calling wait here results in the following runtime crash:
//
// ```
// SomeExecutable.wasm:0x123456 Uncaught (in promise) RuntimeError: Atomics.wait cannot be called in this context
Copy link
Member

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Contributor

@kateinoigakukun kateinoigakukun Oct 25, 2025

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.

// ```
//
// Using the following fatal error here gives wasm runtime users a much more clear error message
// to identify the issue.
//
// If you're running into this error on WASI, refactoring to `get()` instead of `wait()` will
// likely solve the issue.
fatalError(
"NIO's wait() function should not be called on WASI platforms. It will freeze or crash. Use get() instead."
)
#endif // os(WASI)

try self._blockingWaitForFutureCompletion(file: file, line: line)
}

Expand Down