wasi: non-blocking i/o on files on *nix (#1502)

Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com>
This commit is contained in:
Edoardo Vacchi
2023-06-03 01:33:19 +02:00
committed by GitHub
parent 97d0d70b73
commit f2d8461a62
5 changed files with 83 additions and 9 deletions

View File

@@ -310,17 +310,20 @@ func fdFdstatSetFlagsFn(_ context.Context, mod api.Module, params []uint64) sysc
if f, ok := fsc.LookupFile(fd); !ok {
return syscall.EBADF
} else if isPreopenedStdio(fd, f) {
nonblock := wasip1.FD_NONBLOCK&wasiFlag != 0
return f.File.SetNonblock(nonblock)
} else if _, ok := f.File.(socketapi.TCPConn); ok {
nonblock := wasip1.FD_NONBLOCK&wasiFlag != 0
return f.File.SetNonblock(nonblock)
} else {
// For normal files, proceed to apply an append flag.
append := wasip1.FD_APPEND&wasiFlag != 0
return f.File.SetAppend(append)
nonblock := wasip1.FD_NONBLOCK&wasiFlag != 0
errno := f.File.SetNonblock(nonblock)
if errno != 0 {
return errno
}
if stat, err := f.File.Stat(); err == 0 && stat.Mode.IsRegular() {
// For normal files, proceed to apply an append flag.
append := wasip1.FD_APPEND&wasiFlag != 0
return f.File.SetAppend(append)
}
}
return 0
}
// fdFdstatSetRights will not be implemented as rights were removed from WASI.
@@ -1691,6 +1694,9 @@ func openFlags(dirflags, oflags, fdflags uint16, rights uint32) (openFlags int)
openFlags |= syscall.O_CREAT
defaultMode = syscall.O_RDWR
}
if fdflags&wasip1.FD_NONBLOCK != 0 {
openFlags |= syscall.O_NONBLOCK
}
if fdflags&wasip1.FD_APPEND != 0 {
openFlags |= syscall.O_APPEND
defaultMode = syscall.O_RDWR

View File

@@ -162,6 +162,25 @@ void main_sock() {
}
}
void main_nonblock(char* fpath) {
struct timespec tim, tim2;
tim.tv_sec = 0;
tim.tv_nsec = 200 * 1000000;
int fd = open(fpath, O_RDONLY | O_NONBLOCK);
char buf[32];
ssize_t newLen = 0;
while (newLen == 0) {
newLen = read(fd, buf, sizeof(buf));
if (errno == EAGAIN || newLen == 0) {
printf(".");
nanosleep(&tim , &tim2) ;
continue;
}
}
printf("\n%s\n", buf);
close(fd);
}
int main(int argc, char** argv) {
if (strcmp(argv[1],"ls")==0) {
bool repeat = false;
@@ -193,6 +212,8 @@ int main(int argc, char** argv) {
main_open_wronly();
} else if (strcmp(argv[1],"sock")==0) {
main_sock();
} else if (strcmp(argv[1],"nonblock")==0) {
main_nonblock(argv[2]);
} else {
fprintf(stderr, "unknown command: %s\n", argv[1]);
return 1;

View File

@@ -0,0 +1,47 @@
//go:build unix || linux || darwin
package wasi_snapshot_preview1_test
import (
"os"
"strings"
"syscall"
"testing"
"time"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/internal/testing/require"
)
func Test_Nonblock(t *testing.T) {
const fifo = "/test-fifo"
tempDir := t.TempDir()
fifoAbsPath := tempDir + fifo
moduleConfig := wazero.NewModuleConfig().
WithArgs("wasi", "nonblock", fifo).
WithFSConfig(wazero.NewFSConfig().WithDirMount(tempDir, "/")).
WithSysNanosleep()
err := syscall.Mkfifo(fifoAbsPath, 0o666)
require.NoError(t, err)
ch := make(chan string, 1)
go func() { ch <- compileAndRun(t, testCtx, moduleConfig, wasmZigCc) }()
// The test writes a few dots on the console until the pipe has data ready for reading,
// so we wait for a little to ensure those dots are printed.
time.Sleep(500 * time.Millisecond)
f, err := os.OpenFile(fifoAbsPath, os.O_APPEND|os.O_WRONLY, 0)
require.NoError(t, err)
n, err := f.Write([]byte("wazero"))
require.NoError(t, err)
require.NotEqual(t, 0, n)
console := <-ch
lines := strings.Split(console, "\n")
// Check if the first line starts with at least one dot.
require.True(t, strings.HasPrefix(lines[0], "."))
require.Equal(t, "wazero", lines[1])
}