Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/tests/misc_testsuite/component-model-async/backpressure-deadlock.wast
1691 views
;;! component_model_async = true
;;! reference_types = true
;;! gc_types = true
;;! multi_memory = true

;; - Component B asks component A to enable backpressure
;; - Component B makes an async call to component A
;; - Component B asserts this subtask is in the "STARTING" state
;; - Component B adds the subtask to a waitable set and calls waitable-set.wait
;;
;; This leaves both tasks in a deadlock situation, which, as of this writing,
;; Wasmtime will handle by trapping.  In the future, once there's a host API for
;; cancelling tasks, that behavior may change, in which case this test will need
;; to be updated.
(component

  (component $A
    (core func $backpressure.set (canon backpressure.set))
    (core module $m
      (import "" "backpressure.set" (func $backpressure.set (param i32)))

      (func (export "f") (result i32) unreachable)
      (func (export "callback") (param i32 i32 i32) (result i32) unreachable)

      (func (export "turn-on-backpressure")
        (call $backpressure.set (i32.const 1)))
    )

    (core instance $i (instantiate $m
      (with "" (instance
        (export "backpressure.set" (func $backpressure.set))
      ))
    ))

    (func (export "turn-on-backpressure") (canon lift (core func $i "turn-on-backpressure")))
    (func (export "f")
      (canon lift (core func $i "f") async (callback (func $i "callback"))))
  )
  (instance $A (instantiate $A))

  (core module $libc (memory (export "mem") 1))
  (core instance $libc (instantiate $libc))

  (core func $f (canon lower (func $A "f") async (memory $libc "mem")))
  (core func $turn-on-backpressure (canon lower (func $A "turn-on-backpressure")))
  (core func $waitable-set.new (canon waitable-set.new))
  (core func $waitable.join (canon waitable.join))
  (core func $waitable-set.wait (canon waitable-set.wait (memory $libc "mem")))

  (core module $m
    (import "" "f" (func $f (result i32)))
    (import "" "turn-on-backpressure" (func $turn-on-backpressure))
    (import "" "waitable-set.new" (func $waitable-set.new (result i32)))
    (import "" "waitable.join" (func $waitable.join (param i32 i32)))
    (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32)))

    (func (export "f")
      (local $status i32)
      (local $set i32)
      call $turn-on-backpressure

      (local.set $status (call $f))

      ;; low 4 bits should be "STARTING == 0"
      (i32.ne
        (i32.const 0)
        (i32.and
          (local.get $status)
          (i32.const 0xf)))
      if unreachable end

      ;; make a new waitable set and join our subtask into it
      (local.set $set (call $waitable-set.new))
      (call $waitable.join
        (i32.shr_u (local.get $status) (i32.const 4))
        (local.get $set))

      ;; block waiting for our task, which should deadlock (?)
      (call $waitable-set.wait (local.get $set) (i32.const 0))
      unreachable
    )
  )

  (core instance $i (instantiate $m
    (with "" (instance
      (export "f" (func $f))
      (export "turn-on-backpressure" (func $turn-on-backpressure))
      (export "waitable-set.new" (func $waitable-set.new))
      (export "waitable.join" (func $waitable.join))
      (export "waitable-set.wait" (func $waitable-set.wait))
    ))
  ))

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

(assert_trap (invoke "f") "deadlock detected")