From cee331a3b3ed500e2f3311c2c4f84cb5933f87aa Mon Sep 17 00:00:00 2001 From: Chris Howey Date: Tue, 3 Apr 2012 22:24:59 -0500 Subject: [PATCH] BSD - Fix issue reported by robfig EINTR can be returned by kevent in two cases: 1) fork() while parent/child is calling kevent() will result in the process calling kevent() to get EINTR while other process is registering the same kqueue at the kernel level. 2) A file event occurs before timeout expires, but is not yet on the queue to be returned by kevent(). In either case, we can ignore the error and continue as if timeout expired without any events. --- fsnotify_bsd.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/fsnotify_bsd.go b/fsnotify_bsd.go index 0d8e0e5..872778b 100644 --- a/fsnotify_bsd.go +++ b/fsnotify_bsd.go @@ -50,7 +50,9 @@ func (e *FileEvent) IsCreate() bool { return e.create } func (e *FileEvent) IsDelete() bool { return (e.mask & NOTE_DELETE) == NOTE_DELETE } // IsModify reports whether the FileEvent was triggerd by a file modification -func (e *FileEvent) IsModify() bool { return ((e.mask & NOTE_WRITE) == NOTE_WRITE || (e.mask & NOTE_ATTRIB) == NOTE_ATTRIB) } +func (e *FileEvent) IsModify() bool { + return ((e.mask&NOTE_WRITE) == NOTE_WRITE || (e.mask&NOTE_ATTRIB) == NOTE_ATTRIB) +} // IsRename reports whether the FileEvent was triggerd by a change name func (e *FileEvent) IsRename() bool { return (e.mask & NOTE_RENAME) == NOTE_RENAME } @@ -183,10 +185,6 @@ func (w *Watcher) readEvents() { *twait = syscall.NsecToTimespec(keventWaitTime) for { - if len(events) == 0 { - n, errno = syscall.Kevent(w.kq, nil, eventbuf[:], twait) - events = eventbuf[0:n] - } // See if there is a message on the "done" channel var done bool select { @@ -204,9 +202,19 @@ func (w *Watcher) readEvents() { close(w.Error) return } - if n < 0 { - w.Error <- os.NewSyscallError("kevent", errno) - continue + + // Get new events + if len(events) == 0 { + n, errno = syscall.Kevent(w.kq, nil, eventbuf[:], twait) + + // EINTR is okay, basically the syscall was interrupted before + // timeout expired. + if errno != nil && errno != syscall.EINTR { + w.Error <- os.NewSyscallError("kevent", errno) + continue + } else { + events = eventbuf[0:n] + } } // Timeout, no big deal -- 2.50.1