bpo-37205: time.time() cannot fail with fatal error (GH-23314) · python/cpython@ae6cd7c · GitHub
Skip to content

Commit ae6cd7c

Browse files
authored
bpo-37205: time.time() cannot fail with fatal error (GH-23314)
time.time(), time.perf_counter() and time.monotonic() functions can no longer fail with a Python fatal error, instead raise a regular Python exception on failure. Remove _PyTime_Init(): don't check system, monotonic and perf counter clocks at startup anymore. On error, _PyTime_GetSystemClock(), _PyTime_GetMonotonicClock() and _PyTime_GetPerfCounter() now silently ignore the error and return 0. They cannot fail with a Python fatal error anymore. Add py_mach_timebase_info() and win_perf_counter_frequency() sub-functions.
1 parent 5909a49 commit ae6cd7c

5 files changed

Lines changed: 228 additions & 158 deletions

File tree

Include/pytime.h

Lines changed: 28 additions & 24 deletions
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`time.time()`, :func:`time.perf_counter()` and
2+
:func:`time.monotonic()` functions can no longer fail with a Python fatal
3+
error, instead raise a regular Python exception on failure.

Modules/timemodule.c

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
#define _Py_tzname tzname
5252
#endif
5353

54-
#if defined(__APPLE__ ) && defined(__has_builtin)
54+
#if defined(__APPLE__ ) && defined(__has_builtin)
5555
# if __has_builtin(__builtin_available)
5656
# define HAVE_CLOCK_GETTIME_RUNTIME __builtin_available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
5757
# endif
@@ -74,10 +74,21 @@ _PyFloat_FromPyTime(_PyTime_t t)
7474
}
7575

7676

77+
static int
78+
get_system_time(_PyTime_t *t)
79+
{
80+
// Avoid _PyTime_GetSystemClock() which silently ignores errors.
81+
return _PyTime_GetSystemClockWithInfo(t, NULL);
82+
}
83+
84+
7785
static PyObject *
7886
time_time(PyObject *self, PyObject *unused)
7987
{
80-
_PyTime_t t = _PyTime_GetSystemClock();
88+
_PyTime_t t;
89+
if (get_system_time(&t) < 0) {
90+
return NULL;
91+
}
8192
return _PyFloat_FromPyTime(t);
8293
}
8394

@@ -91,7 +102,10 @@ Fractions of a second may be present if the system clock provides them.");
91102
static PyObject *
92103
time_time_ns(PyObject *self, PyObject *unused)
93104
{
94-
_PyTime_t t = _PyTime_GetSystemClock();
105+
_PyTime_t t;
106+
if (get_system_time(&t) < 0) {
107+
return NULL;
108+
}
95109
return _PyTime_AsNanosecondsObject(t);
96110
}
97111

@@ -147,20 +161,11 @@ _PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
147161
}
148162
#endif /* HAVE_CLOCK */
149163

150-
static PyObject*
151-
perf_counter(_Py_clock_info_t *info)
152-
{
153-
_PyTime_t t;
154-
if (_PyTime_GetPerfCounterWithInfo(&t, info) < 0) {
155-
return NULL;
156-
}
157-
return _PyFloat_FromPyTime(t);
158-
}
159164

160165
#ifdef HAVE_CLOCK_GETTIME
161166

162167
#ifdef __APPLE__
163-
/*
168+
/*
164169
* The clock_* functions will be removed from the module
165170
* dict entirely when the C API is not available.
166171
*/
@@ -1096,10 +1101,22 @@ the local timezone used by methods such as localtime, but this behaviour\n\
10961101
should not be relied on.");
10971102
#endif /* HAVE_WORKING_TZSET */
10981103

1104+
1105+
static int
1106+
get_monotonic(_PyTime_t *t)
1107+
{
1108+
// Avoid _PyTime_GetMonotonicClock() which silently ignores errors.
1109+
return _PyTime_GetMonotonicClockWithInfo(t, NULL);
1110+
}
1111+
1112+
10991113
static PyObject *
11001114
time_monotonic(PyObject *self, PyObject *unused)
11011115
{
1102-
_PyTime_t t = _PyTime_GetMonotonicClock();
1116+
_PyTime_t t;
1117+
if (get_monotonic(&t) < 0) {
1118+
return NULL;
1119+
}
11031120
return _PyFloat_FromPyTime(t);
11041121
}
11051122

@@ -1111,7 +1128,10 @@ Monotonic clock, cannot go backward.");
11111128
static PyObject *
11121129
time_monotonic_ns(PyObject *self, PyObject *unused)
11131130
{
1114-
_PyTime_t t = _PyTime_GetMonotonicClock();
1131+
_PyTime_t t;
1132+
if (get_monotonic(&t) < 0) {
1133+
return NULL;
1134+
}
11151135
return _PyTime_AsNanosecondsObject(t);
11161136
}
11171137

@@ -1120,21 +1140,38 @@ PyDoc_STRVAR(monotonic_ns_doc,
11201140
\n\
11211141
Monotonic clock, cannot go backward, as nanoseconds.");
11221142

1143+
1144+
static int
1145+
get_perf_counter(_PyTime_t *t)
1146+
{
1147+
// Avoid _PyTime_GetPerfCounter() which silently ignores errors.
1148+
return _PyTime_GetPerfCounterWithInfo(t, NULL);
1149+
}
1150+
1151+
11231152
static PyObject *
11241153
time_perf_counter(PyObject *self, PyObject *unused)
11251154
{
1126-
return perf_counter(NULL);
1155+
_PyTime_t t;
1156+
if (get_perf_counter(&t) < 0) {
1157+
return NULL;
1158+
}
1159+
return _PyFloat_FromPyTime(t);
11271160
}
11281161

11291162
PyDoc_STRVAR(perf_counter_doc,
11301163
"perf_counter() -> float\n\
11311164
\n\
11321165
Performance counter for benchmarking.");
11331166

1167+
11341168
static PyObject *
11351169
time_perf_counter_ns(PyObject *self, PyObject *unused)
11361170
{
1137-
_PyTime_t t = _PyTime_GetPerfCounter();
1171+
_PyTime_t t;
1172+
if (get_perf_counter(&t) < 0) {
1173+
return NULL;
1174+
}
11381175
return _PyTime_AsNanosecondsObject(t);
11391176
}
11401177

@@ -1421,7 +1458,7 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
14211458

14221459
#if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability)
14231460
static int
1424-
_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
1461+
_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
14251462
__attribute__((availability(macos, introduced=10.12)))
14261463
__attribute__((availability(ios, introduced=10.0)))
14271464
__attribute__((availability(tvos, introduced=10.0)))
@@ -1460,7 +1497,7 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
14601497

14611498
#ifdef HAVE_THREAD_TIME
14621499
#ifdef __APPLE__
1463-
/*
1500+
/*
14641501
* The clock_* functions will be removed from the module
14651502
* dict entirely when the C API is not available.
14661503
*/
@@ -2025,7 +2062,10 @@ pysleep(_PyTime_t secs)
20252062
HANDLE hInterruptEvent;
20262063
#endif
20272064

2028-
deadline = _PyTime_GetMonotonicClock() + secs;
2065+
if (get_monotonic(&monotonic) < 0) {
2066+
return -1;
2067+
}
2068+
deadline = monotonic + secs;
20292069

20302070
do {
20312071
#ifndef MS_WINDOWS
@@ -2077,10 +2117,13 @@ pysleep(_PyTime_t secs)
20772117
if (PyErr_CheckSignals())
20782118
return -1;
20792119

2080-
monotonic = _PyTime_GetMonotonicClock();
2120+
if (get_monotonic(&monotonic) < 0) {
2121+
return -1;
2122+
}
20812123
secs = deadline - monotonic;
2082-
if (secs < 0)
2124+
if (secs < 0) {
20832125
break;
2126+
}
20842127
/* retry with the recomputed delay */
20852128
} while (1);
20862129

Python/pylifecycle.c

Lines changed: 0 additions & 6 deletions

0 commit comments

Comments
 (0)