From ce4a001009a3decd4cd17eae9edca71595dfa253 Mon Sep 17 00:00:00 2001 From: Pawel Knap Date: Tue, 17 Feb 2015 20:29:27 +0100 Subject: [PATCH] inotify: some code formatting and fix for syscall.EPOLLONESHOT bug --- example_inotify_test.go | 10 +++--- watcher_inotify.go | 70 +++++++++++++++++++---------------------- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/example_inotify_test.go b/example_inotify_test.go index 5cd8802..20af89d 100644 --- a/example_inotify_test.go +++ b/example_inotify_test.go @@ -13,9 +13,9 @@ import ( "github.com/rjeczalik/notify" ) -// Watch changes made by text editors when saving a file. Usually, either -// InCloseWrite or InMovedTo (when swapping with a temporary file) event -// is created. +// This example shows how to watch changes made on file-system by text editors +// when saving a file. Usually, either InCloseWrite or InMovedTo (when swapping +// with a temporary file) event is created. func ExampleWatch_linux() { // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. @@ -38,8 +38,8 @@ func ExampleWatch_linux() { } } -// Use Sys() method from EventInfo interface to tie two separate events generated -// by rename(2) function. +// This example shows how to use the Sys() method from EventInfo interface to +// tie two separate events generated by rename(2) function. func ExampleWatch_linuxMove() { // Make the channel buffered to ensure no event is dropped. Notify will drop // an event if the receiver is not able to keep up the sending pace. diff --git a/watcher_inotify.go b/watcher_inotify.go index 9e7a77d..868a056 100644 --- a/watcher_inotify.go +++ b/watcher_inotify.go @@ -68,12 +68,12 @@ func newWatcher(c chan<- EventInfo) *inotify { return i } -// Watch implements notify.Watcher interface. +// Watch implements notify.watcher interface. func (i *inotify) Watch(path string, e Event) error { return i.watch(path, e) } -// Rewatch implements notify.Watcher interface. +// Rewatch implements notify.watcher interface. func (i *inotify) Rewatch(path string, _, newevent Event) error { return i.watch(path, newevent) } @@ -123,8 +123,7 @@ func (i *inotify) lazyinit() error { } i.fd = int32(fd) if err = i.epollinit(); err != nil { - // Ignore errors returned from epollclose and close(2). - _, _ = i.epollclose(), syscall.Close(int(fd)) + _, _ = i.epollclose(), syscall.Close(int(fd)) // Ignore errors. i.fd = invalidDescriptor return err } @@ -153,19 +152,17 @@ func (i *inotify) epollinit() (err error) { i.epes = []syscall.EpollEvent{ { // inotify file descriptor. Events: syscall.EPOLLIN, - Fd: int32(i.fd), + Fd: i.fd, }, { // read end of the pipe used to stop event loop. - Events: syscall.EPOLLIN | syscall.EPOLLONESHOT, + Events: syscall.EPOLLIN, Fd: int32(i.pipefd[0]), }, } - if err = syscall.EpollCtl(i.epfd, syscall.EPOLL_CTL_ADD, int(i.fd), - &i.epes[0]); err != nil { + if err = syscall.EpollCtl(i.epfd, syscall.EPOLL_CTL_ADD, int(i.fd), &i.epes[0]); err != nil { return } - return syscall.EpollCtl(i.epfd, syscall.EPOLL_CTL_ADD, i.pipefd[0], - &i.epes[1]) + return syscall.EpollCtl(i.epfd, syscall.EPOLL_CTL_ADD, i.pipefd[0], &i.epes[1]) } // epollclose closes the file descriptor created by the call to epoll_create(2) @@ -205,13 +202,11 @@ func (i *inotify) loop(esch chan<- []*event) { case int32(i.pipefd[0]): i.Lock() defer i.Unlock() - if err = syscall.Close(int(fd)); err != nil && - err != syscall.EINTR { // Ignore EINTR error. + if err = syscall.Close(int(fd)); err != nil && err != syscall.EINTR { panic("notify: close(2) error - " + err.Error()) } atomic.StoreInt32(&i.fd, invalidDescriptor) if err = i.epollclose(); err != nil && err != syscall.EINTR { - // epollclose method calls syscall.Close function. panic("notify: epollclose error - " + err.Error()) } close(esch) @@ -219,8 +214,7 @@ func (i *inotify) loop(esch chan<- []*event) { } case syscall.EINTR: continue - default: - // In the current implementation we should never reach this line. + default: // We should never reach this line. panic("notify: epoll_wait(2) error - " + err.Error()) } } @@ -246,11 +240,14 @@ func (i *inotify) read() (es []*event) { path = string(bytes.TrimRight(i.buffer[pos:endpos], "\x00")) pos = endpos } - es = append(es, &event{sys: syscall.InotifyEvent{ - Wd: sys.Wd, - Mask: sys.Mask, - Cookie: sys.Cookie, - }, path: path}) + es = append(es, &event{ + sys: syscall.InotifyEvent{ + Wd: sys.Wd, + Mask: sys.Mask, + Cookie: sys.Cookie, + }, + path: path, + }) } return } @@ -329,17 +326,13 @@ func decode(mask Event, e *event) (syse *event) { } imask := encode(mask) switch { - case mask&Create != 0 && - imask&uint32(InCreate|InMovedTo)&e.sys.Mask != 0: + case mask&Create != 0 && imask&uint32(InCreate|InMovedTo)&e.sys.Mask != 0: e.event = Create - case mask&Remove != 0 && - imask&uint32(InDelete|InDeleteSelf)&e.sys.Mask != 0: + case mask&Remove != 0 && imask&uint32(InDelete|InDeleteSelf)&e.sys.Mask != 0: e.event = Remove - case mask&Write != 0 && - imask&uint32(InModify)&e.sys.Mask != 0: + case mask&Write != 0 && imask&uint32(InModify)&e.sys.Mask != 0: e.event = Write - case mask&Rename != 0 && - imask&uint32(InMovedFrom|InMoveSelf)&e.sys.Mask != 0: + case mask&Rename != 0 && imask&uint32(InMovedFrom|InMoveSelf)&e.sys.Mask != 0: e.event = Rename default: e.event = 0 @@ -347,7 +340,7 @@ func decode(mask Event, e *event) (syse *event) { return } -// Unwatch implements notify.Watcher interface. +// Unwatch implements notify.watcher interface. func (i *inotify) Unwatch(path string) (err error) { iwd := int32(-1) i.RLock() @@ -361,8 +354,8 @@ func (i *inotify) Unwatch(path string) (err error) { if iwd < 0 { return errors.New("notify: file/dir " + path + " is unwatched") } - if _, err = syscall.InotifyRmWatch(int(atomic.LoadInt32(&i.fd)), - uint32(iwd)); err != nil { + fd := atomic.LoadInt32(&i.fd) + if _, err = syscall.InotifyRmWatch(int(fd), uint32(iwd)); err != nil { return } i.Lock() @@ -371,22 +364,25 @@ func (i *inotify) Unwatch(path string) (err error) { return nil } +// Close implements notify.watcher interface. It removes all existing watch +// descriptors and wakes up producer goroutine by sending to the write end of +// the pipe. The function waits for a signal from producer which means that all +// operations on current monitoring instance are done. func (i *inotify) Close() (err error) { i.Lock() if fd := atomic.LoadInt32(&i.fd); fd == invalidDescriptor { i.Unlock() return nil } - for iwdkey := range i.m { - if _, e := syscall.InotifyRmWatch(int(i.fd), - uint32(iwdkey)); e != nil && err == nil { + for iwd := range i.m { + if _, e := syscall.InotifyRmWatch(int(i.fd), uint32(iwd)); e != nil && err == nil { err = e } - delete(i.m, iwdkey) + delete(i.m, iwd) } - if _, e := syscall.Write(i.pipefd[1], []byte{0x00}); e != nil && - err == nil { + if _, e := syscall.Write(i.pipefd[1], []byte{0x00}); e != nil && err == nil { err = e + // TODO: nowait } i.Unlock() i.wg.Wait()