From 6566ec5e4b143f47a835223e5bcbe68766c52f7a Mon Sep 17 00:00:00 2001 From: Thomas Herve Date: Fri, 19 Oct 2018 10:45:48 +0200 Subject: [PATCH] Use eventlet Event for loopingcall events This fixes broken logic for finding out how to use green threads. Using threading.Event with eventlet creates useless load related to timers. Change-Id: I62e9f1a7cde8846be368fbec58b8e0825ce02079 Closes-Bug: #1798774 (cherry picked from commit c2463470f5e7edad1ffd369a472267d559590495) --- oslo_service/loopingcall.py | 71 +++++++++----------------- oslo_service/tests/test_loopingcall.py | 3 -- 2 files changed, 24 insertions(+), 50 deletions(-) diff --git a/oslo_service/loopingcall.py b/oslo_service/loopingcall.py index 4bc67a2b..dc958040 100644 --- a/oslo_service/loopingcall.py +++ b/oslo_service/loopingcall.py @@ -17,13 +17,12 @@ import random import sys -import threading import time from eventlet import event from eventlet import greenthread +from eventlet import timeout as eventlettimeout from oslo_log import log as logging -from oslo_utils import eventletutils from oslo_utils import excutils from oslo_utils import reflection from oslo_utils import timeutils @@ -77,51 +76,30 @@ def _safe_wrapper(f, kind, func_name): return func -def _Event(): - if eventletutils.is_monkey_patched('thread'): - return _ThreadingEvent() - else: - return _GreenEvent() +class _Event(object): + """A class that provides consistent eventlet/threading Event API. - -class _ThreadingEvent(object): - def __init__(self): - self._abort = threading.Event() - - def is_running(self): - return not self._abort.is_set() + It's a copy from the oslo_utils repository, as we need the private version + because we don't want to use the threading.Event version. + """ + def __init__(self, *args, **kwargs): + self.clear() def clear(self): - self._abort.clear() + self._set = False + self._event = event.Event() - def wait(self, timeout): - self._abort.wait(timeout) + def is_set(self): + return self._set - def stop(self): - self._abort.set() + def set(self): + self._set = True + self._event.send(True) - def done(self): - pass - - -class _GreenEvent(object): - def __init__(self): - self._running = False - - def is_running(self): - return self._running - - def clear(self): - self._running = True - - def wait(self, timeout): - greenthread.sleep(timeout) - - def stop(self): - self._running = False - - def done(self): - self._running = False + def wait(self, timeout=None): + with eventlettimeout.Timeout(timeout, False): + self._event.wait() + return self.is_set() class LoopingCallBase(object): @@ -136,25 +114,24 @@ class LoopingCallBase(object): self.f = f self._thread = None self.done = None - self._event = _Event() + self._abort = _Event() @property def _running(self): - return self._event.is_running() + return not self._abort.is_set() def stop(self): if self._running: - self._event.stop() + self._abort.set() def wait(self): return self.done.wait() def _on_done(self, gt, *args, **kwargs): self._thread = None - self._event.done() def _sleep(self, timeout): - self._event.wait(timeout) + self._abort.wait(timeout) def _start(self, idle_for, initial_delay=None, stop_on_exception=True): """Start the looping @@ -172,7 +149,7 @@ class LoopingCallBase(object): if self._thread is not None: raise RuntimeError(self._RUN_ONLY_ONE_MESSAGE) self.done = event.Event() - self._event.clear() + self._abort.clear() self._thread = greenthread.spawn( self._run_loop, idle_for, initial_delay=initial_delay, stop_on_exception=stop_on_exception) diff --git a/oslo_service/tests/test_loopingcall.py b/oslo_service/tests/test_loopingcall.py index 82d495dd..35d05a1a 100644 --- a/oslo_service/tests/test_loopingcall.py +++ b/oslo_service/tests/test_loopingcall.py @@ -20,9 +20,6 @@ from oslotest import base as test_base import oslo_service from oslo_service import loopingcall -threading = eventlet.patcher.original('threading') -time = eventlet.patcher.original('time') - class LoopingCallTestCase(test_base.BaseTestCase):