diff -r 89665cc05592 Doc/library/time.rst --- a/Doc/library/time.rst Tue Jul 22 21:29:52 2014 +0100 +++ b/Doc/library/time.rst Wed Jul 23 04:09:37 2014 +0200 @@ -315,9 +315,9 @@ The module defines the following functio processes running for more than 49 days. On more recent versions of Windows and on other operating systems, :func:`monotonic` is system-wide. - Availability: Windows, Mac OS X, Linux, FreeBSD, OpenBSD, Solaris. - .. versionadded:: 3.3 + .. versionchanged:: 3.5 + The function is now always available. .. function:: perf_counter() diff -r 89665cc05592 Include/pytime.h --- a/Include/pytime.h Tue Jul 22 21:29:52 2014 +0100 +++ b/Include/pytime.h Wed Jul 23 04:09:37 2014 +0200 @@ -13,14 +13,11 @@ functions and constants extern "C" { #endif -#ifdef HAVE_GETTIMEOFDAY -typedef struct timeval _PyTime_timeval; -#else +/* Timestamp with nanosecond resolution */ typedef struct { - time_t tv_sec; /* seconds since Jan. 1, 1970 */ - long tv_usec; /* and microseconds */ -} _PyTime_timeval; -#endif + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +} _PyTime_timespec; /* Structure used by time.get_clock_info() */ typedef struct { @@ -33,24 +30,24 @@ typedef struct { /* Similar to POSIX gettimeofday but cannot fail. If system gettimeofday * fails or is not available, fall back to lower resolution clocks. */ -PyAPI_FUNC(void) _PyTime_gettimeofday(_PyTime_timeval *tp); +PyAPI_FUNC(void) _PyTime_gettimeofday(_PyTime_timespec *tp); /* Similar to _PyTime_gettimeofday() but retrieve also information on the * clock used to get the current time. */ PyAPI_FUNC(void) _PyTime_gettimeofday_info( - _PyTime_timeval *tp, + _PyTime_timespec *tp, _Py_clock_info_t *info); #define _PyTime_ADD_SECONDS(tv, interval) \ do { \ - tv.tv_usec += (long) (((long) interval - interval) * 1000000); \ - tv.tv_sec += (time_t) interval + (time_t) (tv.tv_usec / 1000000); \ - tv.tv_usec %= 1000000; \ + tv.tv_nsec += (long) (((long) interval - interval) * 1000000000); \ + tv.tv_sec += (time_t) interval + (time_t) (tv.tv_nsec / 1000000000); \ + tv.tv_nsec %= 1000000000; \ } while (0) #define _PyTime_INTERVAL(tv_start, tv_end) \ ((tv_end.tv_sec - tv_start.tv_sec) + \ - (tv_end.tv_usec - tv_start.tv_usec) * 0.000001) + (tv_end.tv_nsec - tv_start.tv_nsec) * 1e-9) #ifndef Py_LIMITED_API @@ -92,6 +89,20 @@ PyAPI_FUNC(int) _PyTime_ObjectToTimespec time_t *sec, long *nsec, _PyTime_round_t); + +/* Return the value (in fractional seconds) of a monotonic clock, i.e. a clock + that cannot go backwards. The clock is not affected by system clock updates. + The reference point of the returned value is undefined, so that only the + difference between the results of consecutive calls is valid. */ +PyAPI_FUNC(int) _PyTime_monotonic_info( + _PyTime_timespec *ts, + _Py_clock_info_t *info); + +/* Similar to _PyTime_monotonic_info() but it cannot fail: set ts->tv_sec and + tv->tv_nsec to zero instead of raising an exception. */ +PyAPI_FUNC(void) _PyTime_monotonic( + _PyTime_timespec *ts); + #endif /* Dummy to force linking. */ diff -r 89665cc05592 Lib/queue.py --- a/Lib/queue.py Tue Jul 22 21:29:52 2014 +0100 +++ b/Lib/queue.py Wed Jul 23 04:09:37 2014 +0200 @@ -6,10 +6,7 @@ except ImportError: import dummy_threading as threading from collections import deque from heapq import heappush, heappop -try: - from time import monotonic as time -except ImportError: - from time import time +from time import monotonic as time __all__ = ['Empty', 'Full', 'Queue', 'PriorityQueue', 'LifoQueue'] diff -r 89665cc05592 Lib/sched.py --- a/Lib/sched.py Tue Jul 22 21:29:52 2014 +0100 +++ b/Lib/sched.py Wed Jul 23 04:09:37 2014 +0200 @@ -35,10 +35,7 @@ try: import threading except ImportError: import dummy_threading as threading -try: - from time import monotonic as _time -except ImportError: - from time import time as _time +from time import monotonic as _time __all__ = ["scheduler"] diff -r 89665cc05592 Lib/socketserver.py --- a/Lib/socketserver.py Tue Jul 22 21:29:52 2014 +0100 +++ b/Lib/socketserver.py Wed Jul 23 04:09:37 2014 +0200 @@ -136,10 +136,7 @@ try: import threading except ImportError: import dummy_threading as threading -try: - from time import monotonic as time -except ImportError: - from time import time as time +from time import monotonic as time __all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer", "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler", diff -r 89665cc05592 Lib/subprocess.py --- a/Lib/subprocess.py Tue Jul 22 21:29:52 2014 +0100 +++ b/Lib/subprocess.py Wed Jul 23 04:09:37 2014 +0200 @@ -365,10 +365,7 @@ import signal import builtins import warnings import errno -try: - from time import monotonic as _time -except ImportError: - from time import time as _time +from time import monotonic as _time # Exception classes used by this module. class SubprocessError(Exception): pass diff -r 89665cc05592 Lib/telnetlib.py --- a/Lib/telnetlib.py Tue Jul 22 21:29:52 2014 +0100 +++ b/Lib/telnetlib.py Wed Jul 23 04:09:37 2014 +0200 @@ -36,10 +36,7 @@ To do: import sys import socket import selectors -try: - from time import monotonic as _time -except ImportError: - from time import time as _time +from time import monotonic as _time __all__ = ["Telnet"] diff -r 89665cc05592 Lib/test/test_selectors.py --- a/Lib/test/test_selectors.py Tue Jul 22 21:29:52 2014 +0100 +++ b/Lib/test/test_selectors.py Wed Jul 23 04:09:37 2014 +0200 @@ -8,10 +8,7 @@ from test import support from time import sleep import unittest import unittest.mock -try: - from time import monotonic as time -except ImportError: - from time import time as time +from time import monotonic as time try: import resource except ImportError: diff -r 89665cc05592 Lib/threading.py --- a/Lib/threading.py Tue Jul 22 21:29:52 2014 +0100 +++ b/Lib/threading.py Wed Jul 23 04:09:37 2014 +0200 @@ -3,10 +3,7 @@ import sys as _sys import _thread -try: - from time import monotonic as _time -except ImportError: - from time import time as _time +from time import monotonic as _time from traceback import format_exc as _format_exc from _weakrefset import WeakSet from itertools import islice as _islice diff -r 89665cc05592 Lib/trace.py --- a/Lib/trace.py Tue Jul 22 21:29:52 2014 +0100 +++ b/Lib/trace.py Wed Jul 23 04:09:37 2014 +0200 @@ -59,10 +59,7 @@ import gc import dis import pickle from warnings import warn as _warn -try: - from time import monotonic as _time -except ImportError: - from time import time as _time +from time import monotonic as _time try: import threading diff -r 89665cc05592 Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c Tue Jul 22 21:29:52 2014 +0100 +++ b/Modules/_datetimemodule.c Wed Jul 23 04:09:37 2014 +0200 @@ -4103,9 +4103,10 @@ datetime_from_timestamp(PyObject *cls, T static PyObject * datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo) { - _PyTime_timeval t; - _PyTime_gettimeofday(&t); - return datetime_from_timet_and_us(cls, f, t.tv_sec, (int)t.tv_usec, + _PyTime_timespec ts; + _PyTime_gettimeofday(&ts); + return datetime_from_timet_and_us(cls, f, + ts.tv_sec, (int)(ts.tv_nsec / 1000), tzinfo); } diff -r 89665cc05592 Modules/_threadmodule.c --- a/Modules/_threadmodule.c Tue Jul 22 21:29:52 2014 +0100 +++ b/Modules/_threadmodule.c Wed Jul 23 04:09:37 2014 +0200 @@ -52,14 +52,14 @@ static PyLockStatus acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) { PyLockStatus r; - _PyTime_timeval curtime; - _PyTime_timeval endtime; + _PyTime_timespec curtime; + _PyTime_timespec endtime; if (microseconds > 0) { - _PyTime_gettimeofday(&endtime); + _PyTime_monotonic(&endtime); endtime.tv_sec += microseconds / (1000 * 1000); - endtime.tv_usec += microseconds % (1000 * 1000); + endtime.tv_nsec += microseconds % (1000 * 1000) * 1000; } @@ -83,9 +83,9 @@ acquire_timed(PyThread_type_lock lock, P /* If we're using a timeout, recompute the timeout after processing * signals, since those can take time. */ if (microseconds > 0) { - _PyTime_gettimeofday(&curtime); + _PyTime_monotonic(&curtime); microseconds = ((endtime.tv_sec - curtime.tv_sec) * 1000000 + - (endtime.tv_usec - curtime.tv_usec)); + (endtime.tv_nsec - curtime.tv_nsec) / 1000); /* Check for negative values, since those mean block forever. */ diff -r 89665cc05592 Modules/gcmodule.c --- a/Modules/gcmodule.c Tue Jul 22 21:29:52 2014 +0100 +++ b/Modules/gcmodule.c Wed Jul 23 04:09:37 2014 +0200 @@ -25,7 +25,7 @@ #include "Python.h" #include "frameobject.h" /* for PyFrame_ClearFreeList */ -#include "pytime.h" /* for _PyTime_gettimeofday, _PyTime_INTERVAL */ +#include "pytime.h" /* for _PyTime_monotonic */ /* Get an object's GC head */ #define AS_GC(o) ((PyGC_Head *)(o)-1) @@ -908,7 +908,7 @@ collect(int generation, Py_ssize_t *n_co PyGC_Head unreachable; /* non-problematic unreachable trash */ PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ PyGC_Head *gc; - _PyTime_timeval t1; + _PyTime_timespec t1; struct gc_generation_stats *stats = &generation_stats[generation]; @@ -919,7 +919,7 @@ collect(int generation, Py_ssize_t *n_co for (i = 0; i < NUM_GENERATIONS; i++) PySys_FormatStderr(" %zd", gc_list_size(GEN_HEAD(i))); - _PyTime_gettimeofday(&t1); + _PyTime_monotonic(&t1); PySys_WriteStderr("\n"); } @@ -1024,8 +1024,8 @@ collect(int generation, Py_ssize_t *n_co debug_cycle("uncollectable", FROM_GC(gc)); } if (debug & DEBUG_STATS) { - _PyTime_timeval t2; - _PyTime_gettimeofday(&t2); + _PyTime_timespec t2; + _PyTime_monotonic(&t2); if (m == 0 && n == 0) PySys_WriteStderr("gc: done"); @@ -1033,7 +1033,8 @@ collect(int generation, Py_ssize_t *n_co PySys_FormatStderr( "gc: done, %zd unreachable, %zd uncollectable", n+m, n); - PySys_WriteStderr(", %.4fs elapsed\n", _PyTime_INTERVAL(t1, t2)); + PySys_WriteStderr(", %.4fs elapsed\n", + _PyTime_INTERVAL(t1, t2)); } /* Append instances in the uncollectable set to a Python diff -r 89665cc05592 Modules/socketmodule.c --- a/Modules/socketmodule.c Tue Jul 22 21:29:52 2014 +0100 +++ b/Modules/socketmodule.c Wed Jul 23 04:09:37 2014 +0200 @@ -673,11 +673,11 @@ internal_select(PySocketSockObject *s, i #define BEGIN_SELECT_LOOP(s) \ { \ - _PyTime_timeval now, deadline = {0, 0}; \ + _PyTime_timespec now, deadline = {0, 0}; \ double interval = s->sock_timeout; \ int has_timeout = s->sock_timeout > 0.0; \ if (has_timeout) { \ - _PyTime_gettimeofday(&now); \ + _PyTime_monotonic(&now); \ deadline = now; \ _PyTime_ADD_SECONDS(deadline, s->sock_timeout); \ } \ @@ -688,7 +688,7 @@ internal_select(PySocketSockObject *s, i if (!has_timeout || \ (!CHECK_ERRNO(EWOULDBLOCK) && !CHECK_ERRNO(EAGAIN))) \ break; \ - _PyTime_gettimeofday(&now); \ + _PyTime_monotonic(&now); \ interval = _PyTime_INTERVAL(now, deadline); \ } \ } \ diff -r 89665cc05592 Modules/timemodule.c --- a/Modules/timemodule.c Tue Jul 22 21:29:52 2014 +0100 +++ b/Modules/timemodule.c Wed Jul 23 04:09:37 2014 +0200 @@ -903,122 +903,15 @@ the local timezone used by methods such should not be relied on."); #endif /* HAVE_WORKING_TZSET */ -#if defined(MS_WINDOWS) || defined(__APPLE__) \ - || (defined(HAVE_CLOCK_GETTIME) \ - && (defined(CLOCK_HIGHRES) || defined(CLOCK_MONOTONIC))) -#define PYMONOTONIC -#endif - -#ifdef PYMONOTONIC static PyObject* pymonotonic(_Py_clock_info_t *info) { -#if defined(MS_WINDOWS) - static ULONGLONG (*GetTickCount64) (void) = NULL; - static ULONGLONG (CALLBACK *Py_GetTickCount64)(void); - static int has_getickcount64 = -1; - double result; + _PyTime_timespec ts; - if (has_getickcount64 == -1) { - /* GetTickCount64() was added to Windows Vista */ - if (winver.dwMajorVersion >= 6) { - HINSTANCE hKernel32; - hKernel32 = GetModuleHandleW(L"KERNEL32"); - *(FARPROC*)&Py_GetTickCount64 = GetProcAddress(hKernel32, - "GetTickCount64"); - has_getickcount64 = (Py_GetTickCount64 != NULL); - } - else - has_getickcount64 = 0; - } + if (_PyTime_monotonic_info(&ts, info) < 0) + return NULL; - if (has_getickcount64) { - ULONGLONG ticks; - ticks = Py_GetTickCount64(); - result = (double)ticks * 1e-3; - } - else { - static DWORD last_ticks = 0; - static DWORD n_overflow = 0; - DWORD ticks; - - ticks = GetTickCount(); - if (ticks < last_ticks) - n_overflow++; - last_ticks = ticks; - - result = ldexp(n_overflow, 32); - result += ticks; - result *= 1e-3; - } - - if (info) { - DWORD timeAdjustment, timeIncrement; - BOOL isTimeAdjustmentDisabled, ok; - if (has_getickcount64) - info->implementation = "GetTickCount64()"; - else - info->implementation = "GetTickCount()"; - info->monotonic = 1; - ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, - &isTimeAdjustmentDisabled); - if (!ok) { - PyErr_SetFromWindowsErr(0); - return NULL; - } - info->resolution = timeIncrement * 1e-7; - info->adjustable = 0; - } - return PyFloat_FromDouble(result); - -#elif defined(__APPLE__) - static mach_timebase_info_data_t timebase; - uint64_t time; - double secs; - - if (timebase.denom == 0) { - /* According to the Technical Q&A QA1398, mach_timebase_info() cannot - fail: https://developer.apple.com/library/mac/#qa/qa1398/ */ - (void)mach_timebase_info(&timebase); - } - - time = mach_absolute_time(); - secs = (double)time * timebase.numer / timebase.denom * 1e-9; - if (info) { - info->implementation = "mach_absolute_time()"; - info->resolution = (double)timebase.numer / timebase.denom * 1e-9; - info->monotonic = 1; - info->adjustable = 0; - } - return PyFloat_FromDouble(secs); - -#elif defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_HIGHRES) || defined(CLOCK_MONOTONIC)) - struct timespec tp; -#ifdef CLOCK_HIGHRES - const clockid_t clk_id = CLOCK_HIGHRES; - const char *function = "clock_gettime(CLOCK_HIGHRES)"; -#else - const clockid_t clk_id = CLOCK_MONOTONIC; - const char *function = "clock_gettime(CLOCK_MONOTONIC)"; -#endif - - if (clock_gettime(clk_id, &tp) != 0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - if (info) { - struct timespec res; - info->monotonic = 1; - info->implementation = function; - info->adjustable = 0; - if (clock_getres(clk_id, &res) == 0) - info->resolution = res.tv_sec + res.tv_nsec * 1e-9; - else - info->resolution = 1e-9; - } - return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); -#endif + return PyFloat_FromDouble(ts.tv_sec + ts.tv_nsec * 1e-9); } static PyObject * @@ -1031,20 +924,15 @@ PyDoc_STRVAR(monotonic_doc, "monotonic() -> float\n\ \n\ Monotonic clock, cannot go backward."); -#endif /* PYMONOTONIC */ static PyObject* perf_counter(_Py_clock_info_t *info) { -#if defined(WIN32_PERF_COUNTER) || defined(PYMONOTONIC) PyObject *res; -#endif -#if defined(WIN32_PERF_COUNTER) +#ifdef WIN32_PERF_COUNTER static int use_perf_counter = 1; #endif -#ifdef PYMONOTONIC static int use_monotonic = 1; -#endif #ifdef WIN32_PERF_COUNTER if (use_perf_counter) { @@ -1054,7 +942,6 @@ perf_counter(_Py_clock_info_t *info) } #endif -#ifdef PYMONOTONIC if (use_monotonic) { res = pymonotonic(info); if (res != NULL) @@ -1062,7 +949,6 @@ perf_counter(_Py_clock_info_t *info) use_monotonic = 0; PyErr_Clear(); } -#endif return floattime(info); } @@ -1231,10 +1117,8 @@ time_get_clock_info(PyObject *self, PyOb else if (strcmp(name, "clock") == 0) obj = pyclock(&info); #endif -#ifdef PYMONOTONIC else if (strcmp(name, "monotonic") == 0) obj = pymonotonic(&info); -#endif else if (strcmp(name, "perf_counter") == 0) obj = perf_counter(&info); else if (strcmp(name, "process_time") == 0) @@ -1426,9 +1310,7 @@ static PyMethodDef time_methods[] = { #ifdef HAVE_WORKING_TZSET {"tzset", time_tzset, METH_NOARGS, tzset_doc}, #endif -#ifdef PYMONOTONIC {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc}, -#endif {"process_time", time_process_time, METH_NOARGS, process_time_doc}, {"perf_counter", time_perf_counter, METH_NOARGS, perf_counter_doc}, {"get_clock_info", time_get_clock_info, METH_VARARGS, get_clock_info_doc}, @@ -1534,31 +1416,9 @@ PyInit_time(void) static PyObject* floattime(_Py_clock_info_t *info) { - _PyTime_timeval t; -#ifdef HAVE_CLOCK_GETTIME - struct timespec tp; - int ret; - - /* _PyTime_gettimeofday() does not use clock_gettime() - because it would require to link Python to the rt (real-time) - library, at least on Linux */ - ret = clock_gettime(CLOCK_REALTIME, &tp); - if (ret == 0) { - if (info) { - struct timespec res; - info->implementation = "clock_gettime(CLOCK_REALTIME)"; - info->monotonic = 0; - info->adjustable = 1; - if (clock_getres(CLOCK_REALTIME, &res) == 0) - info->resolution = res.tv_sec + res.tv_nsec * 1e-9; - else - info->resolution = 1e-9; - } - return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); - } -#endif - _PyTime_gettimeofday_info(&t, info); - return PyFloat_FromDouble((double)t.tv_sec + t.tv_usec * 1e-6); + _PyTime_timespec ts; + _PyTime_gettimeofday_info(&ts, info); + return PyFloat_FromDouble((double)ts.tv_sec + ts.tv_nsec * 1e-9); } diff -r 89665cc05592 Python/pytime.c --- a/Python/pytime.c Tue Jul 22 21:29:52 2014 +0100 +++ b/Python/pytime.c Wed Jul 23 04:09:37 2014 +0200 @@ -18,23 +18,26 @@ extern int ftime(struct timeb *); #endif +/* one seconde in nanoseconds */ +#define SEC_IN_NANOSECONDS 1000000000 + static void -pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info) +pygettimeofday(_PyTime_timespec *ts, _Py_clock_info_t *info) { #ifdef MS_WINDOWS FILETIME system_time; ULARGE_INTEGER large; - ULONGLONG microseconds; + ULONGLONG nanoseconds; GetSystemTimeAsFileTime(&system_time); large.u.LowPart = system_time.dwLowDateTime; large.u.HighPart = system_time.dwHighDateTime; - /* 11,644,473,600,000,000: number of microseconds between + /* 11,644,473,600,000,000,000: number of nanoseconds between the 1st january 1601 and the 1st january 1970 (369 years + 89 leap days). */ - microseconds = large.QuadPart / 10 - 11644473600000000; - tp->tv_sec = microseconds / 1000000; - tp->tv_usec = microseconds % 1000000; + nanoseconds = large.QuadPart * 100 - 11644473600000000000; + ts->tv_sec = nanoseconds / SEC_IN_NANOSECONDS; + ts->tv_nsec = nanoseconds % SEC_IN_NANOSECONDS; if (info) { DWORD timeAdjustment, timeIncrement; BOOL isTimeAdjustmentDisabled; @@ -47,23 +50,57 @@ pygettimeofday(_PyTime_timeval *tp, _Py_ info->adjustable = 1; } #else - /* There are three ways to get the time: - (1) gettimeofday() -- resolution in microseconds - (2) ftime() -- resolution in milliseconds - (3) time() -- resolution in seconds + /* There are four ways to get the time: + (1) clock_gettime() -- resolution in nanoseconds + (2) gettimeofday() -- resolution in microseconds + (3) ftime() -- resolution in milliseconds + (4) time() -- resolution in seconds In all cases the return value in a timeval struct. Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may fail, so we fall back on ftime() or time(). Note: clock resolution does not imply clock accuracy! */ +#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY) + int err; +#endif +#ifdef HAVE_CLOCK_GETTIME + struct timespec tp; +#endif #ifdef HAVE_GETTIMEOFDAY - int err; + struct timeval tv; +#endif +#ifdef HAVE_FTIME + struct timeb tb; +#endif + +#ifdef HAVE_CLOCK_GETTIME + err = clock_gettime(CLOCK_REALTIME, &tp); + if (err == 0) { + if (info) { + struct timespec res; + info->implementation = "clock_gettime(CLOCK_REALTIME)"; + info->monotonic = 0; + info->adjustable = 1; + if (clock_getres(CLOCK_REALTIME, &res) == 0) + info->resolution = res.tv_sec + res.tv_nsec * 1e-9; + else + info->resolution = 1e-9; + } + ts->tv_sec = tp.tv_sec; + ts->tv_nsec = tp.tv_nsec; + return; + } +#endif + +#ifdef HAVE_GETTIMEOFDAY #ifdef GETTIMEOFDAY_NO_TZ - err = gettimeofday(tp); + err = gettimeofday(&tv); #else - err = gettimeofday(tp, (struct timezone *)NULL); + err = gettimeofday(&tv, (struct timezone *)NULL); #endif if (err == 0) { + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; if (info) { info->implementation = "gettimeofday()"; info->resolution = 1e-6; @@ -74,22 +111,19 @@ pygettimeofday(_PyTime_timeval *tp, _Py_ } #endif /* HAVE_GETTIMEOFDAY */ -#if defined(HAVE_FTIME) - { - struct timeb t; - ftime(&t); - tp->tv_sec = t.time; - tp->tv_usec = t.millitm * 1000; - if (info) { - info->implementation = "ftime()"; - info->resolution = 1e-3; - info->monotonic = 0; - info->adjustable = 1; - } +#ifdef HAVE_FTIME + ftime(&tb); + ts->tv_sec = tb.time; + ts->tv_nsec = tb.millitm * 1000000; + if (info) { + info->implementation = "ftime()"; + info->resolution = 1e-3; + info->monotonic = 0; + info->adjustable = 1; } #else /* !HAVE_FTIME */ tp->tv_sec = time(NULL); - tp->tv_usec = 0; + tp->tv_nsec = 0; if (info) { info->implementation = "time()"; info->resolution = 1.0; @@ -102,13 +136,13 @@ pygettimeofday(_PyTime_timeval *tp, _Py_ } void -_PyTime_gettimeofday(_PyTime_timeval *tp) +_PyTime_gettimeofday(_PyTime_timespec *tp) { pygettimeofday(tp, NULL); } void -_PyTime_gettimeofday_info(_PyTime_timeval *tp, _Py_clock_info_t *info) +_PyTime_gettimeofday_info(_PyTime_timespec *tp, _Py_clock_info_t *info) { pygettimeofday(tp, info); } @@ -151,45 +185,55 @@ PyObject * } static int +_PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator, + double denominator, _PyTime_round_t round, + int raise) +{ + double intpart, err; + /* volatile avoids unsafe optimization on float enabled by gcc -O3 */ + volatile double floatpart; + + floatpart = modf(d, &intpart); + if (floatpart < 0) { + floatpart = 1.0 + floatpart; + intpart -= 1.0; + } + + floatpart *= denominator; + if (round == _PyTime_ROUND_UP) { + if (intpart >= 0) { + floatpart = ceil(floatpart); + if (floatpart >= denominator) { + floatpart -= denominator; + intpart += 1.0; + } + } + else { + floatpart = floor(floatpart); + } + } + + *sec = (time_t)intpart; + err = intpart - (double)*sec; + if (err <= -1.0 || err >= 1.0) { + if (raise) + error_time_t_overflow(); + return -1; + } + + *numerator = (long)floatpart; + return 0; +} + +static int _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator, double denominator, _PyTime_round_t round) { assert(denominator <= LONG_MAX); if (PyFloat_Check(obj)) { - double d, intpart, err; - /* volatile avoids unsafe optimization on float enabled by gcc -O3 */ - volatile double floatpart; - - d = PyFloat_AsDouble(obj); - floatpart = modf(d, &intpart); - if (floatpart < 0) { - floatpart = 1.0 + floatpart; - intpart -= 1.0; - } - - floatpart *= denominator; - if (round == _PyTime_ROUND_UP) { - if (intpart >= 0) { - floatpart = ceil(floatpart); - if (floatpart >= denominator) { - floatpart = 0.0; - intpart += 1.0; - } - } - else { - floatpart = floor(floatpart); - } - } - - *sec = (time_t)intpart; - err = intpart - (double)*sec; - if (err <= -1.0 || err >= 1.0) { - error_time_t_overflow(); - return -1; - } - - *numerator = (long)floatpart; - return 0; + double d = PyFloat_AsDouble(obj); + return _PyTime_DoubleToDenominator(d, sec, numerator, + denominator, round, 1); } else { *sec = _PyLong_AsTime_t(obj); @@ -245,6 +289,146 @@ int return _PyTime_ObjectToDenominator(obj, sec, usec, 1e6, round); } +static int +pymonotonic(_PyTime_timespec *ts, _Py_clock_info_t *info, int raise) +{ +#if defined(MS_WINDOWS) + static ULONGLONG (*GetTickCount64) (void) = NULL; + static ULONGLONG (CALLBACK *Py_GetTickCount64)(void); + static int has_getickcount64 = -1; + double result; + + if (has_getickcount64 == -1) { + /* GetTickCount64() was added to Windows Vista */ + if (winver.dwMajorVersion >= 6) { + HINSTANCE hKernel32; + hKernel32 = GetModuleHandleW(L"KERNEL32"); + *(FARPROC*)&Py_GetTickCount64 = GetProcAddress(hKernel32, + "GetTickCount64"); + has_getickcount64 = (Py_GetTickCount64 != NULL); + } + else + has_getickcount64 = 0; + } + + if (has_getickcount64) { + ULONGLONG ticks; + ticks = Py_GetTickCount64(); + ts->tv_sec = ticks / 1000; + ts->tv_nsec = (ticks % 1000) * 1000000; + } + else { + static DWORD last_ticks = 0; + DWORD ticks; + static ULONGLONG delta = 0; + ULONGLONG result; + + ticks = GetTickCount(); + if (ticks < last_ticks) + delta += (ULONGLONG)1 << 32; + last_ticks = ticks; + + result = (ULONGLONG)ticks + delta; + + ts->tv_sec = result / 1000; + ts->tv_nsec = (result % 1000) * 1000000; + } + + if (info) { + DWORD timeAdjustment, timeIncrement; + BOOL isTimeAdjustmentDisabled, ok; + if (has_getickcount64) + info->implementation = "GetTickCount64()"; + else + info->implementation = "GetTickCount()"; + info->monotonic = 1; + ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, + &isTimeAdjustmentDisabled); + if (!ok) { + if (raise) + PyErr_SetFromWindowsErr(0); + goto error; + } + info->resolution = timeIncrement * 1e-7; + info->adjustable = 0; + } + return 0; + +#elif defined(__APPLE__) + static mach_timebase_info_data_t timebase; + uint64_t time; + double secs; + + if (timebase.denom == 0) { + /* According to the Technical Q&A QA1398, mach_timebase_info() cannot + fail: https://developer.apple.com/library/mac/#qa/qa1398/ */ + (void)mach_timebase_info(&timebase); + } + + time = mach_absolute_time(); + secs = (double)time * timebase.numer / timebase.denom * 1e-9; + + if (_PyTime_DoubleToDenominator(secs, &ts->tv_sec, &ts->nsec, + 1e9, _PyTime_ROUND_DOWN, raise) < 0) + goto error; + + if (info) { + info->implementation = "mach_absolute_time()"; + info->resolution = (double)timebase.numer / timebase.denom * 1e-9; + info->monotonic = 1; + info->adjustable = 0; + } + return 0; + +#elif defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_HIGHRES) || defined(CLOCK_MONOTONIC)) + struct timespec tp; +#ifdef CLOCK_HIGHRES + const clockid_t clk_id = CLOCK_HIGHRES; + const char *function = "clock_gettime(CLOCK_HIGHRES)"; +#else + const clockid_t clk_id = CLOCK_MONOTONIC; + const char *function = "clock_gettime(CLOCK_MONOTONIC)"; +#endif + + if (clock_gettime(clk_id, &tp) != 0) { + if (raise) + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + ts->tv_sec = tp.tv_sec; + ts->tv_nsec = tp.tv_nsec; + + if (info) { + struct timespec res; + info->monotonic = 1; + info->implementation = function; + info->adjustable = 0; + if (clock_getres(clk_id, &res) == 0) + info->resolution = res.tv_sec + res.tv_nsec * 1e-9; + else + info->resolution = 1e-9; + } + return 0; +#endif + +error: + ts->tv_sec = 0; + ts->tv_nsec = 0; + return -1; +} + +void +_PyTime_monotonic(_PyTime_timespec *ts) +{ + (void)pymonotonic(ts, NULL, 0); +} + +int +_PyTime_monotonic_info(_PyTime_timespec *ts, _Py_clock_info_t *info) +{ + return pymonotonic(ts, info, 1); +} + void _PyTime_Init() { diff -r 89665cc05592 configure --- a/configure Tue Jul 22 21:29:52 2014 +0100 +++ b/configure Wed Jul 23 04:09:37 2014 +0200 @@ -11811,6 +11811,7 @@ fi $as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : + LIBS="$LIBS -lrt" $as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h diff -r 89665cc05592 configure.ac --- a/configure.ac Tue Jul 22 21:29:52 2014 +0100 +++ b/configure.ac Wed Jul 23 04:09:37 2014 +0200 @@ -3269,6 +3269,7 @@ AC_CHECK_FUNCS(gettimeofday, AC_CHECK_FUNCS(clock_gettime, [], [ AC_CHECK_LIB(rt, clock_gettime, [ + LIBS="$LIBS -lrt" AC_DEFINE(HAVE_CLOCK_GETTIME, 1) AC_DEFINE(TIMEMODULE_LIB, [rt], [Library needed by timemodule.c: librt may be needed for clock_gettime()])