OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / fsnotify / fsnotify / inotify_poller.go
diff --git a/vendor/github.com/fsnotify/fsnotify/inotify_poller.go b/vendor/github.com/fsnotify/fsnotify/inotify_poller.go
new file mode 100644 (file)
index 0000000..cc7db4b
--- /dev/null
@@ -0,0 +1,187 @@
+// Copyright 2015 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.
+
+// +build linux
+
+package fsnotify
+
+import (
+       "errors"
+
+       "golang.org/x/sys/unix"
+)
+
+type fdPoller struct {
+       fd   int    // File descriptor (as returned by the inotify_init() syscall)
+       epfd int    // Epoll file descriptor
+       pipe [2]int // Pipe for waking up
+}
+
+func emptyPoller(fd int) *fdPoller {
+       poller := new(fdPoller)
+       poller.fd = fd
+       poller.epfd = -1
+       poller.pipe[0] = -1
+       poller.pipe[1] = -1
+       return poller
+}
+
+// Create a new inotify poller.
+// This creates an inotify handler, and an epoll handler.
+func newFdPoller(fd int) (*fdPoller, error) {
+       var errno error
+       poller := emptyPoller(fd)
+       defer func() {
+               if errno != nil {
+                       poller.close()
+               }
+       }()
+       poller.fd = fd
+
+       // Create epoll fd
+       poller.epfd, errno = unix.EpollCreate1(0)
+       if poller.epfd == -1 {
+               return nil, errno
+       }
+       // Create pipe; pipe[0] is the read end, pipe[1] the write end.
+       errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK)
+       if errno != nil {
+               return nil, errno
+       }
+
+       // Register inotify fd with epoll
+       event := unix.EpollEvent{
+               Fd:     int32(poller.fd),
+               Events: unix.EPOLLIN,
+       }
+       errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event)
+       if errno != nil {
+               return nil, errno
+       }
+
+       // Register pipe fd with epoll
+       event = unix.EpollEvent{
+               Fd:     int32(poller.pipe[0]),
+               Events: unix.EPOLLIN,
+       }
+       errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event)
+       if errno != nil {
+               return nil, errno
+       }
+
+       return poller, nil
+}
+
+// Wait using epoll.
+// Returns true if something is ready to be read,
+// false if there is not.
+func (poller *fdPoller) wait() (bool, error) {
+       // 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
+       // I don't know whether epoll_wait returns the number of events returned,
+       // or the total number of events ready.
+       // I decided to catch both by making the buffer one larger than the maximum.
+       events := make([]unix.EpollEvent, 7)
+       for {
+               n, errno := unix.EpollWait(poller.epfd, events, -1)
+               if n == -1 {
+                       if errno == unix.EINTR {
+                               continue
+                       }
+                       return false, errno
+               }
+               if n == 0 {
+                       // If there are no events, try again.
+                       continue
+               }
+               if n > 6 {
+                       // This should never happen. More events were returned than should be possible.
+                       return false, errors.New("epoll_wait returned more events than I know what to do with")
+               }
+               ready := events[:n]
+               epollhup := false
+               epollerr := false
+               epollin := false
+               for _, event := range ready {
+                       if event.Fd == int32(poller.fd) {
+                               if event.Events&unix.EPOLLHUP != 0 {
+                                       // This should not happen, but if it does, treat it as a wakeup.
+                                       epollhup = true
+                               }
+                               if event.Events&unix.EPOLLERR != 0 {
+                                       // If an error is waiting on the file descriptor, we should pretend
+                                       // something is ready to read, and let unix.Read pick up the error.
+                                       epollerr = true
+                               }
+                               if event.Events&unix.EPOLLIN != 0 {
+                                       // There is data to read.
+                                       epollin = true
+                               }
+                       }
+                       if event.Fd == int32(poller.pipe[0]) {
+                               if event.Events&unix.EPOLLHUP != 0 {
+                                       // Write pipe descriptor was closed, by us. This means we're closing down the
+                                       // watcher, and we should wake up.
+                               }
+                               if event.Events&unix.EPOLLERR != 0 {
+                                       // If an error is waiting on the pipe file descriptor.
+                                       // This is an absolute mystery, and should never ever happen.
+                                       return false, errors.New("Error on the pipe descriptor.")
+                               }
+                               if event.Events&unix.EPOLLIN != 0 {
+                                       // This is a regular wakeup, so we have to clear the buffer.
+                                       err := poller.clearWake()
+                                       if err != nil {
+                                               return false, err
+                                       }
+                               }
+                       }
+               }
+
+               if epollhup || epollerr || epollin {
+                       return true, nil
+               }
+               return false, nil
+       }
+}
+
+// Close the write end of the poller.
+func (poller *fdPoller) wake() error {
+       buf := make([]byte, 1)
+       n, errno := unix.Write(poller.pipe[1], buf)
+       if n == -1 {
+               if errno == unix.EAGAIN {
+                       // Buffer is full, poller will wake.
+                       return nil
+               }
+               return errno
+       }
+       return nil
+}
+
+func (poller *fdPoller) clearWake() error {
+       // You have to be woken up a LOT in order to get to 100!
+       buf := make([]byte, 100)
+       n, errno := unix.Read(poller.pipe[0], buf)
+       if n == -1 {
+               if errno == unix.EAGAIN {
+                       // Buffer is empty, someone else cleared our wake.
+                       return nil
+               }
+               return errno
+       }
+       return nil
+}
+
+// Close all poller file descriptors, but not the one passed to it.
+func (poller *fdPoller) close() {
+       if poller.pipe[1] != -1 {
+               unix.Close(poller.pipe[1])
+       }
+       if poller.pipe[0] != -1 {
+               unix.Close(poller.pipe[0])
+       }
+       if poller.epfd != -1 {
+               unix.Close(poller.epfd)
+       }
+}