1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Copyright 2012 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Redistribution and use in source and binary forms, with or without
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# modification, are permitted provided that the following conditions are
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# met:
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#     * Redistributions of source code must retain the above copyright
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       notice, this list of conditions and the following disclaimer.
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#     * Redistributions in binary form must reproduce the above
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       copyright notice, this list of conditions and the following
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       disclaimer in the documentation and/or other materials provided
11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       with the distribution.
12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#     * Neither the name of Google Inc. nor the names of its
13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       contributors may be used to endorse or promote products derived
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       from this software without specific prior written permission.
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport os
30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport signal
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport subprocess
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport sys
33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport tempfile
34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport time
35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfrom ..local import utils
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfrom ..objects import output
38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochdef KillProcessWithID(pid):
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if utils.IsWindows():
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os.popen('taskkill /T /F /PID %d' % pid)
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  else:
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os.kill(pid, signal.SIGTERM)
45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochMAX_SLEEP_TIME = 0.1
48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochINITIAL_SLEEP_TIME = 0.0001
49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochSLEEP_TIME_FACTOR = 1.25
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochSEM_INVALID_VALUE = -1
52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochSEM_NOGPFAULTERRORBOX = 0x0002  # Microsoft Platform SDK WinBase.h
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochdef Win32SetErrorMode(mode):
56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  prev_error_mode = SEM_INVALID_VALUE
57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  try:
58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    import ctypes
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    prev_error_mode = \
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ctypes.windll.kernel32.SetErrorMode(mode)  #@UndefinedVariable
61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  except ImportError:
62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    pass
63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return prev_error_mode
64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochdef RunProcess(verbose, timeout, args, **rest):
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if verbose: print "#", " ".join(args)
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  popen_args = args
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  prev_error_mode = SEM_INVALID_VALUE
70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if utils.IsWindows():
71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    popen_args = subprocess.list2cmdline(args)
72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    # Try to change the error mode to avoid dialogs on fatal errors. Don't
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    # touch any existing error mode flags by merging the existing error mode.
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    # See http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx.
75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    error_mode = SEM_NOGPFAULTERRORBOX
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    prev_error_mode = Win32SetErrorMode(error_mode)
77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Win32SetErrorMode(error_mode | prev_error_mode)
78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  process = subprocess.Popen(
79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    shell=utils.IsWindows(),
80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    args=popen_args,
81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    **rest
82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  )
83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (utils.IsWindows() and prev_error_mode != SEM_INVALID_VALUE):
84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Win32SetErrorMode(prev_error_mode)
85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  # Compute the end time - if the process crosses this limit we
86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  # consider it timed out.
87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if timeout is None: end_time = None
88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  else: end_time = time.time() + timeout
89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  timed_out = False
90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  # Repeatedly check the exit code from the process in a
91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  # loop and keep track of whether or not it times out.
92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  exit_code = None
93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  sleep_time = INITIAL_SLEEP_TIME
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  while exit_code is None:
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (not end_time is None) and (time.time() >= end_time):
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      # Kill the process and wait for it to exit.
97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      KillProcessWithID(process.pid)
98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      exit_code = process.wait()
99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      timed_out = True
100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    else:
101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      exit_code = process.poll()
102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      time.sleep(sleep_time)
103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      sleep_time = sleep_time * SLEEP_TIME_FACTOR
104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if sleep_time > MAX_SLEEP_TIME:
105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        sleep_time = MAX_SLEEP_TIME
106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return (exit_code, timed_out)
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochdef PrintError(string):
110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  sys.stderr.write(string)
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  sys.stderr.write("\n")
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochdef CheckedUnlink(name):
115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  # On Windows, when run with -jN in parallel processes,
116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  # OS often fails to unlink the temp file. Not sure why.
117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  # Need to retry.
118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  # Idea from https://bugs.webkit.org/attachment.cgi?id=75982&action=prettypatch
119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  retry_count = 0
120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  while retry_count < 30:
121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    try:
122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      os.unlink(name)
123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return
124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    except OSError, e:
125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      retry_count += 1
126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      time.sleep(retry_count * 0.1)
127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  PrintError("os.unlink() " + str(e))
128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochdef Execute(args, verbose=False, timeout=None):
131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  try:
132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    args = [ c for c in args if c != "" ]
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    (fd_out, outname) = tempfile.mkstemp()
134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    (fd_err, errname) = tempfile.mkstemp()
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    (exit_code, timed_out) = RunProcess(
136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      verbose,
137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      timeout,
138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      args=args,
139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      stdout=fd_out,
140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      stderr=fd_err
141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    )
142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  finally:
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    # TODO(machenbach): A keyboard interrupt before the assignment to
144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    # fd_out|err can lead to reference errors here.
145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os.close(fd_out)
146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os.close(fd_err)
147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    out = file(outname).read()
148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    errors = file(errname).read()
149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CheckedUnlink(outname)
150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CheckedUnlink(errname)
151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return output.Output(exit_code, timed_out, out, errors)
152