blob: f7c8f433b6ddc5de607a2614e70d55896680e4fa [file] [log] [blame]
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import os
import pipes
import threading
from autotest_lib.client.common_lib import error
class _HelperThread(threading.Thread):
"""Make a thread to run the command in."""
def __init__(self, host, cmd):
super(_HelperThread, self).__init__()
self._host = host
self._cmd = cmd
self._result = None
self.daemon = True
def run(self):'Helper thread running: %s', self._cmd)
# NB: set ignore_status as we're always terminated w/ pkill
self._result =, ignore_status=True)
def result(self):
@returns string result of running our command if the command has
finished, and None otherwise.
return self._result
class Command(object):
Encapsulates a command run on a remote machine.
Future work is to have this get the PID (by prepending 'echo $$;
exec' to the command and parsing the output).
def __init__(self, host, cmd, pkill_argument=None):
Run a command on a remote host in the background.
@param host Host object representing the remote machine.
@param cmd String command to run on the remote machine.
@param pkill_argument String argument to pkill to kill the remote
if pkill_argument is None:
# Attempt to guess what a suitable pkill argument would look like.
pkill_argument = os.path.basename(cmd.split()[0])
self._command_name = pipes.quote(pkill_argument)
self._host = host
self._thread = _HelperThread(self._host, cmd)
def join(self, signal=None, timeout=5.0):
Kills the remote command and waits until it dies. Takes an optional
signal argument to control which signal to send the process to be
@param signal Signal string to give to pkill (e.g. SIGNAL_INT).
@param timeout float number of seconds to wait for join to finish.
if signal is None:
signal_arg = ''
# In theory, it should be hard to pass something evil for signal if
# we make sure it's an integer before passing it to pkill.
signal_arg = '-' + str(int(signal))
# Ignore status because the command may have exited already"pkill %s %s" % (signal_arg, self._command_name),
if self._thread.isAlive():
raise error.TestFail('Failed to kill remote command: %s' %
def __enter__(self):
return self
def __exit__(self, exception, value, traceback):
return False
def result(self):
@returns string result of running our command if the command has
finished, and None otherwise.
return self._thread.result