import sys
import os
import locale
+import time
from conf import settings
+from tools import systeminfo
CMD_PREFIX = 'cmd : '
-_MY_ENCODING = locale.getdefaultlocale()[1]
def _get_stdout():
"""Get stdout value for ``subprocess`` calls.
stdout = []
stderr = []
+ my_encoding = locale.getdefaultlocale()[1]
if msg:
logger.info(msg)
logger.debug('%s%s', CMD_PREFIX, ' '.join(cmd))
try:
- proc = subprocess.Popen(
- cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
+ proc = subprocess.Popen(map(os.path.expanduser, cmd),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, bufsize=0)
while True:
reads = [proc.stdout.fileno(), proc.stderr.fileno()]
if file_d == proc.stdout.fileno():
line = proc.stdout.readline()
if settings.getValue('VERBOSITY') == 'debug':
- sys.stdout.write(line.decode(_MY_ENCODING))
+ sys.stdout.write(line.decode(my_encoding))
stdout.append(line)
if file_d == proc.stderr.fileno():
line = proc.stderr.readline()
- sys.stderr.write(line.decode(_MY_ENCODING))
+ sys.stderr.write(line.decode(my_encoding))
stderr.append(line)
if proc.poll() is not None:
ex = subprocess.CalledProcessError(proc.returncode, cmd, stderr)
handle_error(ex)
- return ('\n'.join(sout.decode(_MY_ENCODING).strip() for sout in stdout),
- ('\n'.join(sout.decode(_MY_ENCODING).strip() for sout in stderr)))
+ return ('\n'.join(sout.decode(my_encoding).strip() for sout in stdout),
+ ('\n'.join(sout.decode(my_encoding).strip() for sout in stderr)))
def run_background_task(cmd, logger, msg):
"""Run task in background and log when started.
logger.info(msg)
logger.debug('%s%s', CMD_PREFIX, ' '.join(cmd))
- proc = subprocess.Popen(cmd, stdout=_get_stdout(), bufsize=0)
+ proc = subprocess.Popen(map(os.path.expanduser, cmd), stdout=_get_stdout(), bufsize=0)
return proc.pid
return child
+def terminate_task_subtree(pid, signal='-15', sleep=10, logger=None):
+ """Terminate given process and all its children
+
+ Function will sent given signal to the process. In case
+ that process will not terminate within given sleep interval
+ and signal was not SIGKILL, then process will be killed by SIGKILL.
+ After that function will check if all children of the process
+ are terminated and if not the same terminating procedure is applied
+ on any living child (only one level of children is considered).
+
+ :param pid: Process ID to terminate
+ :param signal: Signal to be sent to the process
+ :param sleep: Maximum delay in seconds after signal is sent
+ :param logger: Logger to write details to
+ """
+ try:
+ output = subprocess.check_output("pgrep -P " + str(pid), shell=True).decode().rstrip('\n')
+ except subprocess.CalledProcessError:
+ output = ""
+
+ terminate_task(pid, signal, sleep, logger)
+
+ # just for case children were kept alive
+ children = output.split('\n')
+ for child in children:
+ terminate_task(child, signal, sleep, logger)
+
+def terminate_task(pid, signal='-15', sleep=10, logger=None):
+ """Terminate process with given pid
+
+ Function will sent given signal to the process. In case
+ that process will not terminate within given sleep interval
+ and signal was not SIGKILL, then process will be killed by SIGKILL.
+
+ :param pid: Process ID to terminate
+ :param signal: Signal to be sent to the process
+ :param sleep: Maximum delay in seconds after signal is sent
+ :param logger: Logger to write details to
+ """
+ if systeminfo.pid_isalive(pid):
+ run_task(['sudo', 'kill', signal, str(pid)], logger)
+ logger.debug('Wait for process %s to terminate after signal %s', pid, signal)
+ for dummy in range(sleep):
+ time.sleep(1)
+ if not systeminfo.pid_isalive(pid):
+ break
+
+ if signal.lstrip('-').upper() not in ('9', 'KILL', 'SIGKILL') and systeminfo.pid_isalive(pid):
+ terminate_task(pid, '-9', sleep, logger)
class Process(object):
"""Control an instance of a long-running process.
self.kill()
raise exc
- def kill(self):
+ def kill(self, signal='-15', sleep=10):
"""Kill process instance if it is alive.
+
+ :param signal: signal to be sent to the process
+ :param sleep: delay in seconds after signal is sent
"""
- if self._child and self._child.isalive():
- run_task(['sudo', 'kill', '-2', str(self._child.pid)],
- self._logger)
+ if self.is_running():
+ terminate_task_subtree(self._child.pid, signal, sleep, self._logger)
if self.is_relinquished():
self._relinquish_thread.join()
:returns: True if process is running, else False
"""
- return self._child is not None
+ return self._child and self._child.isalive()
def _affinitize_pid(self, core, pid):
"""Affinitize a process with ``pid`` to ``core``.
"""
self._logger.info('Affinitizing process')
- if self._child and self._child.isalive():
+ if self.is_running():
self._affinitize_pid(core, self._child.pid)
class ContinueReadPrintLoop(threading.Thread):