1package fdwait
2
3import (
4 "golang.org/x/sys/unix"
5 "testing"
6 "time"
7)
8
9func TestPollReadinessTimeoutAndReplacement(t *testing.T) {
10 p, err := New()
11 if err != nil {
12 t.Fatal(err)
13 }
14 defer p.Close()
15 fd, err := unix.Eventfd(0, unix.EFD_NONBLOCK|unix.EFD_CLOEXEC)
16 if err != nil {
17 t.Fatal(err)
18 }
19 defer unix.Close(fd)
20 fds := []unix.PollFd{{Fd: int32(fd), Events: unix.POLLIN}}
21 if n, err := p.Poll(fds, 5); n != 0 || err != nil {
22 t.Fatalf("timeout: %d %v", n, err)
23 }
24 done := make(chan error, 1)
25 go func() { _, e := unix.Write(fd, []byte{1, 0, 0, 0, 0, 0, 0, 0}); done <- e }()
26 if n, err := p.Poll(fds, 1000); n != 1 || err != nil || fds[0].Revents&unix.POLLIN == 0 {
27 t.Fatalf("readiness: %d %v %+v", n, err, fds)
28 }
29 if err := <-done; err != nil {
30 t.Fatal(err)
31 }
32 // Level readiness must remain visible before the caller consumes it.
33 if n, err := p.Poll(fds, 1000); n != 1 || err != nil {
34 t.Fatalf("level: %d %v", n, err)
35 }
36 var b [8]byte
37 if _, err := unix.Read(fd, b[:]); err != nil {
38 t.Fatal(err)
39 }
40 if n, err := p.Poll(fds, 5); n != 0 || err != nil {
41 t.Fatalf("consumed: %d %v", n, err)
42 }
43 other, err := unix.Eventfd(0, unix.EFD_NONBLOCK|unix.EFD_CLOEXEC)
44 if err != nil {
45 t.Fatal(err)
46 }
47 defer unix.Close(other)
48 fds[0].Fd = int32(other)
49 if _, err := unix.Write(other, b[:]); err != nil {
50 t.Fatal(err)
51 }
52 if n, err := p.Poll(fds, 1000); n != 1 || err != nil {
53 t.Fatalf("replacement: %d %v", n, err)
54 }
55 if err := p.raw.Control(func(ep uintptr) {
56 var events [1]unix.EpollEvent
57 if n, err := unix.EpollWait(int(ep), events[:], 0); n != 0 || err != nil {
58 t.Errorf("registration retained after Poll returned: %d %v", n, err)
59 }
60 }); err != nil {
61 t.Fatal(err)
62 }
63}
64
65func TestCloseUnblocksPoll(t *testing.T) {
66 p, err := New()
67 if err != nil {
68 t.Fatal(err)
69 }
70 defer p.Close()
71 fd, err := unix.Eventfd(0, unix.EFD_NONBLOCK|unix.EFD_CLOEXEC)
72 if err != nil {
73 t.Fatal(err)
74 }
75 defer unix.Close(fd)
76 done := make(chan error, 1)
77 go func() { _, e := p.Poll([]unix.PollFd{{Fd: int32(fd), Events: unix.POLLIN}}, -1); done <- e }()
78 // Close is safe both before and during the netpoll wait.
79 if err := p.Close(); err != nil {
80 t.Fatal(err)
81 }
82 select {
83 case err := <-done:
84 if err == nil {
85 t.Fatal("closed wait succeeded")
86 }
87 case <-time.After(time.Second):
88 t.Fatal("close did not unblock wait")
89 }
90}