Added support for pre-Vista Windows versions using GetTickCount

This commit is contained in:
Itay Bookstein 2015-12-29 12:28:55 +02:00
parent a29eb9448c
commit 624fa6e062
3 changed files with 51 additions and 18 deletions

View File

@ -11,7 +11,7 @@ it will fall back to an equivalent implementation:
OS | Implementation OS | Implementation
-------------|------------------------- -------------|-------------------------
Linux, *BSD | [clock_gettime][1] Linux, *BSD | [clock_gettime][1]
Windows | [GetTickCount64][2] Windows | [GetTickCount[64]][2]
OS X | [mach_absolute_time][3] OS X | [mach_absolute_time][3]
If no suitable implementation exists for the current platform, If no suitable implementation exists for the current platform,

View File

@ -13,7 +13,7 @@
+-------------+--------------------+ +-------------+--------------------+
| Linux, BSD | clock_gettime(3) | | Linux, BSD | clock_gettime(3) |
+-------------+--------------------+ +-------------+--------------------+
| Windows | GetTickCount64 | | Windows | GetTickCount[64] |
+-------------+--------------------+ +-------------+--------------------+
| OS X | mach_absolute_time | | OS X | mach_absolute_time |
+-------------+--------------------+ +-------------+--------------------+
@ -45,6 +45,7 @@ import platform
import re import re
import sys import sys
import time import time
import threading
__all__ = ('monotonic',) __all__ = ('monotonic',)
@ -87,24 +88,56 @@ except AttributeError:
"""Monotonic clock, cannot go backward.""" """Monotonic clock, cannot go backward."""
return mach_absolute_time() / ticks_per_second return mach_absolute_time() / ticks_per_second
elif sys.platform.startswith('win32'): elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
if sys.platform.startswith('cygwin'):
# Note: cygwin implements clock_gettime (CLOCK_MONOTONIC = 4) since
# version 1.7.6. Using raw WinAPI for maximum version compatibility.
# Ugly hack using the wrong calling convention (in 32-bit mode)
# because ctypes has no windll under cygwin (and it also seems that
# the code letting you select stdcall in _ctypes doesn't exist under
# the preprocessor definitions relevant to cygwin).
# This is 'safe' because:
# 1. The ABI of GetTickCount and GetTickCount64 is identical for
# both calling conventions because they both have no parameters.
# 2. libffi masks the problem because after making the call it doesn't
# touch anything through esp and epilogue code restores a correct
# esp from ebp afterwards.
kernel32 = ctypes.cdll.kernel32
else:
kernel32 = ctypes.windll.kernel32
try:
# Windows Vista / Windows Server 2008 or newer. # Windows Vista / Windows Server 2008 or newer.
GetTickCount64 = ctypes.windll.kernel32.GetTickCount64
GetTickCount64.restype = ctypes.c_ulonglong
def monotonic():
"""Monotonic clock, cannot go backward."""
return GetTickCount64() / 1000.0
elif sys.platform.startswith('cygwin'):
# Cygwin
kernel32 = ctypes.cdll.LoadLibrary('kernel32.dll')
GetTickCount64 = kernel32.GetTickCount64 GetTickCount64 = kernel32.GetTickCount64
GetTickCount64.restype = ctypes.c_ulonglong GetTickCount64.restype = ctypes.c_ulonglong
def monotonic(): def monotonic():
"""Monotonic clock, cannot go backward.""" """Monotonic clock, cannot go backward."""
return GetTickCount64() / 1000.0 return GetTickCount64() / 1000.0
except AttributeError:
# Before Windows Vista.
GetTickCount = kernel32.GetTickCount
GetTickCount.restype = ctypes.c_uint32
get_tick_count_lock = threading.Lock()
get_tick_count_last_sample = 0
get_tick_count_wraparounds = 0
def monotonic():
"""Monotonic clock, cannot go backward."""
global get_tick_count_last_sample
global get_tick_count_wraparounds
with get_tick_count_lock:
current_sample = GetTickCount()
if current_sample < get_tick_count_last_sample:
get_tick_count_wraparounds += 1
get_tick_count_last_sample = current_sample
final_milliseconds = get_tick_count_wraparounds << 32
final_milliseconds += get_tick_count_last_sample
return final_milliseconds / 1000.0
else: else:
try: try:

View File

@ -13,7 +13,7 @@ it will fall back to an equivalent implementation:
+-------------+--------------------+ +-------------+--------------------+
| Linux, BSD | clock_gettime(3) | | Linux, BSD | clock_gettime(3) |
+-------------+--------------------+ +-------------+--------------------+
| Windows | GetTickCount64 | | Windows | GetTickCount[64] |
+-------------+--------------------+ +-------------+--------------------+
| OS X | mach_absolute_time | | OS X | mach_absolute_time |
+-------------+--------------------+ +-------------+--------------------+