Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d5a6adf

Browse files
authored
[3.7] bpo-34323: Enhance IocpProactor.close() log (GH-11565)
* IocpProactor: prevent modification if closed (GH-11494) * _wait_for_handle(), _register() and _unregister() methods of IocpProactor now raise an exception if closed * Add "closed" to IocpProactor.__repr__() * Simplify IocpProactor.close() (cherry picked from commit 9b07681) * bpo-34323: Enhance IocpProactor.close() log (GH-11555) IocpProactor.close() now uses time to decide when to log: wait 1 second before the first log, then log every second. Log also the number of seconds since close() was called. (cherry picked from commit b1e4573) * bpo-34323: Enhance IocpProactor.close() log again (GH-11563) Add repr(self) to the log to display the number of pending overlapped in the log. (cherry picked from commit b91140f)
1 parent 97d6a56 commit d5a6adf

File tree

2 files changed

+38
-8
lines changed

2 files changed

+38
-8
lines changed

Lib/asyncio/windows_events.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import msvcrt
88
import socket
99
import struct
10+
import time
1011
import weakref
1112

1213
from . import events
@@ -392,10 +393,16 @@ def __init__(self, concurrency=0xffffffff):
392393
self._unregistered = []
393394
self._stopped_serving = weakref.WeakSet()
394395

396+
def _check_closed(self):
397+
if self._iocp is None:
398+
raise RuntimeError('IocpProactor is closed')
399+
395400
def __repr__(self):
396-
return ('<%s overlapped#=%s result#=%s>'
397-
% (self.__class__.__name__, len(self._cache),
398-
len(self._results)))
401+
info = ['overlapped#=%s' % len(self._cache),
402+
'result#=%s' % len(self._results)]
403+
if self._iocp is None:
404+
info.append('closed')
405+
return '<%s %s>' % (self.__class__.__name__, " ".join(info))
399406

400407
def set_loop(self, loop):
401408
self._loop = loop
@@ -602,6 +609,8 @@ def _wait_cancel(self, event, done_callback):
602609
return fut
603610

604611
def _wait_for_handle(self, handle, timeout, _is_cancel):
612+
self._check_closed()
613+
605614
if timeout is None:
606615
ms = _winapi.INFINITE
607616
else:
@@ -644,6 +653,8 @@ def _register_with_iocp(self, obj):
644653
# that succeed immediately.
645654

646655
def _register(self, ov, obj, callback):
656+
self._check_closed()
657+
647658
# Return a future which will be set with the result of the
648659
# operation when it completes. The future's value is actually
649660
# the value returned by callback().
@@ -680,6 +691,7 @@ def _unregister(self, ov):
680691
already be signalled (pending in the proactor event queue). It is also
681692
safe if the event is never signalled (because it was cancelled).
682693
"""
694+
self._check_closed()
683695
self._unregistered.append(ov)
684696

685697
def _get_accept_socket(self, family):
@@ -749,6 +761,10 @@ def _stop_serving(self, obj):
749761
self._stopped_serving.add(obj)
750762

751763
def close(self):
764+
if self._iocp is None:
765+
# already closed
766+
return
767+
752768
# Cancel remaining registered operations.
753769
for address, (fut, ov, obj, callback) in list(self._cache.items()):
754770
if fut.cancelled():
@@ -771,14 +787,25 @@ def close(self):
771787
context['source_traceback'] = fut._source_traceback
772788
self._loop.call_exception_handler(context)
773789

790+
# Wait until all cancelled overlapped complete: don't exit with running
791+
# overlapped to prevent a crash. Display progress every second if the
792+
# loop is still running.
793+
msg_update = 1.0
794+
start_time = time.monotonic()
795+
next_msg = start_time + msg_update
774796
while self._cache:
775-
if not self._poll(1):
776-
logger.debug('taking long time to close proactor')
797+
if next_msg <= time.monotonic():
798+
logger.debug('%r is running after closing for %.1f seconds',
799+
self, time.monotonic() - start_time)
800+
next_msg = time.monotonic() + msg_update
801+
802+
# handle a few events, or timeout
803+
self._poll(msg_update)
777804

778805
self._results = []
779-
if self._iocp is not None:
780-
_winapi.CloseHandle(self._iocp)
781-
self._iocp = None
806+
807+
_winapi.CloseHandle(self._iocp)
808+
self._iocp = None
782809

783810
def __del__(self):
784811
self.close()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:mod:`asyncio`: Enhance ``IocpProactor.close()`` log: wait 1 second before
2+
the first log, then log every second. Log also the number of seconds since
3+
``close()`` was called.

0 commit comments

Comments
 (0)