OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / fsnotify / fsnotify / inotify_poller.go
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 // +build linux
6
7 package fsnotify
8
9 import (
10         "errors"
11
12         "golang.org/x/sys/unix"
13 )
14
15 type fdPoller struct {
16         fd   int    // File descriptor (as returned by the inotify_init() syscall)
17         epfd int    // Epoll file descriptor
18         pipe [2]int // Pipe for waking up
19 }
20
21 func emptyPoller(fd int) *fdPoller {
22         poller := new(fdPoller)
23         poller.fd = fd
24         poller.epfd = -1
25         poller.pipe[0] = -1
26         poller.pipe[1] = -1
27         return poller
28 }
29
30 // Create a new inotify poller.
31 // This creates an inotify handler, and an epoll handler.
32 func newFdPoller(fd int) (*fdPoller, error) {
33         var errno error
34         poller := emptyPoller(fd)
35         defer func() {
36                 if errno != nil {
37                         poller.close()
38                 }
39         }()
40         poller.fd = fd
41
42         // Create epoll fd
43         poller.epfd, errno = unix.EpollCreate1(0)
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)
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 }