mirror of
https://github.com/python/cpython.git
synced 2025-10-10 00:43:41 +00:00
asyncio: BaseSubprocessTransport.close() doesn't try to kill the process if it
already finished
This commit is contained in:
parent
832dd5f0d6
commit
8e36812e27
2 changed files with 61 additions and 1 deletions
|
@ -93,7 +93,12 @@ class BaseSubprocessTransport(transports.SubprocessTransport):
|
||||||
continue
|
continue
|
||||||
proto.pipe.close()
|
proto.pipe.close()
|
||||||
|
|
||||||
if self._proc is not None and self._returncode is None:
|
if (self._proc is not None
|
||||||
|
# the child process finished?
|
||||||
|
and self._returncode is None
|
||||||
|
# the child process finished but the transport was not notified yet?
|
||||||
|
and self._proc.poll() is None
|
||||||
|
):
|
||||||
if self._loop.get_debug():
|
if self._loop.get_debug():
|
||||||
logger.warning('Close running child process: kill %r', self)
|
logger.warning('Close running child process: kill %r', self)
|
||||||
|
|
||||||
|
|
|
@ -349,6 +349,61 @@ class SubprocessMixin:
|
||||||
self.loop.run_until_complete(cancel_make_transport())
|
self.loop.run_until_complete(cancel_make_transport())
|
||||||
test_utils.run_briefly(self.loop)
|
test_utils.run_briefly(self.loop)
|
||||||
|
|
||||||
|
def test_close_kill_running(self):
|
||||||
|
@asyncio.coroutine
|
||||||
|
def kill_running():
|
||||||
|
create = self.loop.subprocess_exec(asyncio.SubprocessProtocol,
|
||||||
|
*PROGRAM_BLOCKED)
|
||||||
|
transport, protocol = yield from create
|
||||||
|
proc = transport.get_extra_info('subprocess')
|
||||||
|
proc.kill = mock.Mock()
|
||||||
|
returncode = transport.get_returncode()
|
||||||
|
transport.close()
|
||||||
|
return (returncode, proc.kill.called)
|
||||||
|
|
||||||
|
# Ignore "Close running child process: kill ..." log
|
||||||
|
with test_utils.disable_logger():
|
||||||
|
returncode, killed = self.loop.run_until_complete(kill_running())
|
||||||
|
self.assertIsNone(returncode)
|
||||||
|
|
||||||
|
# transport.close() must kill the process if it is still running
|
||||||
|
self.assertTrue(killed)
|
||||||
|
test_utils.run_briefly(self.loop)
|
||||||
|
|
||||||
|
def test_close_dont_kill_finished(self):
|
||||||
|
@asyncio.coroutine
|
||||||
|
def kill_running():
|
||||||
|
create = self.loop.subprocess_exec(asyncio.SubprocessProtocol,
|
||||||
|
*PROGRAM_BLOCKED)
|
||||||
|
transport, protocol = yield from create
|
||||||
|
proc = transport.get_extra_info('subprocess')
|
||||||
|
|
||||||
|
# kill the process (but asyncio is not notified immediatly)
|
||||||
|
proc.kill()
|
||||||
|
proc.wait()
|
||||||
|
|
||||||
|
proc.kill = mock.Mock()
|
||||||
|
proc_returncode = proc.poll()
|
||||||
|
transport_returncode = transport.get_returncode()
|
||||||
|
transport.close()
|
||||||
|
return (proc_returncode, transport_returncode, proc.kill.called)
|
||||||
|
|
||||||
|
# Ignore "Unknown child process pid ..." log of SafeChildWatcher,
|
||||||
|
# emitted because the test already consumes the exit status:
|
||||||
|
# proc.wait()
|
||||||
|
with test_utils.disable_logger():
|
||||||
|
result = self.loop.run_until_complete(kill_running())
|
||||||
|
test_utils.run_briefly(self.loop)
|
||||||
|
|
||||||
|
proc_returncode, transport_return_code, killed = result
|
||||||
|
|
||||||
|
self.assertIsNotNone(proc_returncode)
|
||||||
|
self.assertIsNone(transport_return_code)
|
||||||
|
|
||||||
|
# transport.close() must not kill the process if it finished, even if
|
||||||
|
# the transport was not notified yet
|
||||||
|
self.assertFalse(killed)
|
||||||
|
|
||||||
|
|
||||||
if sys.platform != 'win32':
|
if sys.platform != 'win32':
|
||||||
# Unix
|
# Unix
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue