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:
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Binary file not shown.
47
imports/wasi_snapshot_preview1/wasi_stdlib_unix_test.go
Normal file
47
imports/wasi_snapshot_preview1/wasi_stdlib_unix_test.go
Normal 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])
|
||||
}
|
||||
Reference in New Issue
Block a user