OLD | NEW |
| (Empty) |
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 (fd_out, outname) = tempfile.mkstemp() | |
135 (fd_err, errname) = tempfile.mkstemp() | |
136 try: | |
137 (exit_code, timed_out) = RunProcess( | |
138 verbose, | |
139 timeout, | |
140 args=args, | |
141 stdout=fd_out, | |
142 stderr=fd_err | |
143 ) | |
144 except: | |
145 raise | |
146 os.close(fd_out) | |
147 os.close(fd_err) | |
148 out = file(outname).read() | |
149 errors = file(errname).read() | |
150 CheckedUnlink(outname) | |
151 CheckedUnlink(errname) | |
152 return output.Output(exit_code, timed_out, out, errors) | |
OLD | NEW |