| f586be11 | 09-Dec-2025 |
Alex Crichton <[email protected]> |
cm-async: Start to fill out `{Future,Stream}Any` (#12142)
* cm-async: Start to fill out `{Future,Stream}Any`
This commit is the first step down the road of filling out the preexisting, but empty/bu
cm-async: Start to fill out `{Future,Stream}Any` (#12142)
* cm-async: Start to fill out `{Future,Stream}Any`
This commit is the first step down the road of filling out the preexisting, but empty/buggy, `FutureAny` and `StreamAny` types. These are intended to behave similarly to `ResourceAny` where the embedder doesn't have static knowledge ahead of time about the type of the future/stream in use. Changes made here are:
* `ComponentType for {Stream,Future}Reader<T>` now correctly typecheck the `T`. * Conversion to/from `*Any` types now properly typechecks the payload type against the expected type. * `{Future,Stream}Any` now live in their own file with the matrix of conversions to the typed variants. * A `close` method was added to `*Any` types.
These types are not currently directly constructible but this will likely be relaxed in the future. Additionally the host can't actually use these values without knowing the type, which is another restriction that will be relaxed in the future (aka implemented).
cc #11161
* Fix tests
* Skip a test on miri
show more ...
|
| efd56f68 | 04-Nov-2025 |
Joel Dice <[email protected]> |
fix a couple of partial read/write bugs (#11981)
* reset read/write state back to `Open` on event delivery
If one end of a stream does a partial read or write, we leave the other end in a `GuestRea
fix a couple of partial read/write bugs (#11981)
* reset read/write state back to `Open` on event delivery
If one end of a stream does a partial read or write, we leave the other end in a `GuestReady` state, allowing further reads or writes to proceed until the buffer has been drained or filled, respectively. However, once we've delivered the event regarding the partial operation, we need to set the state back to `Open`, since we'll have released the buffer back to the guest at that point.
Signed-off-by: Joel Dice <[email protected]>
* delay returning `Dropped` until producer buffer drained
If the `StreamProducer` calls `Destination::set_buffer`, we need to make sure all the items in that buffer have been delivered to the receiver (or the receiver closes its end) before telling it the write end has been dropped.
Signed-off-by: Joel Dice <[email protected]>
* add short reads tests
These cover a couple of scenarios where the guest and/or host read owned resource items one-at-a-time from writes of more than one item, forcing the writer to re-take ownership of the unwritten items between writes.
This also covers the case where the host's `StreamProducer` returns `StreamResult::Dropped` after calling `Destination::set_buffer`, in which case Wasmtime must delay telling the other end about the dropped stream until that buffer has been drained.
Signed-off-by: Joel Dice <[email protected]>
---------
Signed-off-by: Joel Dice <[email protected]>
show more ...
|
| 87d1730b | 27-Oct-2025 |
Alex Crichton <[email protected]> |
Supply type information in `func_new` for components (#11944)
Originally the `Linker::func_new` type for components was modeled after core wasm where a type was provided when the type was defined. T
Supply type information in `func_new` for components (#11944)
Originally the `Linker::func_new` type for components was modeled after core wasm where a type was provided when the type was defined. This was difficult, however, because there's no way to construct types right now and instead a component had to be created and compiled to acquire type information from it. Later various refactorings meant that it was possible to drop the type information entirely from `func_new` meaning that it was "typeless" in a sense, and the functionality relied on the tagged nature of `Val` which always knows its type.
This has proven a bit difficult to integrate into Python in some work I've been doing. Namely in Python component values are (at least IMO) best represented as native Python values where possible. Native Python doesn't distinguish, however, between integer bit widths (or signededness). This means that converting a Python value to a component value requires type information to guide the conversion process. Currently when defining a function in a linker there's no way to get at this type information meaning that the types would need to be supplied in Python, bringing up the same shortcomings of not being able to create types.
In lieu of filling out type constructors, which is itself quite nontrivial, I've opted to do the next-most-easiest thing which is to supply the type to the callee when an import is invoked. This means that the callee has all the type information necessary. While this is somewhat costly in that it clones a few arcs it's expected to be a drop in the bucket compared to the inefficiencies of `Val` so it's at least in the same spirit of the cost of the API right now.
My intention is to use this to update the C API for components and eventually end up with type information when Python is invoked in wasmtime-py. Also while I'm using wasmtime-py as a motivating case here that's sort of just one example of a host embedding which doesn't have the full fidelity of Rust's type system and might benefit from this.
show more ...
|
| ec68a031 | 29-Sep-2025 |
Joel Dice <[email protected]> |
don't trap on idle in `Instance::run_concurrent` (#11756)
Previously, `Instance::run_concurrent` returned `Trap::AsyncDeadlock` when all guest tasks and background host tasks had completed, and yet
don't trap on idle in `Instance::run_concurrent` (#11756)
Previously, `Instance::run_concurrent` returned `Trap::AsyncDeadlock` when all guest tasks and background host tasks had completed, and yet the future parameter it was passed still hadn't resolved. The theory was that this indicated a mistake on the host embedder's part, but it turns out there are scenarios where this is actually what the embedder wanted.
For example, consider a host embedder that implements a pool of worker tasks, each of which runs a loop inside async closure passed to `Instance::run_concurrent`. In this case, each worker accepts jobs (which involve calling guest functions) from a multiple-producer, multiple-consumer job queue, adding them to a `futures::stream::FuturesUnordered` so they can be run concurrently. When all the jobs accepted by a given worker have finished, there may be a lull during which no new jobs are yet available. In that case, the worker _could_ break out of the loop, resolve the future, allow `Instance::run_concurrent` to finish, and wait until the next job arrives before calling `Instance::run_concurrent` again, but that's more awkward (i.e. nested loops, complicated control flow) than just a single loop inside `Instance::run_concurrent` that goes idle now and then.
In short, the closure passed to `Instance::run_concurrent` might experience delays between when a set of guest tasks have completed and when the next set are ready to start, and that's not necessarily a bug.
Internally, I've added a new `run_concurrent_trap_on_idle` function, which provides the original, trapping behavior, and I'm using it to implement `[Typed]Func::call_async`, in which case it _is_ an error if the event loop goes idle without the future resolving. If this turns out to be useful as part of the public API, we can change the `pub(super)` to `pub`.
Signed-off-by: Joel Dice <[email protected]>
show more ...
|