1 // Copyright 2015 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 linux |
|
6 // +build linux |
|
7 |
|
8 package fsnotify |
|
9 |
|
10 import ( |
|
11 "errors" |
|
12 |
|
13 "golang.org/x/sys/unix" |
|
14 ) |
|
15 |
|
16 type fdPoller struct { |
|
17 fd int // File descriptor (as returned by the inotify_init() syscall) |
|
18 epfd int // Epoll file descriptor |
|
19 pipe [2]int // Pipe for waking up |
|
20 } |
|
21 |
|
22 func emptyPoller(fd int) *fdPoller { |
|
23 poller := new(fdPoller) |
|
24 poller.fd = fd |
|
25 poller.epfd = -1 |
|
26 poller.pipe[0] = -1 |
|
27 poller.pipe[1] = -1 |
|
28 return poller |
|
29 } |
|
30 |
|
31 // Create a new inotify poller. |
|
32 // This creates an inotify handler, and an epoll handler. |
|
33 func newFdPoller(fd int) (*fdPoller, error) { |
|
34 var errno error |
|
35 poller := emptyPoller(fd) |
|
36 defer func() { |
|
37 if errno != nil { |
|
38 poller.close() |
|
39 } |
|
40 }() |
|
41 |
|
42 // Create epoll fd |
|
43 poller.epfd, errno = unix.EpollCreate1(unix.EPOLL_CLOEXEC) |
|
44 if poller.epfd == -1 { |
|
45 return nil, errno |
|
46 } |
|
47 // Create pipe; pipe[0] is the read end, pipe[1] the write end. |
|
48 errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK|unix.O_CLOEXEC) |
|
49 if errno != nil { |
|
50 return nil, errno |
|
51 } |
|
52 |
|
53 // Register inotify fd with epoll |
|
54 event := unix.EpollEvent{ |
|
55 Fd: int32(poller.fd), |
|
56 Events: unix.EPOLLIN, |
|
57 } |
|
58 errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event) |
|
59 if errno != nil { |
|
60 return nil, errno |
|
61 } |
|
62 |
|
63 // Register pipe fd with epoll |
|
64 event = unix.EpollEvent{ |
|
65 Fd: int32(poller.pipe[0]), |
|
66 Events: unix.EPOLLIN, |
|
67 } |
|
68 errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event) |
|
69 if errno != nil { |
|
70 return nil, errno |
|
71 } |
|
72 |
|
73 return poller, nil |
|
74 } |
|
75 |
|
76 // Wait using epoll. |
|
77 // Returns true if something is ready to be read, |
|
78 // false if there is not. |
|
79 func (poller *fdPoller) wait() (bool, error) { |
|
80 // 3 possible events per fd, and 2 fds, makes a maximum of 6 events. |
|
81 // I don't know whether epoll_wait returns the number of events returned, |
|
82 // or the total number of events ready. |
|
83 // I decided to catch both by making the buffer one larger than the maximum. |
|
84 events := make([]unix.EpollEvent, 7) |
|
85 for { |
|
86 n, errno := unix.EpollWait(poller.epfd, events, -1) |
|
87 if n == -1 { |
|
88 if errno == unix.EINTR { |
|
89 continue |
|
90 } |
|
91 return false, errno |
|
92 } |
|
93 if n == 0 { |
|
94 // If there are no events, try again. |
|
95 continue |
|
96 } |
|
97 if n > 6 { |
|
98 // This should never happen. More events were returned than should be possible. |
|
99 return false, errors.New("epoll_wait returned more events than I know what to do with") |
|
100 } |
|
101 ready := events[:n] |
|
102 epollhup := false |
|
103 epollerr := false |
|
104 epollin := false |
|
105 for _, event := range ready { |
|
106 if event.Fd == int32(poller.fd) { |
|
107 if event.Events&unix.EPOLLHUP != 0 { |
|
108 // This should not happen, but if it does, treat it as a wakeup. |
|
109 epollhup = true |
|
110 } |
|
111 if event.Events&unix.EPOLLERR != 0 { |
|
112 // If an error is waiting on the file descriptor, we should pretend |
|
113 // something is ready to read, and let unix.Read pick up the error. |
|
114 epollerr = true |
|
115 } |
|
116 if event.Events&unix.EPOLLIN != 0 { |
|
117 // There is data to read. |
|
118 epollin = true |
|
119 } |
|
120 } |
|
121 if event.Fd == int32(poller.pipe[0]) { |
|
122 if event.Events&unix.EPOLLHUP != 0 { |
|
123 // Write pipe descriptor was closed, by us. This means we're closing down the |
|
124 // watcher, and we should wake up. |
|
125 } |
|
126 if event.Events&unix.EPOLLERR != 0 { |
|
127 // If an error is waiting on the pipe file descriptor. |
|
128 // This is an absolute mystery, and should never ever happen. |
|
129 return false, errors.New("Error on the pipe descriptor.") |
|
130 } |
|
131 if event.Events&unix.EPOLLIN != 0 { |
|
132 // This is a regular wakeup, so we have to clear the buffer. |
|
133 err := poller.clearWake() |
|
134 if err != nil { |
|
135 return false, err |
|
136 } |
|
137 } |
|
138 } |
|
139 } |
|
140 |
|
141 if epollhup || epollerr || epollin { |
|
142 return true, nil |
|
143 } |
|
144 return false, nil |
|
145 } |
|
146 } |
|
147 |
|
148 // Close the write end of the poller. |
|
149 func (poller *fdPoller) wake() error { |
|
150 buf := make([]byte, 1) |
|
151 n, errno := unix.Write(poller.pipe[1], buf) |
|
152 if n == -1 { |
|
153 if errno == unix.EAGAIN { |
|
154 // Buffer is full, poller will wake. |
|
155 return nil |
|
156 } |
|
157 return errno |
|
158 } |
|
159 return nil |
|
160 } |
|
161 |
|
162 func (poller *fdPoller) clearWake() error { |
|
163 // You have to be woken up a LOT in order to get to 100! |
|
164 buf := make([]byte, 100) |
|
165 n, errno := unix.Read(poller.pipe[0], buf) |
|
166 if n == -1 { |
|
167 if errno == unix.EAGAIN { |
|
168 // Buffer is empty, someone else cleared our wake. |
|
169 return nil |
|
170 } |
|
171 return errno |
|
172 } |
|
173 return nil |
|
174 } |
|
175 |
|
176 // Close all poller file descriptors, but not the one passed to it. |
|
177 func (poller *fdPoller) close() { |
|
178 if poller.pipe[1] != -1 { |
|
179 unix.Close(poller.pipe[1]) |
|
180 } |
|
181 if poller.pipe[0] != -1 { |
|
182 unix.Close(poller.pipe[0]) |
|
183 } |
|
184 if poller.epfd != -1 { |
|
185 unix.Close(poller.epfd) |
|
186 } |
|
187 } |
|