1dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#!/usr/bin/env python
2dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# Copyright (C) 2010 Google Inc. All rights reserved.
3dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#
4dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# Redistribution and use in source and binary forms, with or without
5dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# modification, are permitted provided that the following conditions are
6dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# met:
7dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#
8dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#     * Redistributions of source code must retain the above copyright
9dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# notice, this list of conditions and the following disclaimer.
10dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#     * Redistributions in binary form must reproduce the above
11dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# copyright notice, this list of conditions and the following disclaimer
12dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# in the documentation and/or other materials provided with the
13dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# distribution.
14dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#     * Neither the Google name nor the names of its
15dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# contributors may be used to endorse or promote products derived from
16dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# this software without specific prior written permission.
17dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#
18dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
30dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block"""Package that implements the ServerProcess wrapper class"""
31dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
32dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport logging
33dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport os
34dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport select
35dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport signal
36dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport subprocess
37dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport sys
38dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport time
395abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrickif sys.platform != 'win32':
405abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick    import fcntl
41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
4221939df44de1705786c545cd1bf519d47250322dBen Murdochfrom webkitpy.common.system.executive import Executive
4321939df44de1705786c545cd1bf519d47250322dBen Murdoch
44dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block_log = logging.getLogger("webkitpy.layout_tests.port.server_process")
45dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
46dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
47dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockclass ServerProcess:
48dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    """This class provides a wrapper around a subprocess that
49dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    implements a simple request/response usage model. The primary benefit
50dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    is that reading responses takes a timeout, so that we don't ever block
51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    indefinitely. The class also handles transparently restarting processes
52dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    as necessary to keep issuing commands."""
53dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
5421939df44de1705786c545cd1bf519d47250322dBen Murdoch    def __init__(self, port_obj, name, cmd, env=None, executive=Executive()):
55dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._port = port_obj
56dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._name = name
57dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._cmd = cmd
58dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._env = env
59dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._reset()
6021939df44de1705786c545cd1bf519d47250322dBen Murdoch        self._executive = executive
61dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
62dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def _reset(self):
63dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._proc = None
64dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._output = ''
65dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self.crashed = False
66dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self.timed_out = False
67dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self.error = ''
68dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
69dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def _start(self):
70dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if self._proc:
71dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            raise ValueError("%s already running" % self._name)
72dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._reset()
7321939df44de1705786c545cd1bf519d47250322dBen Murdoch        # close_fds is a workaround for http://bugs.python.org/issue2320
74dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        close_fds = sys.platform not in ('win32', 'cygwin')
75dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._proc = subprocess.Popen(self._cmd, stdin=subprocess.PIPE,
76dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                      stdout=subprocess.PIPE,
77dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                      stderr=subprocess.PIPE,
78dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                      close_fds=close_fds,
79dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                      env=self._env)
80dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        fd = self._proc.stdout.fileno()
81dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
82dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
83dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        fd = self._proc.stderr.fileno()
84dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
85dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
86dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
87dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def handle_interrupt(self):
88dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """This routine checks to see if the process crashed or exited
89dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        because of a keyboard interrupt and raises KeyboardInterrupt
90dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        accordingly."""
91dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if self.crashed:
92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # This is hex code 0xc000001d, which is used for abrupt
93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # termination. This happens if we hit ctrl+c from the prompt
94dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # and we happen to be waiting on the DumpRenderTree.
95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # sdoyon: Not sure for which OS and in what circumstances the
96dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # above code is valid. What works for me under Linux to detect
97dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # ctrl+c is for the subprocess returncode to be negative
98dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # SIGINT. And that agrees with the subprocess documentation.
99dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if (-1073741510 == self._proc.returncode or
100dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                - signal.SIGINT == self._proc.returncode):
101dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                raise KeyboardInterrupt
102dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return
103dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
104dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def poll(self):
105dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Check to see if the underlying process is running; returns None
106dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if it still is (wrapper around subprocess.poll)."""
107dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if self._proc:
10821939df44de1705786c545cd1bf519d47250322dBen Murdoch            # poll() is not threadsafe and can throw OSError due to:
10921939df44de1705786c545cd1bf519d47250322dBen Murdoch            # http://bugs.python.org/issue1731717
110dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return self._proc.poll()
111dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return None
112dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
113dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def write(self, input):
114dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Write a request to the subprocess. The subprocess is (re-)start()'ed
115dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if is not already running."""
116dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if not self._proc:
117dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            self._start()
1182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        try:
1192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            self._proc.stdin.write(input)
1202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        except IOError, e:
1212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            self.stop()
1222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            self.crashed = True
123dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
124dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def read_line(self, timeout):
125dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Read a single line from the subprocess, waiting until the deadline.
126dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        If the deadline passes, the call times out. Note that even if the
127dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        subprocess has crashed or the deadline has passed, if there is output
128dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        pending, it will be returned.
129dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
130dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        Args:
131dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            timeout: floating-point number of seconds the call is allowed
132dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                to block for. A zero or negative number will attempt to read
133dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                any existing data, but will not block. There is no way to
134dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                block indefinitely.
135dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        Returns:
136dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            output: data returned, if any. If no data is available and the
137dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                call times out or crashes, an empty string is returned. Note
138dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                that the returned string includes the newline ('\n')."""
139dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return self._read(timeout, size=0)
140dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
141dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def read(self, timeout, size):
142dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Attempts to read size characters from the subprocess, waiting until
143dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        the deadline passes. If the deadline passes, any available data will be
144dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        returned. Note that even if the deadline has passed or if the
145dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        subprocess has crashed, any available data will still be returned.
146dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
147dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        Args:
148dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            timeout: floating-point number of seconds the call is allowed
149dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                to block for. A zero or negative number will attempt to read
150dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                any existing data, but will not block. There is no way to
151dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                block indefinitely.
152dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            size: amount of data to read. Must be a postive integer.
153dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        Returns:
154dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            output: data returned, if any. If no data is available, an empty
155dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                string is returned.
156dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """
157dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if size <= 0:
158dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            raise ValueError('ServerProcess.read() called with a '
159dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                             'non-positive size: %d ' % size)
160dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return self._read(timeout, size)
161dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
162dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def _read(self, timeout, size):
163dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Internal routine that actually does the read."""
164dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        index = -1
165dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        out_fd = self._proc.stdout.fileno()
166dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        err_fd = self._proc.stderr.fileno()
167dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        select_fds = (out_fd, err_fd)
168dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        deadline = time.time() + timeout
169dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        while not self.timed_out and not self.crashed:
17021939df44de1705786c545cd1bf519d47250322dBen Murdoch            # poll() is not threadsafe and can throw OSError due to:
17121939df44de1705786c545cd1bf519d47250322dBen Murdoch            # http://bugs.python.org/issue1731717
172dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if self._proc.poll() != None:
173dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                self.crashed = True
174dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                self.handle_interrupt()
175dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
176dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            now = time.time()
177dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if now > deadline:
178dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                self.timed_out = True
179dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
180dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # Check to see if we have any output we can return.
181dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if size and len(self._output) >= size:
182dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                index = size
183dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            elif size == 0:
184dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                index = self._output.find('\n') + 1
185dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
186bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            if index > 0 or self.crashed or self.timed_out:
187dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                output = self._output[0:index]
188dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                self._output = self._output[index:]
189dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                return output
190dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
191dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # Nope - wait for more data.
192dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            (read_fds, write_fds, err_fds) = select.select(select_fds, [],
193dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                                           select_fds,
194dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                                           deadline - now)
195dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            try:
196dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                if out_fd in read_fds:
197dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                    self._output += self._proc.stdout.read()
198dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                if err_fd in read_fds:
199dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                    self.error += self._proc.stderr.read()
200dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            except IOError, e:
201dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                pass
202dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
203dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    def stop(self):
204dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        """Stop (shut down) the subprocess), if it is running."""
205dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        pid = self._proc.pid
206dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._proc.stdin.close()
207dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._proc.stdout.close()
208dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if self._proc.stderr:
209dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            self._proc.stderr.close()
210dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if sys.platform not in ('win32', 'cygwin'):
211dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # Closing stdin/stdout/stderr hangs sometimes on OS X,
212dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # (see restart(), above), and anyway we don't want to hang
213dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # the harness if DumpRenderTree is buggy, so we wait a couple
214dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # seconds to give DumpRenderTree a chance to clean up, but then
215dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            # force-kill the process if necessary.
216dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            KILL_TIMEOUT = 3.0
217dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            timeout = time.time() + KILL_TIMEOUT
21821939df44de1705786c545cd1bf519d47250322dBen Murdoch            # poll() is not threadsafe and can throw OSError due to:
21921939df44de1705786c545cd1bf519d47250322dBen Murdoch            # http://bugs.python.org/issue1731717
220dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            while self._proc.poll() is None and time.time() < timeout:
221dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                time.sleep(0.1)
22221939df44de1705786c545cd1bf519d47250322dBen Murdoch            # poll() is not threadsafe and can throw OSError due to:
22321939df44de1705786c545cd1bf519d47250322dBen Murdoch            # http://bugs.python.org/issue1731717
224dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if self._proc.poll() is None:
225dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                _log.warning('stopping %s timed out, killing it' %
226dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                             self._name)
22721939df44de1705786c545cd1bf519d47250322dBen Murdoch                self._executive.kill_process(self._proc.pid)
228dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                _log.warning('killed')
229dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        self._reset()
230