From 8396f8070bb35006fcd14486296fb203646a8dfa Mon Sep 17 00:00:00 2001 From: Ryan Wilson Date: Fri, 30 May 2014 15:38:51 -0700 Subject: [PATCH] timeval: Use monotonic time in OVS Python timeval library. Python's time.time() function uses the system wall clock. However, if NTP resets the wall clock to be a time in the past, then this causes any applications that poll block based on time, such as ovs-xapi-sync, to poll block indefinitely since the time is unexpectedly negative. This patch fixes the issue by using time.monotonic() if Python's version >= 3.3. Otherwise, the timeval module calls out to the librt C shared library and uses the clock_gettime function with CLOCK_MONOTONIC. Note this is only enabled on Linux-based platforms. This has been tested on Ubuntu 12.04 and Redhat 6.4. Bug #1189434 Signed-off-by: Ryan Wilson Acked-by: Ethan Jackson --- python/ovs/timeval.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/python/ovs/timeval.py b/python/ovs/timeval.py index ba0e54e93..f2681ac70 100644 --- a/python/ovs/timeval.py +++ b/python/ovs/timeval.py @@ -12,13 +12,45 @@ # See the License for the specific language governing permissions and # limitations under the License. +import ctypes +import sys import time +LIBRT = 'librt.so.1' +CLOCK_MONOTONIC = 1 + +class timespec(ctypes.Structure): + _fields_ = [ + ('tv_sec', ctypes.c_long), + ('tv_nsec', ctypes.c_long), + ] + +try: + librt = ctypes.CDLL(LIBRT) + clock_gettime = librt.clock_gettime + clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)] +except: + # Librt shared library could not be loaded + librt = None + +def monotonic(): + if not librt: + return time.time() + + t = timespec() + if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(t)) == 0: + return t.tv_sec + t.tv_nsec * 1e-9 + # Kernel does not support CLOCK_MONOTONIC + return time.time() + +# Use time.monotonic() if Python version >= 3.3 +if not hasattr(time, 'monotonic'): + time.monotonic = monotonic def msec(): """Returns the current time, as the amount of time since the epoch, in milliseconds, as a float.""" - return time.time() * 1000.0 + return time.monotonic() * 1000.0 def postfork(): -- 2.20.1