Changeset 265942 in webkit
- Timestamp:
- Aug 20, 2020, 7:33:58 AM (4 years ago)
- Location:
- trunk/Tools
- Files:
-
- 2 added
- 1 deleted
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r265916 r265942 1 2020-08-20 Jonathan Bedard <jbedard@apple.com> 2 3 [webkitcorepy] Move Timeout to webkitcorepy (Part 1) 4 https://bugs.webkit.org/show_bug.cgi?id=215584 5 <rdar://problem/67270713> 6 7 Reviewed by Darin Adler and Dewei Zhu. 8 9 The Timeout class is a generally useful Python utility, it should not live inside webkitpy. 10 11 * Scripts/libraries/webkitcorepy/README.md: Document Timeout object. 12 * Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py: Expose Timeout object API, increment version. 13 * Scripts/libraries/webkitcorepy/webkitcorepy/mocks/time_.py: 14 (_MetaTime.__enter__): Replace timeout.py's ORIGINAL_SLEEP variable to speed up testing. 15 * Scripts/libraries/webkitcorepy/webkitcorepy/tests/timeout_unittest.py: Added. 16 (TimeoutTests): Added. 17 * Scripts/libraries/webkitcorepy/webkitcorepy/timeout.py: Added. 18 (Timeout): Class representing a stackable Timeout context. 19 (Timeout.Data): Class containing information about a specific deadline. 20 (Timeout.Exception): Exception belonging to the Timeout object. 21 (Timeout.DisableAlarm): For some block of code, disable Timeout alarms. This is useful because many APIs (such as 22 subprocess.run) define their own timeouts which do better cleanup than an interrupt would. 23 (Timeout.default_handler): Default Timeout handler which raises an exception. 24 (Timeout.current): Return the current Timeout.Data class, if one exists. 25 (Timeout.deadline): Return the closest deadline, if one exists. 26 (Timeout.difference): Return the number of seconds between the current time and the closest deadline. 27 (Timeout.check): Check if we have surpassed the closest deadline., raise an exception if we have. 28 (Timeout.bind): Create a signal based on the closest deadline. 29 (Timeout.sleep): Override the sleep function because if we ever request a sleep that is greater than the closest deadline, 30 we should imiediately trigger the timeout logic without waiting for the timeout to actually expire. 31 (Timeout.__init__): Create a Timeout context, 1 second by default. 32 (Timeout.__enter__): 33 (Timeout.__exit__): 34 * Scripts/webkitpy/common/timeout_context.py: 35 (Timeout): Moved to webkitcorepy. 36 1 37 2020-08-19 Kate Cheney <katherine_cheney@apple.com> 2 38 -
trunk/Tools/Scripts/libraries/webkitcorepy/README.md
r265769 r265942 58 58 assert capturer.stdout.getvalue() == 'data\n' 59 59 ``` 60 61 Timeout context: 62 ``` 63 import time 64 65 from webkitcorepy import Timeout 66 67 with Timeout(5, handler=RuntimeError('Exceeded 5 second timeout')): 68 time.sleep(4) 69 ``` -
trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py
r265885 r265942 33 33 from webkitcorepy.string_utils import BytesIO, StringIO, UnicodeIO, unicode 34 34 from webkitcorepy.output_capture import LoggerCapture, OutputCapture, OutputDuplicate 35 from webkitcorepy.timeout import Timeout 35 36 36 version = Version(0, 2, 9)37 version = Version(0, 2, 10) 37 38 38 39 from webkitcorepy.autoinstall import Package, AutoInstall -
trunk/Tools/Scripts/libraries/webkitcorepy/webkitcorepy/mocks/time_.py
r265386 r265942 55 55 patch('time.sleep', new=sleep_func), 56 56 patch('datetime.datetime', new=FakeDateTime), 57 patch('webkitcorepy.timeout.ORIGINAL_SLEEP', new=sleep_func), 57 58 ]) 58 59 -
trunk/Tools/Scripts/webkitpy/common/timeout_context.py
r251955 r265942 1 # Copyright (C) 20 17Apple Inc. All rights reserved.1 # Copyright (C) 2020 Apple Inc. All rights reserved. 2 2 # 3 3 # Redistribution and use in source and binary forms, with or without … … 21 21 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 22 23 import logging 24 import math 25 import os 26 import signal 27 import time 28 import threading 29 30 _log = logging.getLogger(__name__) 31 32 33 class Timeout(object): 34 35 thread_exception = RuntimeError('Timeout originates from a different thread') 36 _process_to_timeout_map = {} 37 38 class TimeoutData(object): 39 40 def __init__(self, alarm_time, handler): 41 self.alarm_time = alarm_time 42 self.handler = handler 43 self.thread_id = threading.current_thread().ident 44 45 @staticmethod 46 def default_handler(signum, frame): 47 raise RuntimeError('Timeout alarm was triggered') 48 49 @staticmethod 50 def current(): 51 result = Timeout._process_to_timeout_map.get(os.getpid(), []) 52 if not result: 53 return None 54 if result[0].thread_id != threading.current_thread().ident: 55 _log.critical('Using both alarms and threading in the same process, this is unsupported') 56 raise Timeout.thread_exception 57 return result[0] 58 59 def __init__(self, seconds=1, handler=None): 60 if seconds == 0: 61 raise RuntimeError('Cannot have a timeout of 0 seconds') 62 63 if isinstance(handler, BaseException): 64 exception = handler 65 66 def exception_handler(signum, frame): 67 raise exception 68 69 handler = exception_handler 70 71 self._timeout = seconds 72 self._handler = handler if handler else Timeout.default_handler 73 self.data = None 74 75 @staticmethod 76 def _bind_timeout_data_to_alarm(data): 77 def handler(signum, frame): 78 assert signum == signal.SIGALRM 79 if data.thread_id != threading.current_thread().ident: 80 raise Timeout.thread_exception 81 data.handler(signum, frame) 82 83 current_time = time.time() 84 if data.alarm_time <= current_time: 85 handler(signal.SIGALRM, None) 86 87 signal.signal(signal.SIGALRM, handler) 88 signal.alarm(int(math.ceil(data.alarm_time - current_time))) 89 90 def __enter__(self): 91 signal.alarm(0) # Imiediatly disable the alarm so we aren't interupted. 92 self.data = Timeout.TimeoutData(time.time() + self._timeout, self._handler) 93 current_timeout = Timeout.current() 94 95 # Another timeout is more urgent. 96 if current_timeout and current_timeout.alarm_time < self.data.alarm_time: 97 for i in range(len(Timeout._process_to_timeout_map[os.getpid()]) - 1): 98 if self.data.alarm_time < Timeout._process_to_timeout_map[os.getpid()][i + 1].alarm_time: 99 Timeout._process_to_timeout_map[os.getpid()].insert(i, self.data) 100 break 101 Timeout._process_to_timeout_map[os.getpid()].append(self.data) 102 103 # This is the most urgent timeout 104 else: 105 Timeout._process_to_timeout_map[os.getpid()] = [self.data] + Timeout._process_to_timeout_map.get(os.getpid(), []) 106 107 Timeout._bind_timeout_data_to_alarm(Timeout.current()) 108 return self 109 110 def __exit__(self, exc_type, exc_value, traceback): 111 signal.alarm(0) # Imiediatly disable the alarm so we aren't interupted. 112 113 if not Timeout._process_to_timeout_map[os.getpid()]: 114 raise RuntimeError('No timeout registered') 115 Timeout._process_to_timeout_map[os.getpid()].remove(self.data) 116 self.data = None 117 118 if Timeout._process_to_timeout_map[os.getpid()]: 119 Timeout._bind_timeout_data_to_alarm(Timeout.current()) 23 from webkitcorepy import Timeout
Note:
See TracChangeset
for help on using the changeset viewer.