1
0
mirror of https://gerrit.ovirt.org/vdsm synced 2026-02-05 12:46:23 +01:00

concurrent: Add Timer class

This patch adds a Timer class to the concurrent module.
The class is based on and behaves pretty much the same
as the threading.Timer class, except that the thread
which carries out the target function is created with
concurrent.thread instead of the regular
threading.Thread. This makes the Timer class available
for use in vdsm, while still ensuring every thread is
created with concurrent.thread.

The Timer also doesn't inherit from the threading.Thread
class, like the threading.Timer does, but instead keeps
the thread object as an attribute.

Change-Id: I28f7f0a7f254088129964bc7d30e5fae846eb3fb
Signed-off-by: Filip Januska <fjanuska@redhat.com>
This commit is contained in:
Filip Januska
2021-11-15 18:58:00 +01:00
committed by Milan Zamazal
parent 9ce1d39532
commit 5075c8b8c0
2 changed files with 68 additions and 0 deletions

View File

@@ -377,3 +377,40 @@ def format_traceback(ident):
if line:
lines.append(" %s" % (line.strip()))
return '\n'.join(lines)
class Timer:
"""
Timer that creates a thread using concurrent.thread.
This Timer is similar to threading.Timer, but uses concurrent.thread()
instead of threading.Thread.
Sample usage:
t = Timer(30.0, f, args=None, kwargs=None)
t.start()
t.cancel() # stop the timer's action if it's still waiting
"""
def __init__(self, interval, function, args=(), kwargs=None,
name=None, daemon=True, log=None):
if kwargs is None:
kwargs = {}
self._function = function
self._args = args
self._kwargs = kwargs
self._interval = interval
self._finished = threading.Event()
self._thread = thread(self._run, name=name, daemon=daemon, log=log)
def cancel(self):
"""Stop the timer if it hasn't finished yet."""
self._finished.set()
def _run(self):
if not self._finished.wait(self._interval):
self._function(*self._args, **self._kwargs)
def start(self):
"""Start the timer."""
self._thread.start()

View File

@@ -524,3 +524,34 @@ class TestValidatingEvent:
assert all(invalidated)
assert not event.valid
class TestTimer:
def test_run(self):
delay = 0.2
finished = threading.Event()
timer = concurrent.Timer(delay, finished.set)
start = time.monotonic()
timer.start()
assert finished.wait(1)
assert time.monotonic() - start >= delay
def test_cancel(self):
delay = 5
finished = threading.Event()
timer = concurrent.Timer(delay, finished.set)
timer.start()
timer.cancel()
timer._thread.join(1)
assert not timer._thread.is_alive()
assert not finished.is_set()
def test_late_cancel(self):
delay = 0
finished = threading.Event()
timer = concurrent.Timer(delay, finished.set)
timer.start()
finished.wait(1)
timer.cancel()
assert finished.is_set()