15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Copyright (C) 2010 Google Inc. All rights reserved.
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Redistribution and use in source and binary forms, with or without
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# modification, are permitted provided that the following conditions are
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# met:
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Redistributions of source code must retain the above copyright
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# notice, this list of conditions and the following disclaimer.
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Redistributions in binary form must reproduce the above
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# copyright notice, this list of conditions and the following disclaimer
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# in the documentation and/or other materials provided with the
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# distribution.
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Neither the Google name nor the names of its
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# contributors may be used to endorse or promote products derived from
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# this software without specific prior written permission.
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)"""Package that implements the ServerProcess wrapper class"""
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import errno
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import logging
33e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)import re
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import signal
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import sys
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import time
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Note that although win32 python does provide an implementation of
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# the win32 select API, it only works on sockets, and not on the named pipes
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# used by subprocess, so we have to use the native APIs directly.
41e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)_quote_cmd = None
42e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)if sys.platform == 'win32':
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    import msvcrt
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    import win32pipe
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    import win32file
47e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    import subprocess
48e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    _quote_cmd = subprocess.list2cmdline
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)else:
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    import fcntl
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    import os
52e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    import pipes
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    import select
54e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    _quote_cmd = lambda cmdline: ' '.join(pipes.quote(arg) for arg in cmdline)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.common.system.executive import ScriptError
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_log = logging.getLogger(__name__)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
62e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)_trailing_spaces_re = re.compile('(.*[^ ])?( +)$')
63e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)
64e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)
65e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)def quote_data(data):
66e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    txt = repr(data).replace('\\n', '\\n\n')[1:-1]
67e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    lines = []
68e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    for l in txt.splitlines():
69e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)        m = _trailing_spaces_re.match(l)
70e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)        if m:
71e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            l = m.group(1) + m.group(2).replace(' ', '\x20')
72e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)        lines.append(l)
73e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    return lines
74e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class ServerProcess(object):
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    """This class provides a wrapper around a subprocess that
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    implements a simple request/response usage model. The primary benefit
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    is that reading responses takes a deadline, so that we don't ever block
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    indefinitely. The class also handles transparently restarting processes
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    as necessary to keep issuing commands."""
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
82e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    def __init__(self, port_obj, name, cmd, env=None, universal_newlines=False, treat_no_data_as_crash=False,
83e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)                 logging=False):
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._port = port_obj
85f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)        self._name = name  # Should be the command name (e.g. content_shell, image_diff)
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._cmd = cmd
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._env = env
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Set if the process outputs non-standard newlines like '\r\n' or '\r'.
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # Don't set if there will be binary data or the data must be ASCII encoded.
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._universal_newlines = universal_newlines
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._treat_no_data_as_crash = treat_no_data_as_crash
92e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)        self._logging = logging
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._host = self._port.host
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._pid = None
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._reset()
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # See comment in imports for why we need the win32 APIs and can't just use select.
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # FIXME: there should be a way to get win32 vs. cygwin from platforminfo.
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._use_win32_apis = sys.platform == 'win32'
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def name(self):
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._name
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def pid(self):
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._pid
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _reset(self):
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if getattr(self, '_proc', None):
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self._proc.stdin:
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._proc.stdin.close()
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._proc.stdin = None
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self._proc.stdout:
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._proc.stdout.close()
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._proc.stdout = None
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self._proc.stderr:
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._proc.stderr.close()
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._proc.stderr = None
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._proc = None
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._output = str()  # bytesarray() once we require Python 2.6
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._error = str()  # bytesarray() once we require Python 2.6
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._crashed = False
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.timed_out = False
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def process_name(self):
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._name
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _start(self):
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._proc:
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            raise ValueError("%s already running" % self._name)
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._reset()
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # close_fds is a workaround for http://bugs.python.org/issue2320
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        close_fds = not self._host.platform.is_win()
134e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)        if self._logging:
135e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            env_str = ''
136e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            if self._env:
137e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)                env_str += '\n'.join("%s=%s" % (k, v) for k, v in self._env.items()) + '\n'
138e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            _log.info('CMD: \n%s%s\n', env_str, _quote_cmd(self._cmd))
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._proc = self._host.executive.popen(self._cmd, stdin=self._host.executive.PIPE,
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            stdout=self._host.executive.PIPE,
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            stderr=self._host.executive.PIPE,
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            close_fds=close_fds,
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            env=self._env,
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            universal_newlines=self._universal_newlines)
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._pid = self._proc.pid
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        fd = self._proc.stdout.fileno()
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if not self._use_win32_apis:
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fl = fcntl.fcntl(fd, fcntl.F_GETFL)
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fd = self._proc.stderr.fileno()
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fl = fcntl.fcntl(fd, fcntl.F_GETFL)
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _handle_possible_interrupt(self):
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """This routine checks to see if the process crashed or exited
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        because of a keyboard interrupt and raises KeyboardInterrupt
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        accordingly."""
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # FIXME: Linux and Mac set the returncode to -signal.SIGINT if a
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # subprocess is killed with a ctrl^C.  Previous comments in this
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # routine said that supposedly Windows returns 0xc000001d, but that's not what
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # -1073741510 evaluates to. Figure out what the right value is
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # for win32 and cygwin here ...
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._proc.returncode in (-1073741510, -signal.SIGINT):
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            raise KeyboardInterrupt
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def poll(self):
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Check to see if the underlying process is running; returns None
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if it still is (wrapper around subprocess.poll)."""
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._proc:
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return self._proc.poll()
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return None
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def write(self, bytes):
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        """Write a request to the subprocess. The subprocess is (re-)start()'ed
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if is not already running."""
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if not self._proc:
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._start()
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try:
179e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            self._log_data(' IN', bytes)
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._proc.stdin.write(bytes)
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        except IOError, e:
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self.stop(0.0)
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # stop() calls _reset(), so we have to set crashed to True after calling stop().
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._crashed = True
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _pop_stdout_line_if_ready(self):
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        index_after_newline = self._output.find('\n') + 1
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if index_after_newline > 0:
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return self._pop_output_bytes(index_after_newline)
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return None
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _pop_stderr_line_if_ready(self):
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        index_after_newline = self._error.find('\n') + 1
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if index_after_newline > 0:
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return self._pop_error_bytes(index_after_newline)
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return None
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def pop_all_buffered_stderr(self):
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._pop_error_bytes(len(self._error))
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def read_stdout_line(self, deadline):
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._read(deadline, self._pop_stdout_line_if_ready)
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def read_stderr_line(self, deadline):
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._read(deadline, self._pop_stderr_line_if_ready)
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def read_either_stdout_or_stderr_line(self, deadline):
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        def retrieve_bytes_from_buffers():
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            stdout_line = self._pop_stdout_line_if_ready()
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if stdout_line:
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return stdout_line, None
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            stderr_line = self._pop_stderr_line_if_ready()
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if stderr_line:
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return None, stderr_line
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return None  # Instructs the caller to keep waiting.
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return_value = self._read(deadline, retrieve_bytes_from_buffers)
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # 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.
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if return_value is None:
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return None, None
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return return_value
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def read_stdout(self, deadline, size):
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if size <= 0:
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            raise ValueError('ServerProcess.read() called with a non-positive size: %d ' % size)
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        def retrieve_bytes_from_stdout_buffer():
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if len(self._output) >= size:
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return self._pop_output_bytes(size)
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return None
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._read(deadline, retrieve_bytes_from_stdout_buffer)
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _log(self, message):
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # This is a bit of a hack, but we first log a blank line to avoid
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # messing up the master process's output.
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        _log.info('')
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        _log.info(message)
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
240e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)    def _log_data(self, prefix, data):
241e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)        if self._logging and data and len(data):
242e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            for line in quote_data(data):
243e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)                _log.info('%s: %s', prefix, line)
244e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _handle_timeout(self):
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.timed_out = True
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._port.sample_process(self._name, self._proc.pid)
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _split_string_after_index(self, string, index):
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return string[:index], string[index:]
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _pop_output_bytes(self, bytes_count):
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        output, self._output = self._split_string_after_index(self._output, bytes_count)
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return output
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _pop_error_bytes(self, bytes_count):
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        output, self._error = self._split_string_after_index(self._error, bytes_count)
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return output
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _wait_for_data_and_update_buffers_using_select(self, deadline, stopping=False):
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._proc.stdout.closed or self._proc.stderr.closed:
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # If the process crashed and is using FIFOs, like Chromium Android, the
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # stdout and stderr pipes will be closed.
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        out_fd = self._proc.stdout.fileno()
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        err_fd = self._proc.stderr.fileno()
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        select_fds = (out_fd, err_fd)
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try:
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            read_fds, _, _ = select.select(select_fds, [], select_fds, max(deadline - time.time(), 0))
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        except select.error, e:
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # We can ignore EINVAL since it's likely the process just crashed and we'll
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # figure that out the next time through the loop in _read().
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if e.args[0] == errno.EINVAL:
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            raise
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try:
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # Note that we may get no data during read() even though
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # select says we got something; see the select() man page
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # on linux. I don't know if this happens on Mac OS and
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # other Unixen as well, but we don't bother special-casing
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # Linux because it's relatively harmless either way.
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if out_fd in read_fds:
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                data = self._proc.stdout.read()
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if not data and not stopping and (self._treat_no_data_as_crash or self._proc.poll()):
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    self._crashed = True
288e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)                self._log_data('OUT', data)
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._output += data
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if err_fd in read_fds:
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                data = self._proc.stderr.read()
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if not data and not stopping and (self._treat_no_data_as_crash or self._proc.poll()):
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    self._crashed = True
295e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)                self._log_data('ERR', data)
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._error += data
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        except IOError, e:
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # We can ignore the IOErrors because we will detect if the subporcess crashed
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # the next time through the loop in _read()
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            pass
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _wait_for_data_and_update_buffers_using_win32_apis(self, deadline):
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # See http://code.activestate.com/recipes/440554-module-to-allow-asynchronous-subprocess-use-on-win/
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # and http://docs.activestate.com/activepython/2.6/pywin32/modules.html
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # for documentation on all of these win32-specific modules.
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        now = time.time()
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        out_fh = msvcrt.get_osfhandle(self._proc.stdout.fileno())
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        err_fh = msvcrt.get_osfhandle(self._proc.stderr.fileno())
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        while (self._proc.poll() is None) and (now < deadline):
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            output = self._non_blocking_read_win32(out_fh)
311e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            self._log_data('OUT', output)
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            error = self._non_blocking_read_win32(err_fh)
313e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            self._log_data('ERR', error)
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if output or error:
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if output:
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    self._output += output
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if error:
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    self._error += error
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            time.sleep(0.01)
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            now = time.time()
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _non_blocking_read_win32(self, handle):
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        try:
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            _, avail, _ = win32pipe.PeekNamedPipe(handle, 0)
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if avail > 0:
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                _, buf = win32file.ReadFile(handle, avail, None)
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return buf
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        except Exception, e:
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if e[0] not in (109, errno.ESHUTDOWN):  # 109 == win32 ERROR_BROKEN_PIPE
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                raise
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return None
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def has_crashed(self):
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if not self._crashed and self.poll():
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._crashed = True
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._handle_possible_interrupt()
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._crashed
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # This read function is a bit oddly-designed, as it polls both stdout and stderr, yet
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # only reads/returns from one of them (buffering both in local self._output/self._error).
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    # It might be cleaner to pass in the file descriptor to poll instead.
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _read(self, deadline, fetch_bytes_from_buffers_callback):
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        while True:
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self.has_crashed():
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return None
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if time.time() > deadline:
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._handle_timeout()
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return None
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            bytes = fetch_bytes_from_buffers_callback()
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if bytes is not None:
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return bytes
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self._use_win32_apis:
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._wait_for_data_and_update_buffers_using_win32_apis(deadline)
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else:
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._wait_for_data_and_update_buffers_using_select(deadline)
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def start(self):
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if not self._proc:
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._start()
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3661e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    def stop(self, timeout_secs=0.0):
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if not self._proc:
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return (None, None)
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        now = time.time()
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._proc.stdin:
372e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)            if self._logging:
373e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)                _log.info(' IN: ^D')
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._proc.stdin.close()
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._proc.stdin = None
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        killed = False
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if timeout_secs:
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            deadline = now + timeout_secs
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            while self._proc.poll() is None and time.time() < deadline:
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                time.sleep(0.01)
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self._proc.poll() is None:
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                _log.warning('stopping %s(pid %d) timed out, killing it' % (self._name, self._proc.pid))
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._proc.poll() is None:
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._kill()
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            killed = True
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            _log.debug('killed pid %d' % self._proc.pid)
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # read any remaining data on the pipes and return it.
3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if not killed:
3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self._use_win32_apis:
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._wait_for_data_and_update_buffers_using_win32_apis(now)
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else:
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                self._wait_for_data_and_update_buffers_using_select(now, stopping=True)
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        out, err = self._output, self._error
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._reset()
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return (out, err)
3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def kill(self):
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.stop(0.0)
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def _kill(self):
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._host.executive.kill_process(self._proc.pid)
4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._proc.poll() is not None:
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._proc.wait()
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def replace_outputs(self, stdout, stderr):
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        assert self._proc
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if stdout:
4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._proc.stdout.close()
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._proc.stdout = stdout
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if stderr:
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._proc.stderr.close()
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._proc.stderr = stderr
415