• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2012 the V8 project authors. All rights reserved.
2# Redistribution and use in source and binary forms, with or without
3# modification, are permitted provided that the following conditions are
4# met:
5#
6#     * Redistributions of source code must retain the above copyright
7#       notice, this list of conditions and the following disclaimer.
8#     * Redistributions in binary form must reproduce the above
9#       copyright notice, this list of conditions and the following
10#       disclaimer in the documentation and/or other materials provided
11#       with the distribution.
12#     * Neither the name of Google Inc. nor the names of its
13#       contributors may be used to endorse or promote products derived
14#       from this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29import os
30import subprocess
31import sys
32from threading import Timer
33
34from ..local import utils
35from ..objects import output
36
37
38SEM_INVALID_VALUE = -1
39SEM_NOGPFAULTERRORBOX = 0x0002  # Microsoft Platform SDK WinBase.h
40
41
42def Win32SetErrorMode(mode):
43  prev_error_mode = SEM_INVALID_VALUE
44  try:
45    import ctypes
46    prev_error_mode = \
47        ctypes.windll.kernel32.SetErrorMode(mode)  #@UndefinedVariable
48  except ImportError:
49    pass
50  return prev_error_mode
51
52
53def RunProcess(verbose, timeout, args, **rest):
54  if verbose: print "#", " ".join(args)
55  popen_args = args
56  prev_error_mode = SEM_INVALID_VALUE
57  if utils.IsWindows():
58    popen_args = subprocess.list2cmdline(args)
59    # Try to change the error mode to avoid dialogs on fatal errors. Don't
60    # touch any existing error mode flags by merging the existing error mode.
61    # See http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx.
62    error_mode = SEM_NOGPFAULTERRORBOX
63    prev_error_mode = Win32SetErrorMode(error_mode)
64    Win32SetErrorMode(error_mode | prev_error_mode)
65
66  env = os.environ.copy()
67  # GTest shard information is read by the V8 tests runner. Make sure it
68  # doesn't leak into the execution of gtests we're wrapping. Those might
69  # otherwise apply a second level of sharding and as a result skip tests.
70  env.pop('GTEST_TOTAL_SHARDS', None)
71  env.pop('GTEST_SHARD_INDEX', None)
72
73  try:
74    process = subprocess.Popen(
75      args=popen_args,
76      stdout=subprocess.PIPE,
77      stderr=subprocess.PIPE,
78      env=env,
79      **rest
80    )
81  except Exception as e:
82    sys.stderr.write("Error executing: %s\n" % popen_args)
83    raise e
84
85  if (utils.IsWindows() and prev_error_mode != SEM_INVALID_VALUE):
86    Win32SetErrorMode(prev_error_mode)
87
88  def kill_process(process, timeout_result):
89    timeout_result[0] = True
90    try:
91      if utils.IsWindows():
92        if verbose:
93          print "Attempting to kill process %d" % process.pid
94          sys.stdout.flush()
95        tk = subprocess.Popen(
96            'taskkill /T /F /PID %d' % process.pid,
97            stdout=subprocess.PIPE,
98            stderr=subprocess.PIPE,
99        )
100        stdout, stderr = tk.communicate()
101        if verbose:
102          print "Taskkill results for %d" % process.pid
103          print stdout
104          print stderr
105          print "Return code: %d" % tk.returncode
106          sys.stdout.flush()
107      else:
108        process.kill()
109    except OSError:
110      sys.stderr.write('Error: Process %s already ended.\n' % process.pid)
111
112  # Pseudo object to communicate with timer thread.
113  timeout_result = [False]
114
115  timer = Timer(timeout, kill_process, [process, timeout_result])
116  timer.start()
117  stdout, stderr = process.communicate()
118  timer.cancel()
119
120  return output.Output(
121      process.returncode,
122      timeout_result[0],
123      stdout.decode('utf-8', 'replace').encode('utf-8'),
124      stderr.decode('utf-8', 'replace').encode('utf-8'),
125      process.pid,
126  )
127
128
129def Execute(args, verbose=False, timeout=None):
130  args = [ c for c in args if c != "" ]
131  return RunProcess(verbose, timeout, args=args)
132