From 5570ba2a0975c69dab2865345b70485755d93866 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 22 Jan 2015 23:35:14 +0100 Subject: Tulip issue #204: Fix IocpProactor.accept_pipe() Overlapped.ConnectNamedPipe() now returns a boolean: True if the pipe is connected (if ConnectNamedPipe() failed with ERROR_PIPE_CONNECTED), False if the connection is in progress. This change removes multiple hacks in IocpProactor. --- asyncio/windows_events.py | 41 +++++++++++++++++------------------------ overlapped.c | 4 ++-- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/asyncio/windows_events.py b/asyncio/windows_events.py index 7d0dbe9..42c5f6e 100644 --- a/asyncio/windows_events.py +++ b/asyncio/windows_events.py @@ -490,16 +490,21 @@ class IocpProactor: def accept_pipe(self, pipe): self._register_with_iocp(pipe) ov = _overlapped.Overlapped(NULL) - ov.ConnectNamedPipe(pipe.fileno()) + 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. + f = futures.Future(loop=self._loop) + f.set_result(pipe) + return f def finish_accept_pipe(trans, key, ov): ov.getresult() return pipe - # FIXME: Tulip issue 196: why do we need register=False? - # See also the comment in the _register() method - return self._register(ov, pipe, finish_accept_pipe, - register=False) + return self._register(ov, pipe, finish_accept_pipe) def _connect_pipe(self, fut, address, delay): # Unfortunately there is no way to do an overlapped connect to a pipe. @@ -581,15 +586,14 @@ class IocpProactor: # to avoid sending notifications to completion port of ops # that succeed immediately. - def _register(self, ov, obj, callback, - wait_for_post=False, register=True): + def _register(self, ov, obj, callback): # 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) if f._source_traceback: del f._source_traceback[-1] - if not ov.pending and not wait_for_post: + if not ov.pending: # 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 @@ -605,18 +609,11 @@ class IocpProactor: # Register the overlapped operation to keep a reference to the # OVERLAPPED object, otherwise the memory is freed and Windows may # read uninitialized memory. - # - # For an unknown reason, ConnectNamedPipe() behaves differently: - # the completion is not notified by GetOverlappedResult() if we - # already called GetOverlappedResult(). For this specific case, we - # don't expect notification (register is set to False). - else: - register = True - if register: - # 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) + + # 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) return f def _unregister(self, ov): @@ -708,10 +705,6 @@ class IocpProactor: elif isinstance(fut, _WaitCancelFuture): # _WaitCancelFuture must not be cancelled pass - elif fut.done(): - # FIXME: Tulip issue 196: remove this case, it should not - # happen - del self._cache[address] else: try: fut.cancel() diff --git a/overlapped.c b/overlapped.c index 8fe2e24..4661152 100644 --- a/overlapped.c +++ b/overlapped.c @@ -1117,10 +1117,10 @@ Overlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *args) switch (err) { case ERROR_PIPE_CONNECTED: mark_as_completed(&self->overlapped); - Py_RETURN_NONE; + Py_RETURN_TRUE; case ERROR_SUCCESS: case ERROR_IO_PENDING: - Py_RETURN_NONE; + Py_RETURN_FALSE; default: self->type = TYPE_NOT_STARTED; return SetFromWindowsErr(err); -- cgit v1.2.1