diff --git a/Lib/threading.py b/Lib/threading.py index 7ab9ad8..dcedd3b 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -3,7 +3,7 @@ import sys as _sys import _thread -from time import monotonic as _time +from time import monotonic as _time, sleep as _sleep from traceback import format_exc as _format_exc from _weakrefset import WeakSet from itertools import islice as _islice, count as _count @@ -296,7 +296,25 @@ class Condition: gotit = True else: if timeout > 0: - gotit = waiter.acquire(True, timeout) + # rhbz#2003758: Avoid waiter.acquire(True, timeout) since + # it uses the system clock internally. + # + # Balancing act: We can't afford a pure busy loop, so we + # have to sleep; but if we sleep the whole timeout time, + # we'll be unresponsive. The scheme here sleeps very + # little at first, longer as time goes on, but never longer + # than 20 times per second (or the timeout time remaining). + endtime = _time() + timeout + delay = 0.0005 # 500 us -> initial delay of 1 ms + while True: + gotit = waiter.acquire(0) + if gotit: + break + remaining = min(endtime - _time(), timeout) + if remaining <= 0: + break + delay = min(delay * 2, remaining, .05) + _sleep(delay) else: gotit = waiter.acquire(False) return gotit