Commit e8912359 authored by Michael Achenbach's avatar Michael Achenbach Committed by Commit Bot

[test] Refactor commands into OS-specific versions

This seperates OS-specific code of the Command class into a Posix and a
WindowsCommand to simplify scattered OS checks.

This also removes some temporary mac debug output that's obsolete after
https://crbug.com/v8/6927 got resolved.

TBR=sergiyb@chromium.org

Bug: v8:6917
Change-Id: Iaab3b527ce556dfba797a164ae58e8dd358eb56f
Reviewed-on: https://chromium-review.googlesource.com/847000Reviewed-by: 's avatarMichael Achenbach <machenbach@chromium.org>
Commit-Queue: Michael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50346}
parent d55f9297
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
# found in the LICENSE file. # found in the LICENSE file.
from contextlib import contextmanager
import os import os
import subprocess import subprocess
import sys import sys
...@@ -14,38 +13,11 @@ from ..local import utils ...@@ -14,38 +13,11 @@ from ..local import utils
from ..objects import output from ..objects import output
@contextmanager SEM_INVALID_VALUE = -1
def win_error_mode(): SEM_NOGPFAULTERRORBOX = 0x0002 # Microsoft Platform SDK WinBase.h
""" Try to change the error mode to avoid dialogs on fatal errors. Don't
touch any existing error mode flags by merging the existing error mode.
See http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx.
"""
def set_error_mode(mode):
prev_error_mode = SEM_INVALID_VALUE
try:
import ctypes
prev_error_mode = (
ctypes.windll.kernel32.SetErrorMode(mode)) #@UndefinedVariable
except ImportError:
pass
return prev_error_mode
SEM_INVALID_VALUE = -1
SEM_NOGPFAULTERRORBOX = 0x0002 # Microsoft Platform SDK WinBase.h
if utils.IsWindows():
error_mode = SEM_NOGPFAULTERRORBOX
prev_error_mode = set_error_mode(error_mode)
set_error_mode(error_mode | prev_error_mode)
yield class BaseCommand(object):
if utils.IsWindows() and prev_error_mode != SEM_INVALID_VALUE:
set_error_mode(prev_error_mode)
class Command(object):
def __init__(self, shell, args=None, cmd_prefix=None, timeout=60, env=None, def __init__(self, shell, args=None, cmd_prefix=None, timeout=60, env=None,
verbose=False): verbose=False):
assert(timeout > 0) assert(timeout > 0)
...@@ -61,23 +33,12 @@ class Command(object): ...@@ -61,23 +33,12 @@ class Command(object):
if self.verbose: if self.verbose:
print '# %s' % self print '# %s' % self
with win_error_mode(): process = self._start_process(**additional_popen_kwargs)
try:
process = subprocess.Popen(
args=self._get_popen_args(),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=self._get_env(),
**additional_popen_kwargs
)
except Exception as e:
sys.stderr.write('Error executing: %s\n' % self)
raise e
# Variable to communicate with the timer. # Variable to communicate with the timer.
timeout_occured = [False] timeout_occured = [False]
timer = threading.Timer( timer = threading.Timer(
self.timeout, self._kill_process, [process, timeout_occured]) self.timeout, self._on_timeout, [process, timeout_occured])
timer.start() timer.start()
start_time = time.time() start_time = time.time()
...@@ -95,11 +56,21 @@ class Command(object): ...@@ -95,11 +56,21 @@ class Command(object):
duration duration
) )
def _start_process(self, **additional_popen_kwargs):
try:
return subprocess.Popen(
args=self._get_popen_args(),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=self._get_env(),
**additional_popen_kwargs
)
except Exception as e:
sys.stderr.write('Error executing: %s\n' % self)
raise e
def _get_popen_args(self): def _get_popen_args(self):
args = self._to_args_list() return self._to_args_list()
if utils.IsWindows():
return subprocess.list2cmdline(args)
return args
def _get_env(self): def _get_env(self):
env = os.environ.copy() env = os.environ.copy()
...@@ -111,55 +82,16 @@ class Command(object): ...@@ -111,55 +82,16 @@ class Command(object):
env.pop('GTEST_SHARD_INDEX', None) env.pop('GTEST_SHARD_INDEX', None)
return env return env
def _kill_process(self, process, timeout_occured): def _kill_process(self, process):
raise NotImplementedError()
def _on_timeout(self, process, timeout_occured):
timeout_occured[0] = True timeout_occured[0] = True
try: try:
if utils.IsWindows(): self._kill_process(process)
self._kill_process_windows(process)
else:
self._kill_process_posix(process)
except OSError: except OSError:
sys.stderr.write('Error: Process %s already ended.\n' % process.pid) sys.stderr.write('Error: Process %s already ended.\n' % process.pid)
def _kill_process_windows(self, process):
if self.verbose:
print 'Attempting to kill process %d' % process.pid
sys.stdout.flush()
tk = subprocess.Popen(
'taskkill /T /F /PID %d' % process.pid,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
stdout, stderr = tk.communicate()
if self.verbose:
print 'Taskkill results for %d' % process.pid
print stdout
print stderr
print 'Return code: %d' % tk.returncode
sys.stdout.flush()
def _kill_process_posix(self, process):
if utils.GuessOS() == 'macos':
# TODO(machenbach): Temporary output for investigating hanging test
# driver on mac.
print 'Attempting to kill process %d - cmd %s' % (process.pid, self)
try:
print subprocess.check_output(
'ps -e | egrep "d8|cctest|unittests"', shell=True)
except Exception:
pass
sys.stdout.flush()
process.kill()
if utils.GuessOS() == 'macos':
# TODO(machenbach): Temporary output for investigating hanging test
# driver on mac. This will probably not print much, since kill only
# sends the signal.
print 'Return code after signalling the kill: %s' % process.returncode
sys.stdout.flush()
def __str__(self): def __str__(self):
return self.to_string() return self.to_string()
...@@ -179,3 +111,61 @@ class Command(object): ...@@ -179,3 +111,61 @@ class Command(object):
def _to_args_list(self): def _to_args_list(self):
return self.cmd_prefix + [self.shell] + self.args return self.cmd_prefix + [self.shell] + self.args
class PosixCommand(BaseCommand):
def _kill_process(self, process):
process.kill()
class WindowsCommand(BaseCommand):
def _start_process(self, **kwargs):
# Try to change the error mode to avoid dialogs on fatal errors. Don't
# touch any existing error mode flags by merging the existing error mode.
# See http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx.
def set_error_mode(mode):
prev_error_mode = SEM_INVALID_VALUE
try:
import ctypes
prev_error_mode = (
ctypes.windll.kernel32.SetErrorMode(mode)) #@UndefinedVariable
except ImportError:
pass
return prev_error_mode
error_mode = SEM_NOGPFAULTERRORBOX
prev_error_mode = set_error_mode(error_mode)
set_error_mode(error_mode | prev_error_mode)
try:
return super(WindowsCommand, self)._start_process(**kwargs)
finally:
if prev_error_mode != SEM_INVALID_VALUE:
set_error_mode(prev_error_mode)
def _get_popen_args(self):
return subprocess.list2cmdline(self._to_args_list())
def _kill_process(self, process):
if self.verbose:
print 'Attempting to kill process %d' % process.pid
sys.stdout.flush()
tk = subprocess.Popen(
'taskkill /T /F /PID %d' % process.pid,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
stdout, stderr = tk.communicate()
if self.verbose:
print 'Taskkill results for %d' % process.pid
print stdout
print stderr
print 'Return code: %d' % tk.returncode
sys.stdout.flush()
# Set the Command class to the OS-specific version.
if utils.IsWindows():
Command = WindowsCommand
else:
Command = PosixCommand
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment