2014-02-18 23:27:48 -04:00
|
|
|
"""Selector and proactor event loops for Windows."""
|
2013-10-17 17:40:50 -03:00
|
|
|
|
2022-01-04 04:44:26 -04:00
|
|
|
import sys
|
|
|
|
|
|
|
|
if sys.platform != 'win32': # pragma: no cover
|
|
|
|
raise ImportError('win32 only')
|
|
|
|
|
2017-11-28 10:19:56 -04:00
|
|
|
import _overlapped
|
2014-01-31 11:25:24 -04:00
|
|
|
import _winapi
|
2013-10-17 17:40:50 -03:00
|
|
|
import errno
|
2024-03-23 12:39:35 -03:00
|
|
|
from functools import partial
|
2014-01-31 11:25:24 -04:00
|
|
|
import math
|
2018-02-25 12:32:14 -04:00
|
|
|
import msvcrt
|
2013-10-17 17:40:50 -03:00
|
|
|
import socket
|
2014-01-31 11:25:24 -04:00
|
|
|
import struct
|
2019-01-15 06:48:00 -04:00
|
|
|
import time
|
2013-10-17 17:40:50 -03:00
|
|
|
import weakref
|
|
|
|
|
2013-11-04 19:50:46 -04:00
|
|
|
from . import events
|
2013-10-30 18:52:03 -03:00
|
|
|
from . import base_subprocess
|
2013-10-17 17:40:50 -03:00
|
|
|
from . import futures
|
2018-09-11 14:13:04 -03:00
|
|
|
from . import exceptions
|
2013-10-17 17:40:50 -03:00
|
|
|
from . import proactor_events
|
|
|
|
from . import selector_events
|
|
|
|
from . import tasks
|
|
|
|
from . import windows_utils
|
2014-06-28 19:46:45 -03:00
|
|
|
from .log import logger
|
2013-10-17 17:40:50 -03:00
|
|
|
|
|
|
|
|
2017-12-10 19:36:12 -04:00
|
|
|
__all__ = (
|
|
|
|
'SelectorEventLoop', 'ProactorEventLoop', 'IocpProactor',
|
2018-06-07 21:44:57 -03:00
|
|
|
'DefaultEventLoopPolicy', 'WindowsSelectorEventLoopPolicy',
|
2023-10-12 11:13:57 -03:00
|
|
|
'WindowsProactorEventLoopPolicy', 'EventLoop',
|
2017-12-10 19:36:12 -04:00
|
|
|
)
|
2013-10-17 17:40:50 -03:00
|
|
|
|
|
|
|
|
2022-01-04 04:42:19 -04:00
|
|
|
NULL = _winapi.NULL
|
|
|
|
INFINITE = _winapi.INFINITE
|
2013-10-17 17:40:50 -03:00
|
|
|
ERROR_CONNECTION_REFUSED = 1225
|
|
|
|
ERROR_CONNECTION_ABORTED = 1236
|
|
|
|
|
2015-01-22 17:55:08 -04:00
|
|
|
# Initial delay in seconds for connect_pipe() before retrying to connect
|
|
|
|
CONNECT_PIPE_INIT_DELAY = 0.001
|
|
|
|
|
|
|
|
# Maximum delay in seconds for connect_pipe() before retrying to connect
|
|
|
|
CONNECT_PIPE_MAX_DELAY = 0.100
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
|
|
|
|
class _OverlappedFuture(futures.Future):
|
|
|
|
"""Subclass of Future which represents an overlapped operation.
|
|
|
|
|
|
|
|
Cancelling it will immediately cancel the overlapped operation.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, ov, *, loop=None):
|
|
|
|
super().__init__(loop=loop)
|
2014-07-24 19:54:53 -03:00
|
|
|
if self._source_traceback:
|
|
|
|
del self._source_traceback[-1]
|
2014-07-25 08:05:20 -03:00
|
|
|
self._ov = ov
|
2013-10-17 17:40:50 -03:00
|
|
|
|
2014-07-29 07:58:23 -03:00
|
|
|
def _repr_info(self):
|
|
|
|
info = super()._repr_info()
|
2014-07-25 08:05:20 -03:00
|
|
|
if self._ov is not None:
|
|
|
|
state = 'pending' if self._ov.pending else 'completed'
|
2017-12-10 19:36:12 -04:00
|
|
|
info.insert(1, f'overlapped=<{state}, {self._ov.address:#x}>')
|
2014-07-29 07:58:23 -03:00
|
|
|
return info
|
2014-07-11 22:11:53 -03:00
|
|
|
|
2014-07-25 08:05:20 -03:00
|
|
|
def _cancel_overlapped(self):
|
|
|
|
if self._ov is None:
|
|
|
|
return
|
|
|
|
try:
|
|
|
|
self._ov.cancel()
|
|
|
|
except OSError as exc:
|
|
|
|
context = {
|
|
|
|
'message': 'Cancelling an overlapped future failed',
|
|
|
|
'exception': exc,
|
|
|
|
'future': self,
|
|
|
|
}
|
|
|
|
if self._source_traceback:
|
|
|
|
context['source_traceback'] = self._source_traceback
|
|
|
|
self._loop.call_exception_handler(context)
|
|
|
|
self._ov = None
|
|
|
|
|
2020-05-15 20:55:50 -03:00
|
|
|
def cancel(self, msg=None):
|
2014-07-25 08:05:20 -03:00
|
|
|
self._cancel_overlapped()
|
2020-05-15 20:55:50 -03:00
|
|
|
return super().cancel(msg=msg)
|
2013-10-17 17:40:50 -03:00
|
|
|
|
2014-07-25 08:05:20 -03:00
|
|
|
def set_exception(self, exception):
|
|
|
|
super().set_exception(exception)
|
|
|
|
self._cancel_overlapped()
|
|
|
|
|
2014-07-25 19:58:34 -03:00
|
|
|
def set_result(self, result):
|
|
|
|
super().set_result(result)
|
|
|
|
self._ov = None
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
class _BaseWaitHandleFuture(futures.Future):
|
2013-10-30 18:44:05 -03:00
|
|
|
"""Subclass of Future which represents a wait handle."""
|
|
|
|
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
def __init__(self, ov, handle, wait_handle, *, loop=None):
|
2013-10-30 18:44:05 -03:00
|
|
|
super().__init__(loop=loop)
|
2014-07-29 07:58:23 -03:00
|
|
|
if self._source_traceback:
|
|
|
|
del self._source_traceback[-1]
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
# Keep a reference to the Overlapped object to keep it alive until the
|
|
|
|
# wait is unregistered
|
2014-07-29 07:58:23 -03:00
|
|
|
self._ov = ov
|
2014-07-25 08:05:20 -03:00
|
|
|
self._handle = handle
|
2013-10-30 18:44:05 -03:00
|
|
|
self._wait_handle = wait_handle
|
|
|
|
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
# Should we call UnregisterWaitEx() if the wait completes
|
|
|
|
# or is cancelled?
|
|
|
|
self._registered = True
|
|
|
|
|
2014-07-25 08:05:20 -03:00
|
|
|
def _poll(self):
|
|
|
|
# non-blocking wait: use a timeout of 0 millisecond
|
|
|
|
return (_winapi.WaitForSingleObject(self._handle, 0) ==
|
|
|
|
_winapi.WAIT_OBJECT_0)
|
|
|
|
|
2014-07-29 07:58:23 -03:00
|
|
|
def _repr_info(self):
|
|
|
|
info = super()._repr_info()
|
2017-12-10 19:36:12 -04:00
|
|
|
info.append(f'handle={self._handle:#x}')
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
if self._handle is not None:
|
2014-07-29 07:58:23 -03:00
|
|
|
state = 'signaled' if self._poll() else 'waiting'
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
info.append(state)
|
|
|
|
if self._wait_handle is not None:
|
2017-12-10 19:36:12 -04:00
|
|
|
info.append(f'wait_handle={self._wait_handle:#x}')
|
2014-07-29 07:58:23 -03:00
|
|
|
return info
|
|
|
|
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
def _unregister_wait_cb(self, fut):
|
|
|
|
# The wait was unregistered: it's not safe to destroy the Overlapped
|
|
|
|
# object
|
|
|
|
self._ov = None
|
|
|
|
|
2014-07-29 07:58:23 -03:00
|
|
|
def _unregister_wait(self):
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
if not self._registered:
|
2014-07-24 19:54:53 -03:00
|
|
|
return
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
self._registered = False
|
|
|
|
|
2015-01-26 17:30:28 -04:00
|
|
|
wait_handle = self._wait_handle
|
|
|
|
self._wait_handle = None
|
2013-10-30 18:44:05 -03:00
|
|
|
try:
|
2015-01-26 17:30:28 -04:00
|
|
|
_overlapped.UnregisterWait(wait_handle)
|
2014-08-25 18:20:52 -03:00
|
|
|
except OSError as exc:
|
2015-01-26 17:30:28 -04:00
|
|
|
if exc.winerror != _overlapped.ERROR_IO_PENDING:
|
2014-08-25 18:20:52 -03:00
|
|
|
context = {
|
|
|
|
'message': 'Failed to unregister the wait handle',
|
|
|
|
'exception': exc,
|
|
|
|
'future': self,
|
|
|
|
}
|
|
|
|
if self._source_traceback:
|
|
|
|
context['source_traceback'] = self._source_traceback
|
|
|
|
self._loop.call_exception_handler(context)
|
2015-01-26 17:30:28 -04:00
|
|
|
return
|
|
|
|
# ERROR_IO_PENDING means that the unregister is pending
|
|
|
|
|
|
|
|
self._unregister_wait_cb(None)
|
2014-07-24 19:54:53 -03:00
|
|
|
|
2020-05-15 20:55:50 -03:00
|
|
|
def cancel(self, msg=None):
|
2014-07-29 07:58:23 -03:00
|
|
|
self._unregister_wait()
|
2020-05-15 20:55:50 -03:00
|
|
|
return super().cancel(msg=msg)
|
2014-07-29 07:58:23 -03:00
|
|
|
|
|
|
|
def set_exception(self, exception):
|
|
|
|
self._unregister_wait()
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
super().set_exception(exception)
|
2014-07-29 07:58:23 -03:00
|
|
|
|
|
|
|
def set_result(self, result):
|
|
|
|
self._unregister_wait()
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
super().set_result(result)
|
|
|
|
|
|
|
|
|
|
|
|
class _WaitCancelFuture(_BaseWaitHandleFuture):
|
|
|
|
"""Subclass of Future which represents a wait for the cancellation of a
|
|
|
|
_WaitHandleFuture using an event.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, ov, event, wait_handle, *, loop=None):
|
|
|
|
super().__init__(ov, event, wait_handle, loop=loop)
|
|
|
|
|
|
|
|
self._done_callback = None
|
|
|
|
|
2015-01-21 19:17:54 -04:00
|
|
|
def cancel(self):
|
|
|
|
raise RuntimeError("_WaitCancelFuture must not be cancelled")
|
|
|
|
|
2016-10-21 00:30:15 -03:00
|
|
|
def set_result(self, result):
|
|
|
|
super().set_result(result)
|
|
|
|
if self._done_callback is not None:
|
|
|
|
self._done_callback(self)
|
|
|
|
|
|
|
|
def set_exception(self, exception):
|
|
|
|
super().set_exception(exception)
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
if self._done_callback is not None:
|
|
|
|
self._done_callback(self)
|
|
|
|
|
|
|
|
|
|
|
|
class _WaitHandleFuture(_BaseWaitHandleFuture):
|
|
|
|
def __init__(self, ov, handle, wait_handle, proactor, *, loop=None):
|
|
|
|
super().__init__(ov, handle, wait_handle, loop=loop)
|
|
|
|
self._proactor = proactor
|
|
|
|
self._unregister_proactor = True
|
|
|
|
self._event = _overlapped.CreateEvent(None, True, False, None)
|
|
|
|
self._event_fut = None
|
|
|
|
|
|
|
|
def _unregister_wait_cb(self, fut):
|
|
|
|
if self._event is not None:
|
|
|
|
_winapi.CloseHandle(self._event)
|
|
|
|
self._event = None
|
|
|
|
self._event_fut = None
|
|
|
|
|
|
|
|
# If the wait was cancelled, the wait may never be signalled, so
|
|
|
|
# it's required to unregister it. Otherwise, IocpProactor.close() will
|
|
|
|
# wait forever for an event which will never come.
|
|
|
|
#
|
|
|
|
# If the IocpProactor already received the event, it's safe to call
|
|
|
|
# _unregister() because we kept a reference to the Overlapped object
|
2016-04-14 23:14:19 -03:00
|
|
|
# which is used as a unique key.
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
self._proactor._unregister(self._ov)
|
|
|
|
self._proactor = None
|
|
|
|
|
|
|
|
super()._unregister_wait_cb(fut)
|
|
|
|
|
|
|
|
def _unregister_wait(self):
|
|
|
|
if not self._registered:
|
|
|
|
return
|
|
|
|
self._registered = False
|
|
|
|
|
2015-01-26 17:30:28 -04:00
|
|
|
wait_handle = self._wait_handle
|
|
|
|
self._wait_handle = None
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
try:
|
2015-01-26 17:30:28 -04:00
|
|
|
_overlapped.UnregisterWaitEx(wait_handle, self._event)
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
except OSError as exc:
|
2015-01-26 17:30:28 -04:00
|
|
|
if exc.winerror != _overlapped.ERROR_IO_PENDING:
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
context = {
|
|
|
|
'message': 'Failed to unregister the wait handle',
|
|
|
|
'exception': exc,
|
|
|
|
'future': self,
|
|
|
|
}
|
|
|
|
if self._source_traceback:
|
|
|
|
context['source_traceback'] = self._source_traceback
|
|
|
|
self._loop.call_exception_handler(context)
|
2015-01-26 17:30:28 -04:00
|
|
|
return
|
|
|
|
# ERROR_IO_PENDING is not an error, the wait was unregistered
|
|
|
|
|
|
|
|
self._event_fut = self._proactor._wait_cancel(self._event,
|
|
|
|
self._unregister_wait_cb)
|
2013-10-30 18:44:05 -03:00
|
|
|
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
class PipeServer(object):
|
|
|
|
"""Class representing a pipe server.
|
|
|
|
|
|
|
|
This is much like a bound, listening socket.
|
|
|
|
"""
|
|
|
|
def __init__(self, address):
|
|
|
|
self._address = address
|
|
|
|
self._free_instances = weakref.WeakSet()
|
2014-08-25 18:20:52 -03:00
|
|
|
# initialize the pipe attribute before calling _server_pipe_handle()
|
|
|
|
# because this function can raise an exception and the destructor calls
|
|
|
|
# the close() method
|
|
|
|
self._pipe = None
|
|
|
|
self._accept_pipe_future = None
|
2013-10-17 17:40:50 -03:00
|
|
|
self._pipe = self._server_pipe_handle(True)
|
|
|
|
|
|
|
|
def _get_unconnected_pipe(self):
|
|
|
|
# Create new instance and return previous one. This ensures
|
|
|
|
# that (until the server is closed) there is always at least
|
|
|
|
# one pipe handle for address. Therefore if a client attempt
|
|
|
|
# to connect it will not fail with FileNotFoundError.
|
|
|
|
tmp, self._pipe = self._pipe, self._server_pipe_handle(False)
|
|
|
|
return tmp
|
|
|
|
|
|
|
|
def _server_pipe_handle(self, first):
|
|
|
|
# Return a wrapper for a new pipe handle.
|
2015-01-26 10:03:20 -04:00
|
|
|
if self.closed():
|
2013-10-17 17:40:50 -03:00
|
|
|
return None
|
|
|
|
flags = _winapi.PIPE_ACCESS_DUPLEX | _winapi.FILE_FLAG_OVERLAPPED
|
|
|
|
if first:
|
|
|
|
flags |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE
|
|
|
|
h = _winapi.CreateNamedPipe(
|
|
|
|
self._address, flags,
|
|
|
|
_winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE |
|
|
|
|
_winapi.PIPE_WAIT,
|
|
|
|
_winapi.PIPE_UNLIMITED_INSTANCES,
|
|
|
|
windows_utils.BUFSIZE, windows_utils.BUFSIZE,
|
|
|
|
_winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL)
|
|
|
|
pipe = windows_utils.PipeHandle(h)
|
|
|
|
self._free_instances.add(pipe)
|
|
|
|
return pipe
|
|
|
|
|
2015-01-26 10:03:20 -04:00
|
|
|
def closed(self):
|
|
|
|
return (self._address is None)
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
def close(self):
|
2014-08-25 18:20:52 -03:00
|
|
|
if self._accept_pipe_future is not None:
|
|
|
|
self._accept_pipe_future.cancel()
|
|
|
|
self._accept_pipe_future = None
|
2013-10-17 17:40:50 -03:00
|
|
|
# Close all instances which have not been connected to by a client.
|
|
|
|
if self._address is not None:
|
|
|
|
for pipe in self._free_instances:
|
|
|
|
pipe.close()
|
|
|
|
self._pipe = None
|
|
|
|
self._address = None
|
|
|
|
self._free_instances.clear()
|
|
|
|
|
|
|
|
__del__ = close
|
|
|
|
|
|
|
|
|
2013-11-04 19:50:46 -04:00
|
|
|
class _WindowsSelectorEventLoop(selector_events.BaseSelectorEventLoop):
|
2013-10-17 17:40:50 -03:00
|
|
|
"""Windows version of selector event loop."""
|
|
|
|
|
|
|
|
|
|
|
|
class ProactorEventLoop(proactor_events.BaseProactorEventLoop):
|
|
|
|
"""Windows version of proactor event loop using IOCP."""
|
|
|
|
|
|
|
|
def __init__(self, proactor=None):
|
|
|
|
if proactor is None:
|
|
|
|
proactor = IocpProactor()
|
|
|
|
super().__init__(proactor)
|
|
|
|
|
2023-10-13 11:12:32 -03:00
|
|
|
def _run_forever_setup(self):
|
|
|
|
assert self._self_reading_future is None
|
|
|
|
self.call_soon(self._loop_self_reading)
|
|
|
|
super()._run_forever_setup()
|
|
|
|
|
|
|
|
def _run_forever_cleanup(self):
|
|
|
|
super()._run_forever_cleanup()
|
|
|
|
if self._self_reading_future is not None:
|
|
|
|
ov = self._self_reading_future._ov
|
|
|
|
self._self_reading_future.cancel()
|
2024-03-20 11:33:28 -03:00
|
|
|
# self_reading_future always uses IOCP, so even though it's
|
|
|
|
# been cancelled, we need to make sure that the IOCP message
|
|
|
|
# is received so that the kernel is not holding on to the
|
|
|
|
# memory, possibly causing memory corruption later. Only
|
|
|
|
# unregister it if IO is complete in all respects. Otherwise
|
|
|
|
# we need another _poll() later to complete the IO.
|
|
|
|
if ov is not None and not ov.pending:
|
2023-10-13 11:12:32 -03:00
|
|
|
self._proactor._unregister(ov)
|
|
|
|
self._self_reading_future = None
|
2018-12-18 17:56:17 -04:00
|
|
|
|
2017-12-08 18:23:48 -04:00
|
|
|
async def create_pipe_connection(self, protocol_factory, address):
|
2013-10-17 17:40:50 -03:00
|
|
|
f = self._proactor.connect_pipe(address)
|
2017-12-08 18:23:48 -04:00
|
|
|
pipe = await f
|
2013-10-17 17:40:50 -03:00
|
|
|
protocol = protocol_factory()
|
|
|
|
trans = self._make_duplex_pipe_transport(pipe, protocol,
|
|
|
|
extra={'addr': address})
|
|
|
|
return trans, protocol
|
|
|
|
|
2017-12-08 18:23:48 -04:00
|
|
|
async def start_serving_pipe(self, protocol_factory, address):
|
2013-10-17 17:40:50 -03:00
|
|
|
server = PipeServer(address)
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2014-08-25 18:20:52 -03:00
|
|
|
def loop_accept_pipe(f=None):
|
2013-10-17 17:40:50 -03:00
|
|
|
pipe = None
|
|
|
|
try:
|
|
|
|
if f:
|
|
|
|
pipe = f.result()
|
|
|
|
server._free_instances.discard(pipe)
|
2015-01-26 10:03:20 -04:00
|
|
|
|
|
|
|
if server.closed():
|
|
|
|
# A client connected before the server was closed:
|
|
|
|
# drop the client (close the pipe) and exit
|
|
|
|
pipe.close()
|
|
|
|
return
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
protocol = protocol_factory()
|
|
|
|
self._make_duplex_pipe_transport(
|
|
|
|
pipe, protocol, extra={'addr': address})
|
2015-01-26 10:03:20 -04:00
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
pipe = server._get_unconnected_pipe()
|
|
|
|
if pipe is None:
|
|
|
|
return
|
2015-01-26 10:03:20 -04:00
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
f = self._proactor.accept_pipe(pipe)
|
2023-01-13 17:24:57 -04:00
|
|
|
except BrokenPipeError:
|
|
|
|
if pipe and pipe.fileno() != -1:
|
|
|
|
pipe.close()
|
|
|
|
self.call_soon(loop_accept_pipe)
|
2014-02-18 19:02:19 -04:00
|
|
|
except OSError as exc:
|
2013-10-17 17:40:50 -03:00
|
|
|
if pipe and pipe.fileno() != -1:
|
2014-02-18 19:02:19 -04:00
|
|
|
self.call_exception_handler({
|
|
|
|
'message': 'Pipe accept failed',
|
|
|
|
'exception': exc,
|
|
|
|
'pipe': pipe,
|
|
|
|
})
|
2013-10-17 17:40:50 -03:00
|
|
|
pipe.close()
|
2014-08-25 18:20:52 -03:00
|
|
|
elif self._debug:
|
|
|
|
logger.warning("Accept pipe failed on pipe %r",
|
|
|
|
pipe, exc_info=True)
|
2023-01-13 17:24:57 -04:00
|
|
|
self.call_soon(loop_accept_pipe)
|
2018-09-11 14:13:04 -03:00
|
|
|
except exceptions.CancelledError:
|
2013-10-17 17:40:50 -03:00
|
|
|
if pipe:
|
|
|
|
pipe.close()
|
|
|
|
else:
|
2014-08-25 18:20:52 -03:00
|
|
|
server._accept_pipe_future = f
|
|
|
|
f.add_done_callback(loop_accept_pipe)
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2014-08-25 18:20:52 -03:00
|
|
|
self.call_soon(loop_accept_pipe)
|
2013-10-17 17:40:50 -03:00
|
|
|
return [server]
|
|
|
|
|
2017-12-08 18:23:48 -04:00
|
|
|
async def _make_subprocess_transport(self, protocol, args, shell,
|
|
|
|
stdin, stdout, stderr, bufsize,
|
|
|
|
extra=None, **kwargs):
|
2016-05-16 16:38:39 -03:00
|
|
|
waiter = self.create_future()
|
2013-10-30 18:52:03 -03:00
|
|
|
transp = _WindowsSubprocessTransport(self, protocol, args, shell,
|
|
|
|
stdin, stdout, stderr, bufsize,
|
2015-01-29 19:05:19 -04:00
|
|
|
waiter=waiter, extra=extra,
|
|
|
|
**kwargs)
|
2015-01-15 09:24:22 -04:00
|
|
|
try:
|
2017-12-08 18:23:48 -04:00
|
|
|
await waiter
|
2019-05-27 09:45:12 -03:00
|
|
|
except (SystemExit, KeyboardInterrupt):
|
|
|
|
raise
|
|
|
|
except BaseException:
|
2015-01-15 09:24:22 -04:00
|
|
|
transp.close()
|
2017-12-08 18:23:48 -04:00
|
|
|
await transp._wait()
|
|
|
|
raise
|
2015-01-15 09:24:22 -04:00
|
|
|
|
2013-10-30 18:52:03 -03:00
|
|
|
return transp
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
|
|
|
|
class IocpProactor:
|
|
|
|
"""Proactor implementation using IOCP."""
|
|
|
|
|
2022-01-04 04:42:19 -04:00
|
|
|
def __init__(self, concurrency=INFINITE):
|
2013-10-17 17:40:50 -03:00
|
|
|
self._loop = None
|
|
|
|
self._results = []
|
|
|
|
self._iocp = _overlapped.CreateIoCompletionPort(
|
|
|
|
_overlapped.INVALID_HANDLE_VALUE, NULL, 0, concurrency)
|
|
|
|
self._cache = {}
|
|
|
|
self._registered = weakref.WeakSet()
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
self._unregistered = []
|
2013-10-17 17:40:50 -03:00
|
|
|
self._stopped_serving = weakref.WeakSet()
|
|
|
|
|
2019-01-10 06:23:26 -04:00
|
|
|
def _check_closed(self):
|
|
|
|
if self._iocp is None:
|
|
|
|
raise RuntimeError('IocpProactor is closed')
|
|
|
|
|
2014-07-24 19:54:53 -03:00
|
|
|
def __repr__(self):
|
2019-01-10 06:23:26 -04:00
|
|
|
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))
|
2014-07-24 19:54:53 -03:00
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
def set_loop(self, loop):
|
|
|
|
self._loop = loop
|
|
|
|
|
|
|
|
def select(self, timeout=None):
|
|
|
|
if not self._results:
|
|
|
|
self._poll(timeout)
|
|
|
|
tmp = self._results
|
|
|
|
self._results = []
|
2022-11-22 11:06:20 -04:00
|
|
|
try:
|
|
|
|
return tmp
|
|
|
|
finally:
|
|
|
|
# Needed to break cycles when an exception occurs.
|
|
|
|
tmp = None
|
2013-10-17 17:40:50 -03:00
|
|
|
|
2015-01-26 17:30:49 -04:00
|
|
|
def _result(self, value):
|
2016-05-16 16:38:39 -03:00
|
|
|
fut = self._loop.create_future()
|
2015-01-26 17:30:49 -04:00
|
|
|
fut.set_result(value)
|
|
|
|
return fut
|
|
|
|
|
2022-10-13 15:05:16 -03:00
|
|
|
@staticmethod
|
|
|
|
def finish_socket_func(trans, key, ov):
|
|
|
|
try:
|
|
|
|
return ov.getresult()
|
|
|
|
except OSError as exc:
|
|
|
|
if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED,
|
|
|
|
_overlapped.ERROR_OPERATION_ABORTED):
|
|
|
|
raise ConnectionResetError(*exc.args)
|
|
|
|
else:
|
|
|
|
raise
|
|
|
|
|
2024-03-23 12:39:35 -03:00
|
|
|
@classmethod
|
|
|
|
def _finish_recvfrom(cls, trans, key, ov, *, empty_result):
|
|
|
|
try:
|
|
|
|
return cls.finish_socket_func(trans, key, ov)
|
|
|
|
except OSError as exc:
|
|
|
|
# WSARecvFrom will report ERROR_PORT_UNREACHABLE when the same
|
|
|
|
# socket is used to send to an address that is not listening.
|
|
|
|
if exc.winerror == _overlapped.ERROR_PORT_UNREACHABLE:
|
|
|
|
return empty_result, None
|
|
|
|
else:
|
|
|
|
raise
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
def recv(self, conn, nbytes, flags=0):
|
|
|
|
self._register_with_iocp(conn)
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
2015-01-26 17:30:49 -04:00
|
|
|
try:
|
|
|
|
if isinstance(conn, socket.socket):
|
|
|
|
ov.WSARecv(conn.fileno(), nbytes, flags)
|
|
|
|
else:
|
|
|
|
ov.ReadFile(conn.fileno(), nbytes)
|
|
|
|
except BrokenPipeError:
|
|
|
|
return self._result(b'')
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2022-10-13 15:05:16 -03:00
|
|
|
return self._register(ov, conn, self.finish_socket_func)
|
2013-10-17 17:40:50 -03:00
|
|
|
|
2017-10-19 16:46:40 -03:00
|
|
|
def recv_into(self, conn, buf, flags=0):
|
|
|
|
self._register_with_iocp(conn)
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
|
|
|
try:
|
|
|
|
if isinstance(conn, socket.socket):
|
|
|
|
ov.WSARecvInto(conn.fileno(), buf, flags)
|
|
|
|
else:
|
|
|
|
ov.ReadFileInto(conn.fileno(), buf)
|
|
|
|
except BrokenPipeError:
|
2020-08-03 21:40:10 -03:00
|
|
|
return self._result(0)
|
2017-10-19 16:46:40 -03:00
|
|
|
|
2022-10-13 15:05:16 -03:00
|
|
|
return self._register(ov, conn, self.finish_socket_func)
|
2017-10-19 16:46:40 -03:00
|
|
|
|
2019-05-28 06:52:15 -03:00
|
|
|
def recvfrom(self, conn, nbytes, flags=0):
|
|
|
|
self._register_with_iocp(conn)
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
|
|
|
try:
|
|
|
|
ov.WSARecvFrom(conn.fileno(), nbytes, flags)
|
|
|
|
except BrokenPipeError:
|
|
|
|
return self._result((b'', None))
|
|
|
|
|
2024-03-23 12:39:35 -03:00
|
|
|
return self._register(ov, conn, partial(self._finish_recvfrom,
|
|
|
|
empty_result=b''))
|
2019-05-28 06:52:15 -03:00
|
|
|
|
2022-03-13 13:42:29 -03:00
|
|
|
def recvfrom_into(self, conn, buf, flags=0):
|
|
|
|
self._register_with_iocp(conn)
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
|
|
|
try:
|
|
|
|
ov.WSARecvFromInto(conn.fileno(), buf, flags)
|
|
|
|
except BrokenPipeError:
|
|
|
|
return self._result((0, None))
|
|
|
|
|
2024-03-23 12:39:35 -03:00
|
|
|
return self._register(ov, conn, partial(self._finish_recvfrom,
|
|
|
|
empty_result=0))
|
2022-03-13 13:42:29 -03:00
|
|
|
|
2019-05-28 06:52:15 -03:00
|
|
|
def sendto(self, conn, buf, flags=0, addr=None):
|
|
|
|
self._register_with_iocp(conn)
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
|
|
|
|
|
|
|
ov.WSASendTo(conn.fileno(), buf, flags, addr)
|
|
|
|
|
2022-10-13 15:05:16 -03:00
|
|
|
return self._register(ov, conn, self.finish_socket_func)
|
2019-05-28 06:52:15 -03:00
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
def send(self, conn, buf, flags=0):
|
|
|
|
self._register_with_iocp(conn)
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
|
|
|
if isinstance(conn, socket.socket):
|
|
|
|
ov.WSASend(conn.fileno(), buf, flags)
|
|
|
|
else:
|
|
|
|
ov.WriteFile(conn.fileno(), buf)
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2022-10-13 15:05:16 -03:00
|
|
|
return self._register(ov, conn, self.finish_socket_func)
|
2013-10-17 17:40:50 -03:00
|
|
|
|
|
|
|
def accept(self, listener):
|
|
|
|
self._register_with_iocp(listener)
|
|
|
|
conn = self._get_accept_socket(listener.family)
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
|
|
|
ov.AcceptEx(listener.fileno(), conn.fileno())
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
def finish_accept(trans, key, ov):
|
|
|
|
ov.getresult()
|
|
|
|
# Use SO_UPDATE_ACCEPT_CONTEXT so getsockname() etc work.
|
|
|
|
buf = struct.pack('@P', listener.fileno())
|
|
|
|
conn.setsockopt(socket.SOL_SOCKET,
|
|
|
|
_overlapped.SO_UPDATE_ACCEPT_CONTEXT, buf)
|
|
|
|
conn.settimeout(listener.gettimeout())
|
|
|
|
return conn, conn.getpeername()
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2017-12-08 18:23:48 -04:00
|
|
|
async def accept_coro(future, conn):
|
2014-01-10 19:03:21 -04:00
|
|
|
# Coroutine closing the accept socket if the future is cancelled
|
|
|
|
try:
|
2017-12-08 18:23:48 -04:00
|
|
|
await future
|
2018-09-11 14:13:04 -03:00
|
|
|
except exceptions.CancelledError:
|
2014-01-10 19:03:21 -04:00
|
|
|
conn.close()
|
|
|
|
raise
|
|
|
|
|
|
|
|
future = self._register(ov, listener, finish_accept)
|
|
|
|
coro = accept_coro(future, conn)
|
2015-05-11 15:48:38 -03:00
|
|
|
tasks.ensure_future(coro, loop=self._loop)
|
2014-01-10 19:03:21 -04:00
|
|
|
return future
|
2013-10-17 17:40:50 -03:00
|
|
|
|
|
|
|
def connect(self, conn, address):
|
2019-05-28 06:52:15 -03:00
|
|
|
if conn.type == socket.SOCK_DGRAM:
|
|
|
|
# WSAConnect will complete immediately for UDP sockets so we don't
|
|
|
|
# need to register any IOCP operation
|
|
|
|
_overlapped.WSAConnect(conn.fileno(), address)
|
|
|
|
fut = self._loop.create_future()
|
|
|
|
fut.set_result(None)
|
|
|
|
return fut
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
self._register_with_iocp(conn)
|
|
|
|
# The socket needs to be locally bound before we call ConnectEx().
|
|
|
|
try:
|
|
|
|
_overlapped.BindLocal(conn.fileno(), conn.family)
|
|
|
|
except OSError as e:
|
|
|
|
if e.winerror != errno.WSAEINVAL:
|
|
|
|
raise
|
|
|
|
# Probably already locally bound; check using getsockname().
|
|
|
|
if conn.getsockname()[1] == 0:
|
|
|
|
raise
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
|
|
|
ov.ConnectEx(conn.fileno(), address)
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
def finish_connect(trans, key, ov):
|
|
|
|
ov.getresult()
|
|
|
|
# Use SO_UPDATE_CONNECT_CONTEXT so getsockname() etc work.
|
|
|
|
conn.setsockopt(socket.SOL_SOCKET,
|
|
|
|
_overlapped.SO_UPDATE_CONNECT_CONTEXT, 0)
|
|
|
|
return conn
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
return self._register(ov, conn, finish_connect)
|
|
|
|
|
2018-02-25 12:32:14 -04:00
|
|
|
def sendfile(self, sock, file, offset, count):
|
|
|
|
self._register_with_iocp(sock)
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
|
|
|
offset_low = offset & 0xffff_ffff
|
|
|
|
offset_high = (offset >> 32) & 0xffff_ffff
|
|
|
|
ov.TransmitFile(sock.fileno(),
|
|
|
|
msvcrt.get_osfhandle(file.fileno()),
|
|
|
|
offset_low, offset_high,
|
|
|
|
count, 0, 0)
|
|
|
|
|
2022-10-13 15:05:16 -03:00
|
|
|
return self._register(ov, sock, self.finish_socket_func)
|
2018-02-25 12:32:14 -04:00
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
def accept_pipe(self, pipe):
|
|
|
|
self._register_with_iocp(pipe)
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
2015-01-22 18:50:03 -04:00
|
|
|
connected = ov.ConnectNamedPipe(pipe.fileno())
|
|
|
|
|
|
|
|
if connected:
|
|
|
|
# ConnectNamePipe() failed with ERROR_PIPE_CONNECTED which means
|
|
|
|
# that the pipe is connected. There is no need to wait for the
|
|
|
|
# completion of the connection.
|
2015-01-26 17:30:49 -04:00
|
|
|
return self._result(pipe)
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2014-02-26 12:35:30 -04:00
|
|
|
def finish_accept_pipe(trans, key, ov):
|
2013-10-17 17:40:50 -03:00
|
|
|
ov.getresult()
|
|
|
|
return pipe
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2015-01-22 18:50:03 -04:00
|
|
|
return self._register(ov, pipe, finish_accept_pipe)
|
2013-10-17 17:40:50 -03:00
|
|
|
|
2017-12-08 18:23:48 -04:00
|
|
|
async def connect_pipe(self, address):
|
2015-01-26 10:04:03 -04:00
|
|
|
delay = CONNECT_PIPE_INIT_DELAY
|
|
|
|
while True:
|
2017-12-10 19:36:12 -04:00
|
|
|
# Unfortunately there is no way to do an overlapped connect to
|
|
|
|
# a pipe. Call CreateFile() in a loop until it doesn't fail with
|
|
|
|
# ERROR_PIPE_BUSY.
|
2015-01-26 10:04:03 -04:00
|
|
|
try:
|
|
|
|
handle = _overlapped.ConnectPipe(address)
|
|
|
|
break
|
|
|
|
except OSError as exc:
|
|
|
|
if exc.winerror != _overlapped.ERROR_PIPE_BUSY:
|
|
|
|
raise
|
|
|
|
|
|
|
|
# ConnectPipe() failed with ERROR_PIPE_BUSY: retry later
|
|
|
|
delay = min(delay * 2, CONNECT_PIPE_MAX_DELAY)
|
2019-05-27 16:56:22 -03:00
|
|
|
await tasks.sleep(delay)
|
2015-01-26 10:04:03 -04:00
|
|
|
|
|
|
|
return windows_utils.PipeHandle(handle)
|
2013-10-17 17:40:50 -03:00
|
|
|
|
2013-10-30 18:44:05 -03:00
|
|
|
def wait_for_handle(self, handle, timeout=None):
|
2014-12-19 12:10:44 -04:00
|
|
|
"""Wait for a handle.
|
|
|
|
|
|
|
|
Return a Future object. The result of the future is True if the wait
|
|
|
|
completed, or False if the wait did not complete (on timeout).
|
|
|
|
"""
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
return self._wait_for_handle(handle, timeout, False)
|
|
|
|
|
|
|
|
def _wait_cancel(self, event, done_callback):
|
|
|
|
fut = self._wait_for_handle(event, None, True)
|
|
|
|
# add_done_callback() cannot be used because the wait may only complete
|
|
|
|
# in IocpProactor.close(), while the event loop is not running.
|
|
|
|
fut._done_callback = done_callback
|
|
|
|
return fut
|
|
|
|
|
|
|
|
def _wait_for_handle(self, handle, timeout, _is_cancel):
|
2019-01-10 06:23:26 -04:00
|
|
|
self._check_closed()
|
|
|
|
|
2013-10-30 18:44:05 -03:00
|
|
|
if timeout is None:
|
|
|
|
ms = _winapi.INFINITE
|
|
|
|
else:
|
2014-01-31 11:25:24 -04:00
|
|
|
# RegisterWaitForSingleObject() has a resolution of 1 millisecond,
|
|
|
|
# round away from zero to wait *at least* timeout seconds.
|
|
|
|
ms = math.ceil(timeout * 1e3)
|
2013-10-30 18:44:05 -03:00
|
|
|
|
|
|
|
# We only create ov so we can use ov.address as a key for the cache.
|
|
|
|
ov = _overlapped.Overlapped(NULL)
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
wait_handle = _overlapped.RegisterWaitWithQueue(
|
2013-10-30 18:44:05 -03:00
|
|
|
handle, self._iocp, ov.address, ms)
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
if _is_cancel:
|
|
|
|
f = _WaitCancelFuture(ov, handle, wait_handle, loop=self._loop)
|
|
|
|
else:
|
|
|
|
f = _WaitHandleFuture(ov, handle, wait_handle, self,
|
|
|
|
loop=self._loop)
|
2014-07-29 07:58:23 -03:00
|
|
|
if f._source_traceback:
|
|
|
|
del f._source_traceback[-1]
|
2013-10-30 18:44:05 -03:00
|
|
|
|
2014-02-26 12:35:30 -04:00
|
|
|
def finish_wait_for_handle(trans, key, ov):
|
2013-11-24 13:50:40 -04:00
|
|
|
# Note that this second wait means that we should only use
|
|
|
|
# this with handles types where a successful wait has no
|
|
|
|
# effect. So events or processes are all right, but locks
|
|
|
|
# or semaphores are not. Also note if the handle is
|
|
|
|
# signalled and then quickly reset, then we may return
|
|
|
|
# False even though we have not timed out.
|
2014-07-29 07:58:23 -03:00
|
|
|
return f._poll()
|
|
|
|
|
|
|
|
self._cache[ov.address] = (f, ov, 0, finish_wait_for_handle)
|
2013-10-30 18:44:05 -03:00
|
|
|
return f
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
def _register_with_iocp(self, obj):
|
|
|
|
# To get notifications of finished ops on this objects sent to the
|
|
|
|
# completion port, were must register the handle.
|
|
|
|
if obj not in self._registered:
|
|
|
|
self._registered.add(obj)
|
|
|
|
_overlapped.CreateIoCompletionPort(obj.fileno(), self._iocp, 0, 0)
|
|
|
|
# XXX We could also use SetFileCompletionNotificationModes()
|
|
|
|
# to avoid sending notifications to completion port of ops
|
|
|
|
# that succeed immediately.
|
|
|
|
|
2015-01-22 18:50:03 -04:00
|
|
|
def _register(self, ov, obj, callback):
|
2019-01-10 06:23:26 -04:00
|
|
|
self._check_closed()
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
# 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().
|
|
|
|
f = _OverlappedFuture(ov, loop=self._loop)
|
2014-07-29 07:58:23 -03:00
|
|
|
if f._source_traceback:
|
|
|
|
del f._source_traceback[-1]
|
2015-01-22 18:50:03 -04:00
|
|
|
if not ov.pending:
|
2013-10-17 17:40:50 -03:00
|
|
|
# The operation has completed, so no need to postpone the
|
|
|
|
# work. We cannot take this short cut if we need the
|
|
|
|
# NumberOfBytes, CompletionKey values returned by
|
|
|
|
# PostQueuedCompletionStatus().
|
|
|
|
try:
|
|
|
|
value = callback(None, None, ov)
|
|
|
|
except OSError as e:
|
|
|
|
f.set_exception(e)
|
|
|
|
else:
|
|
|
|
f.set_result(value)
|
2014-07-27 19:18:43 -03:00
|
|
|
# Even if GetOverlappedResult() was called, we have to wait for the
|
|
|
|
# notification of the completion in GetQueuedCompletionStatus().
|
|
|
|
# Register the overlapped operation to keep a reference to the
|
|
|
|
# OVERLAPPED object, otherwise the memory is freed and Windows may
|
|
|
|
# read uninitialized memory.
|
2015-01-22 18:50:03 -04:00
|
|
|
|
|
|
|
# Register the overlapped operation for later. Note that
|
|
|
|
# we only store obj to prevent it from being garbage
|
|
|
|
# collected too early.
|
|
|
|
self._cache[ov.address] = (f, ov, obj, callback)
|
2013-10-17 17:40:50 -03:00
|
|
|
return f
|
|
|
|
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
def _unregister(self, ov):
|
|
|
|
"""Unregister an overlapped object.
|
|
|
|
|
|
|
|
Call this method when its future has been cancelled. The event can
|
|
|
|
already be signalled (pending in the proactor event queue). It is also
|
|
|
|
safe if the event is never signalled (because it was cancelled).
|
|
|
|
"""
|
2019-01-10 06:23:26 -04:00
|
|
|
self._check_closed()
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
self._unregistered.append(ov)
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
def _get_accept_socket(self, family):
|
|
|
|
s = socket.socket(family)
|
|
|
|
s.settimeout(0)
|
|
|
|
return s
|
|
|
|
|
|
|
|
def _poll(self, timeout=None):
|
|
|
|
if timeout is None:
|
|
|
|
ms = INFINITE
|
|
|
|
elif timeout < 0:
|
|
|
|
raise ValueError("negative timeout")
|
|
|
|
else:
|
2014-01-31 11:25:24 -04:00
|
|
|
# GetQueuedCompletionStatus() has a resolution of 1 millisecond,
|
|
|
|
# round away from zero to wait *at least* timeout seconds.
|
|
|
|
ms = math.ceil(timeout * 1e3)
|
2013-10-17 17:40:50 -03:00
|
|
|
if ms >= INFINITE:
|
|
|
|
raise ValueError("timeout too big")
|
2014-07-29 07:58:23 -03:00
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
while True:
|
|
|
|
status = _overlapped.GetQueuedCompletionStatus(self._iocp, ms)
|
|
|
|
if status is None:
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
break
|
2014-07-29 07:58:23 -03:00
|
|
|
ms = 0
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
err, transferred, key, address = status
|
|
|
|
try:
|
|
|
|
f, ov, obj, callback = self._cache.pop(address)
|
|
|
|
except KeyError:
|
2014-07-27 19:18:43 -03:00
|
|
|
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)),
|
|
|
|
})
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
# 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
|
2014-07-25 19:58:34 -03:00
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
if obj in self._stopped_serving:
|
|
|
|
f.cancel()
|
2014-07-27 19:18:43 -03:00
|
|
|
# Don't call the callback if _register() already read the result or
|
|
|
|
# if the overlapped has been cancelled
|
|
|
|
elif not f.done():
|
2013-10-17 17:40:50 -03:00
|
|
|
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)
|
2022-11-22 11:06:20 -04:00
|
|
|
finally:
|
|
|
|
f = None
|
2013-10-17 17:40:50 -03:00
|
|
|
|
2017-12-13 11:50:16 -04:00
|
|
|
# Remove unregistered futures
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 18:39:51 -04:00
|
|
|
for ov in self._unregistered:
|
|
|
|
self._cache.pop(ov.address, None)
|
|
|
|
self._unregistered.clear()
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
def _stop_serving(self, obj):
|
|
|
|
# obj is a socket or pipe handle. It will be closed in
|
|
|
|
# BaseProactorEventLoop._stop_serving() which will make any
|
|
|
|
# pending operations fail quickly.
|
|
|
|
self._stopped_serving.add(obj)
|
|
|
|
|
|
|
|
def close(self):
|
2019-01-10 06:23:26 -04:00
|
|
|
if self._iocp is None:
|
|
|
|
# already closed
|
|
|
|
return
|
|
|
|
|
2013-10-17 17:40:50 -03:00
|
|
|
# Cancel remaining registered operations.
|
2022-01-11 06:51:34 -04:00
|
|
|
for fut, ov, obj, callback in list(self._cache.values()):
|
2015-01-26 06:02:59 -04:00
|
|
|
if fut.cancelled():
|
2015-01-22 17:47:13 -04:00
|
|
|
# Nothing to do with cancelled futures
|
|
|
|
pass
|
2015-01-21 19:17:54 -04:00
|
|
|
elif isinstance(fut, _WaitCancelFuture):
|
|
|
|
# _WaitCancelFuture must not be cancelled
|
|
|
|
pass
|
2013-10-17 17:40:50 -03:00
|
|
|
else:
|
|
|
|
try:
|
2014-07-24 19:54:53 -03:00
|
|
|
fut.cancel()
|
|
|
|
except OSError as exc:
|
|
|
|
if self._loop is not None:
|
|
|
|
context = {
|
|
|
|
'message': 'Cancelling a future failed',
|
|
|
|
'exception': exc,
|
|
|
|
'future': fut,
|
|
|
|
}
|
|
|
|
if fut._source_traceback:
|
|
|
|
context['source_traceback'] = fut._source_traceback
|
|
|
|
self._loop.call_exception_handler(context)
|
2013-10-17 17:40:50 -03:00
|
|
|
|
2019-01-15 06:48:00 -04:00
|
|
|
# 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
|
2013-10-17 17:40:50 -03:00
|
|
|
while self._cache:
|
2019-01-15 06:48:00 -04:00
|
|
|
if next_msg <= time.monotonic():
|
2019-01-15 07:13:48 -04:00
|
|
|
logger.debug('%r is running after closing for %.1f seconds',
|
|
|
|
self, time.monotonic() - start_time)
|
2019-01-15 06:48:00 -04:00
|
|
|
next_msg = time.monotonic() + msg_update
|
|
|
|
|
|
|
|
# handle a few events, or timeout
|
|
|
|
self._poll(msg_update)
|
2013-10-17 17:40:50 -03:00
|
|
|
|
|
|
|
self._results = []
|
2019-01-10 06:23:26 -04:00
|
|
|
|
|
|
|
_winapi.CloseHandle(self._iocp)
|
|
|
|
self._iocp = None
|
2013-10-30 18:52:03 -03:00
|
|
|
|
2014-07-24 19:54:53 -03:00
|
|
|
def __del__(self):
|
|
|
|
self.close()
|
|
|
|
|
2013-10-30 18:52:03 -03:00
|
|
|
|
|
|
|
class _WindowsSubprocessTransport(base_subprocess.BaseSubprocessTransport):
|
|
|
|
|
|
|
|
def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs):
|
|
|
|
self._proc = windows_utils.Popen(
|
|
|
|
args, shell=shell, stdin=stdin, stdout=stdout, stderr=stderr,
|
|
|
|
bufsize=bufsize, **kwargs)
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2013-10-30 18:52:03 -03:00
|
|
|
def callback(f):
|
|
|
|
returncode = self._proc.poll()
|
|
|
|
self._process_exited(returncode)
|
2013-11-01 18:20:55 -03:00
|
|
|
|
2013-10-30 18:52:03 -03:00
|
|
|
f = self._loop._proactor.wait_for_handle(int(self._proc._handle))
|
|
|
|
f.add_done_callback(callback)
|
2013-11-04 19:50:46 -04:00
|
|
|
|
|
|
|
|
|
|
|
SelectorEventLoop = _WindowsSelectorEventLoop
|
|
|
|
|
|
|
|
|
2018-06-07 21:44:57 -03:00
|
|
|
class WindowsSelectorEventLoopPolicy(events.BaseDefaultEventLoopPolicy):
|
2013-11-04 19:50:46 -04:00
|
|
|
_loop_factory = SelectorEventLoop
|
|
|
|
|
|
|
|
|
2018-06-07 21:44:57 -03:00
|
|
|
class WindowsProactorEventLoopPolicy(events.BaseDefaultEventLoopPolicy):
|
|
|
|
_loop_factory = ProactorEventLoop
|
|
|
|
|
|
|
|
|
2018-09-25 12:27:08 -03:00
|
|
|
DefaultEventLoopPolicy = WindowsProactorEventLoopPolicy
|
2023-10-12 11:13:57 -03:00
|
|
|
EventLoop = ProactorEventLoop
|