|
9 | 9 | import struct
|
10 | 10 | import threading
|
11 | 11 | from ctypes import c_char_p, c_int, c_uint32
|
12 |
| -from functools import partial, reduce |
13 |
| -from typing import TYPE_CHECKING, Any, Callable |
| 12 | +from functools import reduce |
| 13 | +from typing import TYPE_CHECKING |
14 | 14 |
|
15 | 15 | from watchdog.utils import UnsupportedLibcError
|
16 | 16 |
|
@@ -150,16 +150,26 @@ def __init__(self, path: bytes, *, recursive: bool = False, event_mask: int | No
|
150 | 150 | self._inotify_fd = inotify_fd
|
151 | 151 | self._lock = threading.Lock()
|
152 | 152 | self._closed = False
|
153 |
| - self._waiting_to_read = True |
| 153 | + self._is_reading = True |
154 | 154 | self._kill_r, self._kill_w = os.pipe()
|
155 | 155 |
|
| 156 | + # _check_inotify_fd will return true if we can read _inotify_fd without blocking |
156 | 157 | if hasattr(select, "poll"):
|
157 | 158 | self._poller = select.poll()
|
158 | 159 | self._poller.register(self._inotify_fd, select.POLLIN)
|
159 | 160 | self._poller.register(self._kill_r, select.POLLIN)
|
160 |
| - self._poll: Callable[[], Any] = partial(self._poller.poll) |
| 161 | + |
| 162 | + def do_poll() -> bool: |
| 163 | + return any(fd == self._inotify_fd for fd, _ in self._poller.poll()) |
| 164 | + |
| 165 | + self._check_inotify_fd = do_poll |
161 | 166 | else:
|
162 |
| - self._poll = partial(select.select, (self._inotify_fd, self._kill_r)) |
| 167 | + |
| 168 | + def do_select() -> bool: |
| 169 | + result = select.select([self._inotify_fd, self._kill_r], [], []) |
| 170 | + return self._inotify_fd in result[0] |
| 171 | + |
| 172 | + self._check_inotify_fd = do_select |
163 | 173 |
|
164 | 174 | # Stores the watch descriptor for a given path.
|
165 | 175 | self._wd_for_path: dict[bytes, int] = {}
|
@@ -249,7 +259,7 @@ def close(self) -> None:
|
249 | 259 | wd = self._wd_for_path[self._path]
|
250 | 260 | inotify_rm_watch(self._inotify_fd, wd)
|
251 | 261 |
|
252 |
| - if self._waiting_to_read: |
| 262 | + if self._is_reading: |
253 | 263 | # inotify_rm_watch() should write data to _inotify_fd and wake
|
254 | 264 | # the thread, but writing to the kill channel will gaurentee this
|
255 | 265 | os.write(self._kill_w, b"!")
|
@@ -291,25 +301,24 @@ def _recursive_simulate(src_path: bytes) -> list[InotifyEvent]:
|
291 | 301 | events.append(e)
|
292 | 302 | return events
|
293 | 303 |
|
294 |
| - event_buffer = None |
| 304 | + event_buffer = b"" |
295 | 305 | while True:
|
296 | 306 | try:
|
297 | 307 | with self._lock:
|
298 | 308 | if self._closed:
|
299 | 309 | return []
|
300 | 310 |
|
301 |
| - self._waiting_to_read = True |
| 311 | + self._is_reading = True |
302 | 312 |
|
303 |
| - self._poll() |
| 313 | + if self._check_inotify_fd(): |
| 314 | + event_buffer = os.read(self._inotify_fd, event_buffer_size) |
304 | 315 |
|
305 | 316 | with self._lock:
|
306 |
| - self._waiting_to_read = False |
| 317 | + self._is_reading = False |
307 | 318 |
|
308 | 319 | if self._closed:
|
309 | 320 | self._close_resources()
|
310 | 321 | return []
|
311 |
| - |
312 |
| - event_buffer = os.read(self._inotify_fd, event_buffer_size) |
313 | 322 | except OSError as e:
|
314 | 323 | if e.errno == errno.EINTR:
|
315 | 324 | continue
|
|
0 commit comments