1edfa10d6SAndrew Brown(module
2edfa10d6SAndrew Brown  ;; As we have discussed, it makes sense to make the shared memory an import
3edfa10d6SAndrew Brown  ;; so that all
4edfa10d6SAndrew Brown  (import "" "memory" (memory $shmem 1 1 shared))
5edfa10d6SAndrew Brown  (import "wasi_snapshot_preview1" "fd_write"
6edfa10d6SAndrew Brown    (func $__wasi_fd_write (param i32 i32 i32 i32) (result i32)))
7edfa10d6SAndrew Brown  (import "wasi_snapshot_preview1" "proc_exit"
8edfa10d6SAndrew Brown    (func $__wasi_proc_exit (param i32)))
9cacc4160SAndrew Brown  (import "wasi" "thread-spawn"
10edfa10d6SAndrew Brown    (func $__wasi_thread_spawn (param i32) (result i32)))
11edfa10d6SAndrew Brown
12edfa10d6SAndrew Brown  (func (export "_start")
13edfa10d6SAndrew Brown    (local $i i32)
14edfa10d6SAndrew Brown
15edfa10d6SAndrew Brown    ;; Print "Called _start".
16edfa10d6SAndrew Brown    (call $print (i32.const 32) (i32.const 14))
17edfa10d6SAndrew Brown
18edfa10d6SAndrew Brown    ;; Print "Running wasi_thread_start" in several threads.
19edfa10d6SAndrew Brown    (drop (call $__wasi_thread_spawn (i32.const 0)))
20edfa10d6SAndrew Brown    (drop (call $__wasi_thread_spawn (i32.const 0)))
21edfa10d6SAndrew Brown    (drop (call $__wasi_thread_spawn (i32.const 0)))
22edfa10d6SAndrew Brown
23edfa10d6SAndrew Brown    ;; Wait for all the threads to notify us that they are done.
24*f6b16a71SAndrew Brown    (local.set $i (i32.const 0))
25edfa10d6SAndrew Brown    (loop $again
26*f6b16a71SAndrew Brown      ;; Wait for the i32 at address 128 to be incremented by each thread. We
27*f6b16a71SAndrew Brown      ;; maintain a local $i with the atomically loaded value as the expected
28*f6b16a71SAndrew Brown      ;; wait value and to check if all three threads are complete. This wait is
29*f6b16a71SAndrew Brown      ;; for 1ms or until notified, whichever is first.
30*f6b16a71SAndrew Brown      (drop (memory.atomic.wait32 (i32.const 128) (local.get $i) (i64.const 1000000)))
31*f6b16a71SAndrew Brown      (local.set $i (i32.atomic.load (i32.const 128)))
32*f6b16a71SAndrew Brown      (br_if $again (i32.lt_s (local.get $i) (i32.const 3)))
33edfa10d6SAndrew Brown    )
34edfa10d6SAndrew Brown
35edfa10d6SAndrew Brown    ;; Print "Done".
36edfa10d6SAndrew Brown    (call $print (i32.const 64) (i32.const 5))
37edfa10d6SAndrew Brown  )
38edfa10d6SAndrew Brown
39edfa10d6SAndrew Brown  ;; A threads-enabled module must export this spec-designated entry point.
40edfa10d6SAndrew Brown  (func (export "wasi_thread_start") (param $tid i32) (param $start_arg i32)
41edfa10d6SAndrew Brown    (call $print (i32.const 96) (i32.const 26))
42edfa10d6SAndrew Brown    ;; After printing, we atomically increment the value at address 128 and then
43edfa10d6SAndrew Brown    ;; wake up the main thread's join loop.
44edfa10d6SAndrew Brown    (drop (i32.atomic.rmw.add (i32.const 128) (i32.const 1)))
45edfa10d6SAndrew Brown    (drop (memory.atomic.notify (i32.const 128) (i32.const 1)))
46edfa10d6SAndrew Brown  )
47edfa10d6SAndrew Brown
48edfa10d6SAndrew Brown  ;; A helper function for printing ptr-len strings.
49edfa10d6SAndrew Brown  (func $print (param $ptr i32) (param $len i32)
50edfa10d6SAndrew Brown    (i32.store (i32.const 8) (local.get $len))
51edfa10d6SAndrew Brown    (i32.store (i32.const 4) (local.get $ptr))
52edfa10d6SAndrew Brown        (drop (call $__wasi_fd_write
53edfa10d6SAndrew Brown          (i32.const 1)
54edfa10d6SAndrew Brown          (i32.const 4)
55edfa10d6SAndrew Brown          (i32.const 1)
56edfa10d6SAndrew Brown          (i32.const 0)))
57edfa10d6SAndrew Brown  )
58edfa10d6SAndrew Brown
59edfa10d6SAndrew Brown  ;; We still need to export the shared memory for Wiggle's sake.
60edfa10d6SAndrew Brown  (export "memory" (memory $shmem))
61edfa10d6SAndrew Brown
62edfa10d6SAndrew Brown  (data (i32.const 32) "Called _start\0a")
63edfa10d6SAndrew Brown  (data (i32.const 64) "Done\0a")
64edfa10d6SAndrew Brown  (data (i32.const 96) "Running wasi_thread_start\0a")
65edfa10d6SAndrew Brown)
66