github.com/tristanisham/sys@v0.0.0-20240326010300-a16cbabb7555/unix/epoll_zos_test.go (about)

     1  // Copyright 2020 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  //go:build zos && s390x
     6  
     7  package unix_test
     8  
     9  // Modified from Linux tests for epoll.
    10  
    11  import (
    12  	"os"
    13  	"testing"
    14  
    15  	"golang.org/x/sys/unix"
    16  )
    17  
    18  func TestEpollIn(t *testing.T) {
    19  	efd, err := unix.EpollCreate1(0) // no CLOEXEC equivalent on z/OS
    20  	if err != nil {
    21  		t.Fatalf("EpollCreate1: %v", err)
    22  	}
    23  	// no need to defer a close on efd, as it's not a real file descriptor on zos
    24  
    25  	r, w, err := os.Pipe()
    26  	if err != nil {
    27  		t.Fatal(err)
    28  	}
    29  	defer r.Close()
    30  	defer w.Close()
    31  
    32  	fd := int(r.Fd())
    33  	ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)}
    34  
    35  	err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev)
    36  	if err != nil {
    37  		t.Fatalf("EpollCtl: %v", err)
    38  	}
    39  
    40  	if _, err := w.Write([]byte("HELLO GOPHER")); err != nil {
    41  		t.Fatal(err)
    42  	}
    43  
    44  	events := make([]unix.EpollEvent, 128)
    45  	n, err := unix.EpollWait(efd, events, 1)
    46  	if err != nil {
    47  		t.Fatalf("EpollWait: %v", err)
    48  	}
    49  
    50  	if n != 1 {
    51  		t.Errorf("EpollWait: wrong number of events: got %v, expected 1", n)
    52  	}
    53  
    54  	got := int(events[0].Fd)
    55  	if got != fd {
    56  		t.Errorf("EpollWait: wrong Fd in event: got %v, expected %v", got, fd)
    57  	}
    58  
    59  	if events[0].Events&unix.EPOLLIN == 0 {
    60  		t.Errorf("Expected EPOLLIN flag to be set, got %b", events[0].Events)
    61  	}
    62  }
    63  
    64  func TestEpollHup(t *testing.T) {
    65  	efd, err := unix.EpollCreate1(0)
    66  	if err != nil {
    67  		t.Fatalf("EpollCreate1: %v", err)
    68  	}
    69  	// no need to defer a close on efd, as it's not a real file descriptor on zos
    70  
    71  	r, w, err := os.Pipe()
    72  	if err != nil {
    73  		t.Fatal(err)
    74  	}
    75  	defer r.Close()
    76  
    77  	fd := int(r.Fd())
    78  	// EPOLLHUP should be reported even if not explicitly requested
    79  	ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)}
    80  
    81  	err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev)
    82  	if err != nil {
    83  		t.Fatalf("EpollCtl: %v", err)
    84  	}
    85  
    86  	events := make([]unix.EpollEvent, 128)
    87  	n, err := unix.EpollWait(efd, events, 1)
    88  	if err != nil {
    89  		t.Fatalf("EpollWait: %v", err)
    90  	}
    91  
    92  	if events[0].Events&unix.EPOLLHUP != 0 {
    93  		t.Errorf("EPOLLHUP flag aset without hangup event; got n=%d, flags=%b", n, events[0].Events)
    94  	}
    95  
    96  	w.Close()
    97  
    98  	events = make([]unix.EpollEvent, 128)
    99  	n, err = unix.EpollWait(efd, events, 1)
   100  	if err != nil {
   101  		t.Fatalf("EpollWait: %v", err)
   102  	}
   103  
   104  	if n < 1 || events[0].Events&unix.EPOLLHUP == 0 {
   105  		t.Errorf("Expected EPOLLHUP flag to be set, got n=%d, flags=%b", n, events[0].Events)
   106  	}
   107  
   108  }
   109  
   110  func TestEpollInManyFds(t *testing.T) {
   111  	efd, err := unix.EpollCreate1(4) // Like on Linux, size arg is ignored.
   112  	if err != nil {
   113  		t.Fatalf("EpollCreate: %v", err)
   114  	}
   115  	// no need to defer a close on efd, as it's not a real file descriptor on zos
   116  
   117  	rFds := make([]int, 10)
   118  	wPipes := make([]*os.File, 10)
   119  
   120  	for i := 0; i < 10; i++ {
   121  		r, w, err := os.Pipe()
   122  		if err != nil {
   123  			t.Fatal(err)
   124  		}
   125  		defer r.Close()
   126  		defer w.Close()
   127  
   128  		rFds[i] = int(r.Fd())
   129  		wPipes[i] = w
   130  	}
   131  
   132  	// Monitor all 10 read pipes
   133  	for _, fd := range rFds {
   134  		ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)}
   135  		err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev)
   136  		if err != nil {
   137  			t.Fatalf("EpollCtl: %v", err)
   138  		}
   139  	}
   140  
   141  	// Write to only 5 odd-numbered pipes
   142  	for i, w := range wPipes {
   143  		if i%2 == 0 {
   144  			continue
   145  		}
   146  		if _, err := w.Write([]byte("HELLO")); err != nil {
   147  			t.Fatal(err)
   148  		}
   149  	}
   150  
   151  	events := make([]unix.EpollEvent, 128)
   152  	n, err := unix.EpollWait(efd, events, 1)
   153  	if err != nil {
   154  		t.Fatalf("EpollWait: %v", err)
   155  	}
   156  
   157  	if n != 5 {
   158  		t.Errorf("EpollWait: wrong number of events: got %v, expected 5", n)
   159  	}
   160  
   161  	// Check level triggering here
   162  	if _, err := wPipes[0].Write([]byte("HELLO")); err != nil {
   163  		t.Fatal(err)
   164  	}
   165  
   166  	// Now, a total of 6 pipes have been written to - level triggered notifis should number 6
   167  	events = make([]unix.EpollEvent, 128)
   168  	n, err = unix.EpollWait(efd, events, 1)
   169  	if err != nil {
   170  		t.Fatalf("EpollWait: %v", err)
   171  	}
   172  
   173  	if n != 6 {
   174  		t.Errorf("EpollWait: wrong number of events: got %v, expected 6", n)
   175  	}
   176  
   177  }
   178  
   179  func TestMultipleEpolls(t *testing.T) {
   180  	efd1, err := unix.EpollCreate1(4)
   181  	if err != nil {
   182  		t.Fatalf("EpollCreate: %v", err)
   183  	}
   184  	// no need to defer a close on efd1, as it's not a real file descriptor on zos
   185  
   186  	efd2, err := unix.EpollCreate1(4)
   187  	if err != nil {
   188  		t.Fatalf("EpollCreate: %v", err)
   189  	}
   190  	// no need to defer a close on efd2, as it's not a real file descriptor on zos
   191  
   192  	rFds := make([]int, 10)
   193  	wPipes := make([]*os.File, 10)
   194  
   195  	for i := 0; i < 10; i++ {
   196  		r, w, err := os.Pipe()
   197  		if err != nil {
   198  			t.Fatal(err)
   199  		}
   200  		defer r.Close()
   201  		defer w.Close()
   202  
   203  		rFds[i] = int(r.Fd())
   204  		wPipes[i] = w
   205  	}
   206  
   207  	// Monitor first 7 read pipes on epoll1, last 3 on epoll2
   208  	for i, fd := range rFds {
   209  		var efd int
   210  		if i < 7 {
   211  			efd = efd1
   212  		} else {
   213  			efd = efd2
   214  		}
   215  		ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)}
   216  		err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev)
   217  		if err != nil {
   218  			t.Fatalf("EpollCtl: %v", err)
   219  		}
   220  	}
   221  
   222  	// Write to all 10 pipes
   223  	for _, w := range wPipes {
   224  		if _, err := w.Write([]byte("HELLO")); err != nil {
   225  			t.Fatal(err)
   226  		}
   227  	}
   228  
   229  	events := make([]unix.EpollEvent, 128)
   230  	n, err := unix.EpollWait(efd1, events, 1)
   231  	if err != nil {
   232  		t.Fatalf("EpollWait: %v", err)
   233  	}
   234  	if n != 7 {
   235  		t.Errorf("EpollWait: wrong number of events on ep1: got %v, expected 7", n)
   236  	}
   237  
   238  	events = make([]unix.EpollEvent, 128)
   239  	n, err = unix.EpollWait(efd2, events, 1)
   240  	if err != nil {
   241  		t.Fatalf("EpollWait: %v", err)
   242  	}
   243  	if n != 3 {
   244  		t.Errorf("EpollWait: wrong number of events on ep2: got %v, expected 3", n)
   245  	}
   246  }
   247  
   248  func TestEpollErrors(t *testing.T) {
   249  	efd, err := unix.EpollCreate1(4)
   250  	if err != nil {
   251  		t.Fatalf("EpollCreate: %v", err)
   252  	}
   253  	// no need to defer a close on efd, as it's not a real file descriptor on zos
   254  
   255  	r, w, err := os.Pipe()
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  	defer r.Close()
   260  	defer w.Close()
   261  
   262  	fd := int(r.Fd())
   263  
   264  	ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)}
   265  	if err = unix.EpollCtl(efd+1, unix.EPOLL_CTL_ADD, fd, &ev); err != unix.EBADF {
   266  		t.Errorf("EpollCtl: got %v when EpollCtl ADD called with invalid epfd, expected EBADF", err)
   267  	}
   268  
   269  	if err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev); err != nil {
   270  		t.Fatalf("EpollCtl: %v", err)
   271  	}
   272  
   273  	if err = unix.EpollCtl(efd, unix.EPOLL_CTL_MOD, -2, &ev); err != unix.ENOENT {
   274  		t.Errorf("EpollCtl: got %v when EpollCtl MOD called with invalid fd, expected ENOENT", err)
   275  	}
   276  }