As @yamt points out [here], the `wait`/`notify` pairing used in this manual WAT test was not effective. The `wait` always immediately returned, meaning that the main thread essentially spins until a counter is atomically incremented. This is fine for test correctness, but was not the original intent, which was lost in a refactoring. This change uses the `$i` local to keep track of the counter value we expect to see for the `wait`, so that the `wait`/`notify` pair actually waits as expected. [here]: https://github.com/bytecodealliance/wasmtime/pull/5484#discussion_r1101200012
66 lines
2.5 KiB
Plaintext
66 lines
2.5 KiB
Plaintext
(module
|
|
;; As we have discussed, it makes sense to make the shared memory an import
|
|
;; so that all
|
|
(import "" "memory" (memory $shmem 1 1 shared))
|
|
(import "wasi_snapshot_preview1" "fd_write"
|
|
(func $__wasi_fd_write (param i32 i32 i32 i32) (result i32)))
|
|
(import "wasi_snapshot_preview1" "proc_exit"
|
|
(func $__wasi_proc_exit (param i32)))
|
|
(import "wasi" "thread-spawn"
|
|
(func $__wasi_thread_spawn (param i32) (result i32)))
|
|
|
|
(func (export "_start")
|
|
(local $i i32)
|
|
|
|
;; Print "Called _start".
|
|
(call $print (i32.const 32) (i32.const 14))
|
|
|
|
;; Print "Running wasi_thread_start" in several threads.
|
|
(drop (call $__wasi_thread_spawn (i32.const 0)))
|
|
(drop (call $__wasi_thread_spawn (i32.const 0)))
|
|
(drop (call $__wasi_thread_spawn (i32.const 0)))
|
|
|
|
;; Wait for all the threads to notify us that they are done.
|
|
(local.set $i (i32.const 0))
|
|
(loop $again
|
|
;; Wait for the i32 at address 128 to be incremented by each thread. We
|
|
;; maintain a local $i with the atomically loaded value as the expected
|
|
;; wait value and to check if all three threads are complete. This wait is
|
|
;; for 1ms or until notified, whichever is first.
|
|
(drop (memory.atomic.wait32 (i32.const 128) (local.get $i) (i64.const 1000000)))
|
|
(local.set $i (i32.atomic.load (i32.const 128)))
|
|
(br_if $again (i32.lt_s (local.get $i) (i32.const 3)))
|
|
)
|
|
|
|
;; Print "Done".
|
|
(call $print (i32.const 64) (i32.const 5))
|
|
)
|
|
|
|
;; A threads-enabled module must export this spec-designated entry point.
|
|
(func (export "wasi_thread_start") (param $tid i32) (param $start_arg i32)
|
|
(call $print (i32.const 96) (i32.const 26))
|
|
;; After printing, we atomically increment the value at address 128 and then
|
|
;; wake up the main thread's join loop.
|
|
(drop (i32.atomic.rmw.add (i32.const 128) (i32.const 1)))
|
|
(drop (memory.atomic.notify (i32.const 128) (i32.const 1)))
|
|
)
|
|
|
|
;; A helper function for printing ptr-len strings.
|
|
(func $print (param $ptr i32) (param $len i32)
|
|
(i32.store (i32.const 8) (local.get $len))
|
|
(i32.store (i32.const 4) (local.get $ptr))
|
|
(drop (call $__wasi_fd_write
|
|
(i32.const 1)
|
|
(i32.const 4)
|
|
(i32.const 1)
|
|
(i32.const 0)))
|
|
)
|
|
|
|
;; We still need to export the shared memory for Wiggle's sake.
|
|
(export "memory" (memory $shmem))
|
|
|
|
(data (i32.const 32) "Called _start\0a")
|
|
(data (i32.const 64) "Done\0a")
|
|
(data (i32.const 96) "Running wasi_thread_start\0a")
|
|
)
|