Skip to content

Commit 55868f1

Browse files
authored
bpo-45429: Support CREATE_WAITABLE_TIMER_HIGH_RESOLUTION if possible (GH-29203)
1 parent 8b06d01 commit 55868f1

File tree

3 files changed

+37
-9
lines changed

3 files changed

+37
-9
lines changed

Doc/whatsnew/3.11.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,10 @@ time
283283
a resolution of 1 millisecond (10\ :sup:`-3` seconds).
284284
(Contributed by Benjamin Szőke and Victor Stinner in :issue:`21302`.)
285285

286+
* On Windows, :func:`time.sleep` now uses a waitable timer which supports high-resolution timers.
287+
In Python 3.10, the best resolution was 1 ms, from Python 3.11 it's now smaller than 1 ms.
288+
(Contributed by Dong-hee Na and Eryk Sun in :issue:`45429`.)
289+
286290
unicodedata
287291
-----------
288292

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
On Windows, :func:`time.sleep` now uses a waitable timer which supports
2+
high-resolution timers. Patch by Dong-hee Na and Eryk Sun.

Modules/timemodule.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,13 @@ static PyStructSequence_Desc struct_time_type_desc = {
408408
static int initialized;
409409
static PyTypeObject StructTimeType;
410410

411+
#if defined(MS_WINDOWS)
412+
#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
413+
#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002
414+
#endif
415+
416+
static DWORD timer_flags = (DWORD)-1;
417+
#endif
411418

412419
static PyObject *
413420
tmtotuple(struct tm *p
@@ -2017,6 +2024,23 @@ time_exec(PyObject *module)
20172024
utc_string = tm.tm_zone;
20182025
#endif
20192026

2027+
#if defined(MS_WINDOWS)
2028+
if (timer_flags == (DWORD)-1) {
2029+
DWORD test_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION;
2030+
HANDLE timer = CreateWaitableTimerExW(NULL, NULL, test_flags,
2031+
TIMER_ALL_ACCESS);
2032+
if (timer == NULL) {
2033+
// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is not supported.
2034+
timer_flags = 0;
2035+
}
2036+
else {
2037+
// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is supported.
2038+
timer_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION;
2039+
CloseHandle(timer);
2040+
}
2041+
}
2042+
#endif
2043+
20202044
return 0;
20212045
}
20222046

@@ -2150,20 +2174,18 @@ pysleep(_PyTime_t timeout)
21502174
// SetWaitableTimer(): a negative due time indicates relative time
21512175
relative_timeout.QuadPart = -timeout_100ns;
21522176

2153-
HANDLE timer = CreateWaitableTimerW(NULL, FALSE, NULL);
2177+
HANDLE timer = CreateWaitableTimerExW(NULL, NULL, timer_flags,
2178+
TIMER_ALL_ACCESS);
21542179
if (timer == NULL) {
21552180
PyErr_SetFromWindowsErr(0);
21562181
return -1;
21572182
}
21582183

2159-
if (!SetWaitableTimer(timer, &relative_timeout,
2160-
// period: the timer is signaled once
2161-
0,
2162-
// no completion routine
2163-
NULL, NULL,
2164-
// Don't restore a system in suspended power
2165-
// conservation mode when the timer is signaled.
2166-
FALSE))
2184+
if (!SetWaitableTimerEx(timer, &relative_timeout,
2185+
0, // no period; the timer is signaled once
2186+
NULL, NULL, // no completion routine
2187+
NULL, // no wake context; do not resume from suspend
2188+
0)) // no tolerable delay for timer coalescing
21672189
{
21682190
PyErr_SetFromWindowsErr(0);
21692191
goto error;

0 commit comments

Comments
 (0)