@@ -113,7 +113,7 @@ _PyTime_Init(void)
113
113
114
114
115
115
/* Forward declarations */
116
- static int pysleep (_PyTime_t timeout );
116
+ static int pysleep (_PyTime_t timeout , int absolute );
117
117
118
118
119
119
typedef struct {
@@ -420,7 +420,7 @@ time_sleep(PyObject *self, PyObject *timeout_obj)
420
420
"sleep length must be non-negative" );
421
421
return NULL ;
422
422
}
423
- if (pysleep (timeout ) != 0 ) {
423
+ if (pysleep (timeout , 0 ) != 0 ) {
424
424
return NULL ;
425
425
}
426
426
Py_RETURN_NONE ;
@@ -432,6 +432,28 @@ PyDoc_STRVAR(sleep_doc,
432
432
Delay execution for a given number of seconds. The argument may be\n\
433
433
a floating point number for subsecond precision." );
434
434
435
+ static PyObject *
436
+ time_sleep_until (PyObject * self , PyObject * deadline_obj )
437
+ {
438
+ _PyTime_t deadline ;
439
+ if (_PyTime_FromSecondsObject (& deadline , deadline_obj , _PyTime_ROUND_TIMEOUT ))
440
+ return NULL ;
441
+ if (deadline < 0 ) {
442
+ PyErr_SetString (PyExc_ValueError ,
443
+ "sleep_until deadline must be non-negative" );
444
+ return NULL ;
445
+ }
446
+ if (pysleep (deadline , 1 ) != 0 ) {
447
+ return NULL ;
448
+ }
449
+ Py_RETURN_NONE ;
450
+ }
451
+
452
+ PyDoc_STRVAR (sleep_until_doc ,
453
+ "sleep_until(seconds)\n\
454
+ \n\
455
+ Delay execution until the specified system clock time." );
456
+
435
457
static PyStructSequence_Field struct_time_type_fields [] = {
436
458
{"tm_year" , "year, for example, 1993" },
437
459
{"tm_mon" , "month of year, range [1, 12]" },
@@ -1862,6 +1884,7 @@ static PyMethodDef time_methods[] = {
1862
1884
{"pthread_getcpuclockid" , time_pthread_getcpuclockid , METH_VARARGS , pthread_getcpuclockid_doc },
1863
1885
#endif
1864
1886
{"sleep" , time_sleep , METH_O , sleep_doc },
1887
+ {"sleep_until" , time_sleep_until , METH_O , sleep_until_doc },
1865
1888
{"gmtime" , time_gmtime , METH_VARARGS , gmtime_doc },
1866
1889
{"localtime" , time_localtime , METH_VARARGS , localtime_doc },
1867
1890
{"asctime" , time_asctime , METH_VARARGS , asctime_doc },
@@ -2126,8 +2149,9 @@ PyInit_time(void)
2126
2149
// time.sleep() implementation.
2127
2150
// On error, raise an exception and return -1.
2128
2151
// On success, return 0.
2152
+ // If absolute==0, timeout is relative; otherwise timeout is absolute.
2129
2153
static int
2130
- pysleep (_PyTime_t timeout )
2154
+ pysleep (_PyTime_t timeout , int absolute )
2131
2155
{
2132
2156
assert (timeout >= 0 );
2133
2157
@@ -2139,13 +2163,27 @@ pysleep(_PyTime_t timeout)
2139
2163
#else
2140
2164
struct timeval timeout_tv ;
2141
2165
#endif
2142
- _PyTime_t deadline , monotonic ;
2166
+ _PyTime_t deadline , reference ;
2143
2167
int err = 0 ;
2144
2168
2145
- if (get_monotonic (& monotonic ) < 0 ) {
2146
- return -1 ;
2169
+ if (absolute ) {
2170
+ deadline = timeout ;
2171
+ #ifndef HAVE_CLOCK_NANOSLEEP
2172
+ if (get_system_time (& reference ) < 0 ) {
2173
+ return -1 ;
2174
+ }
2175
+ timeout = deadline - reference ;
2176
+ if (timeout < 0 ) {
2177
+ return 0 ;
2178
+ }
2179
+ #endif
2180
+ }
2181
+ else {
2182
+ if (get_monotonic (& reference ) < 0 ) {
2183
+ return -1 ;
2184
+ }
2185
+ deadline = reference + timeout ;
2147
2186
}
2148
- deadline = monotonic + timeout ;
2149
2187
#ifdef HAVE_CLOCK_NANOSLEEP
2150
2188
if (_PyTime_AsTimespec (deadline , & timeout_abs ) < 0 ) {
2151
2189
return -1 ;
@@ -2168,7 +2206,8 @@ pysleep(_PyTime_t timeout)
2168
2206
int ret ;
2169
2207
Py_BEGIN_ALLOW_THREADS
2170
2208
#ifdef HAVE_CLOCK_NANOSLEEP
2171
- ret = clock_nanosleep (CLOCK_MONOTONIC , TIMER_ABSTIME , & timeout_abs , NULL );
2209
+ ret = clock_nanosleep (absolute ? CLOCK_REALTIME : CLOCK_MONOTONIC ,
2210
+ TIMER_ABSTIME , & timeout_abs , NULL );
2172
2211
err = ret ;
2173
2212
#elif defined(HAVE_NANOSLEEP )
2174
2213
ret = nanosleep (& timeout_ts , NULL );
@@ -2195,10 +2234,17 @@ pysleep(_PyTime_t timeout)
2195
2234
}
2196
2235
2197
2236
#ifndef HAVE_CLOCK_NANOSLEEP
2198
- if (get_monotonic (& monotonic ) < 0 ) {
2199
- return -1 ;
2237
+ if (absolute ) {
2238
+ if (get_system_time (& reference ) < 0 ) {
2239
+ return -1 ;
2240
+ }
2241
+ }
2242
+ else {
2243
+ if (get_monotonic (& reference ) < 0 ) {
2244
+ return -1 ;
2245
+ }
2200
2246
}
2201
- timeout = deadline - monotonic ;
2247
+ timeout = deadline - reference ;
2202
2248
if (timeout < 0 ) {
2203
2249
break ;
2204
2250
}
@@ -2223,11 +2269,18 @@ pysleep(_PyTime_t timeout)
2223
2269
return 0 ;
2224
2270
}
2225
2271
2226
- LARGE_INTEGER relative_timeout ;
2272
+ LARGE_INTEGER due_time ;
2227
2273
// No need to check for integer overflow, both types are signed
2228
- assert (sizeof (relative_timeout ) == sizeof (timeout_100ns ));
2229
- // SetWaitableTimer(): a negative due time indicates relative time
2230
- relative_timeout .QuadPart = - timeout_100ns ;
2274
+ assert (sizeof (due_time ) == sizeof (timeout_100ns ));
2275
+ if (absolute ) {
2276
+ // Adjust from Unix time (1970-01-01) to Windows time (1601-01-01)
2277
+ // (the inverse of what is done in py_get_system_clock)
2278
+ due_time .QuadPart = timeout_100ns + 116444736000000000 ;
2279
+ }
2280
+ else {
2281
+ // SetWaitableTimer(): a negative due time indicates relative time
2282
+ due_time .QuadPart = - timeout_100ns ;
2283
+ }
2231
2284
2232
2285
HANDLE timer = CreateWaitableTimerExW (NULL , NULL , timer_flags ,
2233
2286
TIMER_ALL_ACCESS );
@@ -2236,7 +2289,7 @@ pysleep(_PyTime_t timeout)
2236
2289
return -1 ;
2237
2290
}
2238
2291
2239
- if (!SetWaitableTimerEx (timer , & relative_timeout ,
2292
+ if (!SetWaitableTimerEx (timer , & due_time ,
2240
2293
0 , // no period; the timer is signaled once
2241
2294
NULL , NULL , // no completion routine
2242
2295
NULL , // no wake context; do not resume from suspend
0 commit comments