diff options
author | Victor Stinner <vstinner@python.org> | 2022-06-15 12:09:56 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-15 12:09:56 (GMT) |
commit | 0ba80273f2dba5b70de870a333e65ad025cca640 (patch) | |
tree | 7f21af5a00c17463625072031650af5bd50895ea /Lib/test | |
parent | bddbd80cff950b16712ae9e72eeba2a0f26c65e0 (diff) | |
download | cpython-0ba80273f2dba5b70de870a333e65ad025cca640.zip cpython-0ba80273f2dba5b70de870a333e65ad025cca640.tar.gz cpython-0ba80273f2dba5b70de870a333e65ad025cca640.tar.bz2 |
Use support.sleeping_retry() and support.busy_retry() (#93848)
* Replace time.sleep(0.010) with sleeping_retry() to
use an exponential sleep.
* support.wait_process(): reuse sleeping_retry().
* _test_eintr: remove unused variables.
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/_test_eintr.py | 14 | ||||
-rw-r--r-- | Lib/test/signalinterproctester.py | 13 | ||||
-rw-r--r-- | Lib/test/support/__init__.py | 35 | ||||
-rw-r--r-- | Lib/test/support/threading_helper.py | 18 | ||||
-rw-r--r-- | Lib/test/test_asyncio/utils.py | 11 | ||||
-rw-r--r-- | Lib/test/test_asyncore.py | 5 | ||||
-rw-r--r-- | Lib/test/test_logging.py | 13 |
7 files changed, 51 insertions, 58 deletions
diff --git a/Lib/test/_test_eintr.py b/Lib/test/_test_eintr.py index e43b59d..ca637b2 100644 --- a/Lib/test/_test_eintr.py +++ b/Lib/test/_test_eintr.py @@ -403,11 +403,9 @@ class SignalEINTRTest(EINTRBaseTest): old_mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) self.addCleanup(signal.pthread_sigmask, signal.SIG_UNBLOCK, [signum]) - t0 = time.monotonic() proc = self.subprocess(code) with kill_on_error(proc): wait_func(signum) - dt = time.monotonic() - t0 self.assertEqual(proc.wait(), 0) @@ -497,16 +495,18 @@ class FNTLEINTRTest(EINTRBaseTest): proc = self.subprocess(code) with kill_on_error(proc): with open(os_helper.TESTFN, 'wb') as f: - while True: # synchronize the subprocess - dt = time.monotonic() - start_time - if dt > 60.0: - raise Exception("failed to sync child in %.1f sec" % dt) + # synchronize the subprocess + start_time = time.monotonic() + for _ in support.sleeping_retry(60.0, error=False): try: lock_func(f, fcntl.LOCK_EX | fcntl.LOCK_NB) lock_func(f, fcntl.LOCK_UN) - time.sleep(0.01) except BlockingIOError: break + else: + dt = time.monotonic() - start_time + raise Exception("failed to sync child in %.1f sec" % dt) + # the child locked the file just a moment ago for 'sleep_time' seconds # that means that the lock below will block for 'sleep_time' minus some # potential context switch delay diff --git a/Lib/test/signalinterproctester.py b/Lib/test/signalinterproctester.py index bc60b74..cdcd92a 100644 --- a/Lib/test/signalinterproctester.py +++ b/Lib/test/signalinterproctester.py @@ -28,16 +28,15 @@ class InterProcessSignalTests(unittest.TestCase): # (if set) child.wait() - timeout = support.SHORT_TIMEOUT - deadline = time.monotonic() + timeout - - while time.monotonic() < deadline: + start_time = time.monotonic() + for _ in support.busy_retry(support.SHORT_TIMEOUT, error=False): if self.got_signals[signame]: return signal.pause() - - self.fail('signal %s not received after %s seconds' - % (signame, timeout)) + else: + dt = time.monotonic() - start_time + self.fail('signal %s not received after %.1f seconds' + % (signame, dt)) def subprocess_send_signal(self, pid, signame): code = 'import os, signal; os.kill(%s, signal.%s)' % (pid, signame) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index a62e8b4..a875548 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2072,31 +2072,26 @@ def wait_process(pid, *, exitcode, timeout=None): if timeout is None: timeout = SHORT_TIMEOUT - t0 = time.monotonic() - sleep = 0.001 - max_sleep = 0.1 - while True: + + start_time = time.monotonic() + for _ in sleeping_retry(timeout, error=False): pid2, status = os.waitpid(pid, os.WNOHANG) if pid2 != 0: break - # process is still running - - dt = time.monotonic() - t0 - if dt > SHORT_TIMEOUT: - try: - os.kill(pid, signal.SIGKILL) - os.waitpid(pid, 0) - except OSError: - # Ignore errors like ChildProcessError or PermissionError - pass - - raise AssertionError(f"process {pid} is still running " - f"after {dt:.1f} seconds") + # rety: the process is still running + else: + try: + os.kill(pid, signal.SIGKILL) + os.waitpid(pid, 0) + except OSError: + # Ignore errors like ChildProcessError or PermissionError + pass - sleep = min(sleep * 2, max_sleep) - time.sleep(sleep) + dt = time.monotonic() - start_time + raise AssertionError(f"process {pid} is still running " + f"after {dt:.1f} seconds") else: - # Windows implementation + # Windows implementation: don't support timeout :-( pid2, status = os.waitpid(pid, 0) exitcode2 = os.waitstatus_to_exitcode(status) diff --git a/Lib/test/support/threading_helper.py b/Lib/test/support/threading_helper.py index 26cbc6f..b9973c8 100644 --- a/Lib/test/support/threading_helper.py +++ b/Lib/test/support/threading_helper.py @@ -88,19 +88,17 @@ def wait_threads_exit(timeout=None): yield finally: start_time = time.monotonic() - deadline = start_time + timeout - while True: + for _ in support.sleeping_retry(timeout, error=False): + support.gc_collect() count = _thread._count() if count <= old_count: break - if time.monotonic() > deadline: - dt = time.monotonic() - start_time - msg = (f"wait_threads() failed to cleanup {count - old_count} " - f"threads after {dt:.1f} seconds " - f"(count: {count}, old count: {old_count})") - raise AssertionError(msg) - time.sleep(0.010) - support.gc_collect() + else: + dt = time.monotonic() - start_time + msg = (f"wait_threads() failed to cleanup {count - old_count} " + f"threads after {dt:.1f} seconds " + f"(count: {count}, old count: {old_count})") + raise AssertionError(msg) def join_thread(thread, timeout=None): diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index c32494d..07ef33d 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -109,13 +109,12 @@ def run_briefly(loop): def run_until(loop, pred, timeout=support.SHORT_TIMEOUT): - deadline = time.monotonic() + timeout - while not pred(): - if timeout is not None: - timeout = deadline - time.monotonic() - if timeout <= 0: - raise futures.TimeoutError() + for _ in support.busy_retry(timeout, error=False): + if pred(): + break loop.run_until_complete(tasks.sleep(0.001)) + else: + raise futures.TimeoutError() def run_once(loop): diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py index 98ccd3a..1564221 100644 --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -76,8 +76,7 @@ def capture_server(evt, buf, serv): pass else: n = 200 - start = time.monotonic() - while n > 0 and time.monotonic() - start < 3.0: + for _ in support.busy_retry(3.0, error=False): r, w, e = select.select([conn], [], [], 0.1) if r: n -= 1 @@ -86,6 +85,8 @@ def capture_server(evt, buf, serv): buf.write(data.replace(b'\n', b'')) if b'\n' in data: break + if n <= 0: + break time.sleep(0.01) conn.close() diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 4954557..d43742e 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3602,7 +3602,6 @@ class ConfigDictTest(BaseTest): if lspec is not None: cd['handlers']['ah']['listener'] = lspec qh = None - delay = 0.01 try: self.apply_config(cd) qh = logging.getHandlerByName('ah') @@ -3612,12 +3611,14 @@ class ConfigDictTest(BaseTest): logging.debug('foo') logging.info('bar') logging.warning('baz') + # Need to let the listener thread finish its work - deadline = time.monotonic() + support.LONG_TIMEOUT - while not qh.listener.queue.empty(): - time.sleep(delay) - if time.monotonic() > deadline: - self.fail("queue not empty") + while support.sleeping_retry(support.LONG_TIMEOUT, error=False): + if qh.listener.queue.empty(): + break + else: + self.fail("queue not empty") + with open(fn, encoding='utf-8') as f: data = f.read().splitlines() self.assertEqual(data, ['foo', 'bar', 'baz']) |