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 [](https://travis-ci.org/go-fsnotify/fsnotify)|
12
+|kqueue |BSD, OS X, iOS\*|Supported [](https://circleci.com/gh/go-fsnotify/fsnotify)|
13
+|ReadDirectoryChangesW|Windows|Supported [](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