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

wasi-threads: check module instantiability during construction #5741

Closed
wants to merge 1 commit into from

Conversation

abrown
Copy link
Contributor

@abrown abrown commented Feb 7, 2023

Due to #5675, we could not perform an early check whether the module passed to wasi-threads could indeed be instantiated. Now that that issue is resolved, this change performs the instantiation check (via Linker::instantiate_pre) during construction.

Due to bytecodealliance#5675, we could not perform an early check whether the module
passed to `wasi-threads` could indeed be instantiated. Now that that
issue is resolved, this change performs the instantiation check (via
`Linker::instantiate_pre`) during construction.
@abrown abrown requested a review from alexcrichton February 7, 2023 22:09
Comment on lines +30 to 36
if let Err(err) = linker.instantiate_pre(&module) {
bail!(
"wasi-threads will not be able to instantiate the passed module: {:?}",
err
);
}
Ok(Self { module, linker })
Copy link
Member

Choose a reason for hiding this comment

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

Thinking about this again, the WasiThreadsCtx could actually store InstancePre<T> and use that to instantiate as there's no need to recreate it each time a thread is spawned.

Could ::new be refactored to either:

  • Take a &Module and &Linker<T> and persist Arc<InstancePre<T>> within WasiThreadsCtx
  • Or take a InstancePre<T> directly and store an Arc internally in the context

// We have checked during construction that the module can be
// instantiated and an entry point exists with the correct
// signature--these calls should not fail.
let instance = linker.instantiate(&mut store, &module).unwrap();
Copy link
Member

Choose a reason for hiding this comment

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

Thinking about this again, this is fine for now but I think this is still something that the wasi-threads proposal needs to happen. Basically the fallibility of spawning a thread I don't think is handled well. For example the OS could fail to spawn a thread, an embedder may want to limit threads, allocating resources for an Instance may fail (e.g. local linear memories if any). There's a lot of failure modes beyond "the imports didn't line up" so it's possible to trigger this unwrap() I think (although hard for the "CLI world").

Basically I think that the wasi-threads proposal needs a way for an embedder to communicate a thread spawn failure and I think that the failure here needs to be communicated back somehow. That has its own set of thorny questions though because how "blocking" is the thread-spawn intrinsic? E.g. we ideally don't want to instantiate the instance on the caller thread ,but in the child thread like this. That means though that failure would be delayed since the thread may not start for a bit. Anyway I'm rambling now. Fine for now, but I think needs more work on the proposal.

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, this is a good point. This error should be communicated back to the WebAssembly guest; it isn't always a runtime failure. The wasi-threads proposal currently designates negative numbers as error codes so I think what could be done here is specify some of that range to match some of the possible reasons for failure here. How can I get the full list of possible errors that could be unwrapped here?

Copy link
Member

Choose a reason for hiding this comment

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

I am not aware of an exhaustive list of errors, but some examples I can think of are:

  • The OS thread failed to spawn for an OS-defined reason (e.g. not enough kernel memory, not enough user memory, kernel is limiting threads, etc)
  • An embedder-configured limit prevented a thread from being spawned (e.g. your store gets at most 5 threads)
  • Module instantiation on the new thread failed (e.g. not enough memory, some store configuration limited growth of table/memory, not enough virtual memory for a second non-shared linear memory, etc)
  • Module instantiation could fail due to a trap in the start function

And that's sort of just a subset of what could happen. Not necessarily all of those should be communicated through an error code perhaps. For example maybe failure to instantiate is considered a fatal error that aborts all threads, but perhaps failure to spawn a thread at the OS level is communicated back to the thread-spawn caller.

In any case, though, I think the upstream proposal should have a rough set of guidelines for what to do in these failure situations and how embedders communicate this to wasm.

@abrown abrown changed the title wasi-threads: check module instantiatability during construction wasi-threads: check module instantiability during construction Mar 28, 2023
abrown added a commit to abrown/wasmtime that referenced this pull request May 31, 2023
This change relaxes what kinds of modules can be run when wasi-threads
is enabled via `--wasi-modules experimental-wasi-threads`. Previously,
as reported in bytecodealliance#6153, simple modules that made no use of thread spawning
or shared memories were preemptively rejected when the wasi-threads
context was created. This is not ideal because it is too restrictive.

Instead, this change does the following:
- it moves the check for whether a module is valid according to the
  wasi-threads specification to the point a new thread is spawned; this
  resolves bytecodealliance#6153
- as noted in bytecodealliance#6153, this change also adds a better error message
  indicating that wasi-threads expects a shared memory import
- the way this is implemented also improves the module instantiation: by
  constructing an `InstancePre` once when the `WasiThreadsCtx` is built,
  this might shave off a bit of time from the "spawn a thread" call;
  this supercedes bytecodealliance#5741
abrown added a commit to abrown/wasmtime that referenced this pull request May 31, 2023
This change relaxes what kinds of modules can be run when wasi-threads
is enabled via `--wasi-modules experimental-wasi-threads`. Previously,
as reported in bytecodealliance#6153, simple modules that made no use of thread spawning
or shared memories were preemptively rejected when the wasi-threads
context was created. This is too restrictive.

Instead, this change does the following:
- it moves the check for whether a module is valid according to the
  wasi-threads specification to the point a new thread is spawned; this
  resolves bytecodealliance#6153
- as noted in bytecodealliance#6153, this change also adds a better error message
  indicating that wasi-threads expects a shared memory import
- the way this is implemented also improves the module instantiation: by
  constructing an `InstancePre` once when the `WasiThreadsCtx` is built,
  we might shave off a bit of time from the "spawn a thread" call;
  this supercedes a similar effort in bytecodealliance#5741
alexcrichton pushed a commit that referenced this pull request Jun 1, 2023
This change relaxes what kinds of modules can be run when wasi-threads
is enabled via `--wasi-modules experimental-wasi-threads`. Previously,
as reported in #6153, simple modules that made no use of thread spawning
or shared memories were preemptively rejected when the wasi-threads
context was created. This is too restrictive.

Instead, this change does the following:
- it moves the check for whether a module is valid according to the
  wasi-threads specification to the point a new thread is spawned; this
  resolves #6153
- as noted in #6153, this change also adds a better error message
  indicating that wasi-threads expects a shared memory import
- the way this is implemented also improves the module instantiation: by
  constructing an `InstancePre` once when the `WasiThreadsCtx` is built,
  we might shave off a bit of time from the "spawn a thread" call;
  this supercedes a similar effort in #5741
@abrown
Copy link
Contributor Author

abrown commented Jun 1, 2023

Superseded by #6492.

@abrown abrown closed this Jun 1, 2023
dhil pushed a commit to dhil/wasmtime that referenced this pull request Jun 5, 2023
This change relaxes what kinds of modules can be run when wasi-threads
is enabled via `--wasi-modules experimental-wasi-threads`. Previously,
as reported in bytecodealliance#6153, simple modules that made no use of thread spawning
or shared memories were preemptively rejected when the wasi-threads
context was created. This is too restrictive.

Instead, this change does the following:
- it moves the check for whether a module is valid according to the
  wasi-threads specification to the point a new thread is spawned; this
  resolves bytecodealliance#6153
- as noted in bytecodealliance#6153, this change also adds a better error message
  indicating that wasi-threads expects a shared memory import
- the way this is implemented also improves the module instantiation: by
  constructing an `InstancePre` once when the `WasiThreadsCtx` is built,
  we might shave off a bit of time from the "spawn a thread" call;
  this supercedes a similar effort in bytecodealliance#5741
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants