Changeset 115903 in webkit


Ignore:
Timestamp:
May 2, 2012 4:05:52 PM (12 years ago)
Author:
dpranke@chromium.org
Message:

nrwt: make ServerProcess work on chromium win
https://bugs.webkit.org/show_bug.cgi?id=85333

Reviewed by Ojan Vafai.

This change implements a poor man's select() that will
slow-spin doing non-blocking reads on the stdout and stderr
named pipes connecting the worker to the driver. Seems to work
and I have yet to see much overhead or ill effects but it
probably needs more testing.

  • Scripts/webkitpy/layout_tests/port/chromium.py:

(ChromiumDriver.init):

  • Scripts/webkitpy/layout_tests/port/server_process.py:

(ServerProcess._start):
(ServerProcess._wait_for_data_and_update_buffers_using_select):
(ServerProcess._wait_for_data_and_update_buffers_using_win32_apis):
(ServerProcess):
(ServerProcess._non_blocking_read_win32):
(ServerProcess._read):

  • Scripts/webkitpy/layout_tests/port/server_process_unittest.py:

(TestServerProcess.test_basic): Added.

Location:
trunk/Tools
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r115900 r115903  
     12012-05-02  Dirk Pranke  <dpranke@chromium.org>
     2
     3        nrwt: make ServerProcess work on chromium win
     4        https://bugs.webkit.org/show_bug.cgi?id=85333
     5
     6        Reviewed by Ojan Vafai.
     7
     8        This change implements a poor man's select() that will
     9        slow-spin doing non-blocking reads on the stdout and stderr
     10        named pipes connecting the worker to the driver. Seems to work
     11        and I have yet to see much overhead or ill effects but it
     12        probably needs more testing.
     13
     14        * Scripts/webkitpy/layout_tests/port/chromium.py:
     15        (ChromiumDriver.__init__):
     16        * Scripts/webkitpy/layout_tests/port/server_process.py:
     17        (ServerProcess._start):
     18        (ServerProcess._wait_for_data_and_update_buffers_using_select):
     19        (ServerProcess._wait_for_data_and_update_buffers_using_win32_apis):
     20        (ServerProcess):
     21        (ServerProcess._non_blocking_read_win32):
     22        (ServerProcess._read):
     23        * Scripts/webkitpy/layout_tests/port/server_process_unittest.py:
     24        (TestServerProcess.test_basic): Added.
     25
    1262012-05-02  Raphael Kubo da Costa  <rakuco@webkit.org>
    227
  • trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium.py

    r115490 r115903  
    413413        self._image_path = None
    414414
    415         # FIXME: Make the regular webkit driver work on win as well so we can delete all of this driver code.
    416         if port.host.platform.is_win():
    417             if not hasattr(port._options, 'additional_drt_flag'):
    418                 port._options.additional_drt_flag = []
    419             if not '--test-shell' in port._options.additional_drt_flag:
    420                 port._options.additional_drt_flag.append('--test-shell')
    421 
     415        # FIXME: Delete all of this driver code once we're satisfied that it's not needed any more.
    422416        self._test_shell = '--test-shell' in port.get_option('additional_drt_flag', [])
    423417
  • trunk/Tools/Scripts/webkitpy/layout_tests/port/server_process.py

    r115377 r115903  
    3131
    3232import logging
    33 import os
    34 import select
    3533import signal
    3634import subprocess
    3735import sys
    3836import time
    39 if sys.platform != 'win32':
     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.
     41if sys.platform == 'win32':
     42    import errno
     43    import msvcrt
     44    import win32pipe
     45    import win32file
     46else:
    4047    import fcntl
     48    import os
     49    import select
    4150
    4251from webkitpy.common.system.executive import Executive, ScriptError
     
    4655
    4756
    48 class ServerProcess:
     57class ServerProcess(object):
    4958    """This class provides a wrapper around a subprocess that
    5059    implements a simple request/response usage model. The primary benefit
     
    6069        self._reset()
    6170        self._executive = executive
     71
     72        # See comment in imports for why we need the win32 APIs and can't just use select.
     73        # FIXME: there should be a way to get win32 vs. cygwin from platforminfo.
     74        self._use_win32_apis = sys.platform == 'win32'
    6275
    6376    def name(self):
     
    89102                                      env=self._env)
    90103        fd = self._proc.stdout.fileno()
    91         fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    92         fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
    93         fd = self._proc.stderr.fileno()
    94         fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    95         fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
     104        if not self._use_win32_apis:
     105            fl = fcntl.fcntl(fd, fcntl.F_GETFL)
     106            fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
     107            fd = self._proc.stderr.fileno()
     108            fl = fcntl.fcntl(fd, fcntl.F_GETFL)
     109            fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
    96110
    97111    def _handle_possible_interrupt(self):
     
    196210        return output
    197211
    198     def _wait_for_data_and_update_buffers(self, deadline):
     212    def _wait_for_data_and_update_buffers_using_select(self, deadline):
    199213        out_fd = self._proc.stdout.fileno()
    200214        err_fd = self._proc.stderr.fileno()
     
    210224            pass
    211225
     226    def _wait_for_data_and_update_buffers_using_win32_apis(self, deadline):
     227        # See http://code.activestate.com/recipes/440554-module-to-allow-asynchronous-subprocess-use-on-win/
     228        # and http://docs.activestate.com/activepython/2.6/pywin32/modules.html
     229        # for documentation on all of these win32-specific modules.
     230        now = time.time()
     231        out_fh = msvcrt.get_osfhandle(self._proc.stdout.fileno())
     232        err_fh = msvcrt.get_osfhandle(self._proc.stderr.fileno())
     233        while (self._proc.poll() is None) and (now < deadline):
     234            output = self._non_blocking_read_win32(out_fh)
     235            error = self._non_blocking_read_win32(err_fh)
     236            if output or error:
     237                if output:
     238                    self._output += output
     239                if error:
     240                    self._error += error
     241                return
     242            time.sleep(0.01)
     243            now = time.time()
     244        return
     245
     246    def _non_blocking_read_win32(self, handle):
     247        try:
     248            _, avail, _ = win32pipe.PeekNamedPipe(handle, 0)
     249            if avail > 0:
     250                _, buf = win32file.ReadFile(handle, avail, None)
     251                return buf
     252        except Exception, e:
     253            if e[0] not in (109, errno.ESHUTDOWN):  # 109 == win32 ERROR_BROKEN_PIPE
     254                raise
     255        return None
     256
    212257    def has_crashed(self):
    213258        if not self._crashed and self.poll():
     
    232277                return bytes
    233278
    234             self._wait_for_data_and_update_buffers(deadline)
     279            if self._use_win32_apis:
     280                self._wait_for_data_and_update_buffers_using_win32_apis(deadline)
     281            else:
     282                self._wait_for_data_and_update_buffers_using_select(deadline)
    235283
    236284    def start(self):
  • trunk/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py

    r115377 r115903  
    2828
    2929import sys
     30import time
    3031import unittest
    3132
     33from webkitpy.layout_tests.port.factory import PortFactory
    3234from webkitpy.layout_tests.port import server_process
    3335from webkitpy.common.system.executive import ScriptError
    3436from webkitpy.common.system.executive_mock import MockExecutive2
     37from webkitpy.common.system.systemhost import SystemHost
    3538from webkitpy.common.system.outputcapture import OutputCapture
    3639
     
    7982
    8083class TestServerProcess(unittest.TestCase):
     84    def test_basic(self):
     85        cmd = [sys.executable, '-c', 'import sys; import time; time.sleep(0.02); print "stdout"; sys.stdout.flush(); print >>sys.stderr, "stderr"']
     86        host = SystemHost()
     87        factory = PortFactory(host)
     88        port = factory.get()
     89        now = time.time()
     90        proc = server_process.ServerProcess(port, 'python', cmd)
     91        proc.write('')
     92
     93        self.assertEquals(proc.poll(), None)
     94        self.assertFalse(proc.has_crashed())
     95
     96        # check that doing a read after an expired deadline returns
     97        # nothing immediately.
     98        line = proc.read_stdout_line(now - 1)
     99        self.assertEquals(line, None)
     100
     101        line = proc.read_stdout_line(now + 1.0)
     102        self.assertEquals(line.strip(), "stdout")
     103
     104        line = proc.read_stderr_line(now + 1.0)
     105        self.assertEquals(line.strip(), "stderr")
     106
     107        proc.stop()
     108
    81109    def test_broken_pipe(self):
    82110        server_process = FakeServerProcess(port_obj=TrivialMockPort(), name="test", cmd=["test"])
Note: See TracChangeset for help on using the changeset viewer.