Deadlock between Watcher and Debounce threads (fix #187)
fix https://github.com/parcel-bundler/watcher/issues/187
There are two threads involved in Watcher.cc and Debounce.cc each
calling into respective methods of the other and thus each potentially
holding onto locks of the other. This can lead to a deadlock in the
following scenario:
While the Debounce.cc thread is processing callbacks in the
Debounce::notify() method, it holds its own lock. The method loops
over callbacks to process in Watcher.cc which itself requires a lock
in Watcher.cc. If an event gets reported while the debouncer is in
Watcher.triggerCallbacks(), a deadlock is present, because:
- assume the event thread is thread A
- assume the debouncer thread is thread B
- A holds its own lock in
Watcher::notify()and calls intoDebounce.trigger()which requires the debouncer lock - B at this time is inside
Debounce::notify()holding its own lock processing callbacks and about to call intoWatcher.triggerCallbacks() - A deadlocks waiting for B to release the debouncer lock
- B deadlocks waiting for A to release the watcher lock
Thanks for the deep investigation here! This looks good to me.
Could this be merged and published soon, please? We're desperately waiting for a fix :)
@devongovett 👋 yeah, would be great to see a new version with the fix included