Stream: git-wasmtime

Topic: wasmtime / issue #13890 Host tasks created by guest threa...


view this post on Zulip Wasmtime GitHub notifications bot (Jul 16 2026 at 15:30):

alexcrichton opened issue #13890:

This test:

;;! component_model_async = true
;;! component_model_threading = true

(component
  (import "host" (instance $host
    (export "never-return" (func async))
  ))

  (core module $m
    (import "" "never-return" (func $never-return (result i32)))
    (import "" "cancel" (func $cancel (param i32) (result i32)))
    (import "" "drop-subtask" (func $drop-subtask (param i32)))
    (import "" "thread.new-indirect" (func $thread-new (param i32 i32) (result i32)))
    (import "" "thread.index" (func $thread-index (result i32)))
    (import "" "thread.suspend-then-resume" (func $thread-suspend-then-resume (param i32) (result i32)))
    (import "" "thread.resume-later" (func $thread-resume-later (param i32)))
    (import "" "table" (table $table 1 funcref))

    (global $main-thread (mut i32) (i32.const 0))
    (global $subtask (mut i32) (i32.const 0))
    (global $done (mut i32) (i32.const 0))

    (elem (i32.const 0) $creator)

    (func (export "run")
      (global.set $main-thread (call $thread-index))

      ;; Spawn a thread to start a task.
      (drop (call $thread-suspend-then-resume
        (call $thread-new (i32.const 0) (i32.const 0))))
      (if (i32.ne (global.get $done) (i32.const 1)) (then unreachable))

      ;; Should be able to cancel the subtask on this thread.
      (i32.ne
        (call $cancel (global.get $subtask))
        (i32.const 4)) ;; RETURN_CANCELLED
      if unreachable end
      (call $drop-subtask (global.get $subtask))
    )

    ;; Start an import call then exit this thread.
    (func $creator (param i32)
      (local $ret i32)
      (local.set $ret (call $never-return))

      (i32.ne
        (i32.and (local.get $ret) (i32.const 0xf))
        (i32.const 1)) ;; STARTED
      if unreachable end

      (global.set $subtask (i32.shr_u (local.get $ret) (i32.const 4)))
      (global.set $done (i32.const 1))
      (call $thread-resume-later (global.get $main-thread))
    )
  )

  (core module $libc (table (export "table") 1 funcref))
  (core instance $libc (instantiate $libc))
  (alias core export $libc "table" (core table $table))
  (core type $start-func-ty (func (param i32)))

  (core func $never-return (canon lower (func $host "never-return") async))
  (core func $cancel (canon subtask.cancel))
  (core func $drop-subtask (canon subtask.drop))
  (core func $thread.new-indirect (canon thread.new-indirect $start-func-ty (table $table)))
  (core func $thread.index (canon thread.index))
  (core func $thread.suspend-then-resume (canon thread.suspend-then-resume))
  (core func $thread.resume-later (canon thread.resume-later))
  (core instance $i (instantiate $m
      (with "" (instance
          (export "never-return" (func $never-return))
          (export "cancel" (func $cancel))
          (export "drop-subtask" (func $drop-subtask))
          (export "thread.new-indirect" (func $thread.new-indirect))
          (export "thread.index" (func $thread.index))
          (export "thread.suspend-then-resume" (func $thread.suspend-then-resume))
          (export "thread.resume-later" (func $thread.resume-later))
          (export "table" (table $table))
      ))
  ))

  (func (export "f") async
      (canon lift (core func $i "run")))
)

(assert_return (invoke "f"))

currently fails:

$ cargo test --test wast CraneliftNative//home/alex/code/wasmtime/tests/misc_testsuite/component-model-threading/test.wast
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.11s
     Running tests/wast.rs (target/debug/deps/wast-6171bb5a11b49538)

running 1 test
F
failures:

---- CraneliftNative//home/alex/code/wasmtime/tests/misc_testsuite/component-model-threading/test.wast ----
failed to run spec test with default engine

Caused by:
    0: failed directive on /home/alex/code/wasmtime/tests/misc_testsuite/component-model-threading/test.wast:86
    1: resource not present



failures:
    CraneliftNative//home/alex/code/wasmtime/tests/misc_testsuite/component-model-threading/test.wast

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 3517 filtered out; finished in 0.02s

error: test failed, to rerun pass `--test wast`

The reason for this is that the host stores the caller's thread in a HostTask which is then used during lowering the results of the host task once it completes.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 16 2026 at 15:30):

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

view this post on Zulip Wasmtime GitHub notifications bot (Jul 16 2026 at 15:30):

alexcrichton added the wasm-proposal:component-threading label to Issue #13890.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 17 2026 at 21:52):

alexcrichton commented on issue #13890:

In attempting to fix this I've discovered surprising behavior to the point that I'm not actually sure what we should be doing in Wasmtime. I've opened an upstream spec issue - https://github.com/WebAssembly/component-model/issues/678 - for discussion.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 21 2026 at 22:15):

alexcrichton closed issue #13890:

This test:

;;! component_model_async = true
;;! component_model_threading = true

(component
  (import "host" (instance $host
    (export "never-return" (func async))
  ))

  (core module $m
    (import "" "never-return" (func $never-return (result i32)))
    (import "" "cancel" (func $cancel (param i32) (result i32)))
    (import "" "drop-subtask" (func $drop-subtask (param i32)))
    (import "" "thread.new-indirect" (func $thread-new (param i32 i32) (result i32)))
    (import "" "thread.index" (func $thread-index (result i32)))
    (import "" "thread.suspend-then-resume" (func $thread-suspend-then-resume (param i32) (result i32)))
    (import "" "thread.resume-later" (func $thread-resume-later (param i32)))
    (import "" "table" (table $table 1 funcref))

    (global $main-thread (mut i32) (i32.const 0))
    (global $subtask (mut i32) (i32.const 0))
    (global $done (mut i32) (i32.const 0))

    (elem (i32.const 0) $creator)

    (func (export "run")
      (global.set $main-thread (call $thread-index))

      ;; Spawn a thread to start a task.
      (drop (call $thread-suspend-then-resume
        (call $thread-new (i32.const 0) (i32.const 0))))
      (if (i32.ne (global.get $done) (i32.const 1)) (then unreachable))

      ;; Should be able to cancel the subtask on this thread.
      (i32.ne
        (call $cancel (global.get $subtask))
        (i32.const 4)) ;; RETURN_CANCELLED
      if unreachable end
      (call $drop-subtask (global.get $subtask))
    )

    ;; Start an import call then exit this thread.
    (func $creator (param i32)
      (local $ret i32)
      (local.set $ret (call $never-return))

      (i32.ne
        (i32.and (local.get $ret) (i32.const 0xf))
        (i32.const 1)) ;; STARTED
      if unreachable end

      (global.set $subtask (i32.shr_u (local.get $ret) (i32.const 4)))
      (global.set $done (i32.const 1))
      (call $thread-resume-later (global.get $main-thread))
    )
  )

  (core module $libc (table (export "table") 1 funcref))
  (core instance $libc (instantiate $libc))
  (alias core export $libc "table" (core table $table))
  (core type $start-func-ty (func (param i32)))

  (core func $never-return (canon lower (func $host "never-return") async))
  (core func $cancel (canon subtask.cancel))
  (core func $drop-subtask (canon subtask.drop))
  (core func $thread.new-indirect (canon thread.new-indirect $start-func-ty (table $table)))
  (core func $thread.index (canon thread.index))
  (core func $thread.suspend-then-resume (canon thread.suspend-then-resume))
  (core func $thread.resume-later (canon thread.resume-later))
  (core instance $i (instantiate $m
      (with "" (instance
          (export "never-return" (func $never-return))
          (export "cancel" (func $cancel))
          (export "drop-subtask" (func $drop-subtask))
          (export "thread.new-indirect" (func $thread.new-indirect))
          (export "thread.index" (func $thread.index))
          (export "thread.suspend-then-resume" (func $thread.suspend-then-resume))
          (export "thread.resume-later" (func $thread.resume-later))
          (export "table" (table $table))
      ))
  ))

  (func (export "f") async
      (canon lift (core func $i "run")))
)

(assert_return (invoke "f"))

currently fails:

$ cargo test --test wast CraneliftNative//home/alex/code/wasmtime/tests/misc_testsuite/component-model-threading/test.wast
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.11s
     Running tests/wast.rs (target/debug/deps/wast-6171bb5a11b49538)

running 1 test
F
failures:

---- CraneliftNative//home/alex/code/wasmtime/tests/misc_testsuite/component-model-threading/test.wast ----
failed to run spec test with default engine

Caused by:
    0: failed directive on /home/alex/code/wasmtime/tests/misc_testsuite/component-model-threading/test.wast:86
    1: resource not present



failures:
    CraneliftNative//home/alex/code/wasmtime/tests/misc_testsuite/component-model-threading/test.wast

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 3517 filtered out; finished in 0.02s

error: test failed, to rerun pass `--test wast`

The reason for this is that the host stores the caller's thread in a HostTask which is then used during lowering the results of the host task once it completes.


Last updated: Jul 29 2026 at 05:03 UTC