103 lines
2.5 KiB
Go
103 lines
2.5 KiB
Go
|
// Copyright 2019 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.
|
||
|
|
||
|
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||
|
|
||
|
package runtime_test
|
||
|
|
||
|
import (
|
||
|
"runtime"
|
||
|
"syscall"
|
||
|
"testing"
|
||
|
"unsafe"
|
||
|
)
|
||
|
|
||
|
func TestNonblockingPipe(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
// NonblockingPipe is the test name for nonblockingPipe.
|
||
|
r, w, errno := runtime.NonblockingPipe()
|
||
|
if errno != 0 {
|
||
|
t.Fatal(syscall.Errno(errno))
|
||
|
}
|
||
|
defer func() {
|
||
|
runtime.Close(r)
|
||
|
runtime.Close(w)
|
||
|
}()
|
||
|
|
||
|
checkIsPipe(t, r, w)
|
||
|
checkNonblocking(t, r, "reader")
|
||
|
checkCloseonexec(t, r, "reader")
|
||
|
checkNonblocking(t, w, "writer")
|
||
|
checkCloseonexec(t, w, "writer")
|
||
|
}
|
||
|
|
||
|
func checkIsPipe(t *testing.T, r, w int32) {
|
||
|
bw := byte(42)
|
||
|
if n := runtime.Write(uintptr(w), unsafe.Pointer(&bw), 1); n != 1 {
|
||
|
t.Fatalf("Write(w, &b, 1) == %d, expected 1", n)
|
||
|
}
|
||
|
var br byte
|
||
|
if n := runtime.Read(r, unsafe.Pointer(&br), 1); n != 1 {
|
||
|
t.Fatalf("Read(r, &b, 1) == %d, expected 1", n)
|
||
|
}
|
||
|
if br != bw {
|
||
|
t.Errorf("pipe read %d, expected %d", br, bw)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func checkNonblocking(t *testing.T, fd int32, name string) {
|
||
|
t.Helper()
|
||
|
flags, errno := fcntl(uintptr(fd), syscall.F_GETFL, 0)
|
||
|
if errno != 0 {
|
||
|
t.Errorf("fcntl(%s, F_GETFL) failed: %v", name, syscall.Errno(errno))
|
||
|
} else if flags&syscall.O_NONBLOCK == 0 {
|
||
|
t.Errorf("O_NONBLOCK not set in %s flags %#x", name, flags)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func checkCloseonexec(t *testing.T, fd int32, name string) {
|
||
|
t.Helper()
|
||
|
flags, errno := fcntl(uintptr(fd), syscall.F_GETFD, 0)
|
||
|
if errno != 0 {
|
||
|
t.Errorf("fcntl(%s, F_GETFD) failed: %v", name, syscall.Errno(errno))
|
||
|
} else if flags&syscall.FD_CLOEXEC == 0 {
|
||
|
t.Errorf("FD_CLOEXEC not set in %s flags %#x", name, flags)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSetNonblock(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
r, w, errno := runtime.Pipe()
|
||
|
if errno != 0 {
|
||
|
t.Fatal(syscall.Errno(errno))
|
||
|
}
|
||
|
defer func() {
|
||
|
runtime.Close(r)
|
||
|
runtime.Close(w)
|
||
|
}()
|
||
|
|
||
|
checkIsPipe(t, r, w)
|
||
|
|
||
|
runtime.SetNonblock(r)
|
||
|
runtime.SetNonblock(w)
|
||
|
checkNonblocking(t, r, "reader")
|
||
|
checkNonblocking(t, w, "writer")
|
||
|
|
||
|
runtime.Closeonexec(r)
|
||
|
runtime.Closeonexec(w)
|
||
|
checkCloseonexec(t, r, "reader")
|
||
|
checkCloseonexec(t, w, "writer")
|
||
|
}
|
||
|
|
||
|
//extern __go_fcntl_uintptr
|
||
|
func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
|
||
|
|
||
|
// Call fcntl libc function rather than calling syscall.
|
||
|
func fcntl(fd uintptr, cmd int, arg uintptr) (uintptr, syscall.Errno) {
|
||
|
res, errno := fcntlUintptr(fd, uintptr(cmd), arg)
|
||
|
return res, syscall.Errno(errno)
|
||
|
}
|