@@ -367,8 +367,9 @@ time_sleep(PyObject *self, PyObject *obj)
367367 "sleep length must be non-negative" );
368368 return NULL ;
369369 }
370- if (pysleep (secs ) != 0 )
370+ if (pysleep (secs ) != 0 ) {
371371 return NULL ;
372+ }
372373 Py_RETURN_NONE ;
373374}
374375
@@ -2044,47 +2045,42 @@ PyInit_time(void)
20442045 return PyModuleDef_Init (& timemodule );
20452046}
20462047
2047- /* Implement pysleep() for various platforms.
2048- When interrupted (or when another error occurs), return -1 and
2049- set an exception; else return 0. */
20502048
2049+ // time.sleep() implementation.
2050+ // On error, raise an exception and return -1.
2051+ // On success, return 0.
20512052static int
20522053pysleep (_PyTime_t secs )
20532054{
2054- _PyTime_t deadline , monotonic ;
2055+ assert (secs >= 0 );
2056+
20552057#ifndef MS_WINDOWS
20562058#ifdef HAVE_CLOCK_NANOSLEEP
20572059 struct timespec timeout_abs ;
20582060#else
20592061 struct timeval timeout ;
20602062#endif
2063+ _PyTime_t deadline , monotonic ;
20612064 int err = 0 ;
2062- int ret = 0 ;
2063- #else
2064- _PyTime_t millisecs ;
2065- unsigned long ul_millis ;
2066- DWORD rc ;
2067- HANDLE hInterruptEvent ;
2068- #endif
20692065
20702066 if (get_monotonic (& monotonic ) < 0 ) {
20712067 return -1 ;
20722068 }
20732069 deadline = monotonic + secs ;
2074- #if defined( HAVE_CLOCK_NANOSLEEP ) && !defined( MS_WINDOWS )
2070+ #ifdef HAVE_CLOCK_NANOSLEEP
20752071 if (_PyTime_AsTimespec (deadline , & timeout_abs ) < 0 ) {
20762072 return -1 ;
20772073 }
20782074#endif
20792075
20802076 do {
2081- #ifndef MS_WINDOWS
20822077#ifndef HAVE_CLOCK_NANOSLEEP
20832078 if (_PyTime_AsTimeval (secs , & timeout , _PyTime_ROUND_CEILING ) < 0 ) {
20842079 return -1 ;
20852080 }
20862081#endif
20872082
2083+ int ret ;
20882084#ifdef HAVE_CLOCK_NANOSLEEP
20892085 Py_BEGIN_ALLOW_THREADS
20902086 ret = clock_nanosleep (CLOCK_MONOTONIC , TIMER_ABSTIME , & timeout_abs , NULL );
@@ -2106,35 +2102,6 @@ pysleep(_PyTime_t secs)
21062102 PyErr_SetFromErrno (PyExc_OSError );
21072103 return -1 ;
21082104 }
2109- #else
2110- millisecs = _PyTime_AsMilliseconds (secs , _PyTime_ROUND_CEILING );
2111- if (millisecs > (double )ULONG_MAX ) {
2112- PyErr_SetString (PyExc_OverflowError ,
2113- "sleep length is too large" );
2114- return -1 ;
2115- }
2116-
2117- /* Allow sleep(0) to maintain win32 semantics, and as decreed
2118- * by Guido, only the main thread can be interrupted.
2119- */
2120- ul_millis = (unsigned long )millisecs ;
2121- if (ul_millis == 0 || !_PyOS_IsMainThread ()) {
2122- Py_BEGIN_ALLOW_THREADS
2123- Sleep (ul_millis );
2124- Py_END_ALLOW_THREADS
2125- break ;
2126- }
2127-
2128- hInterruptEvent = _PyOS_SigintEvent ();
2129- ResetEvent (hInterruptEvent );
2130-
2131- Py_BEGIN_ALLOW_THREADS
2132- rc = WaitForSingleObjectEx (hInterruptEvent , ul_millis , FALSE);
2133- Py_END_ALLOW_THREADS
2134-
2135- if (rc != WAIT_OBJECT_0 )
2136- break ;
2137- #endif
21382105
21392106 /* sleep was interrupted by SIGINT */
21402107 if (PyErr_CheckSignals ()) {
@@ -2154,4 +2121,104 @@ pysleep(_PyTime_t secs)
21542121 } while (1 );
21552122
21562123 return 0 ;
2124+ #else // MS_WINDOWS
2125+ _PyTime_t timeout = _PyTime_As100Nanoseconds (secs , _PyTime_ROUND_CEILING );
2126+
2127+ // Maintain Windows Sleep() semantics for time.sleep(0)
2128+ if (timeout == 0 ) {
2129+ Py_BEGIN_ALLOW_THREADS
2130+ // A value of zero causes the thread to relinquish the remainder of its
2131+ // time slice to any other thread that is ready to run. If there are no
2132+ // other threads ready to run, the function returns immediately, and
2133+ // the thread continues execution.
2134+ Sleep (0 );
2135+ Py_END_ALLOW_THREADS
2136+ return 0 ;
2137+ }
2138+
2139+ LARGE_INTEGER relative_timeout ;
2140+ // No need to check for integer overflow, both types are signed
2141+ assert (sizeof (relative_timeout ) == sizeof (timeout ));
2142+ // SetWaitableTimer(): a negative due time indicates relative time
2143+ relative_timeout .QuadPart = - timeout ;
2144+
2145+ HANDLE timer = CreateWaitableTimerW (NULL , FALSE, NULL );
2146+ if (timer == NULL ) {
2147+ PyErr_SetFromWindowsErr (0 );
2148+ return -1 ;
2149+ }
2150+
2151+ if (!SetWaitableTimer (timer , & relative_timeout ,
2152+ // period: the timer is signaled once
2153+ 0 ,
2154+ // no completion routine
2155+ NULL , NULL ,
2156+ // Don't restore a system in suspended power
2157+ // conservation mode when the timer is signaled.
2158+ FALSE))
2159+ {
2160+ PyErr_SetFromWindowsErr (0 );
2161+ goto error ;
2162+ }
2163+
2164+ // Only the main thread can be interrupted by SIGINT.
2165+ // Signal handlers are only executed in the main thread.
2166+ if (_PyOS_IsMainThread ()) {
2167+ HANDLE sigint_event = _PyOS_SigintEvent ();
2168+
2169+ while (1 ) {
2170+ // Check for pending SIGINT signal before resetting the event
2171+ if (PyErr_CheckSignals ()) {
2172+ goto error ;
2173+ }
2174+ ResetEvent (sigint_event );
2175+
2176+ HANDLE events [] = {timer , sigint_event };
2177+ DWORD rc ;
2178+
2179+ Py_BEGIN_ALLOW_THREADS
2180+ rc = WaitForMultipleObjects (Py_ARRAY_LENGTH (events ), events ,
2181+ // bWaitAll
2182+ FALSE,
2183+ // No wait timeout
2184+ INFINITE );
2185+ Py_END_ALLOW_THREADS
2186+
2187+ if (rc == WAIT_FAILED ) {
2188+ PyErr_SetFromWindowsErr (0 );
2189+ goto error ;
2190+ }
2191+
2192+ if (rc == WAIT_OBJECT_0 ) {
2193+ // Timer signaled: we are done
2194+ break ;
2195+ }
2196+
2197+ assert (rc == (WAIT_OBJECT_0 + 1 ));
2198+ // The sleep was interrupted by SIGINT: restart sleeping
2199+ }
2200+ }
2201+ else {
2202+ DWORD rc ;
2203+
2204+ Py_BEGIN_ALLOW_THREADS
2205+ rc = WaitForSingleObject (timer , INFINITE );
2206+ Py_END_ALLOW_THREADS
2207+
2208+ if (rc == WAIT_FAILED ) {
2209+ PyErr_SetFromWindowsErr (0 );
2210+ goto error ;
2211+ }
2212+
2213+ assert (rc == WAIT_OBJECT_0 );
2214+ // Timer signaled: we are done
2215+ }
2216+
2217+ CloseHandle (timer );
2218+ return 0 ;
2219+
2220+ error :
2221+ CloseHandle (timer );
2222+ return -1 ;
2223+ #endif
21572224}
0 commit comments