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