Blob Blame History Raw
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