Skip to content

Commit

Permalink
[inotify] Avoid bad file descriptor shutdown (#895)
Browse files Browse the repository at this point in the history
* avoid bad file descriptor shutdown

* add to changelog
  • Loading branch information
altendky authored Jun 9, 2022
1 parent df1574c commit 1dd7fa8
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 3 deletions.
3 changes: 2 additions & 1 deletion changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ Unreleased
- [fsevents] Fix flakey test to assert that there are no errors when stopping the emitter.
- [watchmedo] Make ``auto-restart`` restart the sub-process if it terminates. (`#896 <https://github.com/gorakhargosh/watchdog/pull/896>`__)
- [watchmedo] Avoid zombie sub-processes when running ``shell-command`` without ``--wait``. (`#405 <https://github.com/gorakhargosh/watchdog/issues/405>`__)
- Thanks to our beloved contributors: @samschott, @taleinat
- [inotify] Suppress occasional ``OSError: [Errno 9] Bad file descriptor`` at shutdown (`#805 <https://github.com/gorakhargosh/watchdog/issues/805>`__)
- Thanks to our beloved contributors: @samschott, @taleinat, @altendky

2.1.8
~~~~~
Expand Down
2 changes: 2 additions & 0 deletions src/watchdog/observers/inotify_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ def _recursive_simulate(src_path):
except OSError as e:
if e.errno == errno.EINTR:
continue
elif e.errno == errno.EBADF:
return []
else:
raise
break
Expand Down
25 changes: 23 additions & 2 deletions tests/test_inotify_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import os
import random
import time

from watchdog.observers.inotify_buffer import InotifyBuffer

Expand Down Expand Up @@ -132,8 +133,28 @@ def test_unmount_watched_directory_filesystem(p):
assert not inotify.is_alive()


def test_close_should_terminate_thread(p):
inotify = InotifyBuffer(p('').encode(), recursive=True)
def delay_call(function, seconds):
def delayed(*args, **kwargs):
time.sleep(seconds)

return function(*args, **kwargs)

return delayed


class InotifyBufferDelayedRead(InotifyBuffer):
def run(self, *args, **kwargs):
# Introduce a delay to trigger the race condition where the file descriptor is
# closed prior to a read being triggered.
self._inotify.read_events = delay_call(function=self._inotify.read_events, seconds=1)

return super().run(*args, **kwargs)


@pytest.mark.parametrize(argnames="cls", argvalues=[InotifyBuffer, InotifyBufferDelayedRead])
def test_close_should_terminate_thread(p, cls):
inotify = cls(p('').encode(), recursive=True)

assert inotify.is_alive()
inotify.close()
assert not inotify.is_alive()

0 comments on commit 1dd7fa8

Please sign in to comment.