Skip to content

Commit c5c2184

Browse files
chrisogopherbot
authored andcommittedMay 25, 2023
runtime: implement wasip1 netpoll
Implements netpoll using WASI's poll_oneoff system call. This enables non-blocking I/O support for wasip1. Change-Id: Ie395fa49d651c8b8262d485e2847dd65b0a10bc6 Reviewed-on: https://go-review.googlesource.com/c/go/+/493357 Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> Reviewed-by: Johan Brandhorst-Satzkorn <[email protected]> Reviewed-by: Julien Fabre <[email protected]> Auto-Submit: Johan Brandhorst-Satzkorn <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]>
1 parent 04c6289 commit c5c2184

File tree

12 files changed

+442
-11
lines changed

12 files changed

+442
-11
lines changed
 

‎misc/wasm/go_wasip1_wasm_exec

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
case "$GOWASIRUNTIME" in
77
"wasmedge")
8-
exec wasmedge --dir=/ --env PWD="$PWD" "$1" "${@:2}"
8+
exec wasmedge --dir=/ --env PWD="$PWD" ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
99
;;
1010
"wasmer")
11-
exec wasmer run --dir=/ --env PWD="$PWD" "$1" -- "${@:2}"
11+
exec wasmer run --dir=/ --env PWD="$PWD" ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
1212
;;
1313
"wasmtime")
1414
exec wasmtime run --dir=/ --env PWD="$PWD" --max-wasm-stack 1048576 "$1" -- "${@:2}"

‎src/cmd/dist/test.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,8 @@ func (t *tester) registerTests() {
574574
// registerStdTestSpecially tracks import paths in the standard library
575575
// whose test registration happens in a special way.
576576
registerStdTestSpecially := map[string]bool{
577-
"cmd/internal/testdir": true, // Registered at the bottom with sharding.
577+
"runtime/internal/wasitest": true, // Registered at the bottom as a host test.
578+
"cmd/internal/testdir": true, // Registered at the bottom with sharding.
578579
}
579580

580581
// Fast path to avoid the ~1 second of `go list std cmd` when
@@ -786,6 +787,16 @@ func (t *tester) registerTests() {
786787
t.registerCgoTests(cgoHeading)
787788
}
788789

790+
if goos == "wasip1" {
791+
t.registerTest("wasip1 host tests",
792+
&goTest{
793+
variant: "host",
794+
pkg: "runtime/internal/wasitest",
795+
timeout: 1 * time.Minute,
796+
runOnHost: true,
797+
})
798+
}
799+
789800
if goos != "android" && !t.iOS() {
790801
// Only start multiple test dir shards on builders,
791802
// where they get distributed to multiple machines.

‎src/internal/poll/errno_unix.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build unix
5+
//go:build unix || wasip1
66

77
package poll
88

‎src/internal/poll/fd_poll_wasm.go ‎src/internal/poll/fd_poll_js.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build (js && wasm) || wasip1
5+
//go:build js && wasm
66

77
package poll
88

‎src/internal/poll/fd_poll_runtime.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build unix || windows
5+
//go:build unix || windows || wasip1
66

77
package poll
88

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package wasi_test
6+
7+
import "flag"
8+
9+
var target string
10+
11+
func init() {
12+
// The dist test runner passes -target when running this as a host test.
13+
flag.StringVar(&target, "target", "", "")
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package wasi_test
6+
7+
import (
8+
"bufio"
9+
"fmt"
10+
"io"
11+
"math/rand"
12+
"os"
13+
"os/exec"
14+
"path/filepath"
15+
"syscall"
16+
"testing"
17+
)
18+
19+
// This test creates a set of FIFOs and writes to them in reverse order. It
20+
// checks that the output order matches the write order. The test binary opens
21+
// the FIFOs in their original order and spawns a goroutine for each that reads
22+
// from the FIFO and writes the result to stderr. If I/O was blocking, all
23+
// goroutines would be blocked waiting for one read call to return, and the
24+
// output order wouldn't match.
25+
26+
type fifo struct {
27+
file *os.File
28+
path string
29+
}
30+
31+
func TestNonblock(t *testing.T) {
32+
if target != "wasip1/wasm" {
33+
t.Skip()
34+
}
35+
36+
switch os.Getenv("GOWASIRUNTIME") {
37+
case "wazero", "":
38+
t.Skip("wazero does not support non-blocking I/O")
39+
case "wasmer":
40+
t.Skip("wasmer does not support non-blocking I/O")
41+
}
42+
43+
args := []string{"run", "./testdata/nonblock.go"}
44+
45+
fifos := make([]*fifo, 8)
46+
for i := range fifos {
47+
path := filepath.Join(t.TempDir(), fmt.Sprintf("wasip1-nonblock-fifo-%d-%d", rand.Uint32(), i))
48+
if err := syscall.Mkfifo(path, 0666); err != nil {
49+
t.Fatal(err)
50+
}
51+
52+
file, err := os.OpenFile(path, os.O_RDWR, 0)
53+
if err != nil {
54+
t.Fatal(err)
55+
}
56+
defer file.Close()
57+
58+
args = append(args, path)
59+
fifos[len(fifos)-i-1] = &fifo{file, path}
60+
}
61+
62+
subProcess := exec.Command("go", args...)
63+
64+
subProcess.Env = append(os.Environ(), "GOOS=wasip1", "GOARCH=wasm")
65+
66+
pr, pw := io.Pipe()
67+
defer pw.Close()
68+
69+
subProcess.Stderr = pw
70+
71+
if err := subProcess.Start(); err != nil {
72+
t.Fatal(err)
73+
}
74+
75+
scanner := bufio.NewScanner(pr)
76+
if !scanner.Scan() {
77+
t.Fatal("expected line:", scanner.Err())
78+
} else if scanner.Text() != "waiting" {
79+
t.Fatal("unexpected output:", scanner.Text())
80+
}
81+
82+
for _, fifo := range fifos {
83+
if _, err := fifo.file.WriteString(fifo.path + "\n"); err != nil {
84+
t.Fatal(err)
85+
}
86+
if !scanner.Scan() {
87+
t.Fatal("expected line:", scanner.Err())
88+
} else if scanner.Text() != fifo.path {
89+
t.Fatal("unexpected line:", scanner.Text())
90+
}
91+
}
92+
93+
if err := subProcess.Wait(); err != nil {
94+
t.Fatal(err)
95+
}
96+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"os"
9+
"sync"
10+
)
11+
12+
func main() {
13+
ready := make(chan struct{})
14+
15+
var wg sync.WaitGroup
16+
for _, path := range os.Args[1:] {
17+
f, err := os.Open(path)
18+
if err != nil {
19+
panic(err)
20+
}
21+
22+
spawnWait := make(chan struct{})
23+
24+
wg.Add(1)
25+
go func(f *os.File) {
26+
defer f.Close()
27+
defer wg.Done()
28+
29+
close(spawnWait)
30+
31+
<-ready
32+
33+
var buf [256]byte
34+
n, err := f.Read(buf[:])
35+
if err != nil {
36+
panic(err)
37+
}
38+
os.Stderr.Write(buf[:n])
39+
}(f)
40+
41+
// Spawn one goroutine at a time.
42+
<-spawnWait
43+
}
44+
45+
println("waiting")
46+
close(ready)
47+
wg.Wait()
48+
}

‎src/runtime/netpoll.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,8 @@ func poll_runtime_pollWait(pd *pollDesc, mode int) int {
336336
if errcode != pollNoError {
337337
return errcode
338338
}
339-
// As for now only Solaris, illumos, and AIX use level-triggered IO.
340-
if GOOS == "solaris" || GOOS == "illumos" || GOOS == "aix" {
339+
// As for now only Solaris, illumos, AIX and wasip1 use level-triggered IO.
340+
if GOOS == "solaris" || GOOS == "illumos" || GOOS == "aix" || GOOS == "wasip1" {
341341
netpollarm(pd, mode)
342342
}
343343
for !netpollblock(pd, int32(mode), false) {

‎src/runtime/netpoll_fake.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// Fake network poller for js/wasm and wasip1/wasm.
6-
// Should never be used, because wasm network connections do not honor "SetNonblock".
5+
// Fake network poller for js/wasm.
6+
// Should never be used, because js/wasm network connections do not honor "SetNonblock".
77

8-
//go:build (js && wasm) || wasip1
8+
//go:build js && wasm
99

1010
package runtime
1111

0 commit comments

Comments
 (0)