Title: [220483] trunk/Tools
Revision
220483
Author
jbed...@apple.com
Date
2017-08-09 14:58:18 -0700 (Wed, 09 Aug 2017)

Log Message

Allow nested timeouts in webkitpy
https://bugs.webkit.org/show_bug.cgi?id=175390
<rdar://problem/33803003>

Reviewed by David Kilzer.

We need to be able to nest timeouts in webkitpy. In particular, we have a few cases where functions
which use timeouts also call the executive. For on-device testing, we need to have timeouts inside
the executive to detect and recover from any issues connecting with devices.

* Scripts/webkitpy/benchmark_runner/utils.py:
(TimeoutError): Deleted.
(timeout): Deleted.
* Scripts/webkitpy/common/timeout_context.py: Added.
(Timeout): A timeout context designed to be nested.
(Timeout.TimeoutData): The data required to construct an alarm for a given timeout.
(Timeout.TimeoutData.__init__):
(Timeout.default_handler): Timeout handler used if none is specified.
(Timeout.current): Access data about the most urgent timeout.
(Timeout.__init__): Construct a Timeout object with seconds and an optional handler.
(Timeout._bind_timeout_data_to_alarm): Given data about a timeout, initialize an alarm for that timeout.
(Timeout.__enter__): Un-bind all alarms. Add data for this timeout to the ordered list and bind the most
urgent timeout data.
(Timeout.__exit__): Un-bind all alarms. Remove data for this timeout from the ordered list and bind the
most urgent timeout data, if such data exists.
* Scripts/webkitpy/common/timeout_context_unittest.py: Added.
(TimeoutContextTests):
(TimeoutContextTests.test_current_timeout): Test that accessing the nearest timeout works as expected.
(TimeoutContextTests.test_invalid_timeout): Test a timeout of 0.
(TimeoutContextTests.test_timeout_data): Confirm that timeouts are constructed correctly.
(TimeoutContextTests.test_nested_inner_precedence): Check that a more urgent inner timeout takes precedence
over a less urgent outer timeout.
(TimeoutContextTests.test_nested_outer_precedence): Check that a more urgent outer timeout takes precedence
over a less urgent inner timeout.
(TimeoutContextTests.test_no_timeout): Test a block of code without a timeout.
(TimeoutContextTests.test_basic_timeout): Test a block of code expected to timeout.
(TimeoutContextTests.test_exception_constructor_timeout): Test a timeout where the handler is an exception.
(TimeoutContextTests.test_nested_inner_timeout): Confirm that a more urgent inner timeout is triggered.
(TimeoutContextTests.test_nested_outer_timeout): Confirm that a more urgent outer timeout is triggered.
* Scripts/webkitpy/port/simulator_process.py:
(SimulatorProcess._start): Use Timeout class.
* Scripts/webkitpy/xcode/simulated_device.py:
(SimulatedDevice.launch_app._log_debug_error): Use Timeout class.
(SimulatedDevice.launch_app): Ditto.
(SimulatedDevice.launch_app._install_timeout): Deleted.
* Scripts/webkitpy/xcode/simulator.py:
(Simulator.wait_until_device_is_booted):Use Timeout class.
(Simulator.wait_until_device_is_in_state): Ditto.

Modified Paths

Added Paths

Diff

Modified: trunk/Tools/ChangeLog (220482 => 220483)


--- trunk/Tools/ChangeLog	2017-08-09 21:57:01 UTC (rev 220482)
+++ trunk/Tools/ChangeLog	2017-08-09 21:58:18 UTC (rev 220483)
@@ -1,3 +1,54 @@
+2017-08-09  Jonathan Bedard  <jbed...@apple.com>
+
+        Allow nested timeouts in webkitpy
+        https://bugs.webkit.org/show_bug.cgi?id=175390
+        <rdar://problem/33803003>
+
+        Reviewed by David Kilzer.
+
+        We need to be able to nest timeouts in webkitpy. In particular, we have a few cases where functions
+        which use timeouts also call the executive. For on-device testing, we need to have timeouts inside
+        the executive to detect and recover from any issues connecting with devices.
+
+        * Scripts/webkitpy/benchmark_runner/utils.py:
+        (TimeoutError): Deleted.
+        (timeout): Deleted.
+        * Scripts/webkitpy/common/timeout_context.py: Added.
+        (Timeout): A timeout context designed to be nested.
+        (Timeout.TimeoutData): The data required to construct an alarm for a given timeout.
+        (Timeout.TimeoutData.__init__):
+        (Timeout.default_handler): Timeout handler used if none is specified.
+        (Timeout.current): Access data about the most urgent timeout.
+        (Timeout.__init__): Construct a Timeout object with seconds and an optional handler.
+        (Timeout._bind_timeout_data_to_alarm): Given data about a timeout, initialize an alarm for that timeout.
+        (Timeout.__enter__): Un-bind all alarms. Add data for this timeout to the ordered list and bind the most
+        urgent timeout data.
+        (Timeout.__exit__): Un-bind all alarms. Remove data for this timeout from the ordered list and bind the
+        most urgent timeout data, if such data exists.
+        * Scripts/webkitpy/common/timeout_context_unittest.py: Added.
+        (TimeoutContextTests):
+        (TimeoutContextTests.test_current_timeout): Test that accessing the nearest timeout works as expected.
+        (TimeoutContextTests.test_invalid_timeout): Test a timeout of 0.
+        (TimeoutContextTests.test_timeout_data): Confirm that timeouts are constructed correctly.
+        (TimeoutContextTests.test_nested_inner_precedence): Check that a more urgent inner timeout takes precedence
+        over a less urgent outer timeout.
+        (TimeoutContextTests.test_nested_outer_precedence): Check that a more urgent outer timeout takes precedence
+        over a less urgent inner timeout.
+        (TimeoutContextTests.test_no_timeout): Test a block of code without a timeout.
+        (TimeoutContextTests.test_basic_timeout): Test a block of code expected to timeout.
+        (TimeoutContextTests.test_exception_constructor_timeout): Test a timeout where the handler is an exception.
+        (TimeoutContextTests.test_nested_inner_timeout): Confirm that a more urgent inner timeout is triggered.
+        (TimeoutContextTests.test_nested_outer_timeout): Confirm that a more urgent outer timeout is triggered.
+        * Scripts/webkitpy/port/simulator_process.py:
+        (SimulatorProcess._start): Use Timeout class.
+        * Scripts/webkitpy/xcode/simulated_device.py:
+        (SimulatedDevice.launch_app._log_debug_error): Use Timeout class.
+        (SimulatedDevice.launch_app): Ditto.
+        (SimulatedDevice.launch_app._install_timeout): Deleted.
+        * Scripts/webkitpy/xcode/simulator.py:
+        (Simulator.wait_until_device_is_booted):Use Timeout class.
+        (Simulator.wait_until_device_is_in_state): Ditto.
+
 2017-08-09  Wenson Hsieh  <wenson_hs...@apple.com>
 
         [iOS DnD] ENABLE_DRAG_SUPPORT should be turned off for iOS 10 and enabled by default

Modified: trunk/Tools/Scripts/webkitpy/benchmark_runner/utils.py (220482 => 220483)


--- trunk/Tools/Scripts/webkitpy/benchmark_runner/utils.py	2017-08-09 21:57:01 UTC (rev 220482)
+++ trunk/Tools/Scripts/webkitpy/benchmark_runner/utils.py	2017-08-09 21:58:18 UTC (rev 220483)
@@ -4,9 +4,7 @@
 import inspect
 import logging
 import os
-import signal
 import shutil
-import sys
 
 from webkitpy.common.memoized import memoized
 
@@ -77,26 +75,3 @@
     defaults.setPersistentDomain_forName_(mutable_defaults_for_domain, domain)
     defaults.synchronize()
     return True
-
-
-# Borrow this code from
-# 'http://stackoverflow.com/questions/2281850/timeout-function-if-it-takes-too-long-to-finish'
-class TimeoutError(Exception):
-    pass
-
-
-class timeout:
-
-    def __init__(self, seconds=1, error_message='Timeout'):
-        self.seconds = seconds
-        self.error_message = error_message
-
-    def handle_timeout(self, signum, frame):
-        raise TimeoutError(self.error_message)
-
-    def __enter__(self):
-        signal.signal(signal.SIGALRM, self.handle_timeout)
-        signal.alarm(self.seconds)
-
-    def __exit__(self, type, value, traceback):
-        signal.alarm(0)

Added: trunk/Tools/Scripts/webkitpy/common/timeout_context.py (0 => 220483)


--- trunk/Tools/Scripts/webkitpy/common/timeout_context.py	                        (rev 0)
+++ trunk/Tools/Scripts/webkitpy/common/timeout_context.py	2017-08-09 21:58:18 UTC (rev 220483)
@@ -0,0 +1,119 @@
+# Copyright (C) 2017 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+import math
+import os
+import signal
+import time
+import threading
+
+_log = logging.getLogger(__name__)
+
+
+class Timeout(object):
+
+    thread_exception = RuntimeError('Timeout originates from a different thread')
+    _process_to_timeout_map = {}
+
+    class TimeoutData(object):
+
+        def __init__(self, alarm_time, handler):
+            self.alarm_time = alarm_time
+            self.handler = handler
+            self.thread_id = threading.current_thread().ident
+
+    @staticmethod
+    def default_handler(signum, frame):
+        raise RuntimeError('Timeout alarm was triggered')
+
+    @staticmethod
+    def current():
+        result = Timeout._process_to_timeout_map.get(os.getpid(), [])
+        if not result:
+            return None
+        if result[0].thread_id != threading.current_thread().ident:
+            _log.critical('Using both alarms and threading in the same process, this is unsupported')
+            raise Timeout.thread_exception
+        return result[0]
+
+    def __init__(self, seconds=1, handler=None):
+        if seconds == 0:
+            raise RuntimeError('Cannot have a timeout of 0 seconds')
+
+        if isinstance(handler, BaseException):
+            exception = handler
+
+            def exception_handler(signum, frame):
+                raise exception
+
+            handler = exception_handler
+
+        self._timeout = seconds
+        self._handler = handler if handler else Timeout.default_handler
+        self.data = ""
+
+    @staticmethod
+    def _bind_timeout_data_to_alarm(data):
+        def handler(signum, frame):
+            assert signum == signal.SIGALRM
+            if data.thread_id != threading.current_thread().ident:
+                raise Timeout.thread_exception
+            data.handler(signum, frame)
+
+        current_time = time.time()
+        if data.alarm_time <= current_time:
+            handler(signal.SIGALRM, None)
+
+        signal.signal(signal.SIGALRM, handler)
+        signal.alarm(int(math.ceil(data.alarm_time - current_time)))
+
+    def __enter__(self):
+        signal.alarm(0)  # Imiediatly disable the alarm so we aren't interupted.
+        self.data = "" + self._timeout, self._handler)
+        current_timeout = Timeout.current()
+
+        # Another timeout is more urgent.
+        if current_timeout and current_timeout.alarm_time < self.data.alarm_time:
+            for i in xrange(len(Timeout._process_to_timeout_map[os.getpid()]) - 1):
+                if self.data.alarm_time < Timeout._process_to_timeout_map[os.getpid()][i + 1].alarm_time:
+                    Timeout._process_to_timeout_map[os.getpid()].insert(i, self.data)
+                    break
+            Timeout._process_to_timeout_map[os.getpid()].append(self.data)
+
+        # This is the most urgent timeout
+        else:
+            Timeout._process_to_timeout_map[os.getpid()] = [self.data] + Timeout._process_to_timeout_map.get(os.getpid(), [])
+
+        Timeout._bind_timeout_data_to_alarm(Timeout.current())
+        return self
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        signal.alarm(0)  # Imiediatly disable the alarm so we aren't interupted.
+
+        if not Timeout._process_to_timeout_map[os.getpid()]:
+            raise RuntimeError('No timeout registered')
+        Timeout._process_to_timeout_map[os.getpid()].remove(self.data)
+        self.data = ""
+
+        if Timeout._process_to_timeout_map[os.getpid()]:
+            Timeout._bind_timeout_data_to_alarm(Timeout.current())

Added: trunk/Tools/Scripts/webkitpy/common/timeout_context_unittest.py (0 => 220483)


--- trunk/Tools/Scripts/webkitpy/common/timeout_context_unittest.py	                        (rev 0)
+++ trunk/Tools/Scripts/webkitpy/common/timeout_context_unittest.py	2017-08-09 21:58:18 UTC (rev 220483)
@@ -0,0 +1,98 @@
+# Copyright (C) 2017 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import time
+import threading
+import unittest
+
+from webkitpy.common.timeout_context import Timeout
+
+
+class TimeoutContextTests(unittest.TestCase):
+
+    def test_current_timeout(self):
+        self.assertEqual(None, Timeout.current())
+        with Timeout(1) as tmp:
+            self.assertEqual(tmp.data, Timeout.current())
+        self.assertEqual(None, Timeout.current())
+
+    def test_invalid_timeout(self):
+        self.assertRaises(RuntimeError, Timeout, 0)
+
+    def test_timeout_data(self):
+        tmp = Timeout(1)
+        self.assertEqual(None, tmp.data)
+        with tmp:
+            self.assertNotEqual(None, tmp.data)
+            self.assertEqual(threading.current_thread().ident, tmp.data.thread_id)
+            self.assertGreater(time.time() + 1, tmp.data.alarm_time)
+        self.assertEqual(None, tmp.data)
+
+    def test_nested_inner_precedence(self):
+        tmp_outer = Timeout(2)
+        tmp_inner = Timeout(1)
+        with tmp_outer:
+            self.assertEqual(tmp_outer.data, Timeout.current())
+            with tmp_inner:
+                self.assertEqual(tmp_inner.data, Timeout.current())
+            self.assertEqual(tmp_outer.data, Timeout.current())
+        self.assertEqual(None, Timeout.current())
+
+    def test_nested_outer_precedence(self):
+        tmp_outer = Timeout(1)
+        tmp_inner = Timeout(2)
+        with tmp_outer:
+            self.assertEqual(tmp_outer.data, Timeout.current())
+            with tmp_inner:
+                self.assertEqual(tmp_outer.data, Timeout.current())
+            self.assertEqual(tmp_outer.data, Timeout.current())
+        self.assertEqual(None, Timeout.current())
+
+    def test_no_timeout(self):
+        with Timeout(2):
+            time.sleep(1)
+
+    def test_basic_timeout(self):
+        def should_timeout():
+            with Timeout(1):
+                time.sleep(2)
+        self.assertRaises(RuntimeError, should_timeout)
+
+    def test_exception_constructor_timeout(self):
+        def should_timeout():
+            with Timeout(1, Exception('This should be raised')):
+                time.sleep(2)
+        self.assertRaises(Exception, should_timeout)
+
+    def test_nested_inner_timeout(self):
+        def should_timeout():
+            with Timeout(3, Exception("This shouldn't be raised")):
+                with Timeout(1):
+                    time.sleep(2)
+        self.assertRaises(RuntimeError, should_timeout)
+
+    def test_nested_outer_timeout(self):
+        def should_timeout():
+            with Timeout(1):
+                with Timeout(3, Exception("This shouldn't be raised")):
+                    time.sleep(2)
+        self.assertRaises(RuntimeError, should_timeout)

Modified: trunk/Tools/Scripts/webkitpy/port/simulator_process.py (220482 => 220483)


--- trunk/Tools/Scripts/webkitpy/port/simulator_process.py	2017-08-09 21:57:01 UTC (rev 220482)
+++ trunk/Tools/Scripts/webkitpy/port/simulator_process.py	2017-08-09 21:58:18 UTC (rev 220483)
@@ -22,12 +22,11 @@
 
 
 import os
-import signal
 import time
 
+from webkitpy.common.timeout_context import Timeout
 from webkitpy.port.server_process import ServerProcess
 
-
 class SimulatorProcess(ServerProcess):
 
     class Popen(object):
@@ -95,30 +94,24 @@
         self._target_host.listening_socket.listen(3)
         self._pid = self._target_host.launch_app(self._bundle_id, self._cmd[1:], env=self._env)
 
-        def handler(signum, frame):
-            assert signum == signal.SIGALRM
-            raise RuntimeError('Timed out waiting for pid {} to connect at port {}'.format(self._pid, self._target_host.listening_port()))
-        signal.signal(signal.SIGALRM, handler)
-        signal.alarm(6)  # In seconds
-
-        stdin = None
-        stdout = None
-        stderr = None
-        try:
-            # This order matches the client side connections in Tools/TestRunnerShared/IOSLayoutTestCommunication.cpp setUpIOSLayoutTestCommunication()
-            stdin = SimulatorProcess._accept_connection_create_file(self._target_host.listening_socket, 'w')
-            stdout = SimulatorProcess._accept_connection_create_file(self._target_host.listening_socket, 'rb')
-            stderr = SimulatorProcess._accept_connection_create_file(self._target_host.listening_socket, 'rb')
-        except:
-            # We set self._proc as _reset() and _kill() depend on it.
-            self._proc = SimulatorProcess.Popen(self._pid, stdin, stdout, stderr, self._target_host)
-            if self._proc.poll() is not None:
+        with Timeout(6, RuntimeError('Timed out waiting for pid {} to connect at port {}'.format(self._pid, self._target_host.listening_port()))):
+            stdin = None
+            stdout = None
+            stderr = None
+            try:
+                # This order matches the client side connections in Tools/TestRunnerShared/IOSLayoutTestCommunication.cpp setUpIOSLayoutTestCommunication()
+                stdin = SimulatorProcess._accept_connection_create_file(self._target_host.listening_socket, 'w')
+                stdout = SimulatorProcess._accept_connection_create_file(self._target_host.listening_socket, 'rb')
+                stderr = SimulatorProcess._accept_connection_create_file(self._target_host.listening_socket, 'rb')
+            except:
+                # We set self._proc as _reset() and _kill() depend on it.
+                self._proc = SimulatorProcess.Popen(self._pid, stdin, stdout, stderr, self._target_host)
+                if self._proc.poll() is not None:
+                    self._reset()
+                    raise Exception('App {} with pid {} crashed before stdin could be attached'.format(os.path.basename(self._cmd[0]), self._pid))
+                self._kill()
                 self._reset()
-                raise Exception('App {} with pid {} crashed before stdin could be attached'.format(os.path.basename(self._cmd[0]), self._pid))
-            self._kill()
-            self._reset()
-            raise
-        signal.alarm(0)  # Cancel alarm
+                raise
 
         self._proc = SimulatorProcess.Popen(self._pid, stdin, stdout, stderr, self._target_host)
 

Modified: trunk/Tools/Scripts/webkitpy/xcode/simulated_device.py (220482 => 220483)


--- trunk/Tools/Scripts/webkitpy/xcode/simulated_device.py	2017-08-09 21:57:01 UTC (rev 220482)
+++ trunk/Tools/Scripts/webkitpy/xcode/simulated_device.py	2017-08-09 21:58:18 UTC (rev 220483)
@@ -22,12 +22,12 @@
 
 import logging
 import re
-import signal
 import subprocess
 
+from webkitpy.common.host import Host
 from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.timeout_context import Timeout
 from webkitpy.xcode.simulator import Simulator
-from webkitpy.common.host import Host
 
 _log = logging.getLogger(__name__)
 
@@ -170,29 +170,23 @@
         def _log_debug_error(error):
             _log.debug(error.message_with_output())
 
-        def _install_timeout(signum, frame):
-            assert signum == signal.SIGALRM
-            raise RuntimeError('Timed out waiting for process to open {} on {}'.format(bundle_id, self.udid))
-
         output = None
-        signal.signal(signal.SIGALRM, _install_timeout)
-        signal.alarm(timeout)  # In seconds
-        while True:
-            output = self._host.executive.run_command(
-                ['xcrun', 'simctl', 'launch', self.udid, bundle_id] + args,
-                env=environment_to_use,
-                error_handler=_log_debug_error,
-            )
-            match = re.match(r'(?P<bundle>[^:]+): (?P<pid>\d+)\n', output)
-            # FIXME: We shouldn't need to check the PID <rdar://problem/31154075>.
-            if match and self.executive.check_running_pid(int(match.group('pid'))):
-                break
-            if match:
-                _log.debug('simctl launch reported pid {}, but this process is not running'.format(match.group('pid')))
-            else:
-                _log.debug('simctl launch did not report a pid')
 
-        signal.alarm(0)  # Cancel alarm
+        with Timeout(timeout, RuntimeError('Timed out waiting for process to open {} on {}'.format(bundle_id, self.udid))):
+            while True:
+                output = self._host.executive.run_command(
+                    ['xcrun', 'simctl', 'launch', self.udid, bundle_id] + args,
+                    env=environment_to_use,
+                    error_handler=_log_debug_error,
+                )
+                match = re.match(r'(?P<bundle>[^:]+): (?P<pid>\d+)\n', output)
+                # FIXME: We shouldn't need to check the PID <rdar://problem/31154075>.
+                if match and self.executive.check_running_pid(int(match.group('pid'))):
+                    break
+                if match:
+                    _log.debug('simctl launch reported pid {}, but this process is not running'.format(match.group('pid')))
+                else:
+                    _log.debug('simctl launch did not report a pid')
 
         if match.group('bundle') != bundle_id:
             raise RuntimeError('Failed to find process id for {}: {}'.format(bundle_id, output))

Modified: trunk/Tools/Scripts/webkitpy/xcode/simulator.py (220482 => 220483)


--- trunk/Tools/Scripts/webkitpy/xcode/simulator.py	2017-08-09 21:57:01 UTC (rev 220482)
+++ trunk/Tools/Scripts/webkitpy/xcode/simulator.py	2017-08-09 21:58:18 UTC (rev 220483)
@@ -28,7 +28,7 @@
 import subprocess
 import time
 
-from webkitpy.benchmark_runner.utils import timeout
+from webkitpy.common.timeout_context import Timeout
 from webkitpy.common.host import Host
 
 _log = logging.getLogger(__name__)
@@ -242,7 +242,7 @@
     @staticmethod
     def wait_until_device_is_booted(udid, timeout_seconds=60 * 15):
         Simulator.wait_until_device_is_in_state(udid, Simulator.DeviceState.BOOTED, timeout_seconds)
-        with timeout(seconds=timeout_seconds):
+        with Timeout(seconds=timeout_seconds):
             while True:
                 try:
                     state = subprocess.check_output(['xcrun', 'simctl', 'spawn', udid, 'launchctl', 'print', 'system']).strip()
@@ -260,7 +260,7 @@
     @staticmethod
     def wait_until_device_is_in_state(udid, wait_until_state, timeout_seconds=60 * 15):
         _log.debug('waiting for device %s to enter state %s with timeout %s', udid, Simulator.device_state_description(wait_until_state), timeout_seconds)
-        with timeout(seconds=timeout_seconds):
+        with Timeout(seconds=timeout_seconds):
             device_state = Simulator.device_state(udid)
             while (device_state != wait_until_state):
                 device_state = Simulator.device_state(udid)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to