Skip to content
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

Support for WASI threads #98120

Closed
wants to merge 3 commits into from
Closed

Support for WASI threads #98120

wants to merge 3 commits into from

Conversation

Milek7
Copy link

@Milek7 Milek7 commented Feb 7, 2024

wasi-libc provides pthread implementation, so use that. This way it behaves almost like POSIX-like platform (it does not support signals). Unfortunately macrology does get pretty complicated, because it is WASM, but does not need to use most existing WASM support code but generic POSIX instead.

wasi-sdk is updated to version 21 for WebAssembly/wasi-sdk@c891cd2 and WebAssembly/wasi-libc@ec4566b

pthread_exit does not exist, but returning from start_wrapper seems to work fine, not sure when other ways of exiting a thread are invoked.

Conditionals in csproj are patched to work correctly with WASI threads, but I'm not really sure whether FeatureWasmManagedThreads should be defined at all for this configuration. It's not a browser, has POSIX threads, so this whole complication with ifdefing unsupported browser attributes and adding special assemblies for WebAssembly.Threading seems completely unnecessary. I don't know how to fix this cleanly, though.

When testing on wasmtime it needs bytecodealliance/wasmtime#7884

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Feb 7, 2024
@Milek7
Copy link
Author

Milek7 commented Feb 7, 2024

@dotnet-policy-service agree company="SimRail S.A."

@marek-safar marek-safar added the os-wasi Related to WASI variant of arch-wasm label Feb 7, 2024
message ("CMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}")
message ("CMAKE_SYSTEM_VARIANT=${CMAKE_SYSTEM_VARIANT}")

set(CLR_CMAKE_HOST_OS ${CMAKE_SYSTEM_NAME})
string(TOLOWER ${CLR_CMAKE_HOST_OS} CLR_CMAKE_HOST_OS)
set(CLR_CMAKE_HOST_VARIANT ${CMAKE_SYSTEM_VARIANT})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not super familiar with cmake, but it seems weird that the host variant is either threads or not threads depending on the target you're building for. don't all cmake build hosts have threads?

Copy link
Author

@Milek7 Milek7 Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is referring not to build host but mono runtime host. (as opposed to target system for which runtime will do codegen)
Still, I'm not sure how that interacts with DISABLE_THREADS (shouldn't there be TARGET/HOST_DISABLE_THREADS?), but in any case it was used this way for wasm before.

@lambdageek lambdageek added the arch-wasm WebAssembly architecture label Feb 7, 2024
@ghost
Copy link

ghost commented Feb 7, 2024

Tagging subscribers to 'arch-wasm': @lewing
See info in area-owners.md if you want to be subscribed.

Issue Details

wasi-libc provides pthread implementation, so use that. This way it behaves almost like POSIX-like platform (it does not support signals). Unfortunately macrology does get pretty complicated, because it is WASM, but does not need to use most existing WASM support code but generic POSIX instead.

wasi-sdk is updated to version 21 for WebAssembly/wasi-sdk@c891cd2 and WebAssembly/wasi-libc@ec4566b

pthread_exit does not exist, but returning from start_wrapper seems to work fine, not sure when other ways of exiting a thread are invoked.

Conditionals in csproj are patched to work correctly with WASI threads, but I'm not really sure whether FeatureWasmManagedThreads should be defined at all for this configuration. It's not a browser, has POSIX threads, so this whole complication with ifdefing unsupported browser attributes and adding special assemblies for WebAssembly.Threading seems completely unnecessary. I don't know how to fix this cleanly, though.

When testing on wasmtime it needs bytecodealliance/wasmtime#7884

Author: Milek7
Assignees: -
Labels:

arch-wasm, area-Build-mono, community-contribution, os-wasi

Milestone: -

@pavelsavara
Copy link
Member

This is WASIX extensions, right ? What would happen when we upgrade to WASI preview 2 ?

#elif defined(USE_PTHREAD_WASM_BACKEND)

struct __pthread {
struct pthread *self;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty brittle, what if this structure changes ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how to get stack bounds otherwise, because wasi-libc doesn't have pthread_getattr_np.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Milek7
Copy link
Author

Milek7 commented Feb 8, 2024

This is WASIX extensions, right ? What would happen when we upgrade to WASI preview 2 ?

It uses pthreads from wasi-libc, which is currently implemented using wasi-threads proposal (https://github.com/WebAssembly/wasi-threads)
When wasi-libc switches underlying implementation it shouldn't require changes here, but as far I know component-model based preview2 isn't expected to support threads soon, so pthread-supporting toolchain will stay on preview1 for quite some time.

@pavelsavara
Copy link
Member

pavelsavara commented Feb 12, 2024

@Milek7 we appreciate your efforts!

I would like to share some context to set your and our expectations. As you know, the wasm threading is still developing and the final implementation may be very different from what you are trying to achieve in this PR.

Our view is that we want to have dotnet based on the standard component based WASI, rather than POSIX/WASIX extensions. On the other hand, as you pointed out, threads are not ready.

We are willing to explore this, given that we all know this API would eventually go away.
(The WASI flavor of dotnet is still experimental, probably until WASI itself reaches v1.0, we will not guarantee any compatibility or behavior)

As you probably noticed, our big focus at the moment is to enable threads in the browser (with emscripten). Browser limitations as well as interop with JS requires that we work-around many concepts. Historically we only had Mono on emscripten and that combination was referred to as wasm in the codebase. About year ago we added WASI as another OS and recently made refactoring of the source code directories to reflect browser OS. But part of the #ifdef probably still reflects wasm meaning wasm-browser. Story of FeatureWasmManagedThreads in csproj is similar. It surely makes sense sort it out. This is all Mono, but now there is also NativeAOT experimental branch of dotnet runtime on WASM.

For context, in the browser major features which influence threads are:

  • you need to keep yielding to browser event loop
    • otherwise lot of things don't work: networking, rendering, debugging, new thread creation ...
  • you can't synchronously block on UI thread (roughly for same reasons)
  • you can schedule yourself callback via setTimeout.
    • This is the way how we overcome limitations above.
    • It allows us to implement single-threaded "thread pool" and timer and await JS promises.
  • Some of those limitations are lifted for multi-threaded (MT) browser, but there is JS object thread affinity.

We have following combinations ahead

  • ST browser - stable
  • MT browser - under heavy development
  • ST WASI - possibly after we finish MT browser
  • MT WASIX - we did not prioritize it in any way yet
  • MT WASI - we are waiting for WASI component model

What need to be done for WASI

  • We need to conceptually figure out which of dotnet features we solved for (single-threaded) browser, could be solved for single-threaded WASI.
    • ST "thread pool" to schedule async Task to single thread.
    • Timers - there is no setTimeout in WASI. Maybe subscribe to clock and poll ?
    • PLINQ
    • GC, finalizer
    • knowing this would inform us on the #ifdef
    • enable unit test coverage for all BCL. Right now we only have "hello world" smoke test running on CI.
  • make WASI MT with WASIX shared memory work
    • this may be side-step for us.
    • implement thread-pool, timers, PLINQ, GC - this may be very close to normal unix. We don't need to yield to (browser) event loop etc.
    • enable unit tests for all BCL on MT, fix problems
  • adopt WASIp2 component model in dotnet PAL.
    • Possibly call that API directly rather than via libc. Would wasm-threads libc dependency hold us back ?
    • This may bring networking. Browser HTTP and WS adapters are non-trivial. WASIp3 with futures and streams will change it again. Shall we wait for it to arrive ?
  • make WASI MT with component model thread
    • Is component based MT going to bring WASM linear memory shared across threads ?
    • Would there be host "event loop" ? Because there will be WASIp3 futures.
    • it may mean that we will need to partially align it with browser MT and that WASIX MT will be complexity to get rid of, at that point.

Right now, we are not actively working on any of the above.

Are you still interested ?
Which parts you would like to work on ?
What's your motivation or use-case for working on this ?

@Milek7
Copy link
Author

Milek7 commented Feb 12, 2024

What's your motivation or use-case for working on this ?

My motivation is running existing C# codebase in wasm runtime. As you noted, single-threaded requires yielding to caller, which requires changes to both library code and applications (which may assume that threads exist, use locks, and blocking functions). Multi-threading though makes it fit into posix-like model, which enables library and application code to work without changes.

  • make WASI MT with WASIX shared memory work

This PR uses wasi-threads proposal (as implemented in eg. wasmtime) and does not use wasmer WASIX extensions.

  • implement thread-pool, timers, PLINQ, GC - this may be very close to normal unix. We don't need to yield to (browser) event loop etc.

Indeed that's why I'm pursuing this approach. Admittedly I didn't do extensive testing yet, but this (Thread, ThreadPool, Task, etc.) should already work with this PR.

Given that it seems component model multithreading won't be available for quite some time (I have seen statements that "The Component Model does not have support for threads at this time and that's not expected to be supported until the time scale of years in the future"), I think it is reasonable to merge this approach for time being. When it comes I think it is expected that wasi-libc will still provide pthread implementation requiring no changes here. Targeting component model directly bypassing libc would likely require some changes, though I'm not exactly sure why you would do this, considering that in practice it would probably mean copy-pasting musl code. (unless it would also bring Wasm GC, but that would be complete architecture change anyway).

I can look into threading bugs if some will come up with more testing, and potentially untangle that FeatureWasmManagedThreads flag if there would be guidelines what to do with it. (like I said before, it works but feels superfluous to ifdef UnsupportedOS for browser when this isn't a browser anyway)

@pavelsavara
Copy link
Member

What's your motivation or use-case for working on this ?
My motivation is running existing C# codebase in wasm runtime

I'm interested in more details, if you are willing to share them.
What makes wasm attractive compared with say "chiselled" docker ? (this is Q from wasm fan boy)

I didn't do extensive testing yet, but this (Thread, ThreadPool, Task, etc.) should already work with this PR.

We can help enable WASI full library test suite for you on this PR. Is it ok for us to push into your branch ?

There are also some failing CI legs on this PR, because we will need to bump SDK in the Helix VM images too.

potentially untangle that FeatureWasmManagedThreads flag

We are discussing that with the team. TBH we don't know exactly what we want yet. Will keep you posted.

@vargaz
Copy link
Contributor

vargaz commented Feb 12, 2024

Maybe the bump of the wasi sdk should be done in a separate PR ?

@Milek7
Copy link
Author

Milek7 commented Feb 12, 2024

We can help enable WASI full library test suite for you on this PR. Is it ok for us to push into your branch ?

Thanks, feel free to do it.

I'm interested in more details, if you are willing to share them.

It's probably rather unconventional use-case :) Actually we are embedding it in desktop application, for various reasons it is convenient to have it compiled as WASM module (no extra processes, easy state cleanup for restart).

PS: For testing with wasmtime it will need fresh build (for bytecodealliance/wasmtime#7884)

@pavelsavara
Copy link
Member

PS: For testing with wasmtime it will need fresh build (for bytecodealliance/wasmtime#7884)

Is there feed with nighty build ?

<WasmtimeURL>https://github.com/bytecodealliance/wasmtime/releases/download/v$(WasmtimeVersion)/wasmtime-v$(WasmtimeVersion)-x86_64-linux.tar.xz</WasmtimeURL>
<WasmtimeURL Condition="'$(HostOS)' == 'osx'" >https://github.com/bytecodealliance/wasmtime/releases/download/v$(WasmtimeVersion)/wasmtime-v$(WasmtimeVersion)-x86_64-macos.tar.xz</WasmtimeURL>
<WasmtimeURL Condition="'$(HostOS)' == 'windows'" >https://github.com/bytecodealliance/wasmtime/releases/download/v$(WasmtimeVersion)/wasmtime-v$(WasmtimeVersion)-x86_64-windows.zip</WasmtimeURL>

@vargaz
Copy link
Contributor

vargaz commented Feb 13, 2024

The wasi sdk bump was merged.

@vargaz
Copy link
Contributor

vargaz commented Feb 13, 2024

/azp run runtime-wasm

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@pavelsavara
Copy link
Member

I didn't forget about it and it's still on my TODO list. I plan to cleanup the ifdef situation first, thanks for your patience.

@Milek7
Copy link
Author

Milek7 commented Mar 19, 2024

In the meantime I encountered problem with WasmBuildNative, added fix for that.

@pavelsavara
Copy link
Member

We don't have bandwidth to keep WASIp1 at the same time as we want to switch to WASIp2. It would require even more complex and conditional build scripts. I'm sorry.

@pavelsavara pavelsavara closed this Jul 2, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Aug 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
arch-wasm WebAssembly architecture area-Build-mono community-contribution Indicates that the PR has been added by a community member os-wasi Related to WASI variant of arch-wasm
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants