| // Copyright 2020 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 zos && s390x |
| |
| package unix_test |
| |
| // Modified from Linux tests for epoll. |
| |
| import ( |
| "os" |
| "testing" |
| |
| "golang.org/x/sys/unix" |
| ) |
| |
| func TestEpollIn(t *testing.T) { |
| efd, err := unix.EpollCreate1(0) // no CLOEXEC equivalent on z/OS |
| if err != nil { |
| t.Fatalf("EpollCreate1: %v", err) |
| } |
| // no need to defer a close on efd, as it's not a real file descriptor on zos |
| |
| r, w, err := os.Pipe() |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer r.Close() |
| defer w.Close() |
| |
| fd := int(r.Fd()) |
| ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)} |
| |
| err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev) |
| if err != nil { |
| t.Fatalf("EpollCtl: %v", err) |
| } |
| |
| if _, err := w.Write([]byte("HELLO GOPHER")); err != nil { |
| t.Fatal(err) |
| } |
| |
| events := make([]unix.EpollEvent, 128) |
| n, err := unix.EpollWait(efd, events, 1) |
| if err != nil { |
| t.Fatalf("EpollWait: %v", err) |
| } |
| |
| if n != 1 { |
| t.Errorf("EpollWait: wrong number of events: got %v, expected 1", n) |
| } |
| |
| got := int(events[0].Fd) |
| if got != fd { |
| t.Errorf("EpollWait: wrong Fd in event: got %v, expected %v", got, fd) |
| } |
| |
| if events[0].Events&unix.EPOLLIN == 0 { |
| t.Errorf("Expected EPOLLIN flag to be set, got %b", events[0].Events) |
| } |
| } |
| |
| func TestEpollHup(t *testing.T) { |
| efd, err := unix.EpollCreate1(0) |
| if err != nil { |
| t.Fatalf("EpollCreate1: %v", err) |
| } |
| // no need to defer a close on efd, as it's not a real file descriptor on zos |
| |
| r, w, err := os.Pipe() |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer r.Close() |
| |
| fd := int(r.Fd()) |
| // EPOLLHUP should be reported even if not explicitly requested |
| ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)} |
| |
| err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev) |
| if err != nil { |
| t.Fatalf("EpollCtl: %v", err) |
| } |
| |
| events := make([]unix.EpollEvent, 128) |
| n, err := unix.EpollWait(efd, events, 1) |
| if err != nil { |
| t.Fatalf("EpollWait: %v", err) |
| } |
| |
| if events[0].Events&unix.EPOLLHUP != 0 { |
| t.Errorf("EPOLLHUP flag aset without hangup event; got n=%d, flags=%b", n, events[0].Events) |
| } |
| |
| w.Close() |
| |
| events = make([]unix.EpollEvent, 128) |
| n, err = unix.EpollWait(efd, events, 1) |
| if err != nil { |
| t.Fatalf("EpollWait: %v", err) |
| } |
| |
| if n < 1 || events[0].Events&unix.EPOLLHUP == 0 { |
| t.Errorf("Expected EPOLLHUP flag to be set, got n=%d, flags=%b", n, events[0].Events) |
| } |
| |
| } |
| |
| func TestEpollInManyFds(t *testing.T) { |
| efd, err := unix.EpollCreate1(4) // Like on Linux, size arg is ignored. |
| if err != nil { |
| t.Fatalf("EpollCreate: %v", err) |
| } |
| // no need to defer a close on efd, as it's not a real file descriptor on zos |
| |
| rFds := make([]int, 10) |
| wPipes := make([]*os.File, 10) |
| |
| for i := 0; i < 10; i++ { |
| r, w, err := os.Pipe() |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer r.Close() |
| defer w.Close() |
| |
| rFds[i] = int(r.Fd()) |
| wPipes[i] = w |
| } |
| |
| // Monitor all 10 read pipes |
| for _, fd := range rFds { |
| ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)} |
| err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev) |
| if err != nil { |
| t.Fatalf("EpollCtl: %v", err) |
| } |
| } |
| |
| // Write to only 5 odd-numbered pipes |
| for i, w := range wPipes { |
| if i%2 == 0 { |
| continue |
| } |
| if _, err := w.Write([]byte("HELLO")); err != nil { |
| t.Fatal(err) |
| } |
| } |
| |
| events := make([]unix.EpollEvent, 128) |
| n, err := unix.EpollWait(efd, events, 1) |
| if err != nil { |
| t.Fatalf("EpollWait: %v", err) |
| } |
| |
| if n != 5 { |
| t.Errorf("EpollWait: wrong number of events: got %v, expected 5", n) |
| } |
| |
| // Check level triggering here |
| if _, err := wPipes[0].Write([]byte("HELLO")); err != nil { |
| t.Fatal(err) |
| } |
| |
| // Now, a total of 6 pipes have been written to - level triggered notifis should number 6 |
| events = make([]unix.EpollEvent, 128) |
| n, err = unix.EpollWait(efd, events, 1) |
| if err != nil { |
| t.Fatalf("EpollWait: %v", err) |
| } |
| |
| if n != 6 { |
| t.Errorf("EpollWait: wrong number of events: got %v, expected 6", n) |
| } |
| |
| } |
| |
| func TestMultipleEpolls(t *testing.T) { |
| efd1, err := unix.EpollCreate1(4) |
| if err != nil { |
| t.Fatalf("EpollCreate: %v", err) |
| } |
| // no need to defer a close on efd1, as it's not a real file descriptor on zos |
| |
| efd2, err := unix.EpollCreate1(4) |
| if err != nil { |
| t.Fatalf("EpollCreate: %v", err) |
| } |
| // no need to defer a close on efd2, as it's not a real file descriptor on zos |
| |
| rFds := make([]int, 10) |
| wPipes := make([]*os.File, 10) |
| |
| for i := 0; i < 10; i++ { |
| r, w, err := os.Pipe() |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer r.Close() |
| defer w.Close() |
| |
| rFds[i] = int(r.Fd()) |
| wPipes[i] = w |
| } |
| |
| // Monitor first 7 read pipes on epoll1, last 3 on epoll2 |
| for i, fd := range rFds { |
| var efd int |
| if i < 7 { |
| efd = efd1 |
| } else { |
| efd = efd2 |
| } |
| ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)} |
| err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev) |
| if err != nil { |
| t.Fatalf("EpollCtl: %v", err) |
| } |
| } |
| |
| // Write to all 10 pipes |
| for _, w := range wPipes { |
| if _, err := w.Write([]byte("HELLO")); err != nil { |
| t.Fatal(err) |
| } |
| } |
| |
| events := make([]unix.EpollEvent, 128) |
| n, err := unix.EpollWait(efd1, events, 1) |
| if err != nil { |
| t.Fatalf("EpollWait: %v", err) |
| } |
| if n != 7 { |
| t.Errorf("EpollWait: wrong number of events on ep1: got %v, expected 7", n) |
| } |
| |
| events = make([]unix.EpollEvent, 128) |
| n, err = unix.EpollWait(efd2, events, 1) |
| if err != nil { |
| t.Fatalf("EpollWait: %v", err) |
| } |
| if n != 3 { |
| t.Errorf("EpollWait: wrong number of events on ep2: got %v, expected 3", n) |
| } |
| } |
| |
| func TestEpollErrors(t *testing.T) { |
| efd, err := unix.EpollCreate1(4) |
| if err != nil { |
| t.Fatalf("EpollCreate: %v", err) |
| } |
| // no need to defer a close on efd, as it's not a real file descriptor on zos |
| |
| r, w, err := os.Pipe() |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer r.Close() |
| defer w.Close() |
| |
| fd := int(r.Fd()) |
| |
| ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)} |
| if err = unix.EpollCtl(efd+1, unix.EPOLL_CTL_ADD, fd, &ev); err != unix.EBADF { |
| t.Errorf("EpollCtl: got %v when EpollCtl ADD called with invalid epfd, expected EBADF", err) |
| } |
| |
| if err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev); err != nil { |
| t.Fatalf("EpollCtl: %v", err) |
| } |
| |
| if err = unix.EpollCtl(efd, unix.EPOLL_CTL_MOD, -2, &ev); err != unix.ENOENT { |
| t.Errorf("EpollCtl: got %v when EpollCtl MOD called with invalid fd, expected ENOENT", err) |
| } |
| } |