diff -r 85258e08b69b Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py Mon Jan 05 01:05:36 2015 -0800 +++ b/Lib/asyncio/base_subprocess.py Tue Jan 06 00:58:38 2015 +0100 @@ -96,32 +96,59 @@ class BaseSubprocessTransport(transports def kill(self): self._proc.kill() + def _kill_wait(self): + # Function called when an exception is raised during the creation of a + # subprocess: close pipes, kill the process, and read the process exit + # status. + if self._loop.get_debug(): + logger.info('Exception during subprocess creation, ' + 'kill the subprocess: %r', + self, + exc_info=True) + + proc = self._proc + if proc.stdout: + proc.stdout.close() + if proc.stderr: + proc.stderr.close() + if proc.stdin: + proc.stdin.close() + try: + proc.kill() + except ProcessLookupError: + pass + proc.wait() + @coroutine def _post_init(self): - proc = self._proc - loop = self._loop - if proc.stdin is not None: - _, pipe = yield from loop.connect_write_pipe( - lambda: WriteSubprocessPipeProto(self, 0), - proc.stdin) - self._pipes[0] = pipe - if proc.stdout is not None: - _, pipe = yield from loop.connect_read_pipe( - lambda: ReadSubprocessPipeProto(self, 1), - proc.stdout) - self._pipes[1] = pipe - if proc.stderr is not None: - _, pipe = yield from loop.connect_read_pipe( - lambda: ReadSubprocessPipeProto(self, 2), - proc.stderr) - self._pipes[2] = pipe + try: + proc = self._proc + loop = self._loop + if proc.stdin is not None: + _, pipe = yield from loop.connect_write_pipe( + lambda: WriteSubprocessPipeProto(self, 0), + proc.stdin) + self._pipes[0] = pipe + if proc.stdout is not None: + _, pipe = yield from loop.connect_read_pipe( + lambda: ReadSubprocessPipeProto(self, 1), + proc.stdout) + self._pipes[1] = pipe + if proc.stderr is not None: + _, pipe = yield from loop.connect_read_pipe( + lambda: ReadSubprocessPipeProto(self, 2), + proc.stderr) + self._pipes[2] = pipe - assert self._pending_calls is not None + assert self._pending_calls is not None - self._loop.call_soon(self._protocol.connection_made, self) - for callback, data in self._pending_calls: - self._loop.call_soon(callback, *data) - self._pending_calls = None + self._loop.call_soon(self._protocol.connection_made, self) + for callback, data in self._pending_calls: + self._loop.call_soon(callback, *data) + self._pending_calls = None + except: + self._kill_wait() + raise def _call(self, cb, *data): if self._pending_calls is not None: diff -r 85258e08b69b Lib/asyncio/subprocess.py --- a/Lib/asyncio/subprocess.py Mon Jan 05 01:05:36 2015 -0800 +++ b/Lib/asyncio/subprocess.py Tue Jan 06 00:58:38 2015 +0100 @@ -60,7 +60,9 @@ class SubprocessStreamProtocol(streams.F protocol=self, reader=None, loop=self._loop) - self.waiter.set_result(None) + + if not self.waiter.cancelled(): + self.waiter.set_result(None) def pipe_data_received(self, fd, data): if fd == 1: @@ -215,7 +217,11 @@ def create_subprocess_shell(cmd, stdin=N protocol_factory, cmd, stdin=stdin, stdout=stdout, stderr=stderr, **kwds) - yield from protocol.waiter + try: + yield from protocol.waiter + except: + transport._kill_wait() + raise return Process(transport, protocol, loop) @coroutine @@ -231,5 +237,9 @@ def create_subprocess_exec(program, *arg program, *args, stdin=stdin, stdout=stdout, stderr=stderr, **kwds) - yield from protocol.waiter + try: + yield from protocol.waiter + except: + transport._kill_wait() + raise return Process(transport, protocol, loop) diff -r 85258e08b69b Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py Mon Jan 05 01:05:36 2015 -0800 +++ b/Lib/test/test_asyncio/test_subprocess.py Tue Jan 06 00:58:38 2015 +0100 @@ -223,6 +223,36 @@ class SubprocessMixin: self.assertEqual(output.rstrip(), b'3') self.assertEqual(exitcode, 0) + def test_cancel_make_subprocess_transport_exec(self): + @asyncio.coroutine + def cancel_make_transport(): + coro = asyncio.create_subprocess_exec(*PROGRAM_BLOCKED, + loop=self.loop) + task = self.loop.create_task(coro) + + self.loop.call_soon(task.cancel) + try: + yield from task + except asyncio.CancelledError: + pass + + self.loop.run_until_complete(cancel_make_transport()) + + def test_cancel_post_init(self): + @asyncio.coroutine + def cancel_make_transport(): + coro = self.loop.subprocess_exec(asyncio.SubprocessProtocol, + *PROGRAM_BLOCKED) + task = self.loop.create_task(coro) + + self.loop.call_soon(task.cancel) + try: + yield from task + except asyncio.CancelledError: + pass + + self.loop.run_until_complete(cancel_make_transport()) + if sys.platform != 'win32': # Unix