From c78df850152da88fc77d4724cd98de22027e5c31 Mon Sep 17 00:00:00 2001 From: Dan Kegel Date: Fri, 31 Dec 2021 21:53:20 -0800 Subject: [PATCH] os: Implement Pipe for darwin, add smoke test. Evidently when you read from pipes in Go, you have to adjust your slice length to reflect the number of bytes read. Verified upstream behaves the same way. --- src/os/pipe_test.go | 56 ++++++++++++++++++++++ src/syscall/syscall_libc.go | 4 -- src/syscall/syscall_libc_darwin.go | 17 +++++++ src/syscall/syscall_libc_nintendoswitch.go | 4 ++ src/syscall/syscall_libc_wasi.go | 4 ++ src/syscall/syscall_nonhosted.go | 3 ++ 6 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 src/os/pipe_test.go diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go new file mode 100644 index 00000000..dcb99528 --- /dev/null +++ b/src/os/pipe_test.go @@ -0,0 +1,56 @@ +//go:build windows || darwin || (linux && !baremetal && !wasi) +// +build windows darwin linux,!baremetal,!wasi + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test pipes on Unix and Windows systems. + +package os_test + +import ( + "bytes" + "os" + "testing" +) + +// TestSmokePipe is a simple smoke test for Pipe(). +func TestSmokePipe(t *testing.T) { + // Procedure: + // 1. Get the bytes + // 2. Light the bytes on fire + // 3. Smoke the bytes + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + return // TODO: remove once Fatal is fatal + } + defer r.Close() + defer w.Close() + + msg := []byte("Sed nvlla nisi ardva virtvs") + n, err := w.Write(msg) + if err != nil { + t.Errorf("Writing to fresh pipe failed, error %v", err) + } + want := len(msg) + if n != want { + t.Errorf("Writing to fresh pipe wrote %d bytes, expected %d", n, want) + } + + buf := make([]byte, 2*len(msg)) + n, err = r.Read(buf) + if err != nil { + t.Errorf("Reading from pipe failed, error %v", err) + } + if n != want { + t.Errorf("Reading from pipe got %d bytes, expected %d", n, want) + } + // Read() does not set len(buf), so do it here. + buf = buf[:n] + if !bytes.Equal(buf, msg) { + t.Errorf("Reading from fresh pipe got wrong bytes") + } +} diff --git a/src/syscall/syscall_libc.go b/src/syscall/syscall_libc.go index bbc54888..3fa3db04 100644 --- a/src/syscall/syscall_libc.go +++ b/src/syscall/syscall_libc.go @@ -153,10 +153,6 @@ func Kill(pid int, sig Signal) (err error) { type SysProcAttr struct{} -func Pipe2(p []int, flags int) (err error) { - return ENOSYS // TODO -} - // TODO type WaitStatus uint32 diff --git a/src/syscall/syscall_libc_darwin.go b/src/syscall/syscall_libc_darwin.go index 770e71b5..80acebfc 100644 --- a/src/syscall/syscall_libc_darwin.go +++ b/src/syscall/syscall_libc_darwin.go @@ -246,6 +246,19 @@ func Fdopendir(fd int) (dir uintptr, err error) { return } +func Pipe2(fds []int, flags int) (err error) { + // Mac only has Pipe, which ignores the flags argument + buf := make([]int32, 2) + fail := int(libc_pipe(&buf[0])) + if fail < 0 { + err = getErrno() + } else { + fds[0] = int(buf[0]) + fds[1] = int(buf[1]) + } + return +} + func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (err error) { e1 := libc_readdir_r(unsafe.Pointer(dir), unsafe.Pointer(entry), unsafe.Pointer(result)) if e1 != 0 { @@ -278,3 +291,7 @@ func libc_fstat(fd int32, ptr unsafe.Pointer) int32 // int lstat(const char *path, struct stat * buf); //export lstat$INODE64 func libc_lstat(pathname *byte, ptr unsafe.Pointer) int32 + +// int pipe(int32 *fds); +//export pipe +func libc_pipe(fds *int32) int32 diff --git a/src/syscall/syscall_libc_nintendoswitch.go b/src/syscall/syscall_libc_nintendoswitch.go index 98494643..52b73939 100644 --- a/src/syscall/syscall_libc_nintendoswitch.go +++ b/src/syscall/syscall_libc_nintendoswitch.go @@ -63,3 +63,7 @@ var libcErrno uintptr func getErrno() error { return Errno(libcErrno) } + +func Pipe2(p []int, flags int) (err error) { + return ENOSYS // TODO +} diff --git a/src/syscall/syscall_libc_wasi.go b/src/syscall/syscall_libc_wasi.go index 6bfab090..cf9da47f 100644 --- a/src/syscall/syscall_libc_wasi.go +++ b/src/syscall/syscall_libc_wasi.go @@ -292,6 +292,10 @@ func Lstat(path string, p *Stat_t) (err error) { return } +func Pipe2(p []int, flags int) (err error) { + return ENOSYS // TODO +} + // int stat(const char *path, struct stat * buf); //export stat func libc_stat(pathname *byte, ptr unsafe.Pointer) int32 diff --git a/src/syscall/syscall_nonhosted.go b/src/syscall/syscall_nonhosted.go index 4a558550..3528087f 100644 --- a/src/syscall/syscall_nonhosted.go +++ b/src/syscall/syscall_nonhosted.go @@ -180,6 +180,9 @@ type SysProcAttr struct { func Getgroups() ([]int, error) { return []int{1}, nil } func Gettimeofday(tv *Timeval) error { return ENOSYS } func Kill(pid int, signum Signal) error { return ENOSYS } +func Pipe2(p []int, flags int) (err error) { + return ENOSYS // TODO +} func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { return 0, ENOSYS }