@cryptotaxi247 / kubo / commits / cffef5b54

godeps: update fsnotify to v1.2.0

Henry committed Feb 27, 2015 at 13:29 UTC cffef5b54428722fa11864557c7de4edec9d138d
15 files changed +922 -85
Godeps/Godeps.json
+2 -2
@@ -237,8 +237,8 @@
237 },
238 {
239 "ImportPath": "gopkg.in/fsnotify.v1",
240 - "Comment": "v1.1.0",
241 - "Rev": "f582d920d11386e8ae15227bb5933a8f9b4c3dec"
240 + "Comment": "v1.2.0",
241 + "Rev": "96c060f6a6b7e0d6f75fddd10efeaca3e5d1bcb0"
242 },
243 {
244 "ImportPath": "gopkg.in/natefinch/lumberjack.v2",
Godeps/_workspace/src/gopkg.in/fsnotify.v1/.travis.yml
+5 -3
@@ -1,10 +1,12 @@
1 +sudo: false
2 language: go
3
4 go:
4 - - 1.2
5 - - tip
5 + - 1.4.1
6 +
7 +before_script:
8 + - FIXED=$(go fmt ./... | wc -l); if [ $FIXED -gt 0 ]; then echo "gofmt - $FIXED file(s) not formatted correctly, please run gofmt to fix this." && exit 1; fi
9
7 -# not yet https://github.com/travis-ci/travis-ci/issues/2318
10 os:
11 - linux
12 - osx
Godeps/_workspace/src/gopkg.in/fsnotify.v1/AUTHORS
+1
@@ -21,6 +21,7 @@ Kelvin Fo <vmirage@gmail.com>
21 Matt Layher <mdlayher@gmail.com>
22 Nathan Youngman <git@nathany.com>
23 Paul Hammond <paul@paulhammond.org>
24 +Pieter Droogendijk <pieter@binky.org.uk>
25 Pursuit92 <JoshChase@techpursuit.net>
26 Rob Figueiredo <robfig@gmail.com>
27 Soge Zhang <zhssoge@gmail.com>
Godeps/_workspace/src/gopkg.in/fsnotify.v1/CHANGELOG.md
+15 -1
@@ -1,5 +1,15 @@
1 # Changelog
2
3 +## v1.2.0 / 2015-02-08
4 +
5 +* inotify: use epoll to wake up readEvents [#66](https://github.com/go-fsnotify/fsnotify/pull/66) (thanks @PieterD)
6 +* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/go-fsnotify/fsnotify/pull/63) (thanks @PieterD)
7 +* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/go-fsnotify/fsnotify/issues/59)
8 +
9 +## v1.1.1 / 2015-02-05
10 +
11 +* inotify: Retry read on EINTR [#61](https://github.com/go-fsnotify/fsnotify/issues/61) (thanks @PieterD)
12 +
13 ## v1.1.0 / 2014-12-12
14
15 * kqueue: rework internals [#43](https://github.com/go-fsnotify/fsnotify/pull/43)
@@ -10,7 +20,7 @@
20 * remove calls to os.NewSyscallError
21 * More efficient string concatenation for Event.String() [#52](https://github.com/go-fsnotify/fsnotify/pull/52) (thanks @mdlayher)
22 * kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/go-fsnotify/fsnotify/issues/48)
13 -* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/go-fsnotify/fsnotify/issues/48)
23 +* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/go-fsnotify/fsnotify/issues/51)
24
25 ## v1.0.4 / 2014-09-07
26
@@ -81,6 +91,10 @@
91 * no tests for the current implementation
92 * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
93
94 +## v0.9.3 / 2014-12-31
95 +
96 +* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/go-fsnotify/fsnotify/issues/51)
97 +
98 ## v0.9.2 / 2014-08-17
99
100 * [Backport] Fix missing create events on OS X. [#14](https://github.com/go-fsnotify/fsnotify/issues/14) (thanks @zhsso)
Godeps/_workspace/src/gopkg.in/fsnotify.v1/CONTRIBUTING.md
+25 -20
@@ -1,21 +1,34 @@
1 # Contributing
2
3 -* Send questions to [golang-dev@googlegroups.com](mailto:golang-dev@googlegroups.com).
4 -
5 -### Issues
3 +## Issues
4
5 * Request features and report bugs using the [GitHub Issue Tracker](https://github.com/go-fsnotify/fsnotify/issues).
8 -* Please indicate the platform you are running on.
6 +* Please indicate the platform you are using fsnotify on.
7 +* A code example to reproduce the problem is appreciated.
8 +
9 +## Pull Requests
10
10 -### Pull Requests
11 +### Contributor License Agreement
12
13 fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/go-fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/go-fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
14
15 Please indicate that you have signed the CLA in your pull request.
16
16 -To hack on fsnotify, please use [the workflow outlined by Katrina Owen](https://blog.splice.com/contributing-open-source-git-repositories-go/), in short:
17 +### How fsnotify is Developed
18 +
19 +* Development is done on feature branches.
20 +* Tests are run on BSD, Linux, OS X and Windows.
21 +* Pull requests are reviewed and [applied to master][am] using [hub][].
22 + * Maintainers may modify or squash commits rather than asking contributors to.
23 +* To issue a new release, the maintainers will:
24 + * Update the CHANGELOG
25 + * Tag a version, which will become available through gopkg.in.
26 +
27 +### How to Fork
28
18 -1. Install as usual (`go get -u github.com/go-fsnotify/fsnotify`)
29 +For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
30 +
31 +1. Install from GitHub (`go get -u github.com/go-fsnotify/fsnotify`)
32 2. Create your feature branch (`git checkout -b my-new-feature`)
33 3. Ensure everything works and the tests pass (see below)
34 4. Commit your changes (`git commit -am 'Add some feature'`)
@@ -27,15 +40,7 @@ Contribute upstream:
40 3. Push to the branch (`git push fork my-new-feature`)
41 4. Create a new Pull Request on GitHub
42
30 -If other team members need your patch before it is merged:
31 -
32 -1. Install as usual (`go get -u github.com/go-fsnotify/fsnotify`)
33 -2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
34 -3. Pull your revisions (`git fetch fork; git checkout -b my-new-feature fork/my-new-feature`)
35 -
36 -Notice: For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
37 -
38 -Note: The maintainers will update the CHANGELOG on your behalf. Please don't modify it in your pull request.
43 +This workflow is [thoroughly explained by Katrina Owen](https://blog.splice.com/contributing-open-source-git-repositories-go/).
44
45 ### Testing
46
@@ -62,11 +67,11 @@ Help maintaining fsnotify is welcome. To be a maintainer:
67 * Submit a pull request and sign the CLA as above.
68 * You must be able to run the test suite on Mac, Windows, Linux and BSD.
69
65 -To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful](http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs).
66 -
67 -This requires installing [hub](https://github.com/github/hub). Both version 1 and 2 support `hub am -3`.
70 +To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
71
72 All code changes should be internal pull requests.
73
71 -Releases are tagged using [Semantic Versioning](http://semver.org/), which makes them available through gopkg.in.
74 +Releases are tagged using [Semantic Versioning](http://semver.org/).
75
76 +[hub]: https://github.com/github/hub
77 +[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
Godeps/_workspace/src/gopkg.in/fsnotify.v1/NotUsed.xcworkspace
Godeps/_workspace/src/gopkg.in/fsnotify.v1/README.md
+9 -12
@@ -8,14 +8,14 @@ Cross platform: Windows, Linux, BSD and OS X.
8
9 |Adapter |OS |Status |
10 |----------|----------|----------|
11 -|inotify |Linux, Android\*|Supported|
12 -|kqueue |BSD, OS X, iOS\*|Supported|
13 -|ReadDirectoryChangesW|Windows|Supported|
11 +|inotify |Linux, Android\*|Supported [![Build Status](https://travis-ci.org/go-fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/go-fsnotify/fsnotify)|
12 +|kqueue |BSD, OS X, iOS\*|Supported [![Circle CI](https://circleci.com/gh/go-fsnotify/fsnotify.svg?style=svg)](https://circleci.com/gh/go-fsnotify/fsnotify)|
13 +|ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)|
14 |FSEvents |OS X |[Planned](https://github.com/go-fsnotify/fsnotify/issues/11)|
15 |FEN |Solaris 11 |[Planned](https://github.com/go-fsnotify/fsnotify/issues/12)|
16 |fanotify |Linux 2.6.37+ | |
17 +|USN Journals |Windows |[Maybe](https://github.com/go-fsnotify/fsnotify/issues/53)|
18 |Polling |*All* |[Maybe](https://github.com/go-fsnotify/fsnotify/issues/9)|
18 -| |Plan 9 | |
19
20 \* Android and iOS are untested.
21
@@ -41,8 +41,7 @@ import "gopkg.in/fsnotify.v1"
41
42 Further API changes are [planned](https://github.com/go-fsnotify/fsnotify/milestones), but a new major revision will be tagged, so you can depend on the v1 API.
43
44 -**master** may have untagged changes. Use it to test the very latest code,
45 -but don't expect it to remain API-compatible:
44 +**Master** may have unreleased changes. Use it to test the very latest code or when [contributing][], but don't expect it to remain API-compatible:
45
46 ```go
47 import "github.com/go-fsnotify/fsnotify"
@@ -50,13 +49,11 @@ import "github.com/go-fsnotify/fsnotify"
49
50 ## Contributing
51
53 -* Send questions to [golang-dev@googlegroups.com](mailto:golang-dev@googlegroups.com).
54 -* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/go-fsnotify/fsnotify/issues). Please indicate the platform you are running on.
55 -
56 -fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/go-fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/go-fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
57 -
58 -Please read [CONTRIBUTING](https://github.com/go-fsnotify/fsnotify/blob/master/CONTRIBUTING.md) before opening a pull request.
52 +Please refer to [CONTRIBUTING][] before opening an issue or pull request.
53
54 ## Example
55
56 See [example_test.go](https://github.com/go-fsnotify/fsnotify/blob/master/example_test.go).
57 +
58 +
59 +[contributing]: https://github.com/go-fsnotify/fsnotify/blob/master/CONTRIBUTING.md
Godeps/_workspace/src/gopkg.in/fsnotify.v1/circle.yml new
+26
@@ -0,0 +1,26 @@
1 +## OS X build (CircleCI iOS beta)
2 +
3 +# Pretend like it's an Xcode project, at least to get it running.
4 +machine:
5 + environment:
6 + XCODE_WORKSPACE: NotUsed.xcworkspace
7 + XCODE_SCHEME: NotUsed
8 + # This is where the go project is actually checked out to:
9 + CIRCLE_BUILD_DIR: $HOME/.go_project/src/github.com/go-fsnotify/fsnotify
10 +
11 +dependencies:
12 + pre:
13 + - brew upgrade go
14 +
15 +test:
16 + override:
17 + - go test ./...
18 +
19 +# Idealized future config, eventually with cross-platform build matrix :-)
20 +
21 +# machine:
22 +# go:
23 +# version: 1.4
24 +# os:
25 +# - osx
26 +# - linux
Godeps/_workspace/src/gopkg.in/fsnotify.v1/example_test.go
+1 -1
@@ -9,7 +9,7 @@ package fsnotify_test
9 import (
10 "log"
11
12 - "github.com/jbenet/go-ipfs/Godeps/_workspace/src/gopkg.in/fsnotify.v1"
12 + "github.com/go-fsnotify/fsnotify"
13 )
14
15 func ExampleNewWatcher() {
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify.go
+109 -42
@@ -9,6 +9,7 @@ package fsnotify
9 import (
10 "errors"
11 "fmt"
12 + "io"
13 "os"
14 "path/filepath"
15 "strings"
@@ -21,47 +22,66 @@ import (
22 type Watcher struct {
23 Events chan Event
24 Errors chan error
24 - mu sync.Mutex // Map access
25 - fd int // File descriptor (as returned by the inotify_init() syscall)
25 + mu sync.Mutex // Map access
26 + fd int
27 + poller *fdPoller
28 watches map[string]*watch // Map of inotify watches (key: path)
29 paths map[int]string // Map of watched paths (key: watch descriptor)
28 - done chan bool // Channel for sending a "quit message" to the reader goroutine
29 - isClosed bool // Set to true when Close() is first called
30 + done chan struct{} // Channel for sending a "quit message" to the reader goroutine
31 + doneResp chan struct{} // Channel to respond to Close
32 }
33
34 // NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
35 func NewWatcher() (*Watcher, error) {
36 + // Create inotify fd
37 fd, errno := syscall.InotifyInit()
38 if fd == -1 {
36 - return nil, os.NewSyscallError("inotify_init", errno)
39 + return nil, errno
40 + }
41 + // Create epoll
42 + poller, err := newFdPoller(fd)
43 + if err != nil {
44 + syscall.Close(fd)
45 + return nil, err
46 }
47 w := &Watcher{
39 - fd: fd,
40 - watches: make(map[string]*watch),
41 - paths: make(map[int]string),
42 - Events: make(chan Event),
43 - Errors: make(chan error),
44 - done: make(chan bool, 1),
48 + fd: fd,
49 + poller: poller,
50 + watches: make(map[string]*watch),
51 + paths: make(map[int]string),
52 + Events: make(chan Event),
53 + Errors: make(chan error),
54 + done: make(chan struct{}),
55 + doneResp: make(chan struct{}),
56 }
57
58 go w.readEvents()
59 return w, nil
60 }
61
62 +func (w *Watcher) isClosed() bool {
63 + select {
64 + case <-w.done:
65 + return true
66 + default:
67 + return false
68 + }
69 +}
70 +
71 // Close removes all watches and closes the events channel.
72 func (w *Watcher) Close() error {
53 - if w.isClosed {
73 + if w.isClosed() {
74 return nil
75 }
56 - w.isClosed = true
76
58 - // Remove all watches
59 - for name := range w.watches {
60 - w.Remove(name)
61 - }
77 + // Send 'close' signal to goroutine, and set the Watcher to closed.
78 + close(w.done)
79 +
80 + // Wake up goroutine
81 + w.poller.wake()
82
63 - // Send "quit" message to the reader goroutine
64 - w.done <- true
83 + // Wait for goroutine to close
84 + <-w.doneResp
85
86 return nil
87 }
@@ -69,7 +89,7 @@ func (w *Watcher) Close() error {
89 // Add starts watching the named file or directory (non-recursively).
90 func (w *Watcher) Add(name string) error {
91 name = filepath.Clean(name)
72 - if w.isClosed {
92 + if w.isClosed() {
93 return errors.New("inotify instance already closed")
94 }
95
@@ -88,7 +108,7 @@ func (w *Watcher) Add(name string) error {
108 }
109 wd, errno := syscall.InotifyAddWatch(w.fd, name, flags)
110 if wd == -1 {
91 - return os.NewSyscallError("inotify_add_watch", errno)
111 + return errno
112 }
113
114 w.mu.Lock()
@@ -99,20 +119,33 @@ func (w *Watcher) Add(name string) error {
119 return nil
120 }
121
102 -// Remove stops watching the the named file or directory (non-recursively).
122 +// Remove stops watching the named file or directory (non-recursively).
123 func (w *Watcher) Remove(name string) error {
124 name = filepath.Clean(name)
125 +
126 + // Fetch the watch.
127 w.mu.Lock()
128 defer w.mu.Unlock()
129 watch, ok := w.watches[name]
130 +
131 + // Remove it from inotify.
132 if !ok {
133 return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
134 }
135 + // inotify_rm_watch will return EINVAL if the file has been deleted;
136 + // the inotify will already have been removed.
137 + // That means we can safely delete it from our watches, whatever inotify_rm_watch does.
138 + delete(w.watches, name)
139 success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
140 if success == -1 {
113 - return os.NewSyscallError("inotify_rm_watch", errno)
141 + // TODO: Perhaps it's not helpful to return an error here in every case.
142 + // the only two possible errors are:
143 + // EBADF, which happens when w.fd is not a valid file descriptor of any kind.
144 + // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
145 + // Watch descriptors are invalidated when they are removed explicitly or implicitly;
146 + // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
147 + return errno
148 }
115 - delete(w.watches, name)
149 return nil
150 }
151
@@ -128,35 +161,65 @@ func (w *Watcher) readEvents() {
161 buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
162 n int // Number of bytes read with read()
163 errno error // Syscall errno
164 + ok bool // For poller.wait
165 )
166
167 + defer close(w.doneResp)
168 + defer close(w.Errors)
169 + defer close(w.Events)
170 + defer syscall.Close(w.fd)
171 + defer w.poller.close()
172 +
173 for {
134 - // See if there is a message on the "done" channel
135 - select {
136 - case <-w.done:
137 - syscall.Close(w.fd)
138 - close(w.Events)
139 - close(w.Errors)
174 + // See if we have been closed.
175 + if w.isClosed() {
176 return
141 - default:
177 }
178
144 - n, errno = syscall.Read(w.fd, buf[:])
179 + ok, errno = w.poller.wait()
180 + if errno != nil {
181 + select {
182 + case w.Errors <- errno:
183 + case <-w.done:
184 + return
185 + }
186 + continue
187 + }
188
146 - // If EOF is received
147 - if n == 0 {
148 - syscall.Close(w.fd)
149 - close(w.Events)
150 - close(w.Errors)
151 - return
189 + if !ok {
190 + continue
191 }
192
154 - if n < 0 {
155 - w.Errors <- os.NewSyscallError("read", errno)
193 + n, errno = syscall.Read(w.fd, buf[:])
194 + // If a signal interrupted execution, see if we've been asked to close, and try again.
195 + // http://man7.org/linux/man-pages/man7/signal.7.html :
196 + // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
197 + if errno == syscall.EINTR {
198 continue
199 }
200 +
201 + // syscall.Read might have been woken up by Close. If so, we're done.
202 + if w.isClosed() {
203 + return
204 + }
205 +
206 if n < syscall.SizeofInotifyEvent {
159 - w.Errors <- errors.New("inotify: short read in readEvents()")
207 + var err error
208 + if n == 0 {
209 + // If EOF is received. This should really never happen.
210 + err = io.EOF
211 + } else if n < 0 {
212 + // If an error occured while reading.
213 + err = errno
214 + } else {
215 + // Read was too short.
216 + err = errors.New("notify: short read in readEvents()")
217 + }
218 + select {
219 + case w.Errors <- err:
220 + case <-w.done:
221 + return
222 + }
223 continue
224 }
225
@@ -187,7 +250,11 @@ func (w *Watcher) readEvents() {
250
251 // Send the events that are not ignored on the events channel
252 if !event.ignoreLinux(mask) {
190 - w.Events <- event
253 + select {
254 + case w.Events <- event:
255 + case <-w.done:
256 + return
257 + }
258 }
259
260 // Move to the next event in the buffer
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_poller.go new
+186
@@ -0,0 +1,186 @@
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 + "syscall"
12 +)
13 +
14 +type fdPoller struct {
15 + fd int // File descriptor (as returned by the inotify_init() syscall)
16 + epfd int // Epoll file descriptor
17 + pipe [2]int // Pipe for waking up
18 +}
19 +
20 +func emptyPoller(fd int) *fdPoller {
21 + poller := new(fdPoller)
22 + poller.fd = fd
23 + poller.epfd = -1
24 + poller.pipe[0] = -1
25 + poller.pipe[1] = -1
26 + return poller
27 +}
28 +
29 +// Create a new inotify poller.
30 +// This creates an inotify handler, and an epoll handler.
31 +func newFdPoller(fd int) (*fdPoller, error) {
32 + var errno error
33 + poller := emptyPoller(fd)
34 + defer func() {
35 + if errno != nil {
36 + poller.close()
37 + }
38 + }()
39 + poller.fd = fd
40 +
41 + // Create epoll fd
42 + poller.epfd, errno = syscall.EpollCreate(1)
43 + if poller.epfd == -1 {
44 + return nil, errno
45 + }
46 + // Create pipe; pipe[0] is the read end, pipe[1] the write end.
47 + errno = syscall.Pipe2(poller.pipe[:], syscall.O_NONBLOCK)
48 + if errno != nil {
49 + return nil, errno
50 + }
51 +
52 + // Register inotify fd with epoll
53 + event := syscall.EpollEvent{
54 + Fd: int32(poller.fd),
55 + Events: syscall.EPOLLIN,
56 + }
57 + errno = syscall.EpollCtl(poller.epfd, syscall.EPOLL_CTL_ADD, poller.fd, &event)
58 + if errno != nil {
59 + return nil, errno
60 + }
61 +
62 + // Register pipe fd with epoll
63 + event = syscall.EpollEvent{
64 + Fd: int32(poller.pipe[0]),
65 + Events: syscall.EPOLLIN,
66 + }
67 + errno = syscall.EpollCtl(poller.epfd, syscall.EPOLL_CTL_ADD, poller.pipe[0], &event)
68 + if errno != nil {
69 + return nil, errno
70 + }
71 +
72 + return poller, nil
73 +}
74 +
75 +// Wait using epoll.
76 +// Returns true if something is ready to be read,
77 +// false if there is not.
78 +func (poller *fdPoller) wait() (bool, error) {
79 + // 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
80 + // I don't know whether epoll_wait returns the number of events returned,
81 + // or the total number of events ready.
82 + // I decided to catch both by making the buffer one larger than the maximum.
83 + events := make([]syscall.EpollEvent, 7)
84 + for {
85 + n, errno := syscall.EpollWait(poller.epfd, events, -1)
86 + if n == -1 {
87 + if errno == syscall.EINTR {
88 + continue
89 + }
90 + return false, errno
91 + }
92 + if n == 0 {
93 + // If there are no events, try again.
94 + continue
95 + }
96 + if n > 6 {
97 + // This should never happen. More events were returned than should be possible.
98 + return false, errors.New("epoll_wait returned more events than I know what to do with")
99 + }
100 + ready := events[:n]
101 + epollhup := false
102 + epollerr := false
103 + epollin := false
104 + for _, event := range ready {
105 + if event.Fd == int32(poller.fd) {
106 + if event.Events&syscall.EPOLLHUP != 0 {
107 + // This should not happen, but if it does, treat it as a wakeup.
108 + epollhup = true
109 + }
110 + if event.Events&syscall.EPOLLERR != 0 {
111 + // If an error is waiting on the file descriptor, we should pretend
112 + // something is ready to read, and let syscall.Read pick up the error.
113 + epollerr = true
114 + }
115 + if event.Events&syscall.EPOLLIN != 0 {
116 + // There is data to read.
117 + epollin = true
118 + }
119 + }
120 + if event.Fd == int32(poller.pipe[0]) {
121 + if event.Events&syscall.EPOLLHUP != 0 {
122 + // Write pipe descriptor was closed, by us. This means we're closing down the
123 + // watcher, and we should wake up.
124 + }
125 + if event.Events&syscall.EPOLLERR != 0 {
126 + // If an error is waiting on the pipe file descriptor.
127 + // This is an absolute mystery, and should never ever happen.
128 + return false, errors.New("Error on the pipe descriptor.")
129 + }
130 + if event.Events&syscall.EPOLLIN != 0 {
131 + // This is a regular wakeup, so we have to clear the buffer.
132 + err := poller.clearWake()
133 + if err != nil {
134 + return false, err
135 + }
136 + }
137 + }
138 + }
139 +
140 + if epollhup || epollerr || epollin {
141 + return true, nil
142 + }
143 + return false, nil
144 + }
145 +}
146 +
147 +// Close the write end of the poller.
148 +func (poller *fdPoller) wake() error {
149 + buf := make([]byte, 1)
150 + n, errno := syscall.Write(poller.pipe[1], buf)
151 + if n == -1 {
152 + if errno == syscall.EAGAIN {
153 + // Buffer is full, poller will wake.
154 + return nil
155 + }
156 + return errno
157 + }
158 + return nil
159 +}
160 +
161 +func (poller *fdPoller) clearWake() error {
162 + // You have to be woken up a LOT in order to get to 100!
163 + buf := make([]byte, 100)
164 + n, errno := syscall.Read(poller.pipe[0], buf)
165 + if n == -1 {
166 + if errno == syscall.EAGAIN {
167 + // Buffer is empty, someone else cleared our wake.
168 + return nil
169 + }
170 + return errno
171 + }
172 + return nil
173 +}
174 +
175 +// Close all poller file descriptors, but not the one passed to it.
176 +func (poller *fdPoller) close() {
177 + if poller.pipe[1] != -1 {
178 + syscall.Close(poller.pipe[1])
179 + }
180 + if poller.pipe[0] != -1 {
181 + syscall.Close(poller.pipe[0])
182 + }
183 + if poller.epfd != -1 {
184 + syscall.Close(poller.epfd)
185 + }
186 +}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_poller_test.go new
+228
@@ -0,0 +1,228 @@
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 + "syscall"
11 + "testing"
12 + "time"
13 +)
14 +
15 +type testFd [2]int
16 +
17 +func makeTestFd(t *testing.T) testFd {
18 + var tfd testFd
19 + errno := syscall.Pipe(tfd[:])
20 + if errno != nil {
21 + t.Fatalf("Failed to create pipe: %v", errno)
22 + }
23 + return tfd
24 +}
25 +
26 +func (tfd testFd) fd() int {
27 + return tfd[0]
28 +}
29 +
30 +func (tfd testFd) closeWrite(t *testing.T) {
31 + errno := syscall.Close(tfd[1])
32 + if errno != nil {
33 + t.Fatalf("Failed to close write end of pipe: %v", errno)
34 + }
35 +}
36 +
37 +func (tfd testFd) put(t *testing.T) {
38 + buf := make([]byte, 10)
39 + _, errno := syscall.Write(tfd[1], buf)
40 + if errno != nil {
41 + t.Fatalf("Failed to write to pipe: %v", errno)
42 + }
43 +}
44 +
45 +func (tfd testFd) get(t *testing.T) {
46 + buf := make([]byte, 10)
47 + _, errno := syscall.Read(tfd[0], buf)
48 + if errno != nil {
49 + t.Fatalf("Failed to read from pipe: %v", errno)
50 + }
51 +}
52 +
53 +func (tfd testFd) close() {
54 + syscall.Close(tfd[1])
55 + syscall.Close(tfd[0])
56 +}
57 +
58 +func makePoller(t *testing.T) (testFd, *fdPoller) {
59 + tfd := makeTestFd(t)
60 + poller, err := newFdPoller(tfd.fd())
61 + if err != nil {
62 + t.Fatalf("Failed to create poller: %v", err)
63 + }
64 + return tfd, poller
65 +}
66 +
67 +func TestPollerWithBadFd(t *testing.T) {
68 + _, err := newFdPoller(-1)
69 + if err != syscall.EBADF {
70 + t.Fatalf("Expected EBADF, got: %v", err)
71 + }
72 +}
73 +
74 +func TestPollerWithData(t *testing.T) {
75 + tfd, poller := makePoller(t)
76 + defer tfd.close()
77 + defer poller.close()
78 +
79 + tfd.put(t)
80 + ok, err := poller.wait()
81 + if err != nil {
82 + t.Fatalf("poller failed: %v", err)
83 + }
84 + if !ok {
85 + t.Fatalf("expected poller to return true")
86 + }
87 + tfd.get(t)
88 +}
89 +
90 +func TestPollerWithWakeup(t *testing.T) {
91 + tfd, poller := makePoller(t)
92 + defer tfd.close()
93 + defer poller.close()
94 +
95 + err := poller.wake()
96 + if err != nil {
97 + t.Fatalf("wake failed: %v", err)
98 + }
99 + ok, err := poller.wait()
100 + if err != nil {
101 + t.Fatalf("poller failed: %v", err)
102 + }
103 + if ok {
104 + t.Fatalf("expected poller to return false")
105 + }
106 +}
107 +
108 +func TestPollerWithClose(t *testing.T) {
109 + tfd, poller := makePoller(t)
110 + defer tfd.close()
111 + defer poller.close()
112 +
113 + tfd.closeWrite(t)
114 + ok, err := poller.wait()
115 + if err != nil {
116 + t.Fatalf("poller failed: %v", err)
117 + }
118 + if !ok {
119 + t.Fatalf("expected poller to return true")
120 + }
121 +}
122 +
123 +func TestPollerWithWakeupAndData(t *testing.T) {
124 + tfd, poller := makePoller(t)
125 + defer tfd.close()
126 + defer poller.close()
127 +
128 + tfd.put(t)
129 + err := poller.wake()
130 + if err != nil {
131 + t.Fatalf("wake failed: %v", err)
132 + }
133 +
134 + // both data and wakeup
135 + ok, err := poller.wait()
136 + if err != nil {
137 + t.Fatalf("poller failed: %v", err)
138 + }
139 + if !ok {
140 + t.Fatalf("expected poller to return true")
141 + }
142 +
143 + // data is still in the buffer, wakeup is cleared
144 + ok, err = poller.wait()
145 + if err != nil {
146 + t.Fatalf("poller failed: %v", err)
147 + }
148 + if !ok {
149 + t.Fatalf("expected poller to return true")
150 + }
151 +
152 + tfd.get(t)
153 + // data is gone, only wakeup now
154 + err = poller.wake()
155 + if err != nil {
156 + t.Fatalf("wake failed: %v", err)
157 + }
158 + ok, err = poller.wait()
159 + if err != nil {
160 + t.Fatalf("poller failed: %v", err)
161 + }
162 + if ok {
163 + t.Fatalf("expected poller to return false")
164 + }
165 +}
166 +
167 +func TestPollerConcurrent(t *testing.T) {
168 + tfd, poller := makePoller(t)
169 + defer tfd.close()
170 + defer poller.close()
171 +
172 + oks := make(chan bool)
173 + live := make(chan bool)
174 + defer close(live)
175 + go func() {
176 + defer close(oks)
177 + for {
178 + ok, err := poller.wait()
179 + if err != nil {
180 + t.Fatalf("poller failed: %v", err)
181 + }
182 + oks <- ok
183 + if !<-live {
184 + return
185 + }
186 + }
187 + }()
188 +
189 + // Try a write
190 + select {
191 + case <-time.After(50 * time.Millisecond):
192 + case <-oks:
193 + t.Fatalf("poller did not wait")
194 + }
195 + tfd.put(t)
196 + if !<-oks {
197 + t.Fatalf("expected true")
198 + }
199 + tfd.get(t)
200 + live <- true
201 +
202 + // Try a wakeup
203 + select {
204 + case <-time.After(50 * time.Millisecond):
205 + case <-oks:
206 + t.Fatalf("poller did not wait")
207 + }
208 + err := poller.wake()
209 + if err != nil {
210 + t.Fatalf("wake failed: %v", err)
211 + }
212 + if <-oks {
213 + t.Fatalf("expected false")
214 + }
215 + live <- true
216 +
217 + // Try a close
218 + select {
219 + case <-time.After(50 * time.Millisecond):
220 + case <-oks:
221 + t.Fatalf("poller did not wait")
222 + }
223 + tfd.closeWrite(t)
224 + if !<-oks {
225 + t.Fatalf("expected true")
226 + }
227 + tfd.get(t)
228 +}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/inotify_test.go new
+292
@@ -0,0 +1,292 @@
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 + "os"
11 + "path/filepath"
12 + "syscall"
13 + "testing"
14 + "time"
15 +)
16 +
17 +func TestInotifyCloseRightAway(t *testing.T) {
18 + w, err := NewWatcher()
19 + if err != nil {
20 + t.Fatalf("Failed to create watcher")
21 + }
22 +
23 + // Close immediately; it won't even reach the first syscall.Read.
24 + w.Close()
25 +
26 + // Wait for the close to complete.
27 + <-time.After(50 * time.Millisecond)
28 + isWatcherReallyClosed(t, w)
29 +}
30 +
31 +func TestInotifyCloseSlightlyLater(t *testing.T) {
32 + w, err := NewWatcher()
33 + if err != nil {
34 + t.Fatalf("Failed to create watcher")
35 + }
36 +
37 + // Wait until readEvents has reached syscall.Read, and Close.
38 + <-time.After(50 * time.Millisecond)
39 + w.Close()
40 +
41 + // Wait for the close to complete.
42 + <-time.After(50 * time.Millisecond)
43 + isWatcherReallyClosed(t, w)
44 +}
45 +
46 +func TestInotifyCloseSlightlyLaterWithWatch(t *testing.T) {
47 + testDir := tempMkdir(t)
48 + defer os.RemoveAll(testDir)
49 +
50 + w, err := NewWatcher()
51 + if err != nil {
52 + t.Fatalf("Failed to create watcher")
53 + }
54 + w.Add(testDir)
55 +
56 + // Wait until readEvents has reached syscall.Read, and Close.
57 + <-time.After(50 * time.Millisecond)
58 + w.Close()
59 +
60 + // Wait for the close to complete.
61 + <-time.After(50 * time.Millisecond)
62 + isWatcherReallyClosed(t, w)
63 +}
64 +
65 +func TestInotifyCloseAfterRead(t *testing.T) {
66 + testDir := tempMkdir(t)
67 + defer os.RemoveAll(testDir)
68 +
69 + w, err := NewWatcher()
70 + if err != nil {
71 + t.Fatalf("Failed to create watcher")
72 + }
73 +
74 + err = w.Add(testDir)
75 + if err != nil {
76 + t.Fatalf("Failed to add .")
77 + }
78 +
79 + // Generate an event.
80 + os.Create(filepath.Join(testDir, "somethingSOMETHINGsomethingSOMETHING"))
81 +
82 + // Wait for readEvents to read the event, then close the watcher.
83 + <-time.After(50 * time.Millisecond)
84 + w.Close()
85 +
86 + // Wait for the close to complete.
87 + <-time.After(50 * time.Millisecond)
88 + isWatcherReallyClosed(t, w)
89 +}
90 +
91 +func isWatcherReallyClosed(t *testing.T, w *Watcher) {
92 + select {
93 + case err, ok := <-w.Errors:
94 + if ok {
95 + t.Fatalf("w.Errors is not closed; readEvents is still alive after closing (error: %v)", err)
96 + }
97 + default:
98 + t.Fatalf("w.Errors would have blocked; readEvents is still alive!")
99 + }
100 +
101 + select {
102 + case _, ok := <-w.Events:
103 + if ok {
104 + t.Fatalf("w.Events is not closed; readEvents is still alive after closing")
105 + }
106 + default:
107 + t.Fatalf("w.Events would have blocked; readEvents is still alive!")
108 + }
109 +}
110 +
111 +func TestInotifyCloseCreate(t *testing.T) {
112 + testDir := tempMkdir(t)
113 + defer os.RemoveAll(testDir)
114 +
115 + w, err := NewWatcher()
116 + if err != nil {
117 + t.Fatalf("Failed to create watcher: %v", err)
118 + }
119 + defer w.Close()
120 +
121 + err = w.Add(testDir)
122 + if err != nil {
123 + t.Fatalf("Failed to add testDir: %v", err)
124 + }
125 + h, err := os.Create(filepath.Join(testDir, "testfile"))
126 + if err != nil {
127 + t.Fatalf("Failed to create file in testdir: %v", err)
128 + }
129 + h.Close()
130 + select {
131 + case _ = <-w.Events:
132 + case err := <-w.Errors:
133 + t.Fatalf("Error from watcher: %v", err)
134 + case <-time.After(50 * time.Millisecond):
135 + t.Fatalf("Took too long to wait for event")
136 + }
137 +
138 + // At this point, we've received one event, so the goroutine is ready.
139 + // It's also blocking on syscall.Read.
140 + // Now we try to swap the file descriptor under its nose.
141 + w.Close()
142 + w, err = NewWatcher()
143 + defer w.Close()
144 + if err != nil {
145 + t.Fatalf("Failed to create second watcher: %v", err)
146 + }
147 +
148 + <-time.After(50 * time.Millisecond)
149 + err = w.Add(testDir)
150 + if err != nil {
151 + t.Fatalf("Error adding testDir again: %v", err)
152 + }
153 +}
154 +
155 +func TestInotifyStress(t *testing.T) {
156 + testDir := tempMkdir(t)
157 + defer os.RemoveAll(testDir)
158 + testFile := filepath.Join(testDir, "testfile")
159 +
160 + w, err := NewWatcher()
161 + if err != nil {
162 + t.Fatalf("Failed to create watcher: %v", err)
163 + }
164 + defer w.Close()
165 +
166 + killchan := make(chan struct{})
167 + defer close(killchan)
168 +
169 + err = w.Add(testDir)
170 + if err != nil {
171 + t.Fatalf("Failed to add testDir: %v", err)
172 + }
173 +
174 + proc, err := os.FindProcess(os.Getpid())
175 + if err != nil {
176 + t.Fatalf("Error finding process: %v", err)
177 + }
178 +
179 + go func() {
180 + for {
181 + select {
182 + case <-time.After(5 * time.Millisecond):
183 + err := proc.Signal(syscall.SIGUSR1)
184 + if err != nil {
185 + t.Fatalf("Signal failed: %v", err)
186 + }
187 + case <-killchan:
188 + return
189 + }
190 + }
191 + }()
192 +
193 + go func() {
194 + for {
195 + select {
196 + case <-time.After(11 * time.Millisecond):
197 + err := w.poller.wake()
198 + if err != nil {
199 + t.Fatalf("Wake failed: %v", err)
200 + }
201 + case <-killchan:
202 + return
203 + }
204 + }
205 + }()
206 +
207 + go func() {
208 + for {
209 + select {
210 + case <-killchan:
211 + return
212 + default:
213 + handle, err := os.Create(testFile)
214 + if err != nil {
215 + t.Fatalf("Create failed: %v", err)
216 + }
217 + handle.Close()
218 + time.Sleep(time.Millisecond)
219 + err = os.Remove(testFile)
220 + if err != nil {
221 + t.Fatalf("Remove failed: %v", err)
222 + }
223 + }
224 + }
225 + }()
226 +
227 + creates := 0
228 + removes := 0
229 + after := time.After(5 * time.Second)
230 + for {
231 + select {
232 + case <-after:
233 + if creates-removes > 1 || creates-removes < -1 {
234 + t.Fatalf("Creates and removes should not be off by more than one: %d creates, %d removes", creates, removes)
235 + }
236 + if creates < 50 {
237 + t.Fatalf("Expected at least 50 creates, got %d", creates)
238 + }
239 + return
240 + case err := <-w.Errors:
241 + t.Fatalf("Got an error from watcher: %v", err)
242 + case evt := <-w.Events:
243 + if evt.Name != testFile {
244 + t.Fatalf("Got an event for an unknown file: %s", evt.Name)
245 + }
246 + if evt.Op == Create {
247 + creates++
248 + }
249 + if evt.Op == Remove {
250 + removes++
251 + }
252 + }
253 + }
254 +}
255 +
256 +func TestInotifyRemoveTwice(t *testing.T) {
257 + testDir := tempMkdir(t)
258 + defer os.RemoveAll(testDir)
259 + testFile := filepath.Join(testDir, "testfile")
260 +
261 + handle, err := os.Create(testFile)
262 + if err != nil {
263 + t.Fatalf("Create failed: %v", err)
264 + }
265 + handle.Close()
266 +
267 + w, err := NewWatcher()
268 + if err != nil {
269 + t.Fatalf("Failed to create watcher: %v", err)
270 + }
271 + defer w.Close()
272 +
273 + err = w.Add(testFile)
274 + if err != nil {
275 + t.Fatalf("Failed to add testFile: %v", err)
276 + }
277 +
278 + err = os.Remove(testFile)
279 + if err != nil {
280 + t.Fatalf("Failed to remove testFile: %v", err)
281 + }
282 +
283 + err = w.Remove(testFile)
284 + if err != syscall.EINVAL {
285 + t.Fatalf("Expected EINVAL from Remove, got: %v", err)
286 + }
287 +
288 + err = w.Remove(testFile)
289 + if err == syscall.EINVAL {
290 + t.Fatalf("Got EINVAL again, watch was not removed")
291 + }
292 +}
Godeps/_workspace/src/gopkg.in/fsnotify.v1/integration_test.go
+15
@@ -1109,6 +1109,21 @@ func TestConcurrentRemovalOfWatch(t *testing.T) {
1109 <-removed2
1110 }
1111
1112 +func TestClose(t *testing.T) {
1113 + // Regression test for #59 bad file descriptor from Close
1114 + testDir := tempMkdir(t)
1115 + defer os.RemoveAll(testDir)
1116 +
1117 + watcher := newWatcher(t)
1118 + if err := watcher.Add(testDir); err != nil {
1119 + t.Fatalf("Expected no error on Add, got %v", err)
1120 + }
1121 + err := watcher.Close()
1122 + if err != nil {
1123 + t.Fatalf("Expected no error on Close, got %v.", err)
1124 + }
1125 +}
1126 +
1127 func testRename(file1, file2 string) error {
1128 switch runtime.GOOS {
1129 case "windows", "plan9":
Godeps/_workspace/src/gopkg.in/fsnotify.v1/kqueue.go
+8 -4
@@ -72,16 +72,20 @@ func (w *Watcher) Close() error {
72 w.isClosed = true
73 w.mu.Unlock()
74
75 - // Send "quit" message to the reader goroutine:
76 - w.done <- true
77 -
75 w.mu.Lock()
76 ws := w.watches
77 w.mu.Unlock()
78 +
79 + var err error
80 for name := range ws {
82 - w.Remove(name)
81 + if e := w.Remove(name); e != nil && err == nil {
82 + err = e
83 + }
84 }
85
86 + // Send "quit" message to the reader goroutine:
87 + w.done <- true
88 +
89 return nil
90 }
91