| // 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. | 
 |  | 
 | //go:build aix || darwin || dragonfly || freebsd || hurd || 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) | 
 | } |