Discussion:
[gentoo-portage-dev] [PATCH] EventLoop: implement time method for asyncio compat (bug 591760)
Zac Medico
2018-03-16 08:59:23 UTC
Permalink
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
Loading...