|  | // 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) | 
|  | } | 
|  | } |