From ae6c174aae19ccb8de9c57db0352bb6ceef1d0c9 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Thu, 6 Jul 2023 12:14:02 +0900 Subject: [PATCH] add another set of tests to examine "return from _start" a return from _start is an equivalent of proc_exit(0) and thus should terminate other threads. at least it's what wasi-libc as of today assumes. cf. https://github.com/WebAssembly/wasi-threads/issues/21 ``` (venv) spacetanuki% python3 test-runner/wasi_test_runner.py -t ../wasi-threads/test/testsuite -r ~/git/toywasm/test/wasi-testsuite-adapter.py Test wasi_threads_exit_nonmain_wasi passed Test wasi_threads_exit_main_busy passed Test wasi_threads_return_main_wasi passed Test wasi_threads_return_main_wasi_read passed Test wasi_threads_return_main_block passed Test wasi_threads_exit_main_wasi passed Test wasi_threads_return_main_busy passed Test wasi_threads_exit_nonmain_busy passed Test wasi_threads_spawn passed Test wasi_threads_exit_main_block passed Test wasi_threads_exit_nonmain_wasi_read passed Test wasi_threads_exit_nonmain_block passed Test wasi_threads_exit_main_wasi_read passed ===== Test results ===== Runtime: toywasm v28.0.0 Suite: WASI threads proposal Total: 13 Passed: 13 Failed: 0 Skipped: 0 Test suites: 1 passed, 0 total Tests: 13 passed, 0 total (venv) spacetanuki% ``` --- .../wasi_threads_return_main_block.wat | 42 ++++++++++++++ .../wasi_threads_return_main_busy.wat | 41 ++++++++++++++ .../wasi_threads_return_main_wasi.wat | 51 +++++++++++++++++ .../wasi_threads_return_main_wasi_read.wat | 55 +++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 test/testsuite/wasi_threads_return_main_block.wat create mode 100644 test/testsuite/wasi_threads_return_main_busy.wat create mode 100644 test/testsuite/wasi_threads_return_main_wasi.wat create mode 100644 test/testsuite/wasi_threads_return_main_wasi_read.wat diff --git a/test/testsuite/wasi_threads_return_main_block.wat b/test/testsuite/wasi_threads_return_main_block.wat new file mode 100644 index 0000000..c7c3058 --- /dev/null +++ b/test/testsuite/wasi_threads_return_main_block.wat @@ -0,0 +1,42 @@ +;; When the main thread returns from _start, it should terminate +;; a thread blocking in `memory.atomic.wait32` opcode. +;; +;; linear memory usage: +;; 0: notify/wait + +(module + (memory (export "memory") (import "foo" "bar") 1 1 shared) + (func $thread_spawn (import "wasi" "thread-spawn") (param i32) (result i32)) + (func $proc_exit (import "wasi_snapshot_preview1" "proc_exit") (param i32)) + (func (export "wasi_thread_start") (param i32 i32) + ;; infinite wait + i32.const 0 + i32.const 0 + i64.const -1 + memory.atomic.wait32 + unreachable + ) + (func (export "_start") + ;; spawn a thread + i32.const 0 + call $thread_spawn + ;; check error + i32.const 0 + i32.le_s + if + unreachable + end + ;; wait 500ms to ensure the other thread block + i32.const 0 + i32.const 0 + i64.const 500_000_000 + memory.atomic.wait32 + ;; assert a timeout + i32.const 2 + i32.ne + if + unreachable + end + ;; note: return from _start is the same as proc_exit(0). + ) +) diff --git a/test/testsuite/wasi_threads_return_main_busy.wat b/test/testsuite/wasi_threads_return_main_busy.wat new file mode 100644 index 0000000..c1c05ad --- /dev/null +++ b/test/testsuite/wasi_threads_return_main_busy.wat @@ -0,0 +1,41 @@ +;; When the main thread returns from _start, it should terminate +;; a busy-looping thread. +;; +;; linear memory usage: +;; 0: wait + +(module + (memory (export "memory") (import "foo" "bar") 1 1 shared) + (func $thread_spawn (import "wasi" "thread-spawn") (param i32) (result i32)) + (func $proc_exit (import "wasi_snapshot_preview1" "proc_exit") (param i32)) + (func (export "wasi_thread_start") (param i32 i32) + ;; infinite loop + loop + br 0 + end + unreachable + ) + (func (export "_start") + ;; spawn a thread + i32.const 0 + call $thread_spawn + ;; check error + i32.const 0 + i32.le_s + if + unreachable + end + ;; wait 500ms to ensure the other thread to enter the busy loop + i32.const 0 + i32.const 0 + i64.const 500_000_000 + memory.atomic.wait32 + ;; assert a timeout + i32.const 2 + i32.ne + if + unreachable + end + ;; note: return from _start is the same as proc_exit(0). + ) +) diff --git a/test/testsuite/wasi_threads_return_main_wasi.wat b/test/testsuite/wasi_threads_return_main_wasi.wat new file mode 100644 index 0000000..4338abc --- /dev/null +++ b/test/testsuite/wasi_threads_return_main_wasi.wat @@ -0,0 +1,51 @@ +;; When the main thread returns from _start, it should terminate +;; a thread blocking in a WASI call. (poll_oneoff) +;; +;; linear memory usage: +;; 0: wait +;; 0x100: poll_oneoff subscription +;; 0x200: poll_oneoff event +;; 0x300: poll_oneoff return value + +(module + (memory (export "memory") (import "foo" "bar") 1 1 shared) + (func $thread_spawn (import "wasi" "thread-spawn") (param i32) (result i32)) + (func $proc_exit (import "wasi_snapshot_preview1" "proc_exit") (param i32)) + (func $poll_oneoff (import "wasi_snapshot_preview1" "poll_oneoff") (param i32 i32 i32 i32) (result i32)) + (func (export "wasi_thread_start") (param i32 i32) + ;; long enough block + ;; clock_realtime, !abstime (zeros) + i32.const 0x118 ;; 0x100 + offsetof(subscription, timeout) + i64.const 1_000_000_000 ;; 1s + i64.store + i32.const 0x100 ;; subscription + i32.const 0x200 ;; event (out) + i32.const 1 ;; nsubscriptions + i32.const 0x300 ;; retp (out) + call $poll_oneoff + unreachable + ) + (func (export "_start") + ;; spawn a thread + i32.const 0 + call $thread_spawn + ;; check error + i32.const 0 + i32.le_s + if + unreachable + end + ;; wait 500ms to ensure the other thread block + i32.const 0 + i32.const 0 + i64.const 500_000_000 + memory.atomic.wait32 + ;; assert a timeout + i32.const 2 + i32.ne + if + unreachable + end + ;; note: return from _start is the same as proc_exit(0). + ) +) diff --git a/test/testsuite/wasi_threads_return_main_wasi_read.wat b/test/testsuite/wasi_threads_return_main_wasi_read.wat new file mode 100644 index 0000000..e0d120c --- /dev/null +++ b/test/testsuite/wasi_threads_return_main_wasi_read.wat @@ -0,0 +1,55 @@ +;; When the main thread returns from _start, it should terminate +;; a thread blocking in a WASI call. (fd_read) +;; +;; assumption: read from FD 0 blocks. +;; +;; linear memory usage: +;; 0: wait +;; 100: fd_read iovec +;; 200: buffer +;; 300: result + +(module + (memory (export "memory") (import "foo" "bar") 1 1 shared) + (func $thread_spawn (import "wasi" "thread-spawn") (param i32) (result i32)) + (func $proc_exit (import "wasi_snapshot_preview1" "proc_exit") (param i32)) + (func $fd_read (import "wasi_snapshot_preview1" "fd_read") (param i32 i32 i32 i32) (result i32)) + (func (export "wasi_thread_start") (param i32 i32) + ;; read from FD 0 + i32.const 100 ;; iov_base + i32.const 200 ;; buffer + i32.store + i32.const 104 ;; iov_len + i32.const 1 + i32.store + i32.const 0 ;; fd 0 + i32.const 100 ;; iov_base + i32.const 1 ;; iov count + i32.const 300 ;; retp (out) + call $fd_read + unreachable + ) + (func (export "_start") + ;; spawn a thread + i32.const 0 + call $thread_spawn + ;; check error + i32.const 0 + i32.le_s + if + unreachable + end + ;; wait 500ms to ensure the other thread block + i32.const 0 + i32.const 0 + i64.const 500_000_000 + memory.atomic.wait32 + ;; assert a timeout + i32.const 2 + i32.ne + if + unreachable + end + ;; note: return from _start is the same as proc_exit(0). + ) +)