diff --git a/debug.go b/debug.go deleted file mode 100644 index bd9bc46..0000000 --- a/debug.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// +build !debug - -package notify - -func dbgprint(...interface{}) {} - -func dbgprintf(string, ...interface{}) {} diff --git a/debug_debug.go b/debug_debug.go index f062291..6fca7ec 100644 --- a/debug_debug.go +++ b/debug_debug.go @@ -2,8 +2,6 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -// +build debug - package notify import ( diff --git a/testing_test.go b/testing_test.go index ea18c4f..62e8c28 100644 --- a/testing_test.go +++ b/testing_test.go @@ -160,6 +160,10 @@ func newWatcherTest(t *testing.T, tree string) *W { if err != nil { t.Fatalf(`tmptree("", %q)=%v`, tree, err) } + root, _, err = cleanpath(root) + if err != nil { + t.Fatalf(`cleanpath(%q)=%v`, root, err) + } Sync() return &W{ t: t, diff --git a/watcher_readdcw.go b/watcher_readdcw.go index 5923bfd..48afe2e 100644 --- a/watcher_readdcw.go +++ b/watcher_readdcw.go @@ -279,22 +279,25 @@ func (r *readdcw) watch(path string, event Event, recursive bool) (err error) { r.Lock() wd, ok := r.m[path] r.Unlock() - if !ok { - if err = r.lazyinit(); err != nil { - return - } - r.Lock() - if wd, ok = r.m[path]; ok { - r.Unlock() - return - } - if wd, err = newWatched(r.cph, uint32(event), recursive, path); err != nil { - r.Unlock() - return - } - r.m[path] = wd + if ok { + dbgprintf("watcher: Already watching %v", path) + return nil + } + if err = r.lazyinit(); err != nil { + return + } + r.Lock() + if wd, ok = r.m[path]; ok { r.Unlock() + return } + if wd, err = newWatched(r.cph, uint32(event), recursive, path); err != nil { + r.Unlock() + return + } + r.m[path] = wd + r.Unlock() + dbgprintf("watcher: Started watching %v", path) return nil } @@ -352,19 +355,23 @@ func (r *readdcw) loop() { func (r *readdcw) loopstate(overEx *overlappedEx) { filter := atomic.LoadUint32(&overEx.parent.parent.filter) if filter&onlyMachineStates == 0 { + dbgprintf("loopstate: no machine states") return } if overEx.parent.parent.count--; overEx.parent.parent.count == 0 { switch filter & onlyMachineStates { case stateRewatch: + dbgprintf("loopstate: stateRewatch") r.Lock() overEx.parent.parent.recreate(r.cph) r.Unlock() case stateUnwatch: + dbgprintf("loopstate: stateUnwatch") r.Lock() delete(r.m, syscall.UTF16ToString(overEx.parent.pathw)) r.Unlock() case stateCPClose: + dbgprintf("loopstate: stateCPClose") default: panic(`notify: windows loopstate logic error`) } diff --git a/watcher_readdcw_test.go b/watcher_readdcw_test.go index ea15b4a..6f31743 100644 --- a/watcher_readdcw_test.go +++ b/watcher_readdcw_test.go @@ -6,7 +6,10 @@ package notify -import "testing" +import ( + "testing" + "time" +) // TODO(ppknap) : remove notify.Create event. func rcreate(w *W, path string) WCase { @@ -65,3 +68,26 @@ func TestWatcherReadDirectoryChangesW(t *testing.T) { w.ExpectAny(cases[:]) } + +func TestWatcherReaddcwUnwatchChangeRace(t *testing.T) { + w := NewWatcherTest(t, "testdata/vfs.txt", events...) + defer w.Close() + + rcreate(w, "trigger").Action() + time.Sleep(time.Duration(100) * time.Millisecond) + + rremove(w, "trigger").Action() + w.RecursiveUnwatch("") + time.Sleep(time.Duration(100) * time.Millisecond) + + drainall(w.C) + cases := [...]WCase{ + rcreate(w, "src/github.com/rjeczalik/fs/fs_windows.go"), + rcreate(w, "src/github.com/rjeczalik/fs/subdir/"), + rremove(w, "src/github.com/rjeczalik/fs/fs.go"), + rrename(w, "src/github.com/rjeczalik/fs/LICENSE", "src/github.com/rjeczalik/fs/COPYLEFT"), + rwrite(w, "src/github.com/rjeczalik/fs/cmd/gotree/go.go", []byte("XD")), + } + w.RecursiveWatch("", joinevents(events)) + w.ExpectAny(cases[:]) +}