[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 commit9b07681c09
) * 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 commitb1e45739d8
) * 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 commitb91140fdb1
)
This commit is contained in:
parent
97d6a56d9d
commit
d5a6adf628
|
@ -7,6 +7,7 @@ import math
|
||||||
import msvcrt
|
import msvcrt
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
import time
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
from . import events
|
from . import events
|
||||||
|
@ -392,10 +393,16 @@ class IocpProactor:
|
||||||
self._unregistered = []
|
self._unregistered = []
|
||||||
self._stopped_serving = weakref.WeakSet()
|
self._stopped_serving = weakref.WeakSet()
|
||||||
|
|
||||||
|
def _check_closed(self):
|
||||||
|
if self._iocp is None:
|
||||||
|
raise RuntimeError('IocpProactor is closed')
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return ('<%s overlapped#=%s result#=%s>'
|
info = ['overlapped#=%s' % len(self._cache),
|
||||||
% (self.__class__.__name__, len(self._cache),
|
'result#=%s' % len(self._results)]
|
||||||
len(self._results)))
|
if self._iocp is None:
|
||||||
|
info.append('closed')
|
||||||
|
return '<%s %s>' % (self.__class__.__name__, " ".join(info))
|
||||||
|
|
||||||
def set_loop(self, loop):
|
def set_loop(self, loop):
|
||||||
self._loop = loop
|
self._loop = loop
|
||||||
|
@ -602,6 +609,8 @@ class IocpProactor:
|
||||||
return fut
|
return fut
|
||||||
|
|
||||||
def _wait_for_handle(self, handle, timeout, _is_cancel):
|
def _wait_for_handle(self, handle, timeout, _is_cancel):
|
||||||
|
self._check_closed()
|
||||||
|
|
||||||
if timeout is None:
|
if timeout is None:
|
||||||
ms = _winapi.INFINITE
|
ms = _winapi.INFINITE
|
||||||
else:
|
else:
|
||||||
|
@ -644,6 +653,8 @@ class IocpProactor:
|
||||||
# that succeed immediately.
|
# that succeed immediately.
|
||||||
|
|
||||||
def _register(self, ov, obj, callback):
|
def _register(self, ov, obj, callback):
|
||||||
|
self._check_closed()
|
||||||
|
|
||||||
# Return a future which will be set with the result of the
|
# Return a future which will be set with the result of the
|
||||||
# operation when it completes. The future's value is actually
|
# operation when it completes. The future's value is actually
|
||||||
# the value returned by callback().
|
# the value returned by callback().
|
||||||
|
@ -680,6 +691,7 @@ class IocpProactor:
|
||||||
already be signalled (pending in the proactor event queue). It is also
|
already be signalled (pending in the proactor event queue). It is also
|
||||||
safe if the event is never signalled (because it was cancelled).
|
safe if the event is never signalled (because it was cancelled).
|
||||||
"""
|
"""
|
||||||
|
self._check_closed()
|
||||||
self._unregistered.append(ov)
|
self._unregistered.append(ov)
|
||||||
|
|
||||||
def _get_accept_socket(self, family):
|
def _get_accept_socket(self, family):
|
||||||
|
@ -749,6 +761,10 @@ class IocpProactor:
|
||||||
self._stopped_serving.add(obj)
|
self._stopped_serving.add(obj)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
if self._iocp is None:
|
||||||
|
# already closed
|
||||||
|
return
|
||||||
|
|
||||||
# Cancel remaining registered operations.
|
# Cancel remaining registered operations.
|
||||||
for address, (fut, ov, obj, callback) in list(self._cache.items()):
|
for address, (fut, ov, obj, callback) in list(self._cache.items()):
|
||||||
if fut.cancelled():
|
if fut.cancelled():
|
||||||
|
@ -771,14 +787,25 @@ class IocpProactor:
|
||||||
context['source_traceback'] = fut._source_traceback
|
context['source_traceback'] = fut._source_traceback
|
||||||
self._loop.call_exception_handler(context)
|
self._loop.call_exception_handler(context)
|
||||||
|
|
||||||
|
# Wait until all cancelled overlapped complete: don't exit with running
|
||||||
|
# overlapped to prevent a crash. Display progress every second if the
|
||||||
|
# loop is still running.
|
||||||
|
msg_update = 1.0
|
||||||
|
start_time = time.monotonic()
|
||||||
|
next_msg = start_time + msg_update
|
||||||
while self._cache:
|
while self._cache:
|
||||||
if not self._poll(1):
|
if next_msg <= time.monotonic():
|
||||||
logger.debug('taking long time to close proactor')
|
logger.debug('%r is running after closing for %.1f seconds',
|
||||||
|
self, time.monotonic() - start_time)
|
||||||
|
next_msg = time.monotonic() + msg_update
|
||||||
|
|
||||||
|
# handle a few events, or timeout
|
||||||
|
self._poll(msg_update)
|
||||||
|
|
||||||
self._results = []
|
self._results = []
|
||||||
if self._iocp is not None:
|
|
||||||
_winapi.CloseHandle(self._iocp)
|
_winapi.CloseHandle(self._iocp)
|
||||||
self._iocp = None
|
self._iocp = None
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
:mod:`asyncio`: Enhance ``IocpProactor.close()`` log: wait 1 second before
|
||||||
|
the first log, then log every second. Log also the number of seconds since
|
||||||
|
``close()`` was called.
|
Loading…
Reference in New Issue