X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=lttng_ivc%2Futils%2Fruntime.py;h=6c9f04c04e0deb77c3a8df035113b6d9fbf8b7b3;hb=8e2c5f79e23839ec13866fc4827a1c402aab1687;hp=9efdabee085b0bc7d4c33ec5160209002eddef93;hpb=1cd816fd51c055b54a6baf27e829ffc3eb305ed3;p=deliverable%2Flttng-ivc.git diff --git a/lttng_ivc/utils/runtime.py b/lttng_ivc/utils/runtime.py index 9efdabe..6c9f04c 100644 --- a/lttng_ivc/utils/runtime.py +++ b/lttng_ivc/utils/runtime.py @@ -1,3 +1,23 @@ +# Copyright (c) 2017 Jonathan Rajotte-Julien +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + import os import sys import shlex @@ -7,6 +27,7 @@ import logging import shutil import contextlib import pprint +import signal from tempfile import TemporaryDirectory @@ -73,13 +94,20 @@ class Runtime(object): def subprocess_signal(self, subprocess_uuid, signal): self.__subproces[subprocess_uuid].send_signal(signal) - def subprocess_terminate(self, subprocess_uuid, timeout=60): + def subprocess_terminate(self, subprocess_uuid, timeout=60, check_return=True): process = self.__subprocess[subprocess_uuid] process.terminate() - process.wait(timeout) + try: + process.wait(timeout) + except subprocess.TimeoutExpired: + # Force kill + return self.subprocess_kill(subprocess_uuid) stdout, stderr = self.__stdout_stderr[subprocess_uuid] stdout.close() stderr.close() + if check_return: + if process.returncode != 0: + raise subprocess.CalledProcessError(process.returncode, process.args) return process def subprocess_kill(self, subprocess_uuid): @@ -91,6 +119,17 @@ class Runtime(object): stderr.close() return process + def subprocess_wait(self, subprocess_uuid, check_return=True): + process = self.__subprocess[subprocess_uuid] + process.wait() + stdout, stderr = self.__stdout_stderr[subprocess_uuid] + stdout.close() + stderr.close() + if check_return: + if process.returncode != 0: + raise subprocess.CalledProcessError(process.returncode, process.args) + return process + def get_subprocess_stdout_path(self, subprocess_uuid): stdout, stderr = self.__stdout_stderr[subprocess_uuid] return stdout.name @@ -123,7 +162,7 @@ class Runtime(object): _logger.debug("Spawned sub pid: {} args: {} stdout: {} stderr{}".format(p.pid, p.args, out_path, err_path)) return tmp_id - def run(self, command_line, cwd=None, check_return=True, ld_preload="", classpath=""): + def run(self, command_line, cwd=None, check_return=True, ld_preload="", classpath="", timeout=None): """ Run the command and return a tuple of a (CompletedProcess, stdout_path, stderr_path). The subprocess is already executed and returned. The @@ -155,7 +194,8 @@ class Runtime(object): for key, value in env.items(): env_out.write('{}={}\n'.format(key, value)) - cp = subprocess.run(args, stdout=stdout, stderr=stderr, env=env, cwd=cwd) + cp = subprocess.run(args, stdout=stdout, stderr=stderr, env=env, + cwd=cwd, timeout=timeout) _logger.debug("Command #{} args: {} stdout: {} stderr{}".format(tmp_id, cp.args, out_path, err_path)) # Add to the global log file. This can help a little. Leave the other @@ -249,13 +289,7 @@ class Runtime(object): def close(self): for key, subp in self.__subprocess.items(): - subp.terminate() - for key, subp in self.__subprocess.items(): - # TODO move timeout to settings - subp.wait(timeout=60) - for key, (stdout, stderr) in self.__stdout_stderr.items(): - stdout.close() - stderr.close() + self.subprocess_kill(key) # Always try to remove test module but do not perform check on return # value.