Reputation: 3165
Hello stackoverflow community, I am using github.com/fsnotify/fsnotify to set watchers to a file in Go. My function looks like
func SetWatcher(filename string) {
fmt.Println("Setting watcher to file ", filename)
Watcher, err = fsnotify.NewWatcher()
if err != nil {
fmt.Println("inotify errored. Other methods needs to be implemented.")
panic(err)
}
if err != nil {
log.Fatal(err)
}
done := make(chan bool)
go func() {
for {
select {
case event := <-Watcher.Events:
if event.Op == fsnotify.Remove {
fmt.Println("File removed, needs to kill the process.")
} else if event.Op == fsnotify.Rename {
fmt.Println("File renamed, need to restart seeking.")
}
case err := <-Watcher.Errors:
log.Println("error:", err)
}
}
}()
err = Watcher.Add(filename)
if err != nil {
log.Fatal(err)
}
<-done
}
which works so far and I get outputs as
Setting watcher to file /var/log/syslog
File renamed, need to restart seeking.
However, if I try to remove the closure running in the goroutine and run it as
func SetWatcher(filename string) {
fmt.Println("Setting watcher to file ", filename)
Watcher, err = fsnotify.NewWatcher()
if err != nil {
fmt.Println("inotify errored. Other methods needs to be implemented.")
panic(err)
}
if err != nil {
log.Fatal(err)
}
//defer Watcher.Close()
//done := make(chan bool)
//go func() {
// for {
select {
case event := <-Watcher.Events:
if event.Op == fsnotify.Remove {
fmt.Println("File removed, needs to kill the process.")
} else if event.Op == fsnotify.Rename {
fmt.Println("File renamed, need to restart seeking.")
}
case err := <-Watcher.Errors:
log.Println("error:", err)
}
//}
//}()
err = Watcher.Add(filename)
if err != nil {
log.Fatal(err)
}
//<-done
}
the program never outputs anything. I ran it with strace
and the program is seen stuck at
[pid 5773] pselect6(0, NULL, NULL, NULL, {tv_sec=0, tv_nsec=20000}, NULL <unfinished ...>
[pid 5772] epoll_wait(4, [], 128, 0) = 0
[pid 5772] futex(0x598bf8, FUTEX_WAIT, 0, NULL <unfinished ...>
[pid 5773] <... pselect6 resumed> ) = 0 (Timeout)
[pid 5740] <... pselect6 resumed> ) = 0 (Timeout)
[pid 5773] futex(0x598578, FUTEX_WAIT, 0, {tv_sec=60, tv_nsec=0}
<unfinished ...>
[pid 5740] futex(0xae1f58, FUTEX_WAIT, 0, {tv_sec=60, tv_nsec=0}
and not receiving from the channel and keeps on waiting.
I've read that this could be caused because of non-buffered channel. So to validate that, I modified the library to use a buffered channel and the part of the function that generates the new watcher looks like
w := &Watcher{
fd: fd,
poller: poller,
watches: make(map[string]*watch),
paths: make(map[int]string),
Events: make(chan Event, 10), // Made it buffered here
Errors: make(chan error),
done: make(chan struct{}),
doneResp: make(chan struct{}),
}
But the behavior is the same. Can someone please help me understand why the reading from channel worked when it was in a goroutine, and didn't work without a goroutine?
Thank you.
Upvotes: 1
Views: 368
Reputation: 515
I am not familiar with fsnotify, but it looks like it won't send anything on the channels until Watcher.Add()
is called to watch the file, but the Watcher.Add()
occurs after the select
in the second version. In this case select will block for ever as nothing can be signaled as Watcher.Add()
has not been called. Hence there is deadlock.
Upvotes: 2