mirror of
https://github.com/python/cpython.git
synced 2025-07-24 19:54:21 +00:00
Issue #22043: time.monotonic() is now always available
threading.Lock.acquire(), threading.RLock.acquire() and socket operations now use a monotonic clock, instead of the system clock, when a timeout is used.
This commit is contained in:
parent
9bb758cee7
commit
ae58649721
17 changed files with 226 additions and 176 deletions
175
Python/pytime.c
175
Python/pytime.c
|
@ -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)
|
||||
{
|
||||
|
@ -109,6 +117,160 @@ _PyTime_gettimeofday_info(_PyTime_timeval *tp, _Py_clock_info_t *info)
|
|||
return pygettimeofday(tp, info, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
pymonotonic(_PyTime_timeval *tp, _Py_clock_info_t *info, int raise)
|
||||
{
|
||||
#ifdef Py_DEBUG
|
||||
static _PyTime_timeval last = {-1, -1};
|
||||
#endif
|
||||
#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;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#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;
|
||||
#endif
|
||||
assert(0 <= tp->tv_usec && tp->tv_usec < 1000 * 1000);
|
||||
#ifdef Py_DEBUG
|
||||
/* monotonic clock cannot go backward */
|
||||
assert(tp->tv_sec > last.tv_sec
|
||||
|| (tp->tv_sec == last.tv_sec && tp->tv_usec >= last.tv_usec));
|
||||
last = *tp;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -245,8 +407,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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue