/src/cpython/Modules/timemodule.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Time module */ |
2 | | |
3 | | #include "Python.h" |
4 | | #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH |
5 | | #include "pycore_moduleobject.h" // _PyModule_GetState() |
6 | | #include "pycore_namespace.h" // _PyNamespace_New() |
7 | | #include "pycore_runtime.h" // _Py_ID() |
8 | | #include "pycore_time.h" // _PyTimeFraction |
9 | | |
10 | | #include <time.h> // clock() |
11 | | #ifdef HAVE_SYS_TIMES_H |
12 | | # include <sys/times.h> // times() |
13 | | #endif |
14 | | #ifdef HAVE_SYS_TYPES_H |
15 | | # include <sys/types.h> |
16 | | #endif |
17 | | #if defined(HAVE_SYS_RESOURCE_H) |
18 | | # include <sys/resource.h> // getrusage(RUSAGE_SELF) |
19 | | #endif |
20 | | #ifdef QUICKWIN |
21 | | # include <io.h> |
22 | | #endif |
23 | | #if defined(HAVE_PTHREAD_H) |
24 | | # include <pthread.h> // pthread_getcpuclockid() |
25 | | #endif |
26 | | #if defined(_AIX) |
27 | | # include <sys/thread.h> |
28 | | #endif |
29 | | #if defined(__WATCOMC__) && !defined(__QNX__) |
30 | | # include <i86.h> |
31 | | #else |
32 | | # ifdef MS_WINDOWS |
33 | | # ifndef WIN32_LEAN_AND_MEAN |
34 | | # define WIN32_LEAN_AND_MEAN |
35 | | # endif |
36 | | # include <windows.h> |
37 | | # endif /* MS_WINDOWS */ |
38 | | #endif /* !__WATCOMC__ || __QNX__ */ |
39 | | |
40 | | #ifdef _Py_MEMORY_SANITIZER |
41 | | # include <sanitizer/msan_interface.h> |
42 | | #endif |
43 | | |
44 | | #ifdef _MSC_VER |
45 | | # define _Py_timezone _timezone |
46 | | # define _Py_daylight _daylight |
47 | | # define _Py_tzname _tzname |
48 | | #else |
49 | | # define _Py_timezone timezone |
50 | | # define _Py_daylight daylight |
51 | | # define _Py_tzname tzname |
52 | | #endif |
53 | | |
54 | | #if defined(__APPLE__ ) && defined(__has_builtin) |
55 | | # if __has_builtin(__builtin_available) |
56 | | # define HAVE_CLOCK_GETTIME_RUNTIME __builtin_available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) |
57 | | # endif |
58 | | #endif |
59 | | #ifndef HAVE_CLOCK_GETTIME_RUNTIME |
60 | 16 | # define HAVE_CLOCK_GETTIME_RUNTIME 1 |
61 | | #endif |
62 | | |
63 | | |
64 | 32 | #define SEC_TO_NS (1000 * 1000 * 1000) |
65 | | |
66 | | |
67 | | /*[clinic input] |
68 | | module time |
69 | | [clinic start generated code]*/ |
70 | | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=a668a08771581f36]*/ |
71 | | |
72 | | |
73 | | /* Forward declarations */ |
74 | | static int pysleep(PyTime_t timeout); |
75 | | |
76 | | |
77 | | typedef struct { |
78 | | PyTypeObject *struct_time_type; |
79 | | // gh-115714: Don't use times() on WASI. |
80 | | #if defined(HAVE_TIMES) && !defined(__wasi__) |
81 | | // times() clock frequency in hertz |
82 | | _PyTimeFraction times_base; |
83 | | #endif |
84 | | #ifdef HAVE_CLOCK |
85 | | // clock() frequency in hertz |
86 | | _PyTimeFraction clock_base; |
87 | | #endif |
88 | | } time_module_state; |
89 | | |
90 | | static inline time_module_state* |
91 | | get_time_state(PyObject *module) |
92 | 4.15k | { |
93 | 4.15k | void *state = _PyModule_GetState(module); |
94 | 4.15k | assert(state != NULL); |
95 | 4.15k | return (time_module_state *)state; |
96 | 4.15k | } |
97 | | |
98 | | |
99 | | static PyObject* |
100 | | _PyFloat_FromPyTime(PyTime_t t) |
101 | 0 | { |
102 | 0 | double d = PyTime_AsSecondsDouble(t); |
103 | 0 | return PyFloat_FromDouble(d); |
104 | 0 | } |
105 | | |
106 | | |
107 | | static PyObject * |
108 | | time_time(PyObject *self, PyObject *unused) |
109 | 0 | { |
110 | 0 | PyTime_t t; |
111 | 0 | if (PyTime_Time(&t) < 0) { |
112 | 0 | return NULL; |
113 | 0 | } |
114 | 0 | return _PyFloat_FromPyTime(t); |
115 | 0 | } |
116 | | |
117 | | |
118 | | PyDoc_STRVAR(time_doc, |
119 | | "time() -> floating-point number\n\ |
120 | | \n\ |
121 | | Return the current time in seconds since the Epoch.\n\ |
122 | | Fractions of a second may be present if the system clock provides them."); |
123 | | |
124 | | static PyObject * |
125 | | time_time_ns(PyObject *self, PyObject *unused) |
126 | 0 | { |
127 | 0 | PyTime_t t; |
128 | 0 | if (PyTime_Time(&t) < 0) { |
129 | 0 | return NULL; |
130 | 0 | } |
131 | 0 | return _PyTime_AsLong(t); |
132 | 0 | } |
133 | | |
134 | | PyDoc_STRVAR(time_ns_doc, |
135 | | "time_ns() -> int\n\ |
136 | | \n\ |
137 | | Return the current time in nanoseconds since the Epoch."); |
138 | | |
139 | | #ifdef HAVE_CLOCK |
140 | | |
141 | | #ifndef CLOCKS_PER_SEC |
142 | | # ifdef CLK_TCK |
143 | | # define CLOCKS_PER_SEC CLK_TCK |
144 | | # else |
145 | | # define CLOCKS_PER_SEC 1000000 |
146 | | # endif |
147 | | #endif |
148 | | |
149 | | static int |
150 | | py_clock(time_module_state *state, PyTime_t *tp, _Py_clock_info_t *info) |
151 | 0 | { |
152 | 0 | _PyTimeFraction *base = &state->clock_base; |
153 | |
|
154 | 0 | if (info) { |
155 | 0 | info->implementation = "clock()"; |
156 | 0 | info->resolution = _PyTimeFraction_Resolution(base); |
157 | 0 | info->monotonic = 1; |
158 | 0 | info->adjustable = 0; |
159 | 0 | } |
160 | |
|
161 | 0 | clock_t ticks = clock(); |
162 | 0 | if (ticks == (clock_t)-1) { |
163 | 0 | PyErr_SetString(PyExc_RuntimeError, |
164 | 0 | "the processor time used is not available " |
165 | 0 | "or its value cannot be represented"); |
166 | 0 | return -1; |
167 | 0 | } |
168 | 0 | *tp = _PyTimeFraction_Mul(ticks, base); |
169 | 0 | return 0; |
170 | 0 | } |
171 | | #endif /* HAVE_CLOCK */ |
172 | | |
173 | | |
174 | | #ifdef HAVE_CLOCK_GETTIME |
175 | | |
176 | | #ifdef __APPLE__ |
177 | | /* |
178 | | * The clock_* functions will be removed from the module |
179 | | * dict entirely when the C API is not available. |
180 | | */ |
181 | | #pragma clang diagnostic push |
182 | | #pragma clang diagnostic ignored "-Wunguarded-availability" |
183 | | #endif |
184 | | |
185 | | static int |
186 | | time_clockid_converter(PyObject *obj, clockid_t *p) |
187 | 0 | { |
188 | | #ifdef _AIX |
189 | | long long clk_id = PyLong_AsLongLong(obj); |
190 | | #elif defined(__DragonFly__) || defined(__CYGWIN__) |
191 | | long clk_id = PyLong_AsLong(obj); |
192 | | #else |
193 | 0 | int clk_id = PyLong_AsInt(obj); |
194 | 0 | #endif |
195 | 0 | if (clk_id == -1 && PyErr_Occurred()) { |
196 | 0 | PyErr_Format(PyExc_TypeError, |
197 | 0 | "clk_id should be integer, not %s", |
198 | 0 | _PyType_Name(Py_TYPE(obj))); |
199 | 0 | return 0; |
200 | 0 | } |
201 | | |
202 | | // Make sure that we picked the right type (check sizes type) |
203 | 0 | Py_BUILD_ASSERT(sizeof(clk_id) == sizeof(*p)); |
204 | 0 | *p = (clockid_t)clk_id; |
205 | 0 | return 1; |
206 | 0 | } |
207 | | |
208 | | /*[python input] |
209 | | |
210 | | class clockid_t_converter(CConverter): |
211 | | type = "clockid_t" |
212 | | converter = 'time_clockid_converter' |
213 | | |
214 | | [python start generated code]*/ |
215 | | /*[python end generated code: output=da39a3ee5e6b4b0d input=53867111501f46c8]*/ |
216 | | |
217 | | |
218 | | /*[clinic input] |
219 | | time.clock_gettime |
220 | | |
221 | | clk_id: clockid_t |
222 | | / |
223 | | |
224 | | Return the time of the specified clock clk_id as a float. |
225 | | [clinic start generated code]*/ |
226 | | |
227 | | static PyObject * |
228 | | time_clock_gettime_impl(PyObject *module, clockid_t clk_id) |
229 | | /*[clinic end generated code: output=832b9ebc03328020 input=7e89fcc42ca15e5d]*/ |
230 | 0 | { |
231 | 0 | struct timespec tp; |
232 | 0 | int ret = clock_gettime(clk_id, &tp); |
233 | 0 | if (ret != 0) { |
234 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
235 | 0 | return NULL; |
236 | 0 | } |
237 | 0 | return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); |
238 | 0 | } |
239 | | |
240 | | /*[clinic input] |
241 | | time.clock_gettime_ns |
242 | | |
243 | | clk_id: clockid_t |
244 | | / |
245 | | |
246 | | Return the time of the specified clock clk_id as nanoseconds (int). |
247 | | [clinic start generated code]*/ |
248 | | |
249 | | static PyObject * |
250 | | time_clock_gettime_ns_impl(PyObject *module, clockid_t clk_id) |
251 | | /*[clinic end generated code: output=4a045c3a36e60044 input=aabc248db8c8e3e5]*/ |
252 | 0 | { |
253 | 0 | struct timespec ts; |
254 | 0 | int ret = clock_gettime(clk_id, &ts); |
255 | 0 | if (ret != 0) { |
256 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
257 | 0 | return NULL; |
258 | 0 | } |
259 | | |
260 | 0 | PyTime_t t; |
261 | 0 | if (_PyTime_FromTimespec(&t, &ts) < 0) { |
262 | 0 | return NULL; |
263 | 0 | } |
264 | 0 | return _PyTime_AsLong(t); |
265 | 0 | } |
266 | | #endif /* HAVE_CLOCK_GETTIME */ |
267 | | |
268 | | #ifdef HAVE_CLOCK_SETTIME |
269 | | static PyObject * |
270 | | time_clock_settime(PyObject *self, PyObject *args) |
271 | 0 | { |
272 | 0 | int clk_id; |
273 | 0 | PyObject *obj; |
274 | 0 | PyTime_t t; |
275 | 0 | struct timespec tp; |
276 | 0 | int ret; |
277 | |
|
278 | 0 | if (!PyArg_ParseTuple(args, "iO:clock_settime", &clk_id, &obj)) |
279 | 0 | return NULL; |
280 | | |
281 | 0 | if (_PyTime_FromSecondsObject(&t, obj, _PyTime_ROUND_FLOOR) < 0) |
282 | 0 | return NULL; |
283 | | |
284 | 0 | if (_PyTime_AsTimespec(t, &tp) == -1) |
285 | 0 | return NULL; |
286 | | |
287 | 0 | ret = clock_settime((clockid_t)clk_id, &tp); |
288 | 0 | if (ret != 0) { |
289 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
290 | 0 | return NULL; |
291 | 0 | } |
292 | 0 | Py_RETURN_NONE; |
293 | 0 | } |
294 | | |
295 | | PyDoc_STRVAR(clock_settime_doc, |
296 | | "clock_settime(clk_id, time)\n\ |
297 | | \n\ |
298 | | Set the time of the specified clock clk_id."); |
299 | | |
300 | | static PyObject * |
301 | | time_clock_settime_ns(PyObject *self, PyObject *args) |
302 | 0 | { |
303 | 0 | int clk_id; |
304 | 0 | PyObject *obj; |
305 | 0 | PyTime_t t; |
306 | 0 | struct timespec ts; |
307 | 0 | int ret; |
308 | |
|
309 | 0 | if (!PyArg_ParseTuple(args, "iO:clock_settime", &clk_id, &obj)) { |
310 | 0 | return NULL; |
311 | 0 | } |
312 | | |
313 | 0 | if (_PyTime_FromLong(&t, obj) < 0) { |
314 | 0 | return NULL; |
315 | 0 | } |
316 | 0 | if (_PyTime_AsTimespec(t, &ts) == -1) { |
317 | 0 | return NULL; |
318 | 0 | } |
319 | | |
320 | 0 | ret = clock_settime((clockid_t)clk_id, &ts); |
321 | 0 | if (ret != 0) { |
322 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
323 | 0 | return NULL; |
324 | 0 | } |
325 | 0 | Py_RETURN_NONE; |
326 | 0 | } |
327 | | |
328 | | PyDoc_STRVAR(clock_settime_ns_doc, |
329 | | "clock_settime_ns(clk_id, time)\n\ |
330 | | \n\ |
331 | | Set the time of the specified clock clk_id with nanoseconds."); |
332 | | #endif /* HAVE_CLOCK_SETTIME */ |
333 | | |
334 | | #ifdef HAVE_CLOCK_GETRES |
335 | | static PyObject * |
336 | | time_clock_getres(PyObject *self, PyObject *args) |
337 | 0 | { |
338 | 0 | int ret; |
339 | 0 | int clk_id; |
340 | 0 | struct timespec tp; |
341 | |
|
342 | 0 | if (!PyArg_ParseTuple(args, "i:clock_getres", &clk_id)) |
343 | 0 | return NULL; |
344 | | |
345 | 0 | ret = clock_getres((clockid_t)clk_id, &tp); |
346 | 0 | if (ret != 0) { |
347 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
348 | 0 | return NULL; |
349 | 0 | } |
350 | | |
351 | 0 | return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); |
352 | 0 | } |
353 | | |
354 | | PyDoc_STRVAR(clock_getres_doc, |
355 | | "clock_getres(clk_id) -> floating-point number\n\ |
356 | | \n\ |
357 | | Return the resolution (precision) of the specified clock clk_id."); |
358 | | |
359 | | #ifdef __APPLE__ |
360 | | #pragma clang diagnostic pop |
361 | | #endif |
362 | | |
363 | | #endif /* HAVE_CLOCK_GETRES */ |
364 | | |
365 | | #ifdef HAVE_PTHREAD_GETCPUCLOCKID |
366 | | static PyObject * |
367 | | time_pthread_getcpuclockid(PyObject *self, PyObject *args) |
368 | 0 | { |
369 | 0 | unsigned long thread_id; |
370 | 0 | int err; |
371 | 0 | clockid_t clk_id; |
372 | 0 | if (!PyArg_ParseTuple(args, "k:pthread_getcpuclockid", &thread_id)) { |
373 | 0 | return NULL; |
374 | 0 | } |
375 | 0 | err = pthread_getcpuclockid((pthread_t)thread_id, &clk_id); |
376 | 0 | if (err) { |
377 | 0 | errno = err; |
378 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
379 | 0 | return NULL; |
380 | 0 | } |
381 | | #ifdef _Py_MEMORY_SANITIZER |
382 | | __msan_unpoison(&clk_id, sizeof(clk_id)); |
383 | | #endif |
384 | 0 | return PyLong_FromLong(clk_id); |
385 | 0 | } |
386 | | |
387 | | PyDoc_STRVAR(pthread_getcpuclockid_doc, |
388 | | "pthread_getcpuclockid(thread_id) -> int\n\ |
389 | | \n\ |
390 | | Return the clk_id of a thread's CPU time clock."); |
391 | | #endif /* HAVE_PTHREAD_GETCPUCLOCKID */ |
392 | | |
393 | | static PyObject * |
394 | | time_sleep(PyObject *self, PyObject *timeout_obj) |
395 | 0 | { |
396 | 0 | if (PySys_Audit("time.sleep", "O", timeout_obj) < 0) { |
397 | 0 | return NULL; |
398 | 0 | } |
399 | | |
400 | 0 | PyTime_t timeout; |
401 | 0 | if (_PyTime_FromSecondsObject(&timeout, timeout_obj, _PyTime_ROUND_TIMEOUT)) |
402 | 0 | return NULL; |
403 | 0 | if (timeout < 0) { |
404 | 0 | PyErr_SetString(PyExc_ValueError, |
405 | 0 | "sleep length must be non-negative"); |
406 | 0 | return NULL; |
407 | 0 | } |
408 | 0 | if (pysleep(timeout) != 0) { |
409 | 0 | return NULL; |
410 | 0 | } |
411 | 0 | Py_RETURN_NONE; |
412 | 0 | } |
413 | | |
414 | | PyDoc_STRVAR(sleep_doc, |
415 | | "sleep(seconds)\n\ |
416 | | \n\ |
417 | | Delay execution for a given number of seconds. The argument may be\n\ |
418 | | a floating-point number for subsecond precision."); |
419 | | |
420 | | static PyStructSequence_Field struct_time_type_fields[] = { |
421 | | {"tm_year", "year, for example, 1993"}, |
422 | | {"tm_mon", "month of year, range [1, 12]"}, |
423 | | {"tm_mday", "day of month, range [1, 31]"}, |
424 | | {"tm_hour", "hours, range [0, 23]"}, |
425 | | {"tm_min", "minutes, range [0, 59]"}, |
426 | | {"tm_sec", "seconds, range [0, 61])"}, |
427 | | {"tm_wday", "day of week, range [0, 6], Monday is 0"}, |
428 | | {"tm_yday", "day of year, range [1, 366]"}, |
429 | | {"tm_isdst", "1 if summer time is in effect, 0 if not, and -1 if unknown"}, |
430 | | {"tm_zone", "abbreviation of timezone name"}, |
431 | | {"tm_gmtoff", "offset from UTC in seconds"}, |
432 | | {0} |
433 | | }; |
434 | | |
435 | | static PyStructSequence_Desc struct_time_type_desc = { |
436 | | "time.struct_time", |
437 | | "The time value as returned by gmtime(), localtime(), and strptime(), and\n" |
438 | | " accepted by asctime(), mktime() and strftime(). May be considered as a\n" |
439 | | " sequence of 9 integers.\n\n" |
440 | | " Note that several fields' values are not the same as those defined by\n" |
441 | | " the C language standard for struct tm. For example, the value of the\n" |
442 | | " field tm_year is the actual year, not year - 1900. See individual\n" |
443 | | " fields' descriptions for details.", |
444 | | struct_time_type_fields, |
445 | | 9, |
446 | | }; |
447 | | |
448 | | #if defined(MS_WINDOWS) |
449 | | #ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION |
450 | | #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 |
451 | | #endif |
452 | | |
453 | | static DWORD timer_flags = (DWORD)-1; |
454 | | #endif |
455 | | |
456 | | static PyObject * |
457 | | tmtotuple(time_module_state *state, struct tm *p |
458 | | #ifndef HAVE_STRUCT_TM_TM_ZONE |
459 | | , const char *zone, time_t gmtoff |
460 | | #endif |
461 | | ) |
462 | 0 | { |
463 | 0 | PyObject *v = PyStructSequence_New(state->struct_time_type); |
464 | 0 | if (v == NULL) |
465 | 0 | return NULL; |
466 | | |
467 | 0 | #define SET_ITEM(INDEX, CALL) \ |
468 | 0 | do { \ |
469 | 0 | PyObject *obj = (CALL); \ |
470 | 0 | if (obj == NULL) { \ |
471 | 0 | Py_DECREF(v); \ |
472 | 0 | return NULL; \ |
473 | 0 | } \ |
474 | 0 | PyStructSequence_SET_ITEM(v, (INDEX), obj); \ |
475 | 0 | } while (0) |
476 | | |
477 | 0 | #define SET(INDEX, VAL) \ |
478 | 0 | SET_ITEM((INDEX), PyLong_FromLong((long) (VAL))) |
479 | | |
480 | 0 | SET(0, p->tm_year + 1900); |
481 | 0 | SET(1, p->tm_mon + 1); /* Want January == 1 */ |
482 | 0 | SET(2, p->tm_mday); |
483 | 0 | SET(3, p->tm_hour); |
484 | 0 | SET(4, p->tm_min); |
485 | 0 | SET(5, p->tm_sec); |
486 | 0 | SET(6, (p->tm_wday + 6) % 7); /* Want Monday == 0 */ |
487 | 0 | SET(7, p->tm_yday + 1); /* Want January, 1 == 1 */ |
488 | 0 | SET(8, p->tm_isdst); |
489 | 0 | #ifdef HAVE_STRUCT_TM_TM_ZONE |
490 | 0 | SET_ITEM(9, PyUnicode_DecodeLocale(p->tm_zone, "surrogateescape")); |
491 | 0 | SET(10, p->tm_gmtoff); |
492 | | #else |
493 | | SET_ITEM(9, PyUnicode_DecodeLocale(zone, "surrogateescape")); |
494 | | SET_ITEM(10, _PyLong_FromTime_t(gmtoff)); |
495 | | #endif /* HAVE_STRUCT_TM_TM_ZONE */ |
496 | | |
497 | 0 | #undef SET |
498 | 0 | #undef SET_ITEM |
499 | | |
500 | 0 | return v; |
501 | 0 | } |
502 | | |
503 | | /* Parse arg tuple that can contain an optional float-or-None value; |
504 | | format needs to be "|O:name". |
505 | | Returns non-zero on success (parallels PyArg_ParseTuple). |
506 | | */ |
507 | | static int |
508 | | parse_time_t_args(PyObject *args, const char *format, time_t *pwhen) |
509 | 0 | { |
510 | 0 | PyObject *ot = NULL; |
511 | 0 | time_t whent; |
512 | |
|
513 | 0 | if (!PyArg_ParseTuple(args, format, &ot)) |
514 | 0 | return 0; |
515 | 0 | if (ot == NULL || ot == Py_None) { |
516 | 0 | whent = time(NULL); |
517 | 0 | } |
518 | 0 | else { |
519 | 0 | if (_PyTime_ObjectToTime_t(ot, &whent, _PyTime_ROUND_FLOOR) == -1) |
520 | 0 | return 0; |
521 | 0 | } |
522 | 0 | *pwhen = whent; |
523 | 0 | return 1; |
524 | 0 | } |
525 | | |
526 | | static PyObject * |
527 | | time_gmtime(PyObject *module, PyObject *args) |
528 | 0 | { |
529 | 0 | time_t when; |
530 | 0 | struct tm buf; |
531 | |
|
532 | 0 | if (!parse_time_t_args(args, "|O:gmtime", &when)) |
533 | 0 | return NULL; |
534 | | |
535 | 0 | errno = 0; |
536 | 0 | if (_PyTime_gmtime(when, &buf) != 0) |
537 | 0 | return NULL; |
538 | | |
539 | 0 | time_module_state *state = get_time_state(module); |
540 | 0 | #ifdef HAVE_STRUCT_TM_TM_ZONE |
541 | 0 | return tmtotuple(state, &buf); |
542 | | #else |
543 | | return tmtotuple(state, &buf, "UTC", 0); |
544 | | #endif |
545 | 0 | } |
546 | | |
547 | | #ifndef HAVE_TIMEGM |
548 | | static time_t |
549 | | timegm(struct tm *p) |
550 | | { |
551 | | /* XXX: the following implementation will not work for tm_year < 1970. |
552 | | but it is likely that platforms that don't have timegm do not support |
553 | | negative timestamps anyways. */ |
554 | | return p->tm_sec + p->tm_min*60 + p->tm_hour*3600 + p->tm_yday*86400 + |
555 | | (p->tm_year-70)*31536000 + ((p->tm_year-69)/4)*86400 - |
556 | | ((p->tm_year-1)/100)*86400 + ((p->tm_year+299)/400)*86400; |
557 | | } |
558 | | #endif |
559 | | |
560 | | PyDoc_STRVAR(gmtime_doc, |
561 | | "gmtime([seconds]) -> (tm_year, tm_mon, tm_mday, tm_hour, tm_min,\n\ |
562 | | tm_sec, tm_wday, tm_yday, tm_isdst)\n\ |
563 | | \n\ |
564 | | Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a.\n\ |
565 | | GMT). When 'seconds' is not passed in, convert the current time instead.\n\ |
566 | | \n\ |
567 | | If the platform supports the tm_gmtoff and tm_zone, they are available as\n\ |
568 | | attributes only."); |
569 | | |
570 | | static PyObject * |
571 | | time_localtime(PyObject *module, PyObject *args) |
572 | 0 | { |
573 | 0 | time_t when; |
574 | 0 | struct tm buf; |
575 | |
|
576 | 0 | if (!parse_time_t_args(args, "|O:localtime", &when)) |
577 | 0 | return NULL; |
578 | 0 | if (_PyTime_localtime(when, &buf) != 0) |
579 | 0 | return NULL; |
580 | | |
581 | 0 | time_module_state *state = get_time_state(module); |
582 | 0 | #ifdef HAVE_STRUCT_TM_TM_ZONE |
583 | 0 | return tmtotuple(state, &buf); |
584 | | #else |
585 | | { |
586 | | struct tm local = buf; |
587 | | char zone[100]; |
588 | | time_t gmtoff; |
589 | | strftime(zone, sizeof(zone), "%Z", &buf); |
590 | | gmtoff = timegm(&buf) - when; |
591 | | return tmtotuple(state, &local, zone, gmtoff); |
592 | | } |
593 | | #endif |
594 | 0 | } |
595 | | |
596 | | #if defined(__linux__) && !defined(__GLIBC__) |
597 | | static const char *utc_string = NULL; |
598 | | #endif |
599 | | |
600 | | PyDoc_STRVAR(localtime_doc, |
601 | | "localtime([seconds]) -> (tm_year,tm_mon,tm_mday,tm_hour,tm_min,\n\ |
602 | | tm_sec,tm_wday,tm_yday,tm_isdst)\n\ |
603 | | \n\ |
604 | | Convert seconds since the Epoch to a time tuple expressing local time.\n\ |
605 | | When 'seconds' is not passed in, convert the current time instead."); |
606 | | |
607 | | /* Convert 9-item tuple to tm structure. Return 1 on success, set |
608 | | * an exception and return 0 on error. |
609 | | */ |
610 | | static int |
611 | | gettmarg(time_module_state *state, PyObject *args, |
612 | | struct tm *p, const char *format) |
613 | 0 | { |
614 | 0 | int y; |
615 | |
|
616 | 0 | memset((void *) p, '\0', sizeof(struct tm)); |
617 | |
|
618 | 0 | if (!PyTuple_Check(args)) { |
619 | 0 | PyErr_SetString(PyExc_TypeError, |
620 | 0 | "Tuple or struct_time argument required"); |
621 | 0 | return 0; |
622 | 0 | } |
623 | | |
624 | 0 | if (!PyArg_ParseTuple(args, format, |
625 | 0 | &y, &p->tm_mon, &p->tm_mday, |
626 | 0 | &p->tm_hour, &p->tm_min, &p->tm_sec, |
627 | 0 | &p->tm_wday, &p->tm_yday, &p->tm_isdst)) |
628 | 0 | return 0; |
629 | | |
630 | 0 | if (y < INT_MIN + 1900) { |
631 | 0 | PyErr_SetString(PyExc_OverflowError, "year out of range"); |
632 | 0 | return 0; |
633 | 0 | } |
634 | | |
635 | 0 | p->tm_year = y - 1900; |
636 | 0 | p->tm_mon--; |
637 | 0 | p->tm_wday = (p->tm_wday + 1) % 7; |
638 | 0 | p->tm_yday--; |
639 | 0 | #ifdef HAVE_STRUCT_TM_TM_ZONE |
640 | 0 | if (Py_IS_TYPE(args, state->struct_time_type)) { |
641 | 0 | PyObject *item; |
642 | 0 | item = PyStructSequence_GET_ITEM(args, 9); |
643 | 0 | if (item != Py_None) { |
644 | 0 | p->tm_zone = (char *)PyUnicode_AsUTF8(item); |
645 | 0 | if (p->tm_zone == NULL) { |
646 | 0 | return 0; |
647 | 0 | } |
648 | | #if defined(__linux__) && !defined(__GLIBC__) |
649 | | // Make an attempt to return the C library's own timezone strings to |
650 | | // it. musl refuses to process a tm_zone field unless it produced |
651 | | // it. See issue #34672. |
652 | | if (utc_string && strcmp(p->tm_zone, utc_string) == 0) { |
653 | | p->tm_zone = utc_string; |
654 | | } |
655 | | else if (tzname[0] && strcmp(p->tm_zone, tzname[0]) == 0) { |
656 | | p->tm_zone = tzname[0]; |
657 | | } |
658 | | else if (tzname[1] && strcmp(p->tm_zone, tzname[1]) == 0) { |
659 | | p->tm_zone = tzname[1]; |
660 | | } |
661 | | #endif |
662 | 0 | } |
663 | 0 | item = PyStructSequence_GET_ITEM(args, 10); |
664 | 0 | if (item != Py_None) { |
665 | 0 | p->tm_gmtoff = PyLong_AsLong(item); |
666 | 0 | if (PyErr_Occurred()) |
667 | 0 | return 0; |
668 | 0 | } |
669 | 0 | } |
670 | 0 | #endif /* HAVE_STRUCT_TM_TM_ZONE */ |
671 | 0 | return 1; |
672 | 0 | } |
673 | | |
674 | | /* Check values of the struct tm fields before it is passed to strftime() and |
675 | | * asctime(). Return 1 if all values are valid, otherwise set an exception |
676 | | * and returns 0. |
677 | | */ |
678 | | static int |
679 | | checktm(struct tm* buf) |
680 | 0 | { |
681 | | /* Checks added to make sure strftime() and asctime() does not crash Python by |
682 | | indexing blindly into some array for a textual representation |
683 | | by some bad index (fixes bug #897625 and #6608). |
684 | | |
685 | | Also support values of zero from Python code for arguments in which |
686 | | that is out of range by forcing that value to the lowest value that |
687 | | is valid (fixed bug #1520914). |
688 | | |
689 | | Valid ranges based on what is allowed in struct tm: |
690 | | |
691 | | - tm_year: [0, max(int)] (1) |
692 | | - tm_mon: [0, 11] (2) |
693 | | - tm_mday: [1, 31] |
694 | | - tm_hour: [0, 23] |
695 | | - tm_min: [0, 59] |
696 | | - tm_sec: [0, 60] |
697 | | - tm_wday: [0, 6] (1) |
698 | | - tm_yday: [0, 365] (2) |
699 | | - tm_isdst: [-max(int), max(int)] |
700 | | |
701 | | (1) gettmarg() handles bounds-checking. |
702 | | (2) Python's acceptable range is one greater than the range in C, |
703 | | thus need to check against automatic decrement by gettmarg(). |
704 | | */ |
705 | 0 | if (buf->tm_mon == -1) |
706 | 0 | buf->tm_mon = 0; |
707 | 0 | else if (buf->tm_mon < 0 || buf->tm_mon > 11) { |
708 | 0 | PyErr_SetString(PyExc_ValueError, "month out of range"); |
709 | 0 | return 0; |
710 | 0 | } |
711 | 0 | if (buf->tm_mday == 0) |
712 | 0 | buf->tm_mday = 1; |
713 | 0 | else if (buf->tm_mday < 0 || buf->tm_mday > 31) { |
714 | 0 | PyErr_SetString(PyExc_ValueError, "day of month out of range"); |
715 | 0 | return 0; |
716 | 0 | } |
717 | 0 | if (buf->tm_hour < 0 || buf->tm_hour > 23) { |
718 | 0 | PyErr_SetString(PyExc_ValueError, "hour out of range"); |
719 | 0 | return 0; |
720 | 0 | } |
721 | 0 | if (buf->tm_min < 0 || buf->tm_min > 59) { |
722 | 0 | PyErr_SetString(PyExc_ValueError, "minute out of range"); |
723 | 0 | return 0; |
724 | 0 | } |
725 | 0 | if (buf->tm_sec < 0 || buf->tm_sec > 61) { |
726 | 0 | PyErr_SetString(PyExc_ValueError, "seconds out of range"); |
727 | 0 | return 0; |
728 | 0 | } |
729 | | /* tm_wday does not need checking of its upper-bound since taking |
730 | | ``% 7`` in gettmarg() automatically restricts the range. */ |
731 | 0 | if (buf->tm_wday < 0) { |
732 | 0 | PyErr_SetString(PyExc_ValueError, "day of week out of range"); |
733 | 0 | return 0; |
734 | 0 | } |
735 | 0 | if (buf->tm_yday == -1) |
736 | 0 | buf->tm_yday = 0; |
737 | 0 | else if (buf->tm_yday < 0 || buf->tm_yday > 365) { |
738 | 0 | PyErr_SetString(PyExc_ValueError, "day of year out of range"); |
739 | 0 | return 0; |
740 | 0 | } |
741 | 0 | return 1; |
742 | 0 | } |
743 | | |
744 | | #define STRFTIME_FORMAT_CODES \ |
745 | | "Commonly used format codes:\n\ |
746 | | \n\ |
747 | | %Y Year with century as a decimal number.\n\ |
748 | | %m Month as a decimal number [01,12].\n\ |
749 | | %d Day of the month as a decimal number [01,31].\n\ |
750 | | %H Hour (24-hour clock) as a decimal number [00,23].\n\ |
751 | | %M Minute as a decimal number [00,59].\n\ |
752 | | %S Second as a decimal number [00,61].\n\ |
753 | | %z Time zone offset from UTC.\n\ |
754 | | %a Locale's abbreviated weekday name.\n\ |
755 | | %A Locale's full weekday name.\n\ |
756 | | %b Locale's abbreviated month name.\n\ |
757 | | %B Locale's full month name.\n\ |
758 | | %c Locale's appropriate date and time representation.\n\ |
759 | | %I Hour (12-hour clock) as a decimal number [01,12].\n\ |
760 | | %p Locale's equivalent of either AM or PM.\n\ |
761 | | \n\ |
762 | | Other codes may be available on your platform. See documentation for\n\ |
763 | | the C library strftime function.\n" |
764 | | |
765 | | #ifdef HAVE_STRFTIME |
766 | | #ifdef HAVE_WCSFTIME |
767 | 0 | #define time_char wchar_t |
768 | 0 | #define format_time wcsftime |
769 | | #define time_strlen wcslen |
770 | | #else |
771 | | #define time_char char |
772 | | #define format_time strftime |
773 | | #define time_strlen strlen |
774 | | #endif |
775 | | |
776 | | static PyObject * |
777 | | time_strftime1(time_char **outbuf, size_t *bufsize, |
778 | | time_char *format, size_t fmtlen, |
779 | | struct tm *tm) |
780 | 0 | { |
781 | 0 | size_t buflen; |
782 | | #if defined(MS_WINDOWS) && !defined(HAVE_WCSFTIME) |
783 | | /* check that the format string contains only valid directives */ |
784 | | for (const time_char *f = strchr(format, '%'); |
785 | | f != NULL; |
786 | | f = strchr(f + 2, '%')) |
787 | | { |
788 | | if (f[1] == '#') |
789 | | ++f; /* not documented by python, */ |
790 | | if (f[1] == '\0') |
791 | | break; |
792 | | if ((f[1] == 'y') && tm->tm_year < 0) { |
793 | | PyErr_SetString(PyExc_ValueError, |
794 | | "format %y requires year >= 1900 on Windows"); |
795 | | return NULL; |
796 | | } |
797 | | } |
798 | | #elif (defined(_AIX) || (defined(__sun) && defined(__SVR4))) && defined(HAVE_WCSFTIME) |
799 | | for (const time_char *f = wcschr(format, '%'); |
800 | | f != NULL; |
801 | | f = wcschr(f + 2, '%')) |
802 | | { |
803 | | if (f[1] == L'\0') |
804 | | break; |
805 | | /* Issue #19634: On AIX, wcsftime("y", (1899, 1, 1, 0, 0, 0, 0, 0, 0)) |
806 | | returns "0/" instead of "99" */ |
807 | | if (f[1] == L'y' && tm->tm_year < 0) { |
808 | | PyErr_SetString(PyExc_ValueError, |
809 | | "format %y requires year >= 1900 on AIX"); |
810 | | return NULL; |
811 | | } |
812 | | } |
813 | | #endif |
814 | | |
815 | | /* I hate these functions that presume you know how big the output |
816 | | * will be ahead of time... |
817 | | */ |
818 | 0 | while (1) { |
819 | 0 | if (*bufsize > PY_SSIZE_T_MAX/sizeof(time_char)) { |
820 | 0 | PyErr_NoMemory(); |
821 | 0 | return NULL; |
822 | 0 | } |
823 | 0 | *outbuf = (time_char *)PyMem_Realloc(*outbuf, |
824 | 0 | *bufsize*sizeof(time_char)); |
825 | 0 | if (*outbuf == NULL) { |
826 | 0 | PyErr_NoMemory(); |
827 | 0 | return NULL; |
828 | 0 | } |
829 | | #if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) |
830 | | errno = 0; |
831 | | #endif |
832 | 0 | _Py_BEGIN_SUPPRESS_IPH |
833 | 0 | buflen = format_time(*outbuf, *bufsize, format, tm); |
834 | 0 | _Py_END_SUPPRESS_IPH |
835 | | #if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) |
836 | | /* VisualStudio .NET 2005 does this properly */ |
837 | | if (buflen == 0 && errno == EINVAL) { |
838 | | PyErr_SetString(PyExc_ValueError, "Invalid format string"); |
839 | | return NULL; |
840 | | } |
841 | | #endif |
842 | 0 | if (buflen == 0 && *bufsize < 256 * fmtlen) { |
843 | 0 | *bufsize += *bufsize; |
844 | 0 | continue; |
845 | 0 | } |
846 | | /* If the buffer is 256 times as long as the format, |
847 | | it's probably not failing for lack of room! |
848 | | More likely, the format yields an empty result, |
849 | | e.g. an empty format, or %Z when the timezone |
850 | | is unknown. */ |
851 | 0 | #ifdef HAVE_WCSFTIME |
852 | 0 | return PyUnicode_FromWideChar(*outbuf, buflen); |
853 | | #else |
854 | | return PyUnicode_DecodeLocaleAndSize(*outbuf, buflen, "surrogateescape"); |
855 | | #endif |
856 | 0 | } |
857 | 0 | } |
858 | | |
859 | | static PyObject * |
860 | | time_strftime(PyObject *module, PyObject *args) |
861 | 0 | { |
862 | 0 | PyObject *tup = NULL; |
863 | 0 | struct tm buf; |
864 | 0 | PyObject *format_arg; |
865 | 0 | Py_ssize_t format_size; |
866 | 0 | time_char *format, *outbuf = NULL; |
867 | 0 | size_t fmtlen, bufsize = 1024; |
868 | |
|
869 | 0 | memset((void *) &buf, '\0', sizeof(buf)); |
870 | |
|
871 | 0 | if (!PyArg_ParseTuple(args, "U|O:strftime", &format_arg, &tup)) |
872 | 0 | return NULL; |
873 | | |
874 | 0 | time_module_state *state = get_time_state(module); |
875 | 0 | if (tup == NULL) { |
876 | 0 | time_t tt = time(NULL); |
877 | 0 | if (_PyTime_localtime(tt, &buf) != 0) |
878 | 0 | return NULL; |
879 | 0 | } |
880 | 0 | else if (!gettmarg(state, tup, &buf, |
881 | 0 | "iiiiiiiii;strftime(): illegal time tuple argument") || |
882 | 0 | !checktm(&buf)) |
883 | 0 | { |
884 | 0 | return NULL; |
885 | 0 | } |
886 | | |
887 | | // Some platforms only support a limited range of years. |
888 | | // |
889 | | // Android works with negative years on the emulator, but fails on some |
890 | | // physical devices (#123017). |
891 | | #if defined(_MSC_VER) || (defined(__sun) && defined(__SVR4)) || defined(_AIX) \ |
892 | | || defined(__VXWORKS__) || defined(__ANDROID__) |
893 | | if (buf.tm_year + 1900 < 1 || 9999 < buf.tm_year + 1900) { |
894 | | PyErr_SetString(PyExc_ValueError, |
895 | | "strftime() requires year in [1; 9999]"); |
896 | | return NULL; |
897 | | } |
898 | | #endif |
899 | | |
900 | | /* Normalize tm_isdst just in case someone foolishly implements %Z |
901 | | based on the assumption that tm_isdst falls within the range of |
902 | | [-1, 1] */ |
903 | 0 | if (buf.tm_isdst < -1) |
904 | 0 | buf.tm_isdst = -1; |
905 | 0 | else if (buf.tm_isdst > 1) |
906 | 0 | buf.tm_isdst = 1; |
907 | |
|
908 | 0 | format_size = PyUnicode_GET_LENGTH(format_arg); |
909 | 0 | if ((size_t)format_size > PY_SSIZE_T_MAX/sizeof(time_char) - 1) { |
910 | 0 | PyErr_NoMemory(); |
911 | 0 | return NULL; |
912 | 0 | } |
913 | 0 | format = PyMem_Malloc((format_size + 1)*sizeof(time_char)); |
914 | 0 | if (format == NULL) { |
915 | 0 | PyErr_NoMemory(); |
916 | 0 | return NULL; |
917 | 0 | } |
918 | 0 | PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); |
919 | 0 | if (writer == NULL) { |
920 | 0 | goto error; |
921 | 0 | } |
922 | 0 | Py_ssize_t i = 0; |
923 | 0 | while (i < format_size) { |
924 | 0 | fmtlen = 0; |
925 | 0 | for (; i < format_size; i++) { |
926 | 0 | Py_UCS4 c = PyUnicode_READ_CHAR(format_arg, i); |
927 | 0 | if (!c || c > 127) { |
928 | 0 | break; |
929 | 0 | } |
930 | 0 | format[fmtlen++] = (char)c; |
931 | 0 | } |
932 | 0 | if (fmtlen) { |
933 | 0 | format[fmtlen] = 0; |
934 | 0 | PyObject *unicode = time_strftime1(&outbuf, &bufsize, |
935 | 0 | format, fmtlen, &buf); |
936 | 0 | if (unicode == NULL) { |
937 | 0 | goto error; |
938 | 0 | } |
939 | 0 | if (PyUnicodeWriter_WriteStr(writer, unicode) < 0) { |
940 | 0 | Py_DECREF(unicode); |
941 | 0 | goto error; |
942 | 0 | } |
943 | 0 | Py_DECREF(unicode); |
944 | 0 | } |
945 | | |
946 | 0 | Py_ssize_t start = i; |
947 | 0 | for (; i < format_size; i++) { |
948 | 0 | Py_UCS4 c = PyUnicode_READ_CHAR(format_arg, i); |
949 | 0 | if (c == '%') { |
950 | 0 | break; |
951 | 0 | } |
952 | 0 | } |
953 | 0 | if (PyUnicodeWriter_WriteSubstring(writer, format_arg, start, i) < 0) { |
954 | 0 | goto error; |
955 | 0 | } |
956 | 0 | } |
957 | | |
958 | 0 | PyMem_Free(outbuf); |
959 | 0 | PyMem_Free(format); |
960 | 0 | return PyUnicodeWriter_Finish(writer); |
961 | 0 | error: |
962 | 0 | PyMem_Free(outbuf); |
963 | 0 | PyMem_Free(format); |
964 | 0 | PyUnicodeWriter_Discard(writer); |
965 | 0 | return NULL; |
966 | 0 | } |
967 | | |
968 | | #undef time_char |
969 | | #undef format_time |
970 | | PyDoc_STRVAR(strftime_doc, |
971 | | "strftime(format[, tuple]) -> string\n\ |
972 | | \n\ |
973 | | Convert a time tuple to a string according to a format specification.\n\ |
974 | | See the library reference manual for formatting codes. When the time tuple\n\ |
975 | | is not present, current time as returned by localtime() is used.\n\ |
976 | | \n" STRFTIME_FORMAT_CODES); |
977 | | #endif /* HAVE_STRFTIME */ |
978 | | |
979 | | static PyObject * |
980 | | time_strptime(PyObject *self, PyObject *args) |
981 | 0 | { |
982 | 0 | PyObject *func, *result; |
983 | |
|
984 | 0 | func = PyImport_ImportModuleAttrString("_strptime", "_strptime_time"); |
985 | 0 | if (!func) { |
986 | 0 | return NULL; |
987 | 0 | } |
988 | | |
989 | 0 | result = PyObject_Call(func, args, NULL); |
990 | 0 | Py_DECREF(func); |
991 | 0 | return result; |
992 | 0 | } |
993 | | |
994 | | |
995 | | PyDoc_STRVAR(strptime_doc, |
996 | | "strptime(string, format) -> struct_time\n\ |
997 | | \n\ |
998 | | Parse a string to a time tuple according to a format specification.\n\ |
999 | | See the library reference manual for formatting codes (same as\n\ |
1000 | | strftime()).\n\ |
1001 | | \n" STRFTIME_FORMAT_CODES); |
1002 | | |
1003 | | static PyObject * |
1004 | | _asctime(struct tm *timeptr) |
1005 | 0 | { |
1006 | | /* Inspired by Open Group reference implementation available at |
1007 | | * http://pubs.opengroup.org/onlinepubs/009695399/functions/asctime.html */ |
1008 | 0 | static const char wday_name[7][4] = { |
1009 | 0 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
1010 | 0 | }; |
1011 | 0 | static const char mon_name[12][4] = { |
1012 | 0 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
1013 | 0 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
1014 | 0 | }; |
1015 | 0 | return PyUnicode_FromFormat( |
1016 | 0 | "%s %s%3d %.2d:%.2d:%.2d %d", |
1017 | 0 | wday_name[timeptr->tm_wday], |
1018 | 0 | mon_name[timeptr->tm_mon], |
1019 | 0 | timeptr->tm_mday, timeptr->tm_hour, |
1020 | 0 | timeptr->tm_min, timeptr->tm_sec, |
1021 | 0 | 1900 + timeptr->tm_year); |
1022 | 0 | } |
1023 | | |
1024 | | static PyObject * |
1025 | | time_asctime(PyObject *module, PyObject *args) |
1026 | 0 | { |
1027 | 0 | PyObject *tup = NULL; |
1028 | 0 | struct tm buf; |
1029 | |
|
1030 | 0 | if (!PyArg_UnpackTuple(args, "asctime", 0, 1, &tup)) |
1031 | 0 | return NULL; |
1032 | | |
1033 | 0 | time_module_state *state = get_time_state(module); |
1034 | 0 | if (tup == NULL) { |
1035 | 0 | time_t tt = time(NULL); |
1036 | 0 | if (_PyTime_localtime(tt, &buf) != 0) |
1037 | 0 | return NULL; |
1038 | 0 | } |
1039 | 0 | else if (!gettmarg(state, tup, &buf, |
1040 | 0 | "iiiiiiiii;asctime(): illegal time tuple argument") || |
1041 | 0 | !checktm(&buf)) |
1042 | 0 | { |
1043 | 0 | return NULL; |
1044 | 0 | } |
1045 | 0 | return _asctime(&buf); |
1046 | 0 | } |
1047 | | |
1048 | | PyDoc_STRVAR(asctime_doc, |
1049 | | "asctime([tuple]) -> string\n\ |
1050 | | \n\ |
1051 | | Convert a time tuple to a string, e.g. 'Sat Jun 06 16:26:11 1998'.\n\ |
1052 | | When the time tuple is not present, current time as returned by localtime()\n\ |
1053 | | is used."); |
1054 | | |
1055 | | static PyObject * |
1056 | | time_ctime(PyObject *self, PyObject *args) |
1057 | 0 | { |
1058 | 0 | time_t tt; |
1059 | 0 | struct tm buf; |
1060 | 0 | if (!parse_time_t_args(args, "|O:ctime", &tt)) |
1061 | 0 | return NULL; |
1062 | 0 | if (_PyTime_localtime(tt, &buf) != 0) |
1063 | 0 | return NULL; |
1064 | 0 | return _asctime(&buf); |
1065 | 0 | } |
1066 | | |
1067 | | PyDoc_STRVAR(ctime_doc, |
1068 | | "ctime(seconds) -> string\n\ |
1069 | | \n\ |
1070 | | Convert a time in seconds since the Epoch to a string in local time.\n\ |
1071 | | This is equivalent to asctime(localtime(seconds)). When the time tuple is\n\ |
1072 | | not present, current time as returned by localtime() is used."); |
1073 | | |
1074 | | #ifdef HAVE_MKTIME |
1075 | | static PyObject * |
1076 | | time_mktime(PyObject *module, PyObject *tm_tuple) |
1077 | 0 | { |
1078 | 0 | struct tm tm; |
1079 | 0 | time_t tt; |
1080 | |
|
1081 | 0 | time_module_state *state = get_time_state(module); |
1082 | 0 | if (!gettmarg(state, tm_tuple, &tm, |
1083 | 0 | "iiiiiiiii;mktime(): illegal time tuple argument")) |
1084 | 0 | { |
1085 | 0 | return NULL; |
1086 | 0 | } |
1087 | | |
1088 | | #if defined(_AIX) || (defined(__VXWORKS__) && !defined(_WRS_CONFIG_LP64)) |
1089 | | /* bpo-19748: AIX mktime() valid range is 00:00:00 UTC, January 1, 1970 |
1090 | | to 03:14:07 UTC, January 19, 2038. Thanks to the workaround below, |
1091 | | it is possible to support years in range [1902; 2037] */ |
1092 | | if (tm.tm_year < 2 || tm.tm_year > 137) { |
1093 | | /* bpo-19748: On AIX, mktime() does not report overflow error |
1094 | | for timestamp < -2^31 or timestamp > 2**31-1. VxWorks has the |
1095 | | same issue when working in 32 bit mode. */ |
1096 | | PyErr_SetString(PyExc_OverflowError, |
1097 | | "mktime argument out of range"); |
1098 | | return NULL; |
1099 | | } |
1100 | | #endif |
1101 | | |
1102 | | #ifdef _AIX |
1103 | | /* bpo-34373: AIX mktime() has an integer overflow for years in range |
1104 | | [1902; 1969]. Workaround the issue by using a year greater or equal than |
1105 | | 1970 (tm_year >= 70): mktime() behaves correctly in that case |
1106 | | (ex: properly report errors). tm_year and tm_wday are adjusted after |
1107 | | mktime() call. */ |
1108 | | int orig_tm_year = tm.tm_year; |
1109 | | int delta_days = 0; |
1110 | | while (tm.tm_year < 70) { |
1111 | | /* Use 4 years to account properly leap years */ |
1112 | | tm.tm_year += 4; |
1113 | | delta_days -= (366 + (365 * 3)); |
1114 | | } |
1115 | | #endif |
1116 | | |
1117 | 0 | tm.tm_wday = -1; /* sentinel; original value ignored */ |
1118 | 0 | tt = mktime(&tm); |
1119 | | |
1120 | | /* Return value of -1 does not necessarily mean an error, but tm_wday |
1121 | | * cannot remain set to -1 if mktime succeeded. */ |
1122 | 0 | if (tt == (time_t)(-1) |
1123 | | /* Return value of -1 does not necessarily mean an error, but |
1124 | | * tm_wday cannot remain set to -1 if mktime succeeded. */ |
1125 | 0 | && tm.tm_wday == -1) |
1126 | 0 | { |
1127 | 0 | PyErr_SetString(PyExc_OverflowError, |
1128 | 0 | "mktime argument out of range"); |
1129 | 0 | return NULL; |
1130 | 0 | } |
1131 | | |
1132 | | #ifdef _AIX |
1133 | | if (delta_days != 0) { |
1134 | | tm.tm_year = orig_tm_year; |
1135 | | if (tm.tm_wday != -1) { |
1136 | | tm.tm_wday = (tm.tm_wday + delta_days) % 7; |
1137 | | } |
1138 | | tt += delta_days * (24 * 3600); |
1139 | | } |
1140 | | #endif |
1141 | | |
1142 | 0 | return PyFloat_FromDouble((double)tt); |
1143 | 0 | } |
1144 | | |
1145 | | PyDoc_STRVAR(mktime_doc, |
1146 | | "mktime(tuple) -> floating-point number\n\ |
1147 | | \n\ |
1148 | | Convert a time tuple in local time to seconds since the Epoch.\n\ |
1149 | | Note that mktime(gmtime(0)) will not generally return zero for most\n\ |
1150 | | time zones; instead the returned value will either be equal to that\n\ |
1151 | | of the timezone or altzone attributes on the time module."); |
1152 | | #endif /* HAVE_MKTIME */ |
1153 | | |
1154 | | #ifdef HAVE_WORKING_TZSET |
1155 | | static int init_timezone(PyObject *module); |
1156 | | |
1157 | | static PyObject * |
1158 | | time_tzset(PyObject *self, PyObject *unused) |
1159 | 0 | { |
1160 | 0 | PyObject* m; |
1161 | |
|
1162 | 0 | m = PyImport_ImportModule("time"); |
1163 | 0 | if (m == NULL) { |
1164 | 0 | return NULL; |
1165 | 0 | } |
1166 | | |
1167 | 0 | #if !defined(MS_WINDOWS) || defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) |
1168 | 0 | tzset(); |
1169 | 0 | #endif |
1170 | | |
1171 | | /* Reset timezone, altzone, daylight and tzname */ |
1172 | 0 | if (init_timezone(m) < 0) { |
1173 | 0 | return NULL; |
1174 | 0 | } |
1175 | 0 | Py_DECREF(m); |
1176 | 0 | if (PyErr_Occurred()) |
1177 | 0 | return NULL; |
1178 | | |
1179 | 0 | Py_RETURN_NONE; |
1180 | 0 | } |
1181 | | |
1182 | | PyDoc_STRVAR(tzset_doc, |
1183 | | "tzset()\n\ |
1184 | | \n\ |
1185 | | Initialize, or reinitialize, the local timezone to the value stored in\n\ |
1186 | | os.environ['TZ']. The TZ environment variable should be specified in\n\ |
1187 | | standard Unix timezone format as documented in the tzset man page\n\ |
1188 | | (eg. 'US/Eastern', 'Europe/Amsterdam'). Unknown timezones will silently\n\ |
1189 | | fall back to UTC. If the TZ environment variable is not set, the local\n\ |
1190 | | timezone is set to the systems best guess of wallclock time.\n\ |
1191 | | Changing the TZ environment variable without calling tzset *may* change\n\ |
1192 | | the local timezone used by methods such as localtime, but this behaviour\n\ |
1193 | | should not be relied on."); |
1194 | | #endif /* HAVE_WORKING_TZSET */ |
1195 | | |
1196 | | |
1197 | | static PyObject * |
1198 | | time_monotonic(PyObject *self, PyObject *unused) |
1199 | 0 | { |
1200 | 0 | PyTime_t t; |
1201 | 0 | if (PyTime_Monotonic(&t) < 0) { |
1202 | 0 | return NULL; |
1203 | 0 | } |
1204 | 0 | return _PyFloat_FromPyTime(t); |
1205 | 0 | } |
1206 | | |
1207 | | PyDoc_STRVAR(monotonic_doc, |
1208 | | "monotonic() -> float\n\ |
1209 | | \n\ |
1210 | | Monotonic clock, cannot go backward."); |
1211 | | |
1212 | | static PyObject * |
1213 | | time_monotonic_ns(PyObject *self, PyObject *unused) |
1214 | 0 | { |
1215 | 0 | PyTime_t t; |
1216 | 0 | if (PyTime_Monotonic(&t) < 0) { |
1217 | 0 | return NULL; |
1218 | 0 | } |
1219 | 0 | return _PyTime_AsLong(t); |
1220 | 0 | } |
1221 | | |
1222 | | PyDoc_STRVAR(monotonic_ns_doc, |
1223 | | "monotonic_ns() -> int\n\ |
1224 | | \n\ |
1225 | | Monotonic clock, cannot go backward, as nanoseconds."); |
1226 | | |
1227 | | |
1228 | | static PyObject * |
1229 | | time_perf_counter(PyObject *self, PyObject *unused) |
1230 | 0 | { |
1231 | 0 | PyTime_t t; |
1232 | 0 | if (PyTime_PerfCounter(&t) < 0) { |
1233 | 0 | return NULL; |
1234 | 0 | } |
1235 | 0 | return _PyFloat_FromPyTime(t); |
1236 | 0 | } |
1237 | | |
1238 | | PyDoc_STRVAR(perf_counter_doc, |
1239 | | "perf_counter() -> float\n\ |
1240 | | \n\ |
1241 | | Performance counter for benchmarking."); |
1242 | | |
1243 | | |
1244 | | static PyObject * |
1245 | | time_perf_counter_ns(PyObject *self, PyObject *unused) |
1246 | 0 | { |
1247 | 0 | PyTime_t t; |
1248 | 0 | if (PyTime_PerfCounter(&t) < 0) { |
1249 | 0 | return NULL; |
1250 | 0 | } |
1251 | 0 | return _PyTime_AsLong(t); |
1252 | 0 | } |
1253 | | |
1254 | | PyDoc_STRVAR(perf_counter_ns_doc, |
1255 | | "perf_counter_ns() -> int\n\ |
1256 | | \n\ |
1257 | | Performance counter for benchmarking as nanoseconds."); |
1258 | | |
1259 | | |
1260 | | // gh-115714: Don't use times() on WASI. |
1261 | | #if defined(HAVE_TIMES) && !defined(__wasi__) |
1262 | | static int |
1263 | | process_time_times(time_module_state *state, PyTime_t *tp, |
1264 | | _Py_clock_info_t *info) |
1265 | 0 | { |
1266 | 0 | _PyTimeFraction *base = &state->times_base; |
1267 | |
|
1268 | 0 | struct tms process; |
1269 | 0 | if (times(&process) == (clock_t)-1) { |
1270 | 0 | return 0; |
1271 | 0 | } |
1272 | | |
1273 | 0 | if (info) { |
1274 | 0 | info->implementation = "times()"; |
1275 | 0 | info->resolution = _PyTimeFraction_Resolution(base); |
1276 | 0 | info->monotonic = 1; |
1277 | 0 | info->adjustable = 0; |
1278 | 0 | } |
1279 | |
|
1280 | 0 | PyTime_t ns; |
1281 | 0 | ns = _PyTimeFraction_Mul(process.tms_utime, base); |
1282 | 0 | ns += _PyTimeFraction_Mul(process.tms_stime, base); |
1283 | 0 | *tp = ns; |
1284 | 0 | return 1; |
1285 | 0 | } |
1286 | | #endif |
1287 | | |
1288 | | |
1289 | | static int |
1290 | | py_process_time(time_module_state *state, PyTime_t *tp, |
1291 | | _Py_clock_info_t *info) |
1292 | 0 | { |
1293 | | #if defined(MS_WINDOWS) |
1294 | | HANDLE process; |
1295 | | FILETIME creation_time, exit_time, kernel_time, user_time; |
1296 | | ULARGE_INTEGER large; |
1297 | | PyTime_t ktime, utime; |
1298 | | BOOL ok; |
1299 | | |
1300 | | process = GetCurrentProcess(); |
1301 | | ok = GetProcessTimes(process, &creation_time, &exit_time, |
1302 | | &kernel_time, &user_time); |
1303 | | if (!ok) { |
1304 | | PyErr_SetFromWindowsErr(0); |
1305 | | return -1; |
1306 | | } |
1307 | | |
1308 | | if (info) { |
1309 | | info->implementation = "GetProcessTimes()"; |
1310 | | info->resolution = 1e-7; |
1311 | | info->monotonic = 1; |
1312 | | info->adjustable = 0; |
1313 | | } |
1314 | | |
1315 | | large.u.LowPart = kernel_time.dwLowDateTime; |
1316 | | large.u.HighPart = kernel_time.dwHighDateTime; |
1317 | | ktime = large.QuadPart; |
1318 | | |
1319 | | large.u.LowPart = user_time.dwLowDateTime; |
1320 | | large.u.HighPart = user_time.dwHighDateTime; |
1321 | | utime = large.QuadPart; |
1322 | | |
1323 | | /* ktime and utime have a resolution of 100 nanoseconds */ |
1324 | | *tp = (ktime + utime) * 100; |
1325 | | return 0; |
1326 | | #else |
1327 | | |
1328 | | /* clock_gettime */ |
1329 | | // gh-115714: Don't use CLOCK_PROCESS_CPUTIME_ID on WASI. |
1330 | | /* CLOCK_PROF is defined on NetBSD, but not supported. |
1331 | | * CLOCK_PROCESS_CPUTIME_ID is broken on NetBSD for the same reason as |
1332 | | * CLOCK_THREAD_CPUTIME_ID (see comment below). |
1333 | | */ |
1334 | 0 | #if defined(HAVE_CLOCK_GETTIME) \ |
1335 | 0 | && (defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_PROF)) \ |
1336 | 0 | && !defined(__wasi__) \ |
1337 | 0 | && !defined(__NetBSD__) |
1338 | 0 | struct timespec ts; |
1339 | |
|
1340 | 0 | if (HAVE_CLOCK_GETTIME_RUNTIME) { |
1341 | |
|
1342 | | #ifdef CLOCK_PROF |
1343 | | const clockid_t clk_id = CLOCK_PROF; |
1344 | | const char *function = "clock_gettime(CLOCK_PROF)"; |
1345 | | #else |
1346 | 0 | const clockid_t clk_id = CLOCK_PROCESS_CPUTIME_ID; |
1347 | 0 | const char *function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)"; |
1348 | 0 | #endif |
1349 | |
|
1350 | 0 | if (clock_gettime(clk_id, &ts) == 0) { |
1351 | 0 | if (info) { |
1352 | 0 | struct timespec res; |
1353 | 0 | info->implementation = function; |
1354 | 0 | info->monotonic = 1; |
1355 | 0 | info->adjustable = 0; |
1356 | 0 | if (clock_getres(clk_id, &res)) { |
1357 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
1358 | 0 | return -1; |
1359 | 0 | } |
1360 | 0 | info->resolution = res.tv_sec + res.tv_nsec * 1e-9; |
1361 | 0 | } |
1362 | | |
1363 | 0 | if (_PyTime_FromTimespec(tp, &ts) < 0) { |
1364 | 0 | return -1; |
1365 | 0 | } |
1366 | 0 | return 0; |
1367 | 0 | } |
1368 | 0 | } |
1369 | 0 | #endif |
1370 | | |
1371 | | /* getrusage(RUSAGE_SELF) */ |
1372 | 0 | #if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRUSAGE) |
1373 | 0 | struct rusage ru; |
1374 | |
|
1375 | 0 | if (getrusage(RUSAGE_SELF, &ru) == 0) { |
1376 | 0 | PyTime_t utime, stime; |
1377 | |
|
1378 | 0 | if (info) { |
1379 | 0 | info->implementation = "getrusage(RUSAGE_SELF)"; |
1380 | 0 | info->monotonic = 1; |
1381 | 0 | info->adjustable = 0; |
1382 | 0 | info->resolution = 1e-6; |
1383 | 0 | } |
1384 | |
|
1385 | 0 | if (_PyTime_FromTimeval(&utime, &ru.ru_utime) < 0) { |
1386 | 0 | return -1; |
1387 | 0 | } |
1388 | 0 | if (_PyTime_FromTimeval(&stime, &ru.ru_stime) < 0) { |
1389 | 0 | return -1; |
1390 | 0 | } |
1391 | | |
1392 | 0 | PyTime_t total = utime + stime; |
1393 | 0 | *tp = total; |
1394 | 0 | return 0; |
1395 | 0 | } |
1396 | 0 | #endif |
1397 | | |
1398 | | /* times() */ |
1399 | | // gh-115714: Don't use times() on WASI. |
1400 | 0 | #if defined(HAVE_TIMES) && !defined(__wasi__) |
1401 | 0 | int res = process_time_times(state, tp, info); |
1402 | 0 | if (res < 0) { |
1403 | 0 | return -1; |
1404 | 0 | } |
1405 | 0 | if (res == 1) { |
1406 | 0 | return 0; |
1407 | 0 | } |
1408 | | // times() failed, ignore failure |
1409 | 0 | #endif |
1410 | | |
1411 | | /* clock(). Python 3 requires clock() to build (see gh-66814) */ |
1412 | 0 | return py_clock(state, tp, info); |
1413 | 0 | #endif |
1414 | 0 | } |
1415 | | |
1416 | | static PyObject * |
1417 | | time_process_time(PyObject *module, PyObject *unused) |
1418 | 0 | { |
1419 | 0 | time_module_state *state = get_time_state(module); |
1420 | 0 | PyTime_t t; |
1421 | 0 | if (py_process_time(state, &t, NULL) < 0) { |
1422 | 0 | return NULL; |
1423 | 0 | } |
1424 | 0 | return _PyFloat_FromPyTime(t); |
1425 | 0 | } |
1426 | | |
1427 | | PyDoc_STRVAR(process_time_doc, |
1428 | | "process_time() -> float\n\ |
1429 | | \n\ |
1430 | | Process time for profiling: sum of the kernel and user-space CPU time."); |
1431 | | |
1432 | | static PyObject * |
1433 | | time_process_time_ns(PyObject *module, PyObject *unused) |
1434 | 0 | { |
1435 | 0 | time_module_state *state = get_time_state(module); |
1436 | 0 | PyTime_t t; |
1437 | 0 | if (py_process_time(state, &t, NULL) < 0) { |
1438 | 0 | return NULL; |
1439 | 0 | } |
1440 | 0 | return _PyTime_AsLong(t); |
1441 | 0 | } |
1442 | | |
1443 | | PyDoc_STRVAR(process_time_ns_doc, |
1444 | | "process_time() -> int\n\ |
1445 | | \n\ |
1446 | | Process time for profiling as nanoseconds:\n\ |
1447 | | sum of the kernel and user-space CPU time."); |
1448 | | |
1449 | | |
1450 | | #if defined(MS_WINDOWS) |
1451 | | #define HAVE_THREAD_TIME |
1452 | | static int |
1453 | | _PyTime_GetThreadTimeWithInfo(PyTime_t *tp, _Py_clock_info_t *info) |
1454 | | { |
1455 | | HANDLE thread; |
1456 | | FILETIME creation_time, exit_time, kernel_time, user_time; |
1457 | | ULARGE_INTEGER large; |
1458 | | PyTime_t ktime, utime; |
1459 | | BOOL ok; |
1460 | | |
1461 | | thread = GetCurrentThread(); |
1462 | | ok = GetThreadTimes(thread, &creation_time, &exit_time, |
1463 | | &kernel_time, &user_time); |
1464 | | if (!ok) { |
1465 | | PyErr_SetFromWindowsErr(0); |
1466 | | return -1; |
1467 | | } |
1468 | | |
1469 | | if (info) { |
1470 | | info->implementation = "GetThreadTimes()"; |
1471 | | info->resolution = 1e-7; |
1472 | | info->monotonic = 1; |
1473 | | info->adjustable = 0; |
1474 | | } |
1475 | | |
1476 | | large.u.LowPart = kernel_time.dwLowDateTime; |
1477 | | large.u.HighPart = kernel_time.dwHighDateTime; |
1478 | | ktime = large.QuadPart; |
1479 | | |
1480 | | large.u.LowPart = user_time.dwLowDateTime; |
1481 | | large.u.HighPart = user_time.dwHighDateTime; |
1482 | | utime = large.QuadPart; |
1483 | | |
1484 | | /* ktime and utime have a resolution of 100 nanoseconds */ |
1485 | | *tp = (ktime + utime) * 100; |
1486 | | return 0; |
1487 | | } |
1488 | | |
1489 | | #elif defined(_AIX) |
1490 | | #define HAVE_THREAD_TIME |
1491 | | static int |
1492 | | _PyTime_GetThreadTimeWithInfo(PyTime_t *tp, _Py_clock_info_t *info) |
1493 | | { |
1494 | | /* bpo-40192: On AIX, thread_cputime() is preferred: it has nanosecond |
1495 | | resolution, whereas clock_gettime(CLOCK_THREAD_CPUTIME_ID) |
1496 | | has a resolution of 10 ms. */ |
1497 | | thread_cputime_t tc; |
1498 | | if (thread_cputime(-1, &tc) != 0) { |
1499 | | PyErr_SetFromErrno(PyExc_OSError); |
1500 | | return -1; |
1501 | | } |
1502 | | |
1503 | | if (info) { |
1504 | | info->implementation = "thread_cputime()"; |
1505 | | info->monotonic = 1; |
1506 | | info->adjustable = 0; |
1507 | | info->resolution = 1e-9; |
1508 | | } |
1509 | | *tp = (tc.stime + tc.utime); |
1510 | | return 0; |
1511 | | } |
1512 | | |
1513 | | #elif defined(__sun) && defined(__SVR4) |
1514 | | #define HAVE_THREAD_TIME |
1515 | | static int |
1516 | | _PyTime_GetThreadTimeWithInfo(PyTime_t *tp, _Py_clock_info_t *info) |
1517 | | { |
1518 | | /* bpo-35455: On Solaris, CLOCK_THREAD_CPUTIME_ID clock is not always |
1519 | | available; use gethrvtime() to substitute this functionality. */ |
1520 | | if (info) { |
1521 | | info->implementation = "gethrvtime()"; |
1522 | | info->resolution = 1e-9; |
1523 | | info->monotonic = 1; |
1524 | | info->adjustable = 0; |
1525 | | } |
1526 | | *tp = gethrvtime(); |
1527 | | return 0; |
1528 | | } |
1529 | | |
1530 | | /* CLOCK_THREAD_CPUTIME_ID is broken on NetBSD: the result of clock_gettime() |
1531 | | * includes the sleeping time, that defeats the purpose of the clock. |
1532 | | * Also, clock_getres() does not support it. |
1533 | | * https://github.com/python/cpython/issues/123978 |
1534 | | * https://gnats.netbsd.org/57512 |
1535 | | */ |
1536 | | #elif defined(HAVE_CLOCK_GETTIME) && \ |
1537 | | defined(CLOCK_THREAD_CPUTIME_ID) && \ |
1538 | | !defined(__EMSCRIPTEN__) && !defined(__wasi__) && \ |
1539 | | !defined(__NetBSD__) |
1540 | | #define HAVE_THREAD_TIME |
1541 | | |
1542 | | #if defined(__APPLE__) && _Py__has_attribute(availability) |
1543 | | static int |
1544 | | _PyTime_GetThreadTimeWithInfo(PyTime_t *tp, _Py_clock_info_t *info) |
1545 | | __attribute__((availability(macos, introduced=10.12))) |
1546 | | __attribute__((availability(ios, introduced=10.0))) |
1547 | | __attribute__((availability(tvos, introduced=10.0))) |
1548 | | __attribute__((availability(watchos, introduced=3.0))); |
1549 | | #endif |
1550 | | |
1551 | | static int |
1552 | | _PyTime_GetThreadTimeWithInfo(PyTime_t *tp, _Py_clock_info_t *info) |
1553 | 0 | { |
1554 | 0 | struct timespec ts; |
1555 | 0 | const clockid_t clk_id = CLOCK_THREAD_CPUTIME_ID; |
1556 | 0 | const char *function = "clock_gettime(CLOCK_THREAD_CPUTIME_ID)"; |
1557 | |
|
1558 | 0 | if (clock_gettime(clk_id, &ts)) { |
1559 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
1560 | 0 | return -1; |
1561 | 0 | } |
1562 | 0 | if (info) { |
1563 | 0 | struct timespec res; |
1564 | 0 | info->implementation = function; |
1565 | 0 | info->monotonic = 1; |
1566 | 0 | info->adjustable = 0; |
1567 | 0 | if (clock_getres(clk_id, &res)) { |
1568 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
1569 | 0 | return -1; |
1570 | 0 | } |
1571 | 0 | info->resolution = res.tv_sec + res.tv_nsec * 1e-9; |
1572 | 0 | } |
1573 | | |
1574 | 0 | if (_PyTime_FromTimespec(tp, &ts) < 0) { |
1575 | 0 | return -1; |
1576 | 0 | } |
1577 | 0 | return 0; |
1578 | 0 | } |
1579 | | #endif |
1580 | | |
1581 | | #ifdef HAVE_THREAD_TIME |
1582 | | #ifdef __APPLE__ |
1583 | | /* |
1584 | | * The clock_* functions will be removed from the module |
1585 | | * dict entirely when the C API is not available. |
1586 | | */ |
1587 | | #pragma clang diagnostic push |
1588 | | #pragma clang diagnostic ignored "-Wunguarded-availability" |
1589 | | #endif |
1590 | | |
1591 | | static PyObject * |
1592 | | time_thread_time(PyObject *self, PyObject *unused) |
1593 | 0 | { |
1594 | 0 | PyTime_t t; |
1595 | 0 | if (_PyTime_GetThreadTimeWithInfo(&t, NULL) < 0) { |
1596 | 0 | return NULL; |
1597 | 0 | } |
1598 | 0 | return _PyFloat_FromPyTime(t); |
1599 | 0 | } |
1600 | | |
1601 | | PyDoc_STRVAR(thread_time_doc, |
1602 | | "thread_time() -> float\n\ |
1603 | | \n\ |
1604 | | Thread time for profiling: sum of the kernel and user-space CPU time."); |
1605 | | |
1606 | | static PyObject * |
1607 | | time_thread_time_ns(PyObject *self, PyObject *unused) |
1608 | 0 | { |
1609 | 0 | PyTime_t t; |
1610 | 0 | if (_PyTime_GetThreadTimeWithInfo(&t, NULL) < 0) { |
1611 | 0 | return NULL; |
1612 | 0 | } |
1613 | 0 | return _PyTime_AsLong(t); |
1614 | 0 | } |
1615 | | |
1616 | | PyDoc_STRVAR(thread_time_ns_doc, |
1617 | | "thread_time() -> int\n\ |
1618 | | \n\ |
1619 | | Thread time for profiling as nanoseconds:\n\ |
1620 | | sum of the kernel and user-space CPU time."); |
1621 | | |
1622 | | #ifdef __APPLE__ |
1623 | | #pragma clang diagnostic pop |
1624 | | #endif |
1625 | | |
1626 | | #endif |
1627 | | |
1628 | | |
1629 | | static PyObject * |
1630 | | time_get_clock_info(PyObject *module, PyObject *args) |
1631 | 0 | { |
1632 | 0 | char *name; |
1633 | 0 | _Py_clock_info_t info; |
1634 | 0 | PyObject *obj = NULL, *dict, *ns; |
1635 | 0 | PyTime_t t; |
1636 | |
|
1637 | 0 | if (!PyArg_ParseTuple(args, "s:get_clock_info", &name)) { |
1638 | 0 | return NULL; |
1639 | 0 | } |
1640 | | |
1641 | | #ifdef Py_DEBUG |
1642 | | info.implementation = NULL; |
1643 | | info.monotonic = -1; |
1644 | | info.adjustable = -1; |
1645 | | info.resolution = -1.0; |
1646 | | #else |
1647 | 0 | info.implementation = ""; |
1648 | 0 | info.monotonic = 0; |
1649 | 0 | info.adjustable = 0; |
1650 | 0 | info.resolution = 1.0; |
1651 | 0 | #endif |
1652 | |
|
1653 | 0 | if (strcmp(name, "time") == 0) { |
1654 | 0 | if (_PyTime_TimeWithInfo(&t, &info) < 0) { |
1655 | 0 | return NULL; |
1656 | 0 | } |
1657 | 0 | } |
1658 | 0 | else if (strcmp(name, "monotonic") == 0) { |
1659 | 0 | if (_PyTime_MonotonicWithInfo(&t, &info) < 0) { |
1660 | 0 | return NULL; |
1661 | 0 | } |
1662 | 0 | } |
1663 | 0 | else if (strcmp(name, "perf_counter") == 0) { |
1664 | 0 | if (_PyTime_PerfCounterWithInfo(&t, &info) < 0) { |
1665 | 0 | return NULL; |
1666 | 0 | } |
1667 | 0 | } |
1668 | 0 | else if (strcmp(name, "process_time") == 0) { |
1669 | 0 | time_module_state *state = get_time_state(module); |
1670 | 0 | if (py_process_time(state, &t, &info) < 0) { |
1671 | 0 | return NULL; |
1672 | 0 | } |
1673 | 0 | } |
1674 | 0 | #ifdef HAVE_THREAD_TIME |
1675 | 0 | else if (strcmp(name, "thread_time") == 0) { |
1676 | |
|
1677 | | #ifdef __APPLE__ |
1678 | | if (HAVE_CLOCK_GETTIME_RUNTIME) { |
1679 | | #endif |
1680 | 0 | if (_PyTime_GetThreadTimeWithInfo(&t, &info) < 0) { |
1681 | 0 | return NULL; |
1682 | 0 | } |
1683 | | #ifdef __APPLE__ |
1684 | | } else { |
1685 | | PyErr_SetString(PyExc_ValueError, "unknown clock"); |
1686 | | return NULL; |
1687 | | } |
1688 | | #endif |
1689 | 0 | } |
1690 | 0 | #endif |
1691 | 0 | else { |
1692 | 0 | PyErr_SetString(PyExc_ValueError, "unknown clock"); |
1693 | 0 | return NULL; |
1694 | 0 | } |
1695 | | |
1696 | 0 | dict = PyDict_New(); |
1697 | 0 | if (dict == NULL) { |
1698 | 0 | return NULL; |
1699 | 0 | } |
1700 | | |
1701 | 0 | assert(info.implementation != NULL); |
1702 | 0 | obj = PyUnicode_FromString(info.implementation); |
1703 | 0 | if (obj == NULL) { |
1704 | 0 | goto error; |
1705 | 0 | } |
1706 | 0 | if (PyDict_SetItemString(dict, "implementation", obj) == -1) { |
1707 | 0 | goto error; |
1708 | 0 | } |
1709 | 0 | Py_CLEAR(obj); |
1710 | |
|
1711 | 0 | assert(info.monotonic != -1); |
1712 | 0 | obj = PyBool_FromLong(info.monotonic); |
1713 | 0 | if (obj == NULL) { |
1714 | 0 | goto error; |
1715 | 0 | } |
1716 | 0 | if (PyDict_SetItemString(dict, "monotonic", obj) == -1) { |
1717 | 0 | goto error; |
1718 | 0 | } |
1719 | 0 | Py_CLEAR(obj); |
1720 | |
|
1721 | 0 | assert(info.adjustable != -1); |
1722 | 0 | obj = PyBool_FromLong(info.adjustable); |
1723 | 0 | if (obj == NULL) { |
1724 | 0 | goto error; |
1725 | 0 | } |
1726 | 0 | if (PyDict_SetItemString(dict, "adjustable", obj) == -1) { |
1727 | 0 | goto error; |
1728 | 0 | } |
1729 | 0 | Py_CLEAR(obj); |
1730 | |
|
1731 | 0 | assert(info.resolution > 0.0); |
1732 | 0 | assert(info.resolution <= 1.0); |
1733 | 0 | obj = PyFloat_FromDouble(info.resolution); |
1734 | 0 | if (obj == NULL) { |
1735 | 0 | goto error; |
1736 | 0 | } |
1737 | 0 | if (PyDict_SetItemString(dict, "resolution", obj) == -1) { |
1738 | 0 | goto error; |
1739 | 0 | } |
1740 | 0 | Py_CLEAR(obj); |
1741 | |
|
1742 | 0 | ns = _PyNamespace_New(dict); |
1743 | 0 | Py_DECREF(dict); |
1744 | 0 | return ns; |
1745 | | |
1746 | 0 | error: |
1747 | 0 | Py_DECREF(dict); |
1748 | 0 | Py_XDECREF(obj); |
1749 | 0 | return NULL; |
1750 | 0 | } |
1751 | | |
1752 | | PyDoc_STRVAR(get_clock_info_doc, |
1753 | | "get_clock_info(name: str) -> dict\n\ |
1754 | | \n\ |
1755 | | Get information of the specified clock."); |
1756 | | |
1757 | | #ifndef HAVE_DECL_TZNAME |
1758 | | static void |
1759 | | get_zone(char *zone, int n, struct tm *p) |
1760 | 32 | { |
1761 | 32 | #ifdef HAVE_STRUCT_TM_TM_ZONE |
1762 | 32 | strncpy(zone, p->tm_zone ? p->tm_zone : " ", n); |
1763 | | #else |
1764 | | tzset(); |
1765 | | strftime(zone, n, "%Z", p); |
1766 | | #endif |
1767 | 32 | } |
1768 | | |
1769 | | static time_t |
1770 | | get_gmtoff(time_t t, struct tm *p) |
1771 | 32 | { |
1772 | 32 | #ifdef HAVE_STRUCT_TM_TM_ZONE |
1773 | 32 | return p->tm_gmtoff; |
1774 | | #else |
1775 | | return timegm(p) - t; |
1776 | | #endif |
1777 | 32 | } |
1778 | | #endif // !HAVE_DECL_TZNAME |
1779 | | |
1780 | | static int |
1781 | | init_timezone(PyObject *m) |
1782 | 16 | { |
1783 | 48 | #define ADD_INT(NAME, VALUE) do { \ |
1784 | 48 | if (PyModule_AddIntConstant(m, NAME, VALUE) < 0) { \ |
1785 | 0 | return -1; \ |
1786 | 0 | } \ |
1787 | 48 | } while (0) |
1788 | | |
1789 | 16 | assert(!PyErr_Occurred()); |
1790 | | |
1791 | | /* This code moved from PyInit_time wholesale to allow calling it from |
1792 | | time_tzset. In the future, some parts of it can be moved back |
1793 | | (for platforms that don't HAVE_WORKING_TZSET, when we know what they |
1794 | | are), and the extraneous calls to tzset(3) should be removed. |
1795 | | I haven't done this yet, as I don't want to change this code as |
1796 | | little as possible when introducing the time.tzset and time.tzsetwall |
1797 | | methods. This should simply be a method of doing the following once, |
1798 | | at the top of this function and removing the call to tzset() from |
1799 | | time_tzset(): |
1800 | | |
1801 | | #ifdef HAVE_TZSET |
1802 | | tzset() |
1803 | | #endif |
1804 | | |
1805 | | And I'm lazy and hate C so nyer. |
1806 | | */ |
1807 | | #ifdef HAVE_DECL_TZNAME |
1808 | | PyObject *otz0, *otz1; |
1809 | | #if !defined(MS_WINDOWS) || defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) |
1810 | | tzset(); |
1811 | | #endif |
1812 | | ADD_INT("timezone", _Py_timezone); |
1813 | | #ifdef HAVE_ALTZONE |
1814 | | ADD_INT("altzone", altzone); |
1815 | | #else |
1816 | | ADD_INT("altzone", _Py_timezone-3600); |
1817 | | #endif |
1818 | | ADD_INT("daylight", _Py_daylight); |
1819 | | #ifdef MS_WINDOWS |
1820 | | TIME_ZONE_INFORMATION tzinfo = {0}; |
1821 | | GetTimeZoneInformation(&tzinfo); |
1822 | | otz0 = PyUnicode_FromWideChar(tzinfo.StandardName, -1); |
1823 | | if (otz0 == NULL) { |
1824 | | return -1; |
1825 | | } |
1826 | | otz1 = PyUnicode_FromWideChar(tzinfo.DaylightName, -1); |
1827 | | if (otz1 == NULL) { |
1828 | | Py_DECREF(otz0); |
1829 | | return -1; |
1830 | | } |
1831 | | #else |
1832 | | otz0 = PyUnicode_DecodeLocale(_Py_tzname[0], "surrogateescape"); |
1833 | | if (otz0 == NULL) { |
1834 | | return -1; |
1835 | | } |
1836 | | otz1 = PyUnicode_DecodeLocale(_Py_tzname[1], "surrogateescape"); |
1837 | | if (otz1 == NULL) { |
1838 | | Py_DECREF(otz0); |
1839 | | return -1; |
1840 | | } |
1841 | | #endif // MS_WINDOWS |
1842 | | if (PyModule_Add(m, "tzname", Py_BuildValue("(NN)", otz0, otz1)) < 0) { |
1843 | | return -1; |
1844 | | } |
1845 | | #else // !HAVE_DECL_TZNAME |
1846 | 16 | static const time_t YEAR = (365 * 24 + 6) * 3600; |
1847 | 16 | time_t t; |
1848 | 16 | struct tm p; |
1849 | 16 | time_t janzone_t, julyzone_t; |
1850 | 16 | char janname[10], julyname[10]; |
1851 | 16 | t = (time((time_t *)0) / YEAR) * YEAR; |
1852 | 16 | _PyTime_localtime(t, &p); |
1853 | 16 | get_zone(janname, 9, &p); |
1854 | 16 | janzone_t = -get_gmtoff(t, &p); |
1855 | 16 | janname[9] = '\0'; |
1856 | 16 | t += YEAR/2; |
1857 | 16 | _PyTime_localtime(t, &p); |
1858 | 16 | get_zone(julyname, 9, &p); |
1859 | 16 | julyzone_t = -get_gmtoff(t, &p); |
1860 | 16 | julyname[9] = '\0'; |
1861 | | |
1862 | | /* Sanity check, don't check for the validity of timezones. |
1863 | | In practice, it should be more in range -12 hours .. +14 hours. */ |
1864 | 112 | #define MAX_TIMEZONE (48 * 3600) |
1865 | 16 | if (janzone_t < -MAX_TIMEZONE || janzone_t > MAX_TIMEZONE |
1866 | 16 | || julyzone_t < -MAX_TIMEZONE || julyzone_t > MAX_TIMEZONE) |
1867 | 0 | { |
1868 | 0 | PyErr_SetString(PyExc_RuntimeError, "invalid GMT offset"); |
1869 | 0 | return -1; |
1870 | 0 | } |
1871 | 16 | int janzone = (int)janzone_t; |
1872 | 16 | int julyzone = (int)julyzone_t; |
1873 | | |
1874 | 16 | PyObject *tzname_obj; |
1875 | 16 | if (janzone < julyzone) { |
1876 | | /* DST is reversed in the southern hemisphere */ |
1877 | 0 | ADD_INT("timezone", julyzone); |
1878 | 0 | ADD_INT("altzone", janzone); |
1879 | 0 | ADD_INT("daylight", janzone != julyzone); |
1880 | 0 | tzname_obj = Py_BuildValue("(zz)", julyname, janname); |
1881 | 16 | } else { |
1882 | 16 | ADD_INT("timezone", janzone); |
1883 | 16 | ADD_INT("altzone", julyzone); |
1884 | 16 | ADD_INT("daylight", janzone != julyzone); |
1885 | 16 | tzname_obj = Py_BuildValue("(zz)", janname, julyname); |
1886 | 16 | } |
1887 | 16 | if (PyModule_Add(m, "tzname", tzname_obj) < 0) { |
1888 | 0 | return -1; |
1889 | 0 | } |
1890 | 16 | #endif // !HAVE_DECL_TZNAME |
1891 | 16 | #undef ADD_INT |
1892 | | |
1893 | 16 | if (PyErr_Occurred()) { |
1894 | 0 | return -1; |
1895 | 0 | } |
1896 | 16 | return 0; |
1897 | 16 | } |
1898 | | |
1899 | | |
1900 | | // Include Argument Clinic code after defining converters such as |
1901 | | // time_clockid_converter(). |
1902 | | #include "clinic/timemodule.c.h" |
1903 | | |
1904 | | static PyMethodDef time_methods[] = { |
1905 | | {"time", time_time, METH_NOARGS, time_doc}, |
1906 | | {"time_ns", time_time_ns, METH_NOARGS, time_ns_doc}, |
1907 | | #ifdef HAVE_CLOCK_GETTIME |
1908 | | TIME_CLOCK_GETTIME_METHODDEF |
1909 | | TIME_CLOCK_GETTIME_NS_METHODDEF |
1910 | | #endif |
1911 | | #ifdef HAVE_CLOCK_SETTIME |
1912 | | {"clock_settime", time_clock_settime, METH_VARARGS, clock_settime_doc}, |
1913 | | {"clock_settime_ns",time_clock_settime_ns, METH_VARARGS, clock_settime_ns_doc}, |
1914 | | #endif |
1915 | | #ifdef HAVE_CLOCK_GETRES |
1916 | | {"clock_getres", time_clock_getres, METH_VARARGS, clock_getres_doc}, |
1917 | | #endif |
1918 | | #ifdef HAVE_PTHREAD_GETCPUCLOCKID |
1919 | | {"pthread_getcpuclockid", time_pthread_getcpuclockid, METH_VARARGS, pthread_getcpuclockid_doc}, |
1920 | | #endif |
1921 | | {"sleep", time_sleep, METH_O, sleep_doc}, |
1922 | | {"gmtime", time_gmtime, METH_VARARGS, gmtime_doc}, |
1923 | | {"localtime", time_localtime, METH_VARARGS, localtime_doc}, |
1924 | | {"asctime", time_asctime, METH_VARARGS, asctime_doc}, |
1925 | | {"ctime", time_ctime, METH_VARARGS, ctime_doc}, |
1926 | | #ifdef HAVE_MKTIME |
1927 | | {"mktime", time_mktime, METH_O, mktime_doc}, |
1928 | | #endif |
1929 | | #ifdef HAVE_STRFTIME |
1930 | | {"strftime", time_strftime, METH_VARARGS, strftime_doc}, |
1931 | | #endif |
1932 | | {"strptime", time_strptime, METH_VARARGS, strptime_doc}, |
1933 | | #ifdef HAVE_WORKING_TZSET |
1934 | | {"tzset", time_tzset, METH_NOARGS, tzset_doc}, |
1935 | | #endif |
1936 | | {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc}, |
1937 | | {"monotonic_ns", time_monotonic_ns, METH_NOARGS, monotonic_ns_doc}, |
1938 | | {"process_time", time_process_time, METH_NOARGS, process_time_doc}, |
1939 | | {"process_time_ns", time_process_time_ns, METH_NOARGS, process_time_ns_doc}, |
1940 | | #ifdef HAVE_THREAD_TIME |
1941 | | {"thread_time", time_thread_time, METH_NOARGS, thread_time_doc}, |
1942 | | {"thread_time_ns", time_thread_time_ns, METH_NOARGS, thread_time_ns_doc}, |
1943 | | #endif |
1944 | | {"perf_counter", time_perf_counter, METH_NOARGS, perf_counter_doc}, |
1945 | | {"perf_counter_ns", time_perf_counter_ns, METH_NOARGS, perf_counter_ns_doc}, |
1946 | | {"get_clock_info", time_get_clock_info, METH_VARARGS, get_clock_info_doc}, |
1947 | | {NULL, NULL} /* sentinel */ |
1948 | | }; |
1949 | | |
1950 | | |
1951 | | PyDoc_STRVAR(module_doc, |
1952 | | "This module provides various functions to manipulate time values.\n\ |
1953 | | \n\ |
1954 | | There are two standard representations of time. One is the number\n\ |
1955 | | of seconds since the Epoch, in UTC (a.k.a. GMT). It may be an integer\n\ |
1956 | | or a floating-point number (to represent fractions of seconds).\n\ |
1957 | | The epoch is the point where the time starts, the return value of time.gmtime(0).\n\ |
1958 | | It is January 1, 1970, 00:00:00 (UTC) on all platforms.\n\ |
1959 | | \n\ |
1960 | | The other representation is a tuple of 9 integers giving local time.\n\ |
1961 | | The tuple items are:\n\ |
1962 | | year (including century, e.g. 1998)\n\ |
1963 | | month (1-12)\n\ |
1964 | | day (1-31)\n\ |
1965 | | hours (0-23)\n\ |
1966 | | minutes (0-59)\n\ |
1967 | | seconds (0-59)\n\ |
1968 | | weekday (0-6, Monday is 0)\n\ |
1969 | | Julian day (day in the year, 1-366)\n\ |
1970 | | DST (Daylight Savings Time) flag (-1, 0 or 1)\n\ |
1971 | | If the DST flag is 0, the time is given in the regular time zone;\n\ |
1972 | | if it is 1, the time is given in the DST time zone;\n\ |
1973 | | if it is -1, mktime() should guess based on the date and time.\n"); |
1974 | | |
1975 | | |
1976 | | static int |
1977 | | time_exec(PyObject *module) |
1978 | 16 | { |
1979 | 16 | time_module_state *state = get_time_state(module); |
1980 | | #if defined(__APPLE__) && defined(HAVE_CLOCK_GETTIME) |
1981 | | if (HAVE_CLOCK_GETTIME_RUNTIME) { |
1982 | | /* pass: ^^^ cannot use '!' here */ |
1983 | | } else { |
1984 | | PyObject* dct = PyModule_GetDict(module); |
1985 | | if (dct == NULL) { |
1986 | | return -1; |
1987 | | } |
1988 | | |
1989 | | if (PyDict_PopString(dct, "clock_gettime", NULL) < 0) { |
1990 | | return -1; |
1991 | | } |
1992 | | if (PyDict_PopString(dct, "clock_gettime_ns", NULL) < 0) { |
1993 | | return -1; |
1994 | | } |
1995 | | if (PyDict_PopString(dct, "clock_settime", NULL) < 0) { |
1996 | | return -1; |
1997 | | } |
1998 | | if (PyDict_PopString(dct, "clock_settime_ns", NULL) < 0) { |
1999 | | return -1; |
2000 | | } |
2001 | | if (PyDict_PopString(dct, "clock_getres", NULL) < 0) { |
2002 | | return -1; |
2003 | | } |
2004 | | } |
2005 | | #endif |
2006 | | #if defined(__APPLE__) && defined(HAVE_THREAD_TIME) |
2007 | | if (HAVE_CLOCK_GETTIME_RUNTIME) { |
2008 | | /* pass: ^^^ cannot use '!' here */ |
2009 | | } else { |
2010 | | PyObject* dct = PyModule_GetDict(module); |
2011 | | |
2012 | | if (PyDict_PopString(dct, "thread_time", NULL) < 0) { |
2013 | | return -1; |
2014 | | } |
2015 | | if (PyDict_PopString(dct, "thread_time_ns", NULL) < 0) { |
2016 | | return -1; |
2017 | | } |
2018 | | } |
2019 | | #endif |
2020 | | /* Set, or reset, module variables like time.timezone */ |
2021 | 16 | if (init_timezone(module) < 0) { |
2022 | 0 | return -1; |
2023 | 0 | } |
2024 | | |
2025 | 16 | #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES) |
2026 | 16 | if (HAVE_CLOCK_GETTIME_RUNTIME) { |
2027 | | |
2028 | 16 | #ifdef CLOCK_REALTIME |
2029 | 16 | if (PyModule_AddIntMacro(module, CLOCK_REALTIME) < 0) { |
2030 | 0 | return -1; |
2031 | 0 | } |
2032 | 16 | #endif |
2033 | 16 | #ifdef CLOCK_MONOTONIC |
2034 | 16 | if (PyModule_AddIntMacro(module, CLOCK_MONOTONIC) < 0) { |
2035 | 0 | return -1; |
2036 | 0 | } |
2037 | 16 | #endif |
2038 | 16 | #ifdef CLOCK_MONOTONIC_RAW |
2039 | 16 | if (PyModule_AddIntMacro(module, CLOCK_MONOTONIC_RAW) < 0) { |
2040 | 0 | return -1; |
2041 | 0 | } |
2042 | 16 | #endif |
2043 | | #ifdef CLOCK_HIGHRES |
2044 | | if (PyModule_AddIntMacro(module, CLOCK_HIGHRES) < 0) { |
2045 | | return -1; |
2046 | | } |
2047 | | #endif |
2048 | 16 | #ifdef CLOCK_PROCESS_CPUTIME_ID |
2049 | 16 | if (PyModule_AddIntMacro(module, CLOCK_PROCESS_CPUTIME_ID) < 0) { |
2050 | 0 | return -1; |
2051 | 0 | } |
2052 | 16 | #endif |
2053 | 16 | #ifdef CLOCK_THREAD_CPUTIME_ID |
2054 | 16 | if (PyModule_AddIntMacro(module, CLOCK_THREAD_CPUTIME_ID) < 0) { |
2055 | 0 | return -1; |
2056 | 0 | } |
2057 | 16 | #endif |
2058 | | #ifdef CLOCK_PROF |
2059 | | if (PyModule_AddIntMacro(module, CLOCK_PROF) < 0) { |
2060 | | return -1; |
2061 | | } |
2062 | | #endif |
2063 | 16 | #ifdef CLOCK_BOOTTIME |
2064 | 16 | if (PyModule_AddIntMacro(module, CLOCK_BOOTTIME) < 0) { |
2065 | 0 | return -1; |
2066 | 0 | } |
2067 | 16 | #endif |
2068 | 16 | #ifdef CLOCK_TAI |
2069 | 16 | if (PyModule_AddIntMacro(module, CLOCK_TAI) < 0) { |
2070 | 0 | return -1; |
2071 | 0 | } |
2072 | 16 | #endif |
2073 | | #ifdef CLOCK_UPTIME |
2074 | | if (PyModule_AddIntMacro(module, CLOCK_UPTIME) < 0) { |
2075 | | return -1; |
2076 | | } |
2077 | | #endif |
2078 | | #ifdef CLOCK_UPTIME_RAW |
2079 | | if (PyModule_AddIntMacro(module, CLOCK_UPTIME_RAW) < 0) { |
2080 | | return -1; |
2081 | | } |
2082 | | #endif |
2083 | | #ifdef CLOCK_MONOTONIC_RAW_APPROX |
2084 | | if (PyModule_AddIntMacro(module, CLOCK_MONOTONIC_RAW_APPROX) < 0) { |
2085 | | return -1; |
2086 | | } |
2087 | | #endif |
2088 | | #ifdef CLOCK_UPTIME_RAW_APPROX |
2089 | | if (PyModule_AddIntMacro(module, CLOCK_UPTIME_RAW_APPROX) < 0) { |
2090 | | return -1; |
2091 | | } |
2092 | | #endif |
2093 | 16 | } |
2094 | | |
2095 | 16 | #endif /* defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES) */ |
2096 | | |
2097 | 16 | if (PyModule_AddIntConstant(module, "_STRUCT_TM_ITEMS", 11)) { |
2098 | 0 | return -1; |
2099 | 0 | } |
2100 | | |
2101 | | // struct_time type |
2102 | 16 | state->struct_time_type = PyStructSequence_NewType(&struct_time_type_desc); |
2103 | 16 | if (state->struct_time_type == NULL) { |
2104 | 0 | return -1; |
2105 | 0 | } |
2106 | 16 | if (PyModule_AddType(module, state->struct_time_type)) { |
2107 | 0 | return -1; |
2108 | 0 | } |
2109 | | |
2110 | | #if defined(__linux__) && !defined(__GLIBC__) |
2111 | | struct tm tm; |
2112 | | const time_t zero = 0; |
2113 | | if (gmtime_r(&zero, &tm) != NULL) |
2114 | | utc_string = tm.tm_zone; |
2115 | | #endif |
2116 | | |
2117 | | #if defined(MS_WINDOWS) |
2118 | | if (timer_flags == (DWORD)-1) { |
2119 | | DWORD test_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION; |
2120 | | HANDLE timer = CreateWaitableTimerExW(NULL, NULL, test_flags, |
2121 | | TIMER_ALL_ACCESS); |
2122 | | if (timer == NULL) { |
2123 | | // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is not supported. |
2124 | | timer_flags = 0; |
2125 | | } |
2126 | | else { |
2127 | | // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is supported. |
2128 | | timer_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION; |
2129 | | CloseHandle(timer); |
2130 | | } |
2131 | | } |
2132 | | #endif |
2133 | | |
2134 | | // gh-115714: Don't use times() on WASI. |
2135 | 16 | #if defined(HAVE_TIMES) && !defined(__wasi__) |
2136 | 16 | long ticks_per_second; |
2137 | 16 | if (_Py_GetTicksPerSecond(&ticks_per_second) < 0) { |
2138 | 0 | PyErr_SetString(PyExc_RuntimeError, |
2139 | 0 | "cannot read ticks_per_second"); |
2140 | 0 | return -1; |
2141 | 0 | } |
2142 | 16 | if (_PyTimeFraction_Set(&state->times_base, SEC_TO_NS, |
2143 | 16 | ticks_per_second) < 0) { |
2144 | 0 | PyErr_Format(PyExc_OverflowError, "ticks_per_second is too large"); |
2145 | 0 | return -1; |
2146 | 0 | } |
2147 | 16 | #endif |
2148 | | |
2149 | 16 | #ifdef HAVE_CLOCK |
2150 | 16 | if (_PyTimeFraction_Set(&state->clock_base, SEC_TO_NS, |
2151 | 16 | CLOCKS_PER_SEC) < 0) { |
2152 | 0 | PyErr_Format(PyExc_OverflowError, "CLOCKS_PER_SEC is too large"); |
2153 | 0 | return -1; |
2154 | 0 | } |
2155 | 16 | #endif |
2156 | | |
2157 | 16 | return 0; |
2158 | 16 | } |
2159 | | |
2160 | | |
2161 | | static int |
2162 | | time_module_traverse(PyObject *module, visitproc visit, void *arg) |
2163 | 4.13k | { |
2164 | 4.13k | time_module_state *state = get_time_state(module); |
2165 | 4.13k | Py_VISIT(state->struct_time_type); |
2166 | 4.13k | return 0; |
2167 | 4.13k | } |
2168 | | |
2169 | | |
2170 | | static int |
2171 | | time_module_clear(PyObject *module) |
2172 | 0 | { |
2173 | 0 | time_module_state *state = get_time_state(module); |
2174 | 0 | Py_CLEAR(state->struct_time_type); |
2175 | 0 | return 0; |
2176 | 0 | } |
2177 | | |
2178 | | |
2179 | | static void |
2180 | | time_module_free(void *module) |
2181 | 0 | { |
2182 | 0 | time_module_clear((PyObject *)module); |
2183 | 0 | } |
2184 | | |
2185 | | |
2186 | | static struct PyModuleDef_Slot time_slots[] = { |
2187 | | {Py_mod_exec, time_exec}, |
2188 | | {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, |
2189 | | {Py_mod_gil, Py_MOD_GIL_NOT_USED}, |
2190 | | {0, NULL} |
2191 | | }; |
2192 | | |
2193 | | static struct PyModuleDef timemodule = { |
2194 | | PyModuleDef_HEAD_INIT, |
2195 | | .m_name = "time", |
2196 | | .m_doc = module_doc, |
2197 | | .m_size = sizeof(time_module_state), |
2198 | | .m_methods = time_methods, |
2199 | | .m_slots = time_slots, |
2200 | | .m_traverse = time_module_traverse, |
2201 | | .m_clear = time_module_clear, |
2202 | | .m_free = time_module_free, |
2203 | | }; |
2204 | | |
2205 | | PyMODINIT_FUNC |
2206 | | PyInit_time(void) |
2207 | 16 | { |
2208 | 16 | return PyModuleDef_Init(&timemodule); |
2209 | 16 | } |
2210 | | |
2211 | | |
2212 | | // time.sleep() implementation. |
2213 | | // On error, raise an exception and return -1. |
2214 | | // On success, return 0. |
2215 | | static int |
2216 | | pysleep(PyTime_t timeout) |
2217 | 0 | { |
2218 | 0 | assert(timeout >= 0); |
2219 | |
|
2220 | 0 | #ifndef MS_WINDOWS |
2221 | 0 | #ifdef HAVE_CLOCK_NANOSLEEP |
2222 | 0 | struct timespec timeout_abs; |
2223 | | #elif defined(HAVE_NANOSLEEP) |
2224 | | struct timespec timeout_ts; |
2225 | | #else |
2226 | | struct timeval timeout_tv; |
2227 | | #endif |
2228 | 0 | PyTime_t deadline, monotonic; |
2229 | 0 | int err = 0; |
2230 | |
|
2231 | 0 | if (PyTime_Monotonic(&monotonic) < 0) { |
2232 | 0 | return -1; |
2233 | 0 | } |
2234 | 0 | deadline = monotonic + timeout; |
2235 | 0 | #ifdef HAVE_CLOCK_NANOSLEEP |
2236 | 0 | if (_PyTime_AsTimespec(deadline, &timeout_abs) < 0) { |
2237 | 0 | return -1; |
2238 | 0 | } |
2239 | 0 | #endif |
2240 | | |
2241 | 0 | do { |
2242 | 0 | #ifdef HAVE_CLOCK_NANOSLEEP |
2243 | | // use timeout_abs |
2244 | | #elif defined(HAVE_NANOSLEEP) |
2245 | | if (_PyTime_AsTimespec(timeout, &timeout_ts) < 0) { |
2246 | | return -1; |
2247 | | } |
2248 | | #else |
2249 | | if (_PyTime_AsTimeval(timeout, &timeout_tv, _PyTime_ROUND_CEILING) < 0) { |
2250 | | return -1; |
2251 | | } |
2252 | | #endif |
2253 | |
|
2254 | 0 | int ret; |
2255 | 0 | Py_BEGIN_ALLOW_THREADS |
2256 | 0 | #ifdef HAVE_CLOCK_NANOSLEEP |
2257 | 0 | ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &timeout_abs, NULL); |
2258 | 0 | err = ret; |
2259 | | #elif defined(HAVE_NANOSLEEP) |
2260 | | ret = nanosleep(&timeout_ts, NULL); |
2261 | | err = errno; |
2262 | | #else |
2263 | | ret = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout_tv); |
2264 | | err = errno; |
2265 | | #endif |
2266 | 0 | Py_END_ALLOW_THREADS |
2267 | |
|
2268 | 0 | if (ret == 0) { |
2269 | 0 | break; |
2270 | 0 | } |
2271 | | |
2272 | 0 | if (err != EINTR) { |
2273 | 0 | errno = err; |
2274 | 0 | PyErr_SetFromErrno(PyExc_OSError); |
2275 | 0 | return -1; |
2276 | 0 | } |
2277 | | |
2278 | | /* sleep was interrupted by SIGINT */ |
2279 | 0 | if (PyErr_CheckSignals()) { |
2280 | 0 | return -1; |
2281 | 0 | } |
2282 | |
|
2283 | | #ifndef HAVE_CLOCK_NANOSLEEP |
2284 | | if (PyTime_Monotonic(&monotonic) < 0) { |
2285 | | return -1; |
2286 | | } |
2287 | | timeout = deadline - monotonic; |
2288 | | if (timeout < 0) { |
2289 | | break; |
2290 | | } |
2291 | | /* retry with the recomputed delay */ |
2292 | | #endif |
2293 | 0 | } while (1); |
2294 | | |
2295 | 0 | return 0; |
2296 | | #else // MS_WINDOWS |
2297 | | PyTime_t timeout_100ns = _PyTime_As100Nanoseconds(timeout, |
2298 | | _PyTime_ROUND_CEILING); |
2299 | | |
2300 | | // Maintain Windows Sleep() semantics for time.sleep(0) |
2301 | | if (timeout_100ns == 0) { |
2302 | | Py_BEGIN_ALLOW_THREADS |
2303 | | // A value of zero causes the thread to relinquish the remainder of its |
2304 | | // time slice to any other thread that is ready to run. If there are no |
2305 | | // other threads ready to run, the function returns immediately, and |
2306 | | // the thread continues execution. |
2307 | | Sleep(0); |
2308 | | Py_END_ALLOW_THREADS |
2309 | | return 0; |
2310 | | } |
2311 | | |
2312 | | LARGE_INTEGER relative_timeout; |
2313 | | // No need to check for integer overflow, both types are signed |
2314 | | assert(sizeof(relative_timeout) == sizeof(timeout_100ns)); |
2315 | | // SetWaitableTimer(): a negative due time indicates relative time |
2316 | | relative_timeout.QuadPart = -timeout_100ns; |
2317 | | |
2318 | | HANDLE timer = CreateWaitableTimerExW(NULL, NULL, timer_flags, |
2319 | | TIMER_ALL_ACCESS); |
2320 | | if (timer == NULL) { |
2321 | | PyErr_SetFromWindowsErr(0); |
2322 | | return -1; |
2323 | | } |
2324 | | |
2325 | | if (!SetWaitableTimerEx(timer, &relative_timeout, |
2326 | | 0, // no period; the timer is signaled once |
2327 | | NULL, NULL, // no completion routine |
2328 | | NULL, // no wake context; do not resume from suspend |
2329 | | 0)) // no tolerable delay for timer coalescing |
2330 | | { |
2331 | | PyErr_SetFromWindowsErr(0); |
2332 | | goto error; |
2333 | | } |
2334 | | |
2335 | | // Only the main thread can be interrupted by SIGINT. |
2336 | | // Signal handlers are only executed in the main thread. |
2337 | | if (_PyOS_IsMainThread()) { |
2338 | | HANDLE sigint_event = _PyOS_SigintEvent(); |
2339 | | |
2340 | | while (1) { |
2341 | | // Check for pending SIGINT signal before resetting the event |
2342 | | if (PyErr_CheckSignals()) { |
2343 | | goto error; |
2344 | | } |
2345 | | ResetEvent(sigint_event); |
2346 | | |
2347 | | HANDLE events[] = {timer, sigint_event}; |
2348 | | DWORD rc; |
2349 | | |
2350 | | Py_BEGIN_ALLOW_THREADS |
2351 | | rc = WaitForMultipleObjects(Py_ARRAY_LENGTH(events), events, |
2352 | | // bWaitAll |
2353 | | FALSE, |
2354 | | // No wait timeout |
2355 | | INFINITE); |
2356 | | Py_END_ALLOW_THREADS |
2357 | | |
2358 | | if (rc == WAIT_FAILED) { |
2359 | | PyErr_SetFromWindowsErr(0); |
2360 | | goto error; |
2361 | | } |
2362 | | |
2363 | | if (rc == WAIT_OBJECT_0) { |
2364 | | // Timer signaled: we are done |
2365 | | break; |
2366 | | } |
2367 | | |
2368 | | assert(rc == (WAIT_OBJECT_0 + 1)); |
2369 | | // The sleep was interrupted by SIGINT: restart sleeping |
2370 | | } |
2371 | | } |
2372 | | else { |
2373 | | DWORD rc; |
2374 | | |
2375 | | Py_BEGIN_ALLOW_THREADS |
2376 | | rc = WaitForSingleObject(timer, INFINITE); |
2377 | | Py_END_ALLOW_THREADS |
2378 | | |
2379 | | if (rc == WAIT_FAILED) { |
2380 | | PyErr_SetFromWindowsErr(0); |
2381 | | goto error; |
2382 | | } |
2383 | | |
2384 | | assert(rc == WAIT_OBJECT_0); |
2385 | | // Timer signaled: we are done |
2386 | | } |
2387 | | |
2388 | | CloseHandle(timer); |
2389 | | return 0; |
2390 | | |
2391 | | error: |
2392 | | CloseHandle(timer); |
2393 | | return -1; |
2394 | | #endif |
2395 | 0 | } |