commit: a997f3e2d4318b8b9129d5cccd3c5f2c5677d11d Author: Zac Medico <zmedico <AT> gentoo <DOT> org> AuthorDate: Fri Mar 16 08:40:42 2018 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Fri Mar 16 17:17:53 2018 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=a997f3e2
EventLoop: implement time method for asyncio compat (bug 591760) Use time.monotonic() which is available in Python 3.3 and later, and otherwise emulate it by using an offset to counteract any backward movements. Bug: https://bugs.gentoo.org/591760 pym/portage/util/_eventloop/EventLoop.py | 19 +++++++++++++----- pym/portage/util/monotonic.py | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/pym/portage/util/_eventloop/EventLoop.py b/pym/portage/util/_eventloop/EventLoop.py index 89ac2a3b3..f472a3dae 100644 --- a/pym/portage/util/_eventloop/EventLoop.py +++ b/pym/portage/util/_eventloop/EventLoop.py @@ -1,4 +1,4 @@ -# Copyright 1999-2016 Gentoo Foundation +# Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import division @@ -9,7 +9,6 @@ import os import select import signal import sys -import time try: import fcntl @@ -29,6 +28,7 @@ portage.proxy.lazyimport.lazyimport(globals(), from portage import OrderedDict from portage.util import writemsg_level +from portage.util.monotonic import monotonic from ..SlotObject import SlotObject from .PollConstants import PollConstants from .PollSelectAdapter import PollSelectAdapter @@ -515,7 +515,7 @@ class EventLoop(object): self._timeout_handlers[source_id] = \ self._timeout_handler_class( interval=interval, function=function, args=args, - source_id=source_id, timestamp=time.time()) + source_id=source_id, timestamp=self.time()) if self._timeout_interval is None or \ self._timeout_interval > interval: self._timeout_interval = interval @@ -538,7 +538,7 @@ class EventLoop(object): return bool(calls) ready_timeouts = [] - current_time = time.time() + current_time = self.time() for x in self._timeout_handlers.values(): elapsed_seconds = current_time - x.timestamp # elapsed_seconds < 0 means the system clock has been adjusted @@ -558,7 +558,7 @@ class EventLoop(object): calls += 1 x.calling = True try: - x.timestamp = time.time() + x.timestamp = self.time() if not x.function(*x.args): self.source_remove(x.source_id) finally: @@ -684,6 +684,15 @@ class EventLoop(object): # The call_soon method inherits thread safety from the idle_add method. call_soon_threadsafe = call_soon + def time(self): + """Return the time according to the event loop's clock. + + This is a float expressed in seconds since an epoch, but the + epoch, precision, accuracy and drift are unspecified and may + differ per event loop. + """ + return monotonic() + def call_later(self, delay, callback, *args): """ Arrange for the callback to be called after the given delay seconds diff --git a/pym/portage/util/monotonic.py b/pym/portage/util/monotonic.py new file mode 100644 index 000000000..e50564851 --- /dev/null +++ b/pym/portage/util/monotonic.py @@ -0,0 +1,34 @@ +# Copyright 2018 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +__all__ = ['monotonic'] + +import time +try: + import threading +except ImportError: + import dummy_threading as threading + +monotonic = getattr(time, 'monotonic', None) + +if monotonic is None: + def monotonic(): + """ + Emulate time.monotonic() which is available in Python 3.3 and later. + + @return: A float expressed in seconds since an epoch. + """ + with monotonic._lock: + current = time.time() + monotonic._offset + delta = current - monotonic._previous + if delta < 0: + monotonic._offset -= delta + current = monotonic._previous + else: + monotonic._previous = current + return current + + # offset is used to counteract any backward movements + monotonic._offset = 0 + monotonic._previous = time.time() + monotonic._lock = threading.Lock()