1// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
6
7package runtime_test
8
9import (
10	"runtime"
11	"syscall"
12	"testing"
13	"unsafe"
14)
15
16func TestNonblockingPipe(t *testing.T) {
17	t.Parallel()
18
19	// NonblockingPipe is the test name for nonblockingPipe.
20	r, w, errno := runtime.NonblockingPipe()
21	if errno != 0 {
22		t.Fatal(syscall.Errno(errno))
23	}
24	defer func() {
25		runtime.Close(r)
26		runtime.Close(w)
27	}()
28
29	checkIsPipe(t, r, w)
30	checkNonblocking(t, r, "reader")
31	checkCloseonexec(t, r, "reader")
32	checkNonblocking(t, w, "writer")
33	checkCloseonexec(t, w, "writer")
34}
35
36func checkIsPipe(t *testing.T, r, w int32) {
37	bw := byte(42)
38	if n := runtime.Write(uintptr(w), unsafe.Pointer(&bw), 1); n != 1 {
39		t.Fatalf("Write(w, &b, 1) == %d, expected 1", n)
40	}
41	var br byte
42	if n := runtime.Read(r, unsafe.Pointer(&br), 1); n != 1 {
43		t.Fatalf("Read(r, &b, 1) == %d, expected 1", n)
44	}
45	if br != bw {
46		t.Errorf("pipe read %d, expected %d", br, bw)
47	}
48}
49
50func checkNonblocking(t *testing.T, fd int32, name string) {
51	t.Helper()
52	flags, errno := fcntl(uintptr(fd), syscall.F_GETFL, 0)
53	if errno != 0 {
54		t.Errorf("fcntl(%s, F_GETFL) failed: %v", name, syscall.Errno(errno))
55	} else if flags&syscall.O_NONBLOCK == 0 {
56		t.Errorf("O_NONBLOCK not set in %s flags %#x", name, flags)
57	}
58}
59
60func checkCloseonexec(t *testing.T, fd int32, name string) {
61	t.Helper()
62	flags, errno := fcntl(uintptr(fd), syscall.F_GETFD, 0)
63	if errno != 0 {
64		t.Errorf("fcntl(%s, F_GETFD) failed: %v", name, syscall.Errno(errno))
65	} else if flags&syscall.FD_CLOEXEC == 0 {
66		t.Errorf("FD_CLOEXEC not set in %s flags %#x", name, flags)
67	}
68}
69
70func TestSetNonblock(t *testing.T) {
71	t.Parallel()
72
73	r, w, errno := runtime.Pipe()
74	if errno != 0 {
75		t.Fatal(syscall.Errno(errno))
76	}
77	defer func() {
78		runtime.Close(r)
79		runtime.Close(w)
80	}()
81
82	checkIsPipe(t, r, w)
83
84	runtime.SetNonblock(r)
85	runtime.SetNonblock(w)
86	checkNonblocking(t, r, "reader")
87	checkNonblocking(t, w, "writer")
88
89	runtime.Closeonexec(r)
90	runtime.Closeonexec(w)
91	checkCloseonexec(t, r, "reader")
92	checkCloseonexec(t, w, "writer")
93}
94
95//extern __go_fcntl_uintptr
96func fcntlUintptr(fd, cmd, arg uintptr) (uintptr, uintptr)
97
98// Call fcntl libc function rather than calling syscall.
99func fcntl(fd uintptr, cmd int, arg uintptr) (uintptr, syscall.Errno) {
100	res, errno := fcntlUintptr(fd, uintptr(cmd), arg)
101	return res, syscall.Errno(errno)
102}
103