Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit b4e74e7

Browse files
committed
refactor {Stream,Future}|{Reader,Writer} APIs and internals
This makes a several changes to how `{Stream,Future}|{Reader,Writer}` work to make them more efficient and, in some ways, more ergonomic: - The background tasks have been removed, allowing reads and writes to complete without task context switching. We now only allocate and use oneshot channels lazily when the other end is not yet ready; this improves real world performance benchmarks (e.g. wasi-http request handling) considerably. - Instances of `{Stream,Future}Reader` can now be lifted and lowered directly; no need for `Host{Stream,Future}` anymore. - The type parameter for `Stream{Reader,Writer}` no longer refers to the buffer type -- just the payload type (i.e. `StreamReader<u8>` instead of `StreamReader<Vec<u8>>`), meaning any buffer type may be used for a given read or write operation. This also means the compiler needs help with type inference less often when calling `Instance::stream`. - Instances of `{Stream,Future}|{Reader,Writer}` now require access to the store in order to be disposed of properly. I've added RAII wrapper structs (`WithAccessor[AndValue]`) to help with this, but they can only provide a "best-effort" guarantee since using an `Accessor` from within a `Drop::drop` implementation won't always work. - In order to ensure that resources containing `{Stream,Future}|{Reader,Writer}` instances are disposed of properly, I've added `LinkerInstance::resource_concurrent` and have updated `wasmtime-wit-bindgen` to use it. This gives resource drop functions access to a `StoreContextMut` via an `Accessor`, allowing the stream and future handles to be disposed of. - In order to make this work, I had to change `Accessor::instance` from a `Instance` to an `Option<Instance>`, which is awkward but temporary since we're planning to remove `Accessor::instance` entirely once we've moved concurrent state from `ComponentInstance` to `Store`. That problem of disposal is definitely the most awkward part of all this. In simple cases, it's easy enough to ensure that read and write handles are disposed of properly, but both `wasmtime-wasi` and `wasmtime-wasi-http` have some pretty complicated functions where handles are passed between tasks and/or stored inside resources, so it can be tricky to ensure proper disposal on all code paths. I'm open to ideas for improving this, but I suspect we'll need new Rust language features (e.g. linear types) to make it truly ergonomic, robust, and efficient. While testing the above, I discovered an issue with `Instance::poll_until` such that it would prematurely give up and return a "deadlock" trap error, believing that there was no further work to do, even though the future passed to it was ready to resolve the next time it was polled. I've fixed this by polling it one last time and only trapping if it returns pending. Note that I've moved a few associated functions from `ConcurrentState` to `Instance` (e.g. `guest_drop_writable` and others) since they now need access to the store; they're unchanged otherwise. Apologies for the diff noise. Finally, I've tweaked how `wasmtime serve` to poll the guest for content before handing the response to Hyper, which helps performance by ensuring the first content chunk can be sent with the same TCP packet as the beginning of the response. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
1 parent 9c83732 commit b4e74e7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2102
-1977
lines changed

crates/component-macro/tests/expanded/char_concurrent.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ pub mod foo {
206206
"take-char",
207207
move |caller: &wasmtime::component::Accessor<T>, (arg0,): (char,)| {
208208
wasmtime::component::__internal::Box::pin(async move {
209-
let accessor = &mut unsafe { caller.with_data(host_getter) };
209+
let accessor = &caller.with_data(host_getter);
210210
let r = <D as HostConcurrent>::take_char(accessor, arg0)
211211
.await;
212212
Ok(r)
@@ -217,7 +217,7 @@ pub mod foo {
217217
"return-char",
218218
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
219219
wasmtime::component::__internal::Box::pin(async move {
220-
let accessor = &mut unsafe { caller.with_data(host_getter) };
220+
let accessor = &caller.with_data(host_getter);
221221
let r = <D as HostConcurrent>::return_char(accessor).await;
222222
Ok((r,))
223223
})

crates/component-macro/tests/expanded/conventions_concurrent.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ pub mod foo {
294294
"kebab-case",
295295
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
296296
wasmtime::component::__internal::Box::pin(async move {
297-
let accessor = &mut unsafe { caller.with_data(host_getter) };
297+
let accessor = &caller.with_data(host_getter);
298298
let r = <D as HostConcurrent>::kebab_case(accessor).await;
299299
Ok(r)
300300
})
@@ -307,7 +307,7 @@ pub mod foo {
307307
(arg0,): (LudicrousSpeed,)|
308308
{
309309
wasmtime::component::__internal::Box::pin(async move {
310-
let accessor = &mut unsafe { caller.with_data(host_getter) };
310+
let accessor = &caller.with_data(host_getter);
311311
let r = <D as HostConcurrent>::foo(accessor, arg0).await;
312312
Ok(r)
313313
})
@@ -317,7 +317,7 @@ pub mod foo {
317317
"function-with-dashes",
318318
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
319319
wasmtime::component::__internal::Box::pin(async move {
320-
let accessor = &mut unsafe { caller.with_data(host_getter) };
320+
let accessor = &caller.with_data(host_getter);
321321
let r = <D as HostConcurrent>::function_with_dashes(accessor)
322322
.await;
323323
Ok(r)
@@ -328,7 +328,7 @@ pub mod foo {
328328
"function-with-no-weird-characters",
329329
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
330330
wasmtime::component::__internal::Box::pin(async move {
331-
let accessor = &mut unsafe { caller.with_data(host_getter) };
331+
let accessor = &caller.with_data(host_getter);
332332
let r = <D as HostConcurrent>::function_with_no_weird_characters(
333333
accessor,
334334
)
@@ -341,7 +341,7 @@ pub mod foo {
341341
"apple",
342342
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
343343
wasmtime::component::__internal::Box::pin(async move {
344-
let accessor = &mut unsafe { caller.with_data(host_getter) };
344+
let accessor = &caller.with_data(host_getter);
345345
let r = <D as HostConcurrent>::apple(accessor).await;
346346
Ok(r)
347347
})
@@ -351,7 +351,7 @@ pub mod foo {
351351
"apple-pear",
352352
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
353353
wasmtime::component::__internal::Box::pin(async move {
354-
let accessor = &mut unsafe { caller.with_data(host_getter) };
354+
let accessor = &caller.with_data(host_getter);
355355
let r = <D as HostConcurrent>::apple_pear(accessor).await;
356356
Ok(r)
357357
})
@@ -361,7 +361,7 @@ pub mod foo {
361361
"apple-pear-grape",
362362
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
363363
wasmtime::component::__internal::Box::pin(async move {
364-
let accessor = &mut unsafe { caller.with_data(host_getter) };
364+
let accessor = &caller.with_data(host_getter);
365365
let r = <D as HostConcurrent>::apple_pear_grape(accessor)
366366
.await;
367367
Ok(r)
@@ -372,7 +372,7 @@ pub mod foo {
372372
"a0",
373373
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
374374
wasmtime::component::__internal::Box::pin(async move {
375-
let accessor = &mut unsafe { caller.with_data(host_getter) };
375+
let accessor = &caller.with_data(host_getter);
376376
let r = <D as HostConcurrent>::a0(accessor).await;
377377
Ok(r)
378378
})
@@ -382,7 +382,7 @@ pub mod foo {
382382
"is-XML",
383383
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
384384
wasmtime::component::__internal::Box::pin(async move {
385-
let accessor = &mut unsafe { caller.with_data(host_getter) };
385+
let accessor = &caller.with_data(host_getter);
386386
let r = <D as HostConcurrent>::is_xml(accessor).await;
387387
Ok(r)
388388
})
@@ -392,7 +392,7 @@ pub mod foo {
392392
"explicit",
393393
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
394394
wasmtime::component::__internal::Box::pin(async move {
395-
let accessor = &mut unsafe { caller.with_data(host_getter) };
395+
let accessor = &caller.with_data(host_getter);
396396
let r = <D as HostConcurrent>::explicit(accessor).await;
397397
Ok(r)
398398
})
@@ -402,7 +402,7 @@ pub mod foo {
402402
"explicit-kebab",
403403
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
404404
wasmtime::component::__internal::Box::pin(async move {
405-
let accessor = &mut unsafe { caller.with_data(host_getter) };
405+
let accessor = &caller.with_data(host_getter);
406406
let r = <D as HostConcurrent>::explicit_kebab(accessor)
407407
.await;
408408
Ok(r)
@@ -413,7 +413,7 @@ pub mod foo {
413413
"bool",
414414
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
415415
wasmtime::component::__internal::Box::pin(async move {
416-
let accessor = &mut unsafe { caller.with_data(host_getter) };
416+
let accessor = &caller.with_data(host_getter);
417417
let r = <D as HostConcurrent>::bool(accessor).await;
418418
Ok(r)
419419
})

crates/component-macro/tests/expanded/dead-code_concurrent.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ pub mod a {
213213
"f",
214214
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
215215
wasmtime::component::__internal::Box::pin(async move {
216-
let accessor = &mut unsafe { caller.with_data(host_getter) };
216+
let accessor = &caller.with_data(host_getter);
217217
let r = <D as HostConcurrent>::f(accessor).await;
218218
Ok((r,))
219219
})

crates/component-macro/tests/expanded/direct-import_concurrent.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ const _: () = {
170170
"foo",
171171
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
172172
wasmtime::component::__internal::Box::pin(async move {
173-
let accessor = &mut unsafe { caller.with_data(host_getter) };
173+
let accessor = &caller.with_data(host_getter);
174174
let r = <D as FooImportsConcurrent>::foo(accessor).await;
175175
Ok(r)
176176
})

crates/component-macro/tests/expanded/flags_concurrent.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ pub mod foo {
349349
"roundtrip-flag1",
350350
move |caller: &wasmtime::component::Accessor<T>, (arg0,): (Flag1,)| {
351351
wasmtime::component::__internal::Box::pin(async move {
352-
let accessor = &mut unsafe { caller.with_data(host_getter) };
352+
let accessor = &caller.with_data(host_getter);
353353
let r = <D as HostConcurrent>::roundtrip_flag1(
354354
accessor,
355355
arg0,
@@ -363,7 +363,7 @@ pub mod foo {
363363
"roundtrip-flag2",
364364
move |caller: &wasmtime::component::Accessor<T>, (arg0,): (Flag2,)| {
365365
wasmtime::component::__internal::Box::pin(async move {
366-
let accessor = &mut unsafe { caller.with_data(host_getter) };
366+
let accessor = &caller.with_data(host_getter);
367367
let r = <D as HostConcurrent>::roundtrip_flag2(
368368
accessor,
369369
arg0,
@@ -377,7 +377,7 @@ pub mod foo {
377377
"roundtrip-flag4",
378378
move |caller: &wasmtime::component::Accessor<T>, (arg0,): (Flag4,)| {
379379
wasmtime::component::__internal::Box::pin(async move {
380-
let accessor = &mut unsafe { caller.with_data(host_getter) };
380+
let accessor = &caller.with_data(host_getter);
381381
let r = <D as HostConcurrent>::roundtrip_flag4(
382382
accessor,
383383
arg0,
@@ -391,7 +391,7 @@ pub mod foo {
391391
"roundtrip-flag8",
392392
move |caller: &wasmtime::component::Accessor<T>, (arg0,): (Flag8,)| {
393393
wasmtime::component::__internal::Box::pin(async move {
394-
let accessor = &mut unsafe { caller.with_data(host_getter) };
394+
let accessor = &caller.with_data(host_getter);
395395
let r = <D as HostConcurrent>::roundtrip_flag8(
396396
accessor,
397397
arg0,
@@ -405,7 +405,7 @@ pub mod foo {
405405
"roundtrip-flag16",
406406
move |caller: &wasmtime::component::Accessor<T>, (arg0,): (Flag16,)| {
407407
wasmtime::component::__internal::Box::pin(async move {
408-
let accessor = &mut unsafe { caller.with_data(host_getter) };
408+
let accessor = &caller.with_data(host_getter);
409409
let r = <D as HostConcurrent>::roundtrip_flag16(
410410
accessor,
411411
arg0,
@@ -419,7 +419,7 @@ pub mod foo {
419419
"roundtrip-flag32",
420420
move |caller: &wasmtime::component::Accessor<T>, (arg0,): (Flag32,)| {
421421
wasmtime::component::__internal::Box::pin(async move {
422-
let accessor = &mut unsafe { caller.with_data(host_getter) };
422+
let accessor = &caller.with_data(host_getter);
423423
let r = <D as HostConcurrent>::roundtrip_flag32(
424424
accessor,
425425
arg0,
@@ -433,7 +433,7 @@ pub mod foo {
433433
"roundtrip-flag64",
434434
move |caller: &wasmtime::component::Accessor<T>, (arg0,): (Flag64,)| {
435435
wasmtime::component::__internal::Box::pin(async move {
436-
let accessor = &mut unsafe { caller.with_data(host_getter) };
436+
let accessor = &caller.with_data(host_getter);
437437
let r = <D as HostConcurrent>::roundtrip_flag64(
438438
accessor,
439439
arg0,

crates/component-macro/tests/expanded/floats_concurrent.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ pub mod foo {
217217
"f32-param",
218218
move |caller: &wasmtime::component::Accessor<T>, (arg0,): (f32,)| {
219219
wasmtime::component::__internal::Box::pin(async move {
220-
let accessor = &mut unsafe { caller.with_data(host_getter) };
220+
let accessor = &caller.with_data(host_getter);
221221
let r = <D as HostConcurrent>::f32_param(accessor, arg0)
222222
.await;
223223
Ok(r)
@@ -228,7 +228,7 @@ pub mod foo {
228228
"f64-param",
229229
move |caller: &wasmtime::component::Accessor<T>, (arg0,): (f64,)| {
230230
wasmtime::component::__internal::Box::pin(async move {
231-
let accessor = &mut unsafe { caller.with_data(host_getter) };
231+
let accessor = &caller.with_data(host_getter);
232232
let r = <D as HostConcurrent>::f64_param(accessor, arg0)
233233
.await;
234234
Ok(r)
@@ -239,7 +239,7 @@ pub mod foo {
239239
"f32-result",
240240
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
241241
wasmtime::component::__internal::Box::pin(async move {
242-
let accessor = &mut unsafe { caller.with_data(host_getter) };
242+
let accessor = &caller.with_data(host_getter);
243243
let r = <D as HostConcurrent>::f32_result(accessor).await;
244244
Ok((r,))
245245
})
@@ -249,7 +249,7 @@ pub mod foo {
249249
"f64-result",
250250
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
251251
wasmtime::component::__internal::Box::pin(async move {
252-
let accessor = &mut unsafe { caller.with_data(host_getter) };
252+
let accessor = &caller.with_data(host_getter);
253253
let r = <D as HostConcurrent>::f64_result(accessor).await;
254254
Ok((r,))
255255
})

crates/component-macro/tests/expanded/host-world_concurrent.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ const _: () = {
170170
"foo",
171171
move |caller: &wasmtime::component::Accessor<T>, (): ()| {
172172
wasmtime::component::__internal::Box::pin(async move {
173-
let accessor = &mut unsafe { caller.with_data(host_getter) };
173+
let accessor = &caller.with_data(host_getter);
174174
let r = <D as Host_ImportsConcurrent>::foo(accessor).await;
175175
Ok(r)
176176
})

0 commit comments

Comments
 (0)