[Python-checkins] [3.7] bpo-34323: Enhance IocpProactor.close() log (GH-11565)
Victor Stinner
webhook-mailer at python.org
Tue Jan 15 07:05:35 EST 2019
https://github.com/python/cpython/commit/d5a6adf6285ec8892b977a32c22143ebd1025b50
commit: d5a6adf6285ec8892b977a32c22143ebd1025b50
branch: 3.7
author: Victor Stinner <vstinner at redhat.com>
committer: GitHub <noreply at github.com>
date: 2019-01-15T13:05:28+01:00
summary:
[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 9b07681c09182d4b9d23cd52566a4992b8afecbb)
* 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 b1e45739d832e1e402a563c6727defda92e193b7)
* 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 b91140fdb17472d03a7b7971f143c08a40fde923)
files:
A Misc/NEWS.d/next/Library/2019-01-14-17-34-36.bpo-34323.CRErrt.rst
M Lib/asyncio/windows_events.py
diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py
index 2ec542764375..e3778688ab5b 100644
--- a/Lib/asyncio/windows_events.py
+++ b/Lib/asyncio/windows_events.py
@@ -7,6 +7,7 @@
import msvcrt
import socket
import struct
+import time
import weakref
from . import events
@@ -392,10 +393,16 @@ def __init__(self, concurrency=0xffffffff):
self._unregistered = []
self._stopped_serving = weakref.WeakSet()
+ def _check_closed(self):
+ if self._iocp is None:
+ raise RuntimeError('IocpProactor is closed')
+
def __repr__(self):
- return ('<%s overlapped#=%s result#=%s>'
- % (self.__class__.__name__, len(self._cache),
- len(self._results)))
+ info = ['overlapped#=%s' % len(self._cache),
+ 'result#=%s' % len(self._results)]
+ if self._iocp is None:
+ info.append('closed')
+ return '<%s %s>' % (self.__class__.__name__, " ".join(info))
def set_loop(self, loop):
self._loop = loop
@@ -602,6 +609,8 @@ def _wait_cancel(self, event, done_callback):
return fut
def _wait_for_handle(self, handle, timeout, _is_cancel):
+ self._check_closed()
+
if timeout is None:
ms = _winapi.INFINITE
else:
@@ -644,6 +653,8 @@ def _register_with_iocp(self, obj):
# that succeed immediately.
def _register(self, ov, obj, callback):
+ self._check_closed()
+
# Return a future which will be set with the result of the
# operation when it completes. The future's value is actually
# the value returned by callback().
@@ -680,6 +691,7 @@ def _unregister(self, ov):
already be signalled (pending in the proactor event queue). It is also
safe if the event is never signalled (because it was cancelled).
"""
+ self._check_closed()
self._unregistered.append(ov)
def _get_accept_socket(self, family):
@@ -749,6 +761,10 @@ def _stop_serving(self, obj):
self._stopped_serving.add(obj)
def close(self):
+ if self._iocp is None:
+ # already closed
+ return
+
# Cancel remaining registered operations.
for address, (fut, ov, obj, callback) in list(self._cache.items()):
if fut.cancelled():
@@ -771,14 +787,25 @@ def close(self):
context['source_traceback'] = fut._source_traceback
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:
- if not self._poll(1):
- logger.debug('taking long time to close proactor')
+ if next_msg <= time.monotonic():
+ 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 = []
- if self._iocp is not None:
- _winapi.CloseHandle(self._iocp)
- self._iocp = None
+
+ _winapi.CloseHandle(self._iocp)
+ self._iocp = None
def __del__(self):
self.close()
diff --git a/Misc/NEWS.d/next/Library/2019-01-14-17-34-36.bpo-34323.CRErrt.rst b/Misc/NEWS.d/next/Library/2019-01-14-17-34-36.bpo-34323.CRErrt.rst
new file mode 100644
index 000000000000..59269244cc47
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-01-14-17-34-36.bpo-34323.CRErrt.rst
@@ -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.
More information about the Python-checkins
mailing list