Use simctl instead of LayoutTestRelay
[WebKit.git] / Tools / Scripts / webkitpy / port / server_process.py
1 # Copyright (C) 2017 Apple Inc. All rights reserved.
2 # Copyright (C) 2010 Google Inc. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 #     * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 #     * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
13 # distribution.
14 #     * Neither the Google name nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 """Package that implements the ServerProcess wrapper class"""
31
32 import errno
33 import logging
34 import signal
35 import sys
36 import time
37
38 # Note that although win32 python does provide an implementation of
39 # the win32 select API, it only works on sockets, and not on the named pipes
40 # used by subprocess, so we have to use the native APIs directly.
41 if sys.platform.startswith('win'):
42     import msvcrt
43     import win32pipe
44     import win32file
45 else:
46     import fcntl
47     import os
48     import select
49
50 from webkitpy.common.system.executive import ScriptError
51
52
53 _log = logging.getLogger(__name__)
54
55
56 class ServerProcess(object):
57     """This class provides a wrapper around a subprocess that
58     implements a simple request/response usage model. The primary benefit
59     is that reading responses takes a deadline, so that we don't ever block
60     indefinitely. The class also handles transparently restarting processes
61     as necessary to keep issuing commands."""
62
63     def __init__(self, port_obj, name, cmd, env=None, universal_newlines=False, treat_no_data_as_crash=False, worker_number=None):
64         self._port = port_obj
65         self._name = name  # Should be the command name (e.g. DumpRenderTree, ImageDiff)
66         self._cmd = cmd
67         self._env = env
68         # Set if the process outputs non-standard newlines like '\r\n' or '\r'.
69         # Don't set if there will be binary data or the data must be ASCII encoded.
70         self._universal_newlines = universal_newlines
71         self._treat_no_data_as_crash = treat_no_data_as_crash
72         self._host = self._port.host
73         self._pid = None
74         self._reset()
75
76         # See comment in imports for why we need the win32 APIs and can't just use select.
77         # FIXME: there should be a way to get win32 vs. cygwin from platforminfo.
78         self._use_win32_apis = sys.platform.startswith('win')
79
80     def name(self):
81         return self._name
82
83     def pid(self):
84         return self._pid
85
86     def _reset(self):
87         if getattr(self, '_proc', None):
88             if self._proc.stdin:
89                 self._proc.stdin.close()
90                 self._proc.stdin = None
91             if self._proc.stdout:
92                 self._proc.stdout.close()
93                 self._proc.stdout = None
94             if self._proc.stderr:
95                 self._proc.stderr.close()
96                 self._proc.stderr = None
97
98         self._proc = None
99         self._output = str()  # bytesarray() once we require Python 2.6
100         self._error = str()  # bytesarray() once we require Python 2.6
101         self._crashed = False
102         self.timed_out = False
103
104     def process_name(self):
105         return self._name
106
107     @staticmethod
108     def _set_file_nonblocking(file):
109         flags = fcntl.fcntl(file.fileno(), fcntl.F_GETFL)
110         fcntl.fcntl(file.fileno(), fcntl.F_SETFL, flags | os.O_NONBLOCK)
111
112     def _start(self):
113         if self._proc:
114             raise ValueError("%s already running" % self._name)
115         self._reset()
116         # close_fds is a workaround for http://bugs.python.org/issue2320
117         close_fds = not self._host.platform.is_win()
118         self._proc = self._host.executive.popen(self._cmd, stdin=self._host.executive.PIPE,
119             stdout=self._host.executive.PIPE,
120             stderr=self._host.executive.PIPE,
121             close_fds=close_fds,
122             env=self._env,
123             universal_newlines=self._universal_newlines)
124         self._pid = self._proc.pid
125         self._port.find_system_pid(self.name(), self._pid)
126         if not self._use_win32_apis:
127             self._set_file_nonblocking(self._proc.stdout)
128             self._set_file_nonblocking(self._proc.stderr)
129
130     def _handle_possible_interrupt(self):
131         """This routine checks to see if the process crashed or exited
132         because of a keyboard interrupt and raises KeyboardInterrupt
133         accordingly."""
134         # FIXME: Linux and Mac set the returncode to -signal.SIGINT if a
135         # subprocess is killed with a ctrl^C.  Previous comments in this
136         # routine said that supposedly Windows returns 0xc000001d, but that's not what
137         # -1073741510 evaluates to. Figure out what the right value is
138         # for win32 and cygwin here ...
139         if self._proc.returncode in (-1073741510, -signal.SIGINT):
140             raise KeyboardInterrupt
141
142     def poll(self):
143         """Check to see if the underlying process is running; returns None
144         if it still is (wrapper around subprocess.poll)."""
145         if self._proc:
146             return self._proc.poll()
147         return None
148
149     def write(self, bytes, ignore_crash=False):
150         """Write a request to the subprocess. The subprocess is (re-)start()'ed
151         if is not already running."""
152         if not self._proc:
153             self._start()
154         try:
155             self._proc.stdin.write(bytes)
156         except IOError, e:
157             self.stop(0.0)
158             # stop() calls _reset(), so we have to set crashed to True after calling stop()
159             # unless we already know that this is a timeout.
160             if not ignore_crash:
161                 _log.debug('This test marked as a crash because of a broken pipe when writing to stdin of the server process.')
162                 self._crashed = True
163
164     def _pop_stdout_line_if_ready(self):
165         index_after_newline = self._output.find('\n') + 1
166         if index_after_newline > 0:
167             return self._pop_output_bytes(index_after_newline)
168         return None
169
170     def _pop_stderr_line_if_ready(self):
171         index_after_newline = self._error.find('\n') + 1
172         if index_after_newline > 0:
173             return self._pop_error_bytes(index_after_newline)
174         return None
175
176     def pop_all_buffered_stderr(self):
177         return self._pop_error_bytes(len(self._error))
178
179     def read_stdout_line(self, deadline):
180         return self._read(deadline, self._pop_stdout_line_if_ready)
181
182     def read_stderr_line(self, deadline):
183         return self._read(deadline, self._pop_stderr_line_if_ready)
184
185     def read_either_stdout_or_stderr_line(self, deadline):
186         def retrieve_bytes_from_buffers():
187             stdout_line = self._pop_stdout_line_if_ready()
188             if stdout_line:
189                 return stdout_line, None
190             stderr_line = self._pop_stderr_line_if_ready()
191             if stderr_line:
192                 return None, stderr_line
193             return None  # Instructs the caller to keep waiting.
194
195         return_value = self._read(deadline, retrieve_bytes_from_buffers)
196         # FIXME: This is a bit of a hack around the fact that _read normally only returns one value, but this caller wants it to return two.
197         if return_value is None:
198             return None, None
199         return return_value
200
201     def read_stdout(self, deadline, size):
202         if size <= 0:
203             raise ValueError('ServerProcess.read() called with a non-positive size: %d ' % size)
204
205         def retrieve_bytes_from_stdout_buffer():
206             if len(self._output) >= size:
207                 return self._pop_output_bytes(size)
208             return None
209
210         return self._read(deadline, retrieve_bytes_from_stdout_buffer)
211
212     def _log(self, message):
213         # This is a bit of a hack, but we first log a blank line to avoid
214         # messing up the master process's output.
215         _log.info('')
216         _log.info(message)
217
218     def _handle_timeout(self):
219         self.timed_out = True
220         if self._port.get_option("sample_on_timeout"):
221             self._port.sample_process(self._name, self._proc.pid)
222
223     def _split_string_after_index(self, string, index):
224         return string[:index], string[index:]
225
226     def _pop_output_bytes(self, bytes_count):
227         output, self._output = self._split_string_after_index(self._output, bytes_count)
228         return output
229
230     def _pop_error_bytes(self, bytes_count):
231         output, self._error = self._split_string_after_index(self._error, bytes_count)
232         return output
233
234     def _wait_for_data_and_update_buffers_using_select(self, deadline, stopping=False):
235         if self._proc.stdout.closed or self._proc.stderr.closed:
236             # If the process crashed and is using FIFOs, like Chromium Android, the
237             # stdout and stderr pipes will be closed.
238             return
239
240         out_fd = self._proc.stdout.fileno()
241         err_fd = self._proc.stderr.fileno()
242         select_fds = (out_fd, err_fd)
243         try:
244             read_fds, _, _ = select.select(select_fds, [], select_fds, max(deadline - time.time(), 0))
245         except select.error, e:
246             # We can ignore EINVAL since it's likely the process just crashed and we'll
247             # figure that out the next time through the loop in _read().
248             if e.args[0] == errno.EINVAL:
249                 return
250             raise
251
252         try:
253             # Note that we may get no data during read() even though
254             # select says we got something; see the select() man page
255             # on linux. I don't know if this happens on Mac OS and
256             # other Unixen as well, but we don't bother special-casing
257             # Linux because it's relatively harmless either way.
258             if out_fd in read_fds:
259                 data = self._proc.stdout.read()
260                 if not data and not stopping and (self._treat_no_data_as_crash or self._proc.poll()):
261                     _log.debug('This test marked as a crash because of no data while reading stdout for the server process.')
262                     self._crashed = True
263                 self._output += data
264
265             if err_fd in read_fds:
266                 data = self._proc.stderr.read()
267                 if not data and not stopping and (self._treat_no_data_as_crash or self._proc.poll()):
268                     _log.debug('This test marked as a crash because of no data while reading stdout for the server process.')
269                     self._crashed = True
270                 self._error += data
271         except IOError, e:
272             # We can ignore the IOErrors because we will detect if the subporcess crashed
273             # the next time through the loop in _read()
274             pass
275
276     def _wait_for_data_and_update_buffers_using_win32_apis(self, deadline):
277         # See http://code.activestate.com/recipes/440554-module-to-allow-asynchronous-subprocess-use-on-win/
278         # and http://docs.activestate.com/activepython/2.6/pywin32/modules.html
279         # for documentation on all of these win32-specific modules.
280         now = time.time()
281         out_fh = msvcrt.get_osfhandle(self._proc.stdout.fileno())
282         err_fh = msvcrt.get_osfhandle(self._proc.stderr.fileno())
283         while (self._proc.poll() is None) and (now < deadline):
284             output = self._non_blocking_read_win32(out_fh)
285             error = self._non_blocking_read_win32(err_fh)
286             if output or error:
287                 if output:
288                     self._output += output
289                 if error:
290                     self._error += error
291                 return
292             time.sleep(0.01)
293             now = time.time()
294         return
295
296     def _non_blocking_read_win32(self, handle):
297         try:
298             _, avail, _ = win32pipe.PeekNamedPipe(handle, 0)
299             if avail > 0:
300                 _, buf = win32file.ReadFile(handle, avail, None)
301                 return buf
302         except Exception, e:
303             if e[0] not in (109, errno.ESHUTDOWN):  # 109 == win32 ERROR_BROKEN_PIPE
304                 raise
305         return None
306
307     def has_crashed(self):
308         if not self._crashed and self.poll():
309             _log.debug('This test marked as a crash because of failure to poll the server process.')
310             self._crashed = True
311             self._handle_possible_interrupt()
312         return self._crashed
313
314     # This read function is a bit oddly-designed, as it polls both stdout and stderr, yet
315     # only reads/returns from one of them (buffering both in local self._output/self._error).
316     # It might be cleaner to pass in the file descriptor to poll instead.
317     def _read(self, deadline, fetch_bytes_from_buffers_callback):
318         while True:
319             if self.has_crashed():
320                 return None
321
322             if time.time() > deadline:
323                 self._handle_timeout()
324                 return None
325
326             bytes = fetch_bytes_from_buffers_callback()
327             if bytes is not None:
328                 return bytes
329
330             if self._use_win32_apis:
331                 self._wait_for_data_and_update_buffers_using_win32_apis(deadline)
332             else:
333                 self._wait_for_data_and_update_buffers_using_select(deadline)
334
335     def start(self):
336         if not self._proc:
337             self._start()
338
339     def stop(self, timeout_secs=3.0):
340         if not self._proc:
341             return (None, None)
342
343         # Only bother to check for leaks or stderr if the process is still running.
344         if self.poll() is None:
345             self._port.check_for_leaks(self.name(), self.pid())
346
347         now = time.time()
348         if self._proc.stdin:
349             self._proc.stdin.close()
350             self._proc.stdin = None
351         killed = False
352         if timeout_secs:
353             deadline = now + timeout_secs
354             while self._proc.poll() is None and time.time() < deadline:
355                 time.sleep(0.01)
356             if self._proc.poll() is None:
357                 _log.warning('stopping %s(pid %d) timed out, killing it' % (self._name, self._proc.pid))
358
359         if self._proc.poll() is None:
360             self._kill()
361             killed = True
362             _log.debug('killed pid %d' % self._proc.pid)
363
364         # read any remaining data on the pipes and return it.
365         if not killed:
366             if self._use_win32_apis:
367                 self._wait_for_data_and_update_buffers_using_win32_apis(now)
368             else:
369                 self._wait_for_data_and_update_buffers_using_select(now, stopping=True)
370         out, err = self._output, self._error
371         self._reset()
372         return (out, err)
373
374     def kill(self):
375         self.stop(0.0)
376
377     def _kill(self):
378         self._host.executive.kill_process(self._proc.pid)
379         if self._proc.poll() is not None:
380             self._proc.wait()
381
382     def replace_outputs(self, stdout, stderr):
383         assert self._proc
384         if stdout:
385             self._proc.stdout.close()
386             self._proc.stdout = stdout
387         if stderr:
388             self._proc.stderr.close()
389             self._proc.stderr = stderr