Home | History | Annotate | Download | only in local
      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 
     29 import os
     30 import signal
     31 import subprocess
     32 import sys
     33 import tempfile
     34 import time
     35 
     36 from ..local import utils
     37 from ..objects import output
     38 
     39 
     40 def KillProcessWithID(pid):
     41   if utils.IsWindows():
     42     os.popen('taskkill /T /F /PID %d' % pid)
     43   else:
     44     os.kill(pid, signal.SIGTERM)
     45 
     46 
     47 MAX_SLEEP_TIME = 0.1
     48 INITIAL_SLEEP_TIME = 0.0001
     49 SLEEP_TIME_FACTOR = 1.25
     50 
     51 SEM_INVALID_VALUE = -1
     52 SEM_NOGPFAULTERRORBOX = 0x0002  # Microsoft Platform SDK WinBase.h
     53 
     54 
     55 def Win32SetErrorMode(mode):
     56   prev_error_mode = SEM_INVALID_VALUE
     57   try:
     58     import ctypes
     59     prev_error_mode = \
     60         ctypes.windll.kernel32.SetErrorMode(mode)  #@UndefinedVariable
     61   except ImportError:
     62     pass
     63   return prev_error_mode
     64 
     65 
     66 def RunProcess(verbose, timeout, args, **rest):
     67   if verbose: print "#", " ".join(args)
     68   popen_args = args
     69   prev_error_mode = SEM_INVALID_VALUE
     70   if utils.IsWindows():
     71     popen_args = subprocess.list2cmdline(args)
     72     # Try to change the error mode to avoid dialogs on fatal errors. Don't
     73     # touch any existing error mode flags by merging the existing error mode.
     74     # See http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx.
     75     error_mode = SEM_NOGPFAULTERRORBOX
     76     prev_error_mode = Win32SetErrorMode(error_mode)
     77     Win32SetErrorMode(error_mode | prev_error_mode)
     78   process = subprocess.Popen(
     79     shell=utils.IsWindows(),
     80     args=popen_args,
     81     **rest
     82   )
     83   if (utils.IsWindows() and prev_error_mode != SEM_INVALID_VALUE):
     84     Win32SetErrorMode(prev_error_mode)
     85   # Compute the end time - if the process crosses this limit we
     86   # consider it timed out.
     87   if timeout is None: end_time = None
     88   else: end_time = time.time() + timeout
     89   timed_out = False
     90   # Repeatedly check the exit code from the process in a
     91   # loop and keep track of whether or not it times out.
     92   exit_code = None
     93   sleep_time = INITIAL_SLEEP_TIME
     94   try:
     95     while exit_code is None:
     96       if (not end_time is None) and (time.time() >= end_time):
     97         # Kill the process and wait for it to exit.
     98         KillProcessWithID(process.pid)
     99         exit_code = process.wait()
    100         timed_out = True
    101       else:
    102         exit_code = process.poll()
    103         time.sleep(sleep_time)
    104         sleep_time = sleep_time * SLEEP_TIME_FACTOR
    105         if sleep_time > MAX_SLEEP_TIME:
    106           sleep_time = MAX_SLEEP_TIME
    107     return (exit_code, timed_out)
    108   except KeyboardInterrupt:
    109     raise
    110 
    111 
    112 def PrintError(string):
    113   sys.stderr.write(string)
    114   sys.stderr.write("\n")
    115 
    116 
    117 def CheckedUnlink(name):
    118   # On Windows, when run with -jN in parallel processes,
    119   # OS often fails to unlink the temp file. Not sure why.
    120   # Need to retry.
    121   # Idea from https://bugs.webkit.org/attachment.cgi?id=75982&action=prettypatch
    122   retry_count = 0
    123   while retry_count < 30:
    124     try:
    125       os.unlink(name)
    126       return
    127     except OSError, e:
    128       retry_count += 1
    129       time.sleep(retry_count * 0.1)
    130   PrintError("os.unlink() " + str(e))
    131 
    132 
    133 def Execute(args, verbose=False, timeout=None):
    134   args = [ c for c in args if c != "" ]
    135   (fd_out, outname) = tempfile.mkstemp()
    136   (fd_err, errname) = tempfile.mkstemp()
    137   try:
    138     (exit_code, timed_out) = RunProcess(
    139       verbose,
    140       timeout,
    141       args=args,
    142       stdout=fd_out,
    143       stderr=fd_err
    144     )
    145   except:
    146     raise
    147   os.close(fd_out)
    148   os.close(fd_err)
    149   out = file(outname).read()
    150   errors = file(errname).read()
    151   CheckedUnlink(outname)
    152   CheckedUnlink(errname)
    153   return output.Output(exit_code, timed_out, out, errors)
    154