Skip to content

Evolve the wasip3 async C ABI for tasks#1637

Open
alexcrichton wants to merge 3 commits into
bytecodealliance:mainfrom
alexcrichton:evolve-abi
Open

Evolve the wasip3 async C ABI for tasks#1637
alexcrichton wants to merge 3 commits into
bytecodealliance:mainfrom
alexcrichton:evolve-abi

Conversation

@alexcrichton

Copy link
Copy Markdown
Member

This commit is an evolution of the C ABI used to managed task-related infrastructure in WASIp3 with the goal of solving #1618. The basic problem of #1618 is that waitables in Rust aren't guaranteed to be polled within the context of the original task. For example by mixing an async Rust export and block_on it's possible to "cross the wires" and poll in one context while dropping/completing in another context. This can lead to buggy situations where a waitable is left in a set, not added to an appropriate set, or generally mis-managed.

The solution here is to enhance the current C ABI of task management with clone/drop operations. Notably this enables waitables to retain a strong reference to the task state as opposed to always consulting what the current task in. This fixes a few situations such as:

  • When dropping a half-finished waitable it no longer needs to be dropped in the context of the original task. Dropping will unregister the waitable from a task that it was originally registered with.
  • When a waitable is moved from one task to another it needs to implicitly de-register with the previous task, and this was not previously done. Now with a retained strong reference it's able to clear out previous state upon re-registering with a new task.

This change requires some finesse as this needs to be ABI-stable to work with previous versions of the wit-bindgen crate. The runtime support additionally can't assume that the new ABI bits are available and instead needs to handle the previous ABI as well. Not too too bad, in the end, though.

This additionally did some refactoring of the state associated with async tasks to juggle things around and better represent the raw pointers/Arc/etc from before.

Closes #1618

This commit is an evolution of the C ABI used to managed task-related
infrastructure in WASIp3 with the goal of solving bytecodealliance#1618. The basic
problem of bytecodealliance#1618 is that waitables in Rust aren't guaranteed to be
polled within the context of the original task. For example by mixing an
`async` Rust export and `block_on` it's possible to "cross the wires"
and poll in one context while dropping/completing in another context.
This can lead to buggy situations where a waitable is left in a set, not
added to an appropriate set, or generally mis-managed.

The solution here is to enhance the current C ABI of task management
with clone/drop operations. Notably this enables waitables to retain a
strong reference to the task state as opposed to always consulting what
the current task in. This fixes a few situations such as:

* When dropping a half-finished waitable it no longer needs to be
  dropped in the context of the original task. Dropping will unregister
  the waitable from a task that it was originally registered with.
* When a waitable is moved from one task to another it needs to
  implicitly de-register with the previous task, and this was not
  previously done. Now with a retained strong reference it's able to
  clear out previous state upon re-registering with a new task.

This change requires some finesse as this needs to be ABI-stable to work
with previous versions of the `wit-bindgen` crate. The runtime support
additionally can't assume that the new ABI bits are available and
instead needs to handle the previous ABI as well. Not too too bad, in
the end, though.

This additionally did some refactoring of the state associated with
async tasks to juggle things around and better represent the raw
pointers/`Arc`/etc from before.

Closes bytecodealliance#1618
@alexcrichton alexcrichton requested a review from dicej June 17, 2026 20:27
pub struct wasip3_task_vtable {
/// Currently `WASIP3_TASK_V2` as that was the first version that specified
/// vtables.
pub version: u32,

@dicej dicej Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do we need a version field here and also in wasip3_task?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

My thinking was that this vtable would grow over time independent of the original wasip3_task but that might be a bit too overeager thinking on my part. Does that sound reasonable?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't have strong feelings, but I would imagine that the one in wasip3_task could cover everything, including the vtable.

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.

assertion left == right failed at src/rt/async_support/waitable.rs:201

2 participants