-
-
Notifications
You must be signed in to change notification settings - Fork 888
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
avoid deadlocks on close. Fixes #187 #188
Conversation
probably addresses #145 as well. |
confirmed. this patch makes test in #145 pass. |
if index > 10 { | ||
return | ||
} | ||
index += 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should replace index += 1 with index++
select { | ||
case event := <-watcher.Events: | ||
log.Println("event:", event) | ||
notifications += 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should replace notifications += 1 with notifications++
Ping. Please merge this. |
raw channel work (not inside a select) should always be prohibited in production code, as it readily causes deadlocks on shutdown. Also adds the test TestWatcherClose from #145. This request duplicates that test, with two lines fixed to address the houndcli-bot review concerns. Fixes #187 Fixes #145
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@glycerine I'd like to get this merged ASAP as its a serious bug. If it's cool with you may I take over?
@nathany I believe this covers #211 and #145 so after this is merged, those should probably be closed.
if err != nil { | ||
select { | ||
case w.Errors <- err: | ||
case <-w.done: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given the only way this function can return is if w.done
is closed, I think this should instead be the default case.
|
||
func consumeEvent(t *testing.T, watcher *Watcher, wg *sync.WaitGroup) { | ||
defer func() { | ||
//time.Sleep(time.Second) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
debugging line should be removed.
func TestWatcherClose(t *testing.T) { | ||
dir, err := ioutil.TempDir("./", "example") | ||
if err != nil { | ||
panic(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this panic and the others should be t.Fatal
if err != nil { | ||
panic(err) | ||
} | ||
ioutil.TempFile(dir, "example") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extraneous line.
if err != nil { | ||
panic(err) | ||
} | ||
_, err = ioutil.TempFile(dir, "example") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary line.
watcher.Close() | ||
wg.Done() | ||
}() | ||
log.Println("Came here") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
debugging line.
maxNotifications := 1 | ||
for { | ||
if notifications >= maxNotifications { | ||
log.Println("Reached max notifications") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
debugging line.
} | ||
select { | ||
case event := <-watcher.Events: | ||
log.Println("event:", event) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should use t.Log
.
index++ | ||
} | ||
} | ||
func TestWatcherClose(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this test could be made much simpler. We just need the watcher to be listening on some file, modify the file and then close the watcher without listening on either the errors or events channels.
// Send "quit" message to the reader goroutine: | ||
w.done <- true | ||
// send a "quit" message to the reader goroutine | ||
close(w.done) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should change w.done to be a chan struct{}
.
by all means. |
Raw channel work (not inside a select) is subject to deadlock on shutdown.
Hence Close() can deadlock.
This is already fixed in the linux inotify.go code.
Fixes #187