wasi: add nonblock_test.go from gotip, fix nonblock read on Unix-like (#1517)
Some checks failed
Release CLI / Pre-release build (push) Has been cancelled
Release CLI / Pre-release test (macos-12) (push) Has been cancelled
Release CLI / Pre-release test (ubuntu-22.04) (push) Has been cancelled
Release CLI / Pre-release test (windows-2022) (push) Has been cancelled
Release CLI / Release (push) Has been cancelled
Some checks failed
Release CLI / Pre-release build (push) Has been cancelled
Release CLI / Pre-release test (macos-12) (push) Has been cancelled
Release CLI / Pre-release test (ubuntu-22.04) (push) Has been cancelled
Release CLI / Pre-release test (windows-2022) (push) Has been cancelled
Release CLI / Release (push) Has been cancelled
Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com>
This commit is contained in:
@@ -28,7 +28,7 @@ var (
|
||||
emptyFile = "empty.txt"
|
||||
)
|
||||
|
||||
func TestFileSetNonblock(t *testing.T) {
|
||||
func TestStdioFileSetNonblock(t *testing.T) {
|
||||
// Test using os.Pipe as it is known to support non-blocking reads.
|
||||
r, w, err := os.Pipe()
|
||||
require.NoError(t, err)
|
||||
@@ -47,6 +47,54 @@ func TestFileSetNonblock(t *testing.T) {
|
||||
require.False(t, rF.IsNonblock())
|
||||
}
|
||||
|
||||
func TestRegularFileSetNonblock(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Nonblock on regular files is not supported on Windows")
|
||||
}
|
||||
|
||||
// Test using os.Pipe as it is known to support non-blocking reads.
|
||||
r, w, err := os.Pipe()
|
||||
require.NoError(t, err)
|
||||
defer r.Close()
|
||||
defer w.Close()
|
||||
|
||||
rF := newOsFile("", syscall.O_RDONLY, 0, r)
|
||||
|
||||
errno := rF.SetNonblock(true)
|
||||
require.EqualErrno(t, 0, errno)
|
||||
require.True(t, rF.IsNonblock())
|
||||
|
||||
// Read from the file without ever writing to it should not block.
|
||||
buf := make([]byte, 8)
|
||||
_, e := rF.Read(buf)
|
||||
require.EqualErrno(t, syscall.EAGAIN, e)
|
||||
|
||||
errno = rF.SetNonblock(false)
|
||||
require.EqualErrno(t, 0, errno)
|
||||
require.False(t, rF.IsNonblock())
|
||||
}
|
||||
|
||||
func TestReadFdNonblock(t *testing.T) {
|
||||
// Test using os.Pipe as it is known to support non-blocking reads.
|
||||
r, w, err := os.Pipe()
|
||||
require.NoError(t, err)
|
||||
defer r.Close()
|
||||
defer w.Close()
|
||||
|
||||
fd := r.Fd()
|
||||
err = setNonblock(fd, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read from the file without ever writing to it should not block.
|
||||
buf := make([]byte, 8)
|
||||
_, e := readFd(fd, buf)
|
||||
if runtime.GOOS == "windows" {
|
||||
require.EqualErrno(t, syscall.ENOSYS, e)
|
||||
} else {
|
||||
require.EqualErrno(t, syscall.EAGAIN, e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileSetAppend(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
|
||||
21
internal/sysfs/file_unix.go
Normal file
21
internal/sysfs/file_unix.go
Normal file
@@ -0,0 +1,21 @@
|
||||
//go:build unix || darwin || linux
|
||||
|
||||
package sysfs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/platform"
|
||||
)
|
||||
|
||||
const NonBlockingFileIoSupported = true
|
||||
|
||||
// readFd exposes syscall.Read.
|
||||
func readFd(fd uintptr, buf []byte) (int, syscall.Errno) {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0 // Short-circuit 0-len reads.
|
||||
}
|
||||
n, err := syscall.Read(int(fd), buf)
|
||||
errno := platform.UnwrapOSError(err)
|
||||
return n, errno
|
||||
}
|
||||
12
internal/sysfs/file_unsupported.go
Normal file
12
internal/sysfs/file_unsupported.go
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build !unix && !linux && !darwin
|
||||
|
||||
package sysfs
|
||||
|
||||
import "syscall"
|
||||
|
||||
const NonBlockingFileIoSupported = false
|
||||
|
||||
// readFd returns ENOSYS on unsupported platforms.
|
||||
func readFd(fd uintptr, buf []byte) (int, syscall.Errno) {
|
||||
return -1, syscall.ENOSYS
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
func newOsFile(openPath string, openFlag int, openPerm fs.FileMode, f *os.File) fsapi.File {
|
||||
return &windowsOsFile{
|
||||
osFile: osFile{path: openPath, flag: openFlag, perm: openPerm, file: f},
|
||||
osFile: osFile{path: openPath, flag: openFlag, perm: openPerm, file: f, fd: f.Fd()},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func newDefaultOsFile(openPath string, openFlag int, openPerm fs.FileMode, f *os.File) fsapi.File {
|
||||
return &osFile{path: openPath, flag: openFlag, perm: openPerm, file: f}
|
||||
return &osFile{path: openPath, flag: openFlag, perm: openPerm, file: f, fd: f.Fd()}
|
||||
}
|
||||
|
||||
// osFile is a file opened with this package, and uses os.File or syscalls to
|
||||
@@ -22,6 +22,7 @@ type osFile struct {
|
||||
flag int
|
||||
perm fs.FileMode
|
||||
file *os.File
|
||||
fd uintptr
|
||||
|
||||
// closed is true when closed was called. This ensures proper syscall.EBADF
|
||||
closed bool
|
||||
@@ -92,7 +93,7 @@ func (f *osFile) SetNonblock(enable bool) (errno syscall.Errno) {
|
||||
} else {
|
||||
f.flag &= ^fsapi.O_NONBLOCK
|
||||
}
|
||||
if err := setNonblock(f.file.Fd(), enable); err != nil {
|
||||
if err := setNonblock(f.fd, enable); err != nil {
|
||||
return fileError(f, f.closed, platform.UnwrapOSError(err))
|
||||
}
|
||||
return 0
|
||||
@@ -126,7 +127,15 @@ func (f *osFile) Stat() (fsapi.Stat_t, syscall.Errno) {
|
||||
|
||||
// Read implements the same method as documented on fsapi.File
|
||||
func (f *osFile) Read(buf []byte) (n int, errno syscall.Errno) {
|
||||
if n, errno = read(f.file, buf); errno != 0 {
|
||||
if len(buf) == 0 {
|
||||
return 0, 0 // Short-circuit 0-len reads.
|
||||
}
|
||||
if NonBlockingFileIoSupported && f.IsNonblock() {
|
||||
n, errno = readFd(f.fd, buf)
|
||||
} else {
|
||||
n, errno = read(f.file, buf)
|
||||
}
|
||||
if errno != 0 {
|
||||
// Defer validation overhead until we've already had an error.
|
||||
errno = fileError(f, f.closed, errno)
|
||||
}
|
||||
@@ -160,7 +169,7 @@ func (f *osFile) Seek(offset int64, whence int) (newOffset int64, errno syscall.
|
||||
// PollRead implements the same method as documented on fsapi.File
|
||||
func (f *osFile) PollRead(timeout *time.Duration) (ready bool, errno syscall.Errno) {
|
||||
fdSet := platform.FdSet{}
|
||||
fd := int(f.file.Fd())
|
||||
fd := int(f.fd)
|
||||
fdSet.Set(fd)
|
||||
nfds := fd + 1 // See https://man7.org/linux/man-pages/man2/select.2.html#:~:text=condition%20has%20occurred.-,nfds,-This%20argument%20should
|
||||
count, err := _select(nfds, &fdSet, nil, nil, timeout)
|
||||
@@ -232,7 +241,7 @@ func (f *osFile) Chown(uid, gid int) syscall.Errno {
|
||||
return syscall.EBADF
|
||||
}
|
||||
|
||||
return fchown(f.file.Fd(), uid, gid)
|
||||
return fchown(f.fd, uid, gid)
|
||||
}
|
||||
|
||||
// Utimens implements the same method as documented on fsapi.File
|
||||
@@ -241,7 +250,7 @@ func (f *osFile) Utimens(times *[2]syscall.Timespec) syscall.Errno {
|
||||
return syscall.EBADF
|
||||
}
|
||||
|
||||
err := futimens(f.file.Fd(), times)
|
||||
err := futimens(f.fd, times)
|
||||
return platform.UnwrapOSError(err)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user