Skip to content

Commit 5135dab

Browse files
committed
check and split fd-like to int FD in proactor add_reader
matches tornado behavior tornado handles this in IOLoop, so we need to include it
1 parent a720ba0 commit 5135dab

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

Lib/asyncio/_selector_thread.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ async def thread_manager_anext() -> None:
109109
context=self._main_thread_ctx,
110110
)
111111

112-
self._readers: Dict[_FileDescriptorLike, Callable] = {}
113-
self._writers: Dict[_FileDescriptorLike, Callable] = {}
112+
self._readers: Dict[int, Tuple[_FileDescriptorLike, Callable]] = {}
113+
self._writers: Dict[int, Tuple[_FileDescriptorLike, Callable]] = {}
114114

115115
# Writing to _waker_w will wake up the selector thread, which
116116
# watches for _waker_r to be readable.
@@ -261,27 +261,45 @@ def _handle_select(
261261
def _handle_event(
262262
self,
263263
fd: _FileDescriptorLike,
264-
cb_map: Dict[_FileDescriptorLike, Callable],
264+
cb_map: Dict[int, Tuple[_FileDescriptorLike, Callable]],
265265
) -> None:
266266
try:
267-
callback = cb_map[fd]
267+
fileobj, callback = cb_map[fd]
268268
except KeyError:
269269
return
270270
callback()
271271

272+
def _split_fd(self, fd: _FileDescriptorLike) -> Tuple[int, _FileDescriptorLike]:
273+
"""Return fd, file object
274+
275+
Keeps a handle on the fileobject given,
276+
but always registers integer FD
277+
"""
278+
fileno = fd
279+
if not isinstance(fileno, int):
280+
try:
281+
fileno = int(fileno.fileno())
282+
except (AttributeError, TypeError, ValueError):
283+
# This code matches selectors._fileobj_to_fd function.
284+
raise ValueError(f"Invalid file object: {fd!r}") from None
285+
return fileno, fd
286+
272287
def add_reader(
273288
self, fd: _FileDescriptorLike, callback: Callable[..., None], *args: Any
274289
) -> None:
275-
self._readers[fd] = functools.partial(callback, *args)
290+
fd, fileobj = self._split_fd(fd)
291+
self._readers[fd] = (fileobj, functools.partial(callback, *args))
276292
self._wake_selector()
277293

278294
def add_writer(
279295
self, fd: _FileDescriptorLike, callback: Callable[..., None], *args: Any
280296
) -> None:
281-
self._writers[fd] = functools.partial(callback, *args)
297+
fd, fileobj = self._split_fd(fd)
298+
self._writers[fd] = (fileobj, functools.partial(callback, *args))
282299
self._wake_selector()
283300

284301
def remove_reader(self, fd: _FileDescriptorLike) -> bool:
302+
fd, _ = self._split_fd(fd)
285303
try:
286304
del self._readers[fd]
287305
except KeyError:
@@ -290,6 +308,7 @@ def remove_reader(self, fd: _FileDescriptorLike) -> bool:
290308
return True
291309

292310
def remove_writer(self, fd: _FileDescriptorLike) -> bool:
311+
fd, _ = self._split_fd(fd)
293312
try:
294313
del self._writers[fd]
295314
except KeyError:

Lib/test/test_asyncio/test_windows_events.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -357,17 +357,17 @@ def read():
357357

358358
self.loop.add_reader(b, read)
359359
_selector_thread = self.loop._selector_thread
360-
assert b in _selector_thread._readers
360+
assert b.fileno() in _selector_thread._readers
361361
assert _selector_thread is not None
362362
self.loop.add_writer(a, write)
363363
assert self.loop._selector_thread is _selector_thread
364-
assert a in _selector_thread._writers
364+
assert a.fileno() in _selector_thread._writers
365365
msg = await asyncio.wait_for(read_future, timeout=10)
366366

367367
self.loop.remove_writer(a)
368-
assert a not in _selector_thread._writers
368+
assert a.fileno() not in _selector_thread._writers
369369
self.loop.remove_reader(b)
370-
assert b not in _selector_thread._readers
370+
assert b.fileno() not in _selector_thread._readers
371371
a.close()
372372
b.close()
373373
assert self.loop._selector_thread is _selector_thread

0 commit comments

Comments
 (0)