Stream: git-wasmtime

Topic: wasmtime / issue #14284 Allow hosts to temporarily suspen...


view this post on Zulip Wasmtime GitHub notifications bot (Sep 05 2026 at 05:25):

EFEXP opened issue #14284:

Feature

Add some way for the host to temporarily make a Component Model async guest task ineligible to enter or resume guest execution.

The motivating case is similar to Cloudflare Durable Objects' blockConcurrencyWhile: if async exports A and B are running concurrently in the same component instance, A should be able to enter an exclusive section during which B executes no guest code, while A and host-side async work continue to make progress.

It could look like:

pause_task(task: GuestTaskId)
resume_task(task: GuestTaskId)

or some equivalent scheduler-level abstraction.

This seems related to #11896, which discusses pausing tasks in the concurrent scheduler while allowing a privileged debugger task to continue. I'm mainly interested in whether there is already an intended abstraction for this kind of scheduler control.

Benefit

This would allow an embedder to implement exclusive execution regions across concurrent Component Model async calls without requiring cooperation from the guest.

The important distinction from instance backpressure is that the affected task may already have started. It might be waiting for an event or already queued for thread/fiber resumption, so the restriction needs to apply to both starting and re-entering guest code.

While a task is paused:

This would also seem useful as a more general scheduler primitive for cases such as the debugger work discussed in #11896.

Implementation

Current main appears to already carry QualifiedThreadId on both ResumeThread and ResumeFiber, so all guest-executing work items seem to have enough identity to associate them with a task.

One possible implementation would be to add a task-level scheduler eligibility check covering guest-call start/event delivery as well as thread/fiber resumption, and retain ineligible work until the task becomes runnable again.

I'm not sure whether the natural unit should be exactly one GuestTaskId, or a root export task together with work descended from it. For the motivating use case, root-task semantics would probably be more useful.

I'd be interested in whether this matches the scheduler direction already envisioned for #11896, or whether Wasmtime would model this differently.

Alternatives

One alternative is to implement the exclusion in the guest, for example by wrapping exports so that non-owning tasks return Pending while another task holds the exclusive section. That works, but requires cooperation from each guest language/runtime and therefore cannot be enforced by the host for arbitrary components.

Another alternative is to delay host-originated completion futures. That can prevent some event deliveries, but does not cover already-queued starts, guest-to-guest events, or thread/fiber resumption.

Instance backpressure is also insufficient because it only controls starting calls, not resuming already-started task

view this post on Zulip Wasmtime GitHub notifications bot (Sep 08 2026 at 18:58):

alexcrichton added the wasm-proposal:component-model-async label to Issue #14284.

view this post on Zulip Wasmtime GitHub notifications bot (Sep 08 2026 at 18:59):

alexcrichton commented on issue #14284:

cc @lukewagner you might have thoughts on this feature request (and @dicej too) -- do y'all feel that this is something that'd be reasonable to add to the host-side runtime?

Personally the first question in my mind would be to push a bit harder on the alternative you mention in the issue here @EFEXP -- would guest-side handling work for your use case? I understand that it wouldn't work for arbitrary components, but from the perspective of not complicating the host runtime further it does seem like an attractive alternative.

view this post on Zulip Wasmtime GitHub notifications bot (Sep 08 2026 at 19:35):

lukewagner commented on issue #14284:

If I'm reading the documentation for blockConcurrencyWhile correctly, it prevents new async exported functions from being called by the host, but it doesn't prevent any already-started async tasks from resuming execution. (This behavior also makes sense to me: if there were any pre-existing async tasks already running and blockConcurrencyWhile prevented them from executing, this could easily cause intra-instance deadlocks.) If my reading is correct, then I think blockConcurrencyWhile could be implemented using the CM's current backpressure.{inc,dec} built-ins which has exactly this effect.

view this post on Zulip Wasmtime GitHub notifications bot (Sep 15 2026 at 04:34):

EFEXP commented on issue #14284:

@alexcrichton @lukewagner
Thanks for the feedback.

Guest-side handling could work if we controlled the guest scheduler. The motivation for host-side support is to provide the same execution guarantees across components built with different languages and runtimes, without requiring scheduler changes in each of them.

The specific case is:

  1. Task B starts and waits for I/O.
  2. Task A enters an exclusive section and also waits for I/O.
  3. B’s I/O completes.

At step 3, we want to defer B’s re-entry into guest code until A leaves the section, while A and host-side I/O continue making progress. Preventing new export calls from starting would not cover this case.

Regarding blockConcurrencyWhile, I checked workerd’s implementation. Its input gate explicitly includes subrequest responses, timers, and input streams, and its critical sections block delivery of events initiated outside the section:

I agree that dependencies on suspended tasks can cause deadlocks. The treatment of child tasks and reentrant calls would need careful definition.

Would a host-controlled scheduler eligibility hook fit Wasmtime’s intended direction, with the embedder responsible for the exclusion policy?

view this post on Zulip Wasmtime GitHub notifications bot (Sep 15 2026 at 15:27):

lukewagner commented on issue #14284:

I'm a bit skeptical that a host that treats the guest as a black-box and has no cooperation from the guest scheduler would be able to do a robust job implementing a critical section like you're describing. In the workerd code you link to: that code is effectively part of the JS guest scheduler and thus it can discriminate which events to let though (b/c they "part of" the critical section) and which to block; I think what you're asking for would be analogous to implementing blockConcurrencyWhile as part of a generic container runtime that runs an unmodified oblivious workerd.

That being said, one thing I believe you can do robustly from the host today is pause all execution of a whole Store (which could contain a single root component instance as a host choice). So in your scenario, that would allow Step 2 to pause the whole Store until Task A's I/O was done, preventing Task B from running until Task A resumed. It's only once you want to attempt to do intra-component-instance task/thread discrimination that I think things get murky without the guest scheduler's participation.

view this post on Zulip Wasmtime GitHub notifications bot (Sep 16 2026 at 02:49):

EFEXP closed issue #14284:

Feature

Add some way for the host to temporarily make a Component Model async guest task ineligible to enter or resume guest execution.

The motivating case is similar to Cloudflare Durable Objects' blockConcurrencyWhile: if async exports A and B are running concurrently in the same component instance, A should be able to enter an exclusive section during which B executes no guest code, while A and host-side async work continue to make progress.

It could look like:

pause_task(task: GuestTaskId)
resume_task(task: GuestTaskId)

or some equivalent scheduler-level abstraction.

This seems related to #11896, which discusses pausing tasks in the concurrent scheduler while allowing a privileged debugger task to continue. I'm mainly interested in whether there is already an intended abstraction for this kind of scheduler control.

Benefit

This would allow an embedder to implement exclusive execution regions across concurrent Component Model async calls without requiring cooperation from the guest.

The important distinction from instance backpressure is that the affected task may already have started. It might be waiting for an event or already queued for thread/fiber resumption, so the restriction needs to apply to both starting and re-entering guest code.

While a task is paused:

This would also seem useful as a more general scheduler primitive for cases such as the debugger work discussed in #11896.

Implementation

Current main appears to already carry QualifiedThreadId on both ResumeThread and ResumeFiber, so all guest-executing work items seem to have enough identity to associate them with a task.

One possible implementation would be to add a task-level scheduler eligibility check covering guest-call start/event delivery as well as thread/fiber resumption, and retain ineligible work until the task becomes runnable again.

I'm not sure whether the natural unit should be exactly one GuestTaskId, or a root export task together with work descended from it. For the motivating use case, root-task semantics would probably be more useful.

I'd be interested in whether this matches the scheduler direction already envisioned for #11896, or whether Wasmtime would model this differently.

Alternatives

One alternative is to implement the exclusion in the guest, for example by wrapping exports so that non-owning tasks return Pending while another task holds the exclusive section. That works, but requires cooperation from each guest language/runtime and therefore cannot be enforced by the host for arbitrary components.

Another alternative is to delay host-originated completion futures. That can prevent some event deliveries, but does not cover already-queued starts, guest-to-guest events, or thread/fiber resumption.

Instance backpressure is also insufficient because it only controls starting calls, not resuming already-started task

view this post on Zulip Wasmtime GitHub notifications bot (Sep 16 2026 at 02:49):

EFEXP commented on issue #14284:

Thanks, Luke. I was able to get close to the desired behavior by pausing the whole Store using Store::call_hook_async.
I agree with your point that distinguishing guest work inside a critical section from unrelated work requires cooperation from the guest scheduler.
I’ll explore coordinating the guest scheduler with the host to achieve workerd-like behavior without modifying Wasmtime itself.


Last updated: Sep 20 2026 at 18:08 UTC