syscall: implement wasip1 Fcntl
CL 494915 broke non-blocking I/O on wasip1 for files
opened with os.NewFile. This is fixed by providing an
implementation of fcntl(F_GETFL) for wasip1.
Change-Id: I78979076b95495fd4b94814552e5f5b043270cd0
Reviewed-on: https://go-review.googlesource.com/c/go/+/498195
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Achille Roussel <achille.roussel@gmail.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
diff --git a/src/internal/syscall/unix/fcntl_wasm.go b/src/internal/syscall/unix/fcntl_js.go
similarity index 91%
rename from src/internal/syscall/unix/fcntl_wasm.go
rename to src/internal/syscall/unix/fcntl_js.go
index c630273..bdfb8e0 100644
--- a/src/internal/syscall/unix/fcntl_wasm.go
+++ b/src/internal/syscall/unix/fcntl_js.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build js && wasm
+
package unix
import "syscall"
diff --git a/src/internal/syscall/unix/fcntl_wasm.go b/src/internal/syscall/unix/fcntl_wasip1.go
similarity index 69%
copy from src/internal/syscall/unix/fcntl_wasm.go
copy to src/internal/syscall/unix/fcntl_wasip1.go
index c630273..e70cd74 100644
--- a/src/internal/syscall/unix/fcntl_wasm.go
+++ b/src/internal/syscall/unix/fcntl_wasip1.go
@@ -2,10 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build wasip1
+
package unix
import "syscall"
func Fcntl(fd int, cmd int, arg int) (int, error) {
+ if cmd == syscall.F_GETFL {
+ flags, err := fd_fdstat_get_flags(fd)
+ return int(flags), err
+ }
return 0, syscall.ENOSYS
}
diff --git a/src/runtime/internal/wasitest/nonblock_test.go b/src/runtime/internal/wasitest/nonblock_test.go
index d873ef5..8fb2860 100644
--- a/src/runtime/internal/wasitest/nonblock_test.go
+++ b/src/runtime/internal/wasitest/nonblock_test.go
@@ -43,57 +43,61 @@
t.Skip("wasmer does not support non-blocking I/O")
}
- args := []string{"run", "./testdata/nonblock.go"}
+ for _, mode := range []string{"os.OpenFile", "os.NewFile"} {
+ t.Run(mode, func(t *testing.T) {
+ args := []string{"run", "./testdata/nonblock.go", mode}
- fifos := make([]*fifo, 8)
- for i := range fifos {
- path := filepath.Join(t.TempDir(), fmt.Sprintf("wasip1-nonblock-fifo-%d-%d", rand.Uint32(), i))
- if err := syscall.Mkfifo(path, 0666); err != nil {
- t.Fatal(err)
- }
+ fifos := make([]*fifo, 8)
+ for i := range fifos {
+ path := filepath.Join(t.TempDir(), fmt.Sprintf("wasip1-nonblock-fifo-%d-%d", rand.Uint32(), i))
+ if err := syscall.Mkfifo(path, 0666); err != nil {
+ t.Fatal(err)
+ }
- file, err := os.OpenFile(path, os.O_RDWR, 0)
- if err != nil {
- t.Fatal(err)
- }
- defer file.Close()
+ file, err := os.OpenFile(path, os.O_RDWR, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer file.Close()
- args = append(args, path)
- fifos[len(fifos)-i-1] = &fifo{file, path}
- }
+ args = append(args, path)
+ fifos[len(fifos)-i-1] = &fifo{file, path}
+ }
- subProcess := exec.Command("go", args...)
+ subProcess := exec.Command("go", args...)
- subProcess.Env = append(os.Environ(), "GOOS=wasip1", "GOARCH=wasm")
+ subProcess.Env = append(os.Environ(), "GOOS=wasip1", "GOARCH=wasm")
- pr, pw := io.Pipe()
- defer pw.Close()
+ pr, pw := io.Pipe()
+ defer pw.Close()
- subProcess.Stderr = pw
+ subProcess.Stderr = pw
- if err := subProcess.Start(); err != nil {
- t.Fatal(err)
- }
+ if err := subProcess.Start(); err != nil {
+ t.Fatal(err)
+ }
- scanner := bufio.NewScanner(pr)
- if !scanner.Scan() {
- t.Fatal("expected line:", scanner.Err())
- } else if scanner.Text() != "waiting" {
- t.Fatal("unexpected output:", scanner.Text())
- }
+ scanner := bufio.NewScanner(pr)
+ if !scanner.Scan() {
+ t.Fatal("expected line:", scanner.Err())
+ } else if scanner.Text() != "waiting" {
+ t.Fatal("unexpected output:", scanner.Text())
+ }
- for _, fifo := range fifos {
- if _, err := fifo.file.WriteString(fifo.path + "\n"); err != nil {
- t.Fatal(err)
- }
- if !scanner.Scan() {
- t.Fatal("expected line:", scanner.Err())
- } else if scanner.Text() != fifo.path {
- t.Fatal("unexpected line:", scanner.Text())
- }
- }
+ for _, fifo := range fifos {
+ if _, err := fifo.file.WriteString(fifo.path + "\n"); err != nil {
+ t.Fatal(err)
+ }
+ if !scanner.Scan() {
+ t.Fatal("expected line:", scanner.Err())
+ } else if scanner.Text() != fifo.path {
+ t.Fatal("unexpected line:", scanner.Text())
+ }
+ }
- if err := subProcess.Wait(); err != nil {
- t.Fatal(err)
+ if err := subProcess.Wait(); err != nil {
+ t.Fatal(err)
+ }
+ })
}
}
diff --git a/src/runtime/internal/wasitest/testdata/nonblock.go b/src/runtime/internal/wasitest/testdata/nonblock.go
index 947abe7..8cbf21b 100644
--- a/src/runtime/internal/wasitest/testdata/nonblock.go
+++ b/src/runtime/internal/wasitest/testdata/nonblock.go
@@ -7,17 +7,34 @@
import (
"os"
"sync"
+ "syscall"
)
func main() {
+ if len(os.Args) < 2 {
+ panic("usage: nonblock <MODE> [PATH...]")
+ }
+ mode := os.Args[1]
+
ready := make(chan struct{})
var wg sync.WaitGroup
- for _, path := range os.Args[1:] {
+ for _, path := range os.Args[2:] {
f, err := os.Open(path)
if err != nil {
panic(err)
}
+ switch mode {
+ case "os.OpenFile":
+ case "os.NewFile":
+ fd := f.Fd()
+ if err := syscall.SetNonblock(int(fd), true); err != nil {
+ panic(err)
+ }
+ f = os.NewFile(fd, path)
+ default:
+ panic("invalid test mode")
+ }
spawnWait := make(chan struct{})