qvm-run: fix race condition in SIGCHLD handling
Don't terminate qvm-run on any SIGCHLD, check if the process we're waiting for have finished. Currently the only situation when it's broken is a test (which starts additional process, whose SIGCHLD may be caught here), but lets do not assume that much (starting only one process) about environment.
This commit is contained in:
parent
17ca883c7c
commit
54d5ec79b5
@ -74,6 +74,10 @@ class TestProcess(object):
|
|||||||
self.stdin_close()
|
self.stdin_close()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def poll(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class _AssertNotRaisesContext(object):
|
class _AssertNotRaisesContext(object):
|
||||||
"""A context manager used to implement TestCase.assertNotRaises methods.
|
"""A context manager used to implement TestCase.assertNotRaises methods.
|
||||||
|
|
||||||
|
@ -112,6 +112,12 @@ class DataCopyProtocol(asyncio.Protocol):
|
|||||||
self.eof_callback()
|
self.eof_callback()
|
||||||
|
|
||||||
|
|
||||||
|
def stop_loop_if_terminated(proc, loop):
|
||||||
|
'''Stop event loop if given process is terminated'''
|
||||||
|
if proc.poll():
|
||||||
|
loop.stop()
|
||||||
|
|
||||||
|
|
||||||
def main(args=None, app=None):
|
def main(args=None, app=None):
|
||||||
'''Main function of qvm-run tool'''
|
'''Main function of qvm-run tool'''
|
||||||
args = parser.parse_args(args, app=app)
|
args = parser.parse_args(args, app=app)
|
||||||
@ -173,9 +179,6 @@ def main(args=None, app=None):
|
|||||||
wait_session = vm.run_service('qubes.WaitForSession',
|
wait_session = vm.run_service('qubes.WaitForSession',
|
||||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
wait_session.communicate(vm.default_user.encode())
|
wait_session.communicate(vm.default_user.encode())
|
||||||
if args.passio and not args.localcmd:
|
|
||||||
loop = asyncio.new_event_loop()
|
|
||||||
loop.add_signal_handler(signal.SIGCHLD, loop.stop)
|
|
||||||
if args.service:
|
if args.service:
|
||||||
proc = vm.run_service(args.cmd,
|
proc = vm.run_service(args.cmd,
|
||||||
user=args.user,
|
user=args.user,
|
||||||
@ -191,10 +194,14 @@ def main(args=None, app=None):
|
|||||||
proc.stdin.write(vm.prepare_input_for_vmshell(args.cmd))
|
proc.stdin.write(vm.prepare_input_for_vmshell(args.cmd))
|
||||||
proc.stdin.flush()
|
proc.stdin.flush()
|
||||||
if args.passio and not args.localcmd:
|
if args.passio and not args.localcmd:
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
loop.add_signal_handler(signal.SIGCHLD,
|
||||||
|
functools.partial(stop_loop_if_terminated, proc, loop))
|
||||||
asyncio.ensure_future(loop.connect_read_pipe(
|
asyncio.ensure_future(loop.connect_read_pipe(
|
||||||
functools.partial(DataCopyProtocol, proc.stdin,
|
functools.partial(DataCopyProtocol, proc.stdin,
|
||||||
loop.stop),
|
loop.stop),
|
||||||
sys.stdin), loop=loop)
|
sys.stdin), loop=loop)
|
||||||
|
stop_loop_if_terminated(proc, loop)
|
||||||
loop.run_forever()
|
loop.run_forever()
|
||||||
loop.close()
|
loop.close()
|
||||||
proc.stdin.close()
|
proc.stdin.close()
|
||||||
|
Loading…
Reference in New Issue
Block a user