gh-154971: Split IocpProactor._poll() (#155142)
kumaraditya303 <[email protected]> Tue, 04 Aug 2026 04:35:15 -0400 (EDT)
| Newsgroups | gmane.comp.python.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://github.com/python/cpython/commit/089b713e01665c5fec8865a16716d1e4bce7c1d9 commit: 089b713e01665c5fec8865a16716d1e4bce7c1d9 branch: main author: Timofei Ivankov <[email protected]> committer: kumaraditya303 <[email protected]> date: 2026-08-04T14:04:54+05:30 summary: gh-154971: Split IocpProactor._poll() (#155142) files: M Lib/asyncio/windows_events.py M Lib/test/test_asyncio/test_windows_events.py diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py index efc7c0c158d390..2a7c18cda8a76a 100644 --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -760,6 +760,46 @@ def _get_accept_socket(self, family): s.settimeout(0) return s + def _process_completion_status(self, status): + """Process a single status from the completion port. + + A caller that waits on the completion port itself can pass each + status it receives here. + """ + err, transferred, key, address = status + try: + f, ov, obj, callback = self._cache.pop(address) + except KeyError: + if self._loop.get_debug(): + self._loop.call_exception_handler({ + 'message': ('GetQueuedCompletionStatus() returned an ' + 'unexpected event'), + 'status': ('err=%s transferred=%s key=%#x address=%#x' + % (err, transferred, key, address)), + }) + + # key is either zero, or it is used to return a pipe + # handle which should be closed to avoid a leak. + if key not in (0, _overlapped.INVALID_HANDLE_VALUE): + _winapi.CloseHandle(key) + return + + if obj in self._stopped_serving: + f.cancel() + # Don't call the callback if _register() already read the result or + # if the overlapped has been cancelled + elif not f.done(): + try: + value = callback(transferred, key, ov) + except OSError as e: + f.set_exception(e) + self._results.append(f) + else: + f.set_result(value) + self._results.append(f) + finally: + f = None + def _poll(self, timeout=None): if timeout is None: ms = INFINITE @@ -778,39 +818,8 @@ def _poll(self, timeout=None): break ms = 0 - err, transferred, key, address = status - try: - f, ov, obj, callback = self._cache.pop(address) - except KeyError: - if self._loop.get_debug(): - self._loop.call_exception_handler({ - 'message': ('GetQueuedCompletionStatus() returned an ' - 'unexpected event'), - 'status': ('err=%s transferred=%s key=%#x address=%#x' - % (err, transferred, key, address)), - }) - - # key is either zero, or it is used to return a pipe - # handle which should be closed to avoid a leak. - if key not in (0, _overlapped.INVALID_HANDLE_VALUE): - _winapi.CloseHandle(key) - continue - - if obj in self._stopped_serving: - f.cancel() - # Don't call the callback if _register() already read the result or - # if the overlapped has been cancelled - elif not f.done(): - try: - value = callback(transferred, key, ov) - except OSError as e: - f.set_exception(e) - self._results.append(f) - else: - f.set_result(value) - self._results.append(f) - finally: - f = None + # gh-154971: split out so custom event loops can call it directly + self._process_completion_status(status) # Remove unregistered futures for ov in self._unregistered: diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py index c23427b8652069..bb4ba74f19a17f 100644 --- a/Lib/test/test_asyncio/test_windows_events.py +++ b/Lib/test/test_asyncio/test_windows_events.py @@ -327,6 +327,28 @@ def threadMain(): stop.set() thr.join() + def test_custom_poll_integration(self): + # gh-154971: a caller can wait on the completion port and process statuses itself + proactor = self.loop._proactor + + a, b = socket.socketpair() + self.addCleanup(a.close) + self.addCleanup(b.close) + + fut = proactor.recv(a, 100) + self.assertFalse(fut.done()) + + b.send(b'data') + + deadline = time.monotonic() + support.SHORT_TIMEOUT + while not fut.done() and time.monotonic() < deadline: + status = _overlapped.GetQueuedCompletionStatus(proactor._iocp, 100) + if status is not None: + proactor._process_completion_status(status) + + self.assertTrue(fut.done()) + self.assertEqual(fut.result(), b'data') + class ProactorPipeObjectSupportTests(unittest.TestCase): _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]