--- a/Python/pytime.c Sun Aug 31 14:47:56 2014 +0200 |
+++ b/Python/pytime.c Sun Aug 31 15:02:13 2014 +0200 |
@@ -3,6 +3,14 @@ |
#include <windows.h> |
#endif |
+#if defined(__APPLE__) |
+#include <mach/mach_time.h> /* mach_absolute_time(), mach_timebase_info() */ |
+#endif |
+ |
+#ifdef MS_WINDOWS |
+static OSVERSIONINFOEX winver; |
+#endif |
+ |
static int |
pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info, int raise) |
{ |
@@ -112,6 +120,152 @@ int |
return pygettimeofday(tp, info, 1); |
} |
+static int |
+pymonotonic(_PyTime_timeval *tp, _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_gettickcount64 = -1; |
+ ULONGLONG result; |
+ |
+ assert(info == NULL || raise); |
+ |
+ if (has_gettickcount64 == -1) { |
+ /* GetTickCount64() was added to Windows Vista */ |
+ has_gettickcount64 = (winver.dwMajorVersion >= 6); |
+ if (has_gettickcount64) { |
+ HINSTANCE hKernel32; |
+ hKernel32 = GetModuleHandleW(L"KERNEL32"); |
+ *(FARPROC*)&Py_GetTickCount64 = GetProcAddress(hKernel32, |
+ "GetTickCount64"); |
+ assert(Py_GetTickCount64 != NULL); |
+ } |
+ } |
+ |
+ if (has_gettickcount64) { |
+ result = Py_GetTickCount64(); |
+ } |
+ 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 = (ULONGLONG)n_overflow << 32; |
+ result += ticks; |
+ } |
+ |
+ tp->tv_sec = result / 1000; |
+ tp->tv_usec = (result % 1000) * 1000; |
+ |
+ if (info) { |
+ DWORD timeAdjustment, timeIncrement; |
+ BOOL isTimeAdjustmentDisabled, ok; |
+ if (has_gettickcount64) |
+ info->implementation = "GetTickCount64()"; |
+ else |
+ info->implementation = "GetTickCount()"; |
+ info->monotonic = 1; |
+ ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, |
+ &isTimeAdjustmentDisabled); |
+ if (!ok) { |
+ PyErr_SetFromWindowsErr(0); |
+ return -1; |
+ } |
+ info->resolution = timeIncrement * 1e-7; |
+ info->adjustable = 0; |
+ } |
+ return 0; |
+ |
+#elif defined(__APPLE__) |
+ static mach_timebase_info_data_t timebase; |
+ uint64_t time; |
+ |
+ 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(); |
+ |
+ /* nanoseconds => microseconds */ |
+ time /= 1000; |
+ /* apply timebase factor */ |
+ time *= timebase.numer; |
+ time /= timebase.denom; |
+ tp->tv_sec = time / (1000 * 1000); |
+ tp->tv_usec = time % (1000 * 1000); |
+ |
+ if (info) { |
+ info->implementation = "mach_absolute_time()"; |
+ info->resolution = (double)timebase.numer / timebase.denom * 1e-9; |
+ info->monotonic = 1; |
+ info->adjustable = 0; |
+ } |
+ return 0; |
+ |
+#else |
+ struct timespec ts; |
+#ifdef CLOCK_HIGHRES |
+ const clockid_t clk_id = CLOCK_HIGHRES; |
+ const char *implementation = "clock_gettime(CLOCK_HIGHRES)"; |
+#else |
+ const clockid_t clk_id = CLOCK_MONOTONIC; |
+ const char *implementation = "clock_gettime(CLOCK_MONOTONIC)"; |
+#endif |
+ |
+ assert(info == NULL || raise); |
+ |
+ if (clock_gettime(clk_id, &ts) != 0) { |
+ if (raise) { |
+ PyErr_SetFromErrno(PyExc_OSError); |
+ return -1; |
+ } |
+ tp->tv_sec = 0; |
+ tp->tv_usec = 0; |
+ return -1; |
+ } |
+ |
+ if (info) { |
+ struct timespec res; |
+ info->monotonic = 1; |
+ info->implementation = implementation; |
+ info->adjustable = 0; |
+ if (clock_getres(clk_id, &res) != 0) { |
+ PyErr_SetFromErrno(PyExc_OSError); |
+ return -1; |
+ } |
+ info->resolution = res.tv_sec + res.tv_nsec * 1e-9; |
+ } |
+ tp->tv_sec = ts.tv_sec; |
+ tp->tv_usec = ts.tv_nsec / 1000; |
+ return 0; |
+#endif |
+} |
+ |
+void |
+_PyTime_monotonic(_PyTime_timeval *tp) |
+{ |
+ if (pymonotonic(tp, NULL, 0) < 0) { |
+ /* cannot happen, _PyTime_Init() checks that pymonotonic() works */ |
+ assert(0); |
+ tp->tv_sec = 0; |
+ tp->tv_usec = 0; |
+ } |
+} |
+ |
+int |
+_PyTime_monotonic_info(_PyTime_timeval *tp, _Py_clock_info_t *info) |
+{ |
+ return pymonotonic(tp, info, 1); |
+} |
+ |
static void |
error_time_t_overflow(void) |
{ |
@@ -248,8 +402,21 @@ int |
_PyTime_Init(void) |
{ |
_PyTime_timeval tv; |
+ |
+#ifdef MS_WINDOWS |
+ winver.dwOSVersionInfoSize = sizeof(winver); |
+ if (!GetVersionEx((OSVERSIONINFO*)&winver)) { |
+ PyErr_SetFromWindowsErr(0); |
+ return -1; |
+ } |
+#endif |
+ |
/* ensure that the system clock works */ |
if (_PyTime_gettimeofday_info(&tv, NULL) < 0) |
return -1; |
+ |
+ /* ensure that the operating system provides a monotonic clock */ |
+ if (_PyTime_monotonic_info(&tv, NULL) < 0) |
+ return -1; |
return 0; |
} |