Skip to content

Commit f6d4fc0

Browse files
committed
test: use wait/notify to improve threads.wat test
Previously, the test simply executed in a loop for some hardcoded number of iterations. This changes uses `wait` and `notify` and atomic operations to keep track of when the spawned threads are done and join on the main thread appropriately.
1 parent 746f49a commit f6d4fc0

File tree

2 files changed

+29
-18
lines changed

2 files changed

+29
-18
lines changed

tests/all/cli_tests.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,13 @@ fn run_threads() -> Result<()> {
488488
wasm.path().to_str().unwrap(),
489489
])?;
490490

491-
assert!(stdout.contains("Hello _start"));
492-
assert!(stdout.contains("Hello wasi_thread_start"));
493-
assert!(stdout.contains("Hello done"));
491+
assert!(
492+
stdout
493+
== "Called _start\n\
494+
Running wasi_thread_start\n\
495+
Running wasi_thread_start\n\
496+
Running wasi_thread_start\n\
497+
Done\n"
498+
);
494499
Ok(())
495500
}

tests/all/cli_tests/threads.wat

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,42 @@
44
(import "" "memory" (memory $shmem 1 1 shared))
55
(import "wasi_snapshot_preview1" "fd_write"
66
(func $__wasi_fd_write (param i32 i32 i32 i32) (result i32)))
7+
(import "wasi_snapshot_preview1" "proc_exit"
8+
(func $__wasi_proc_exit (param i32)))
79
(import "wasi" "thread_spawn"
810
(func $__wasi_thread_spawn (param i32) (result i32)))
911

1012
(func (export "_start")
1113
(local $i i32)
1214

13-
;; Print "Hello _start".
14-
(call $print (i32.const 32) (i32.const 13))
15+
;; Print "Called _start".
16+
(call $print (i32.const 32) (i32.const 14))
1517

16-
;; Print "Hello wasi_thread_start" in several threads.
18+
;; Print "Running wasi_thread_start" in several threads.
1719
(drop (call $__wasi_thread_spawn (i32.const 0)))
1820
(drop (call $__wasi_thread_spawn (i32.const 0)))
1921
(drop (call $__wasi_thread_spawn (i32.const 0)))
2022

21-
;; Spin to allow the threads to do their work. TODO: replace this with
22-
;; a loop over `wait` with `notify` instructions in the
23-
;; `wasi_thread_start` entry point.
24-
(local.set $i (i32.const 4000000))
23+
;; Wait for all the threads to notify us that they are done.
2524
(loop $again
26-
(local.set $i (i32.sub (local.get $i) (i32.const 1)))
27-
(br_if $again (i32.gt_s (local.get $i) (i32.const 0)))
25+
;; Retrieve the i32 at address 128, compare it to -1 (it should always
26+
;; fail) and load it atomically to check if all three threads are
27+
;; complete. This wait is for 1ms or until notified, whichever is first.
28+
(drop (memory.atomic.wait32 (i32.const 128) (i32.const -1) (i64.const 1000000)))
29+
(br_if $again (i32.lt_s (i32.atomic.load (i32.const 128)) (i32.const 3)))
2830
)
2931

30-
;; Print "Hello done".
31-
(call $print (i32.const 64) (i32.const 11))
32+
;; Print "Done".
33+
(call $print (i32.const 64) (i32.const 5))
3234
)
3335

3436
;; A threads-enabled module must export this spec-designated entry point.
3537
(func (export "wasi_thread_start") (param $tid i32) (param $start_arg i32)
36-
(call $print (i32.const 96) (i32.const 24))
38+
(call $print (i32.const 96) (i32.const 26))
39+
;; After printing, we atomically increment the value at address 128 and then
40+
;; wake up the main thread's join loop.
41+
(drop (i32.atomic.rmw.add (i32.const 128) (i32.const 1)))
42+
(drop (memory.atomic.notify (i32.const 128) (i32.const 1)))
3743
)
3844

3945
;; A helper function for printing ptr-len strings.
@@ -50,7 +56,7 @@
5056
;; We still need to export the shared memory for Wiggle's sake.
5157
(export "memory" (memory $shmem))
5258

53-
(data (i32.const 32) "Hello _start\0a")
54-
(data (i32.const 64) "Hello done\0a")
55-
(data (i32.const 96) "Hello wasi_thread_start\0a")
59+
(data (i32.const 32) "Called _start\0a")
60+
(data (i32.const 64) "Done\0a")
61+
(data (i32.const 96) "Running wasi_thread_start\0a")
5662
)

0 commit comments

Comments
 (0)