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            | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+), 5 deletions(-)
 create mode 100644 pym/portage/util/monotonic.py

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..da1cce1c5
--- /dev/null
+++ b/pym/portage/util/monotonic.py
@@ -0,0 +1,32 @@
+# 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()
+                       delta = current - monotonic._previous
+                       if delta < 0:
+                               monotonic._offset -= delta
+                       monotonic._previous = current + monotonic._offset
+                       return monotonic._previous
+
+       # offset is used to counteract any backward movements
+       monotonic._offset = 0
+       monotonic._previous = time.time()
+       monotonic._lock = threading.Lock()
-- 
2.13.6


Reply via email to