Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 28 additions & 24 deletions Include/pytime.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,22 +164,6 @@ PyAPI_FUNC(_PyTime_t) _PyTime_MulDiv(_PyTime_t ticks,
_PyTime_t mul,
_PyTime_t div);

/* Get the current time from the system clock.

The function cannot fail. _PyTime_Init() ensures that the system clock
works. */
PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void);

/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards.
The clock is not affected by system clock updates. The reference point of
the returned value is undefined, so that only the difference between the
results of consecutive calls is valid.

The function cannot fail. _PyTime_Init() ensures that a monotonic clock
is available and works. */
PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void);


/* Structure used by time.get_clock_info() */
typedef struct {
const char *implementation;
Expand All @@ -189,13 +173,34 @@ typedef struct {
} _Py_clock_info_t;

/* Get the current time from the system clock.
* Fill clock information if info is not NULL.
* Raise an exception and return -1 on error, return 0 on success.

If the internal clock fails, silently ignore the error and return 0.
On integer overflow, silently ignore the overflow and truncated the clock to
_PyTime_MIN or _PyTime_MAX.

Use _PyTime_GetSystemClockWithInfo() to check for failure. */
PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void);

/* Get the current time from the system clock.
* On success, set *t and *info (if not NULL), and return 0.
* On error, raise an exception and return -1.
*/
PyAPI_FUNC(int) _PyTime_GetSystemClockWithInfo(
_PyTime_t *t,
_Py_clock_info_t *info);

/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards.
The clock is not affected by system clock updates. The reference point of
the returned value is undefined, so that only the difference between the
results of consecutive calls is valid.

If the internal clock fails, silently ignore the error and return 0.
On integer overflow, silently ignore the overflow and truncated the clock to
_PyTime_MIN or _PyTime_MAX.

Use _PyTime_GetMonotonicClockWithInfo() to check for failure. */
PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void);

/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards.
The clock is not affected by system clock updates. The reference point of
the returned value is undefined, so that only the difference between the
Expand All @@ -209,10 +214,6 @@ PyAPI_FUNC(int) _PyTime_GetMonotonicClockWithInfo(
_Py_clock_info_t *info);


/* Initialize time.
Return 0 on success, raise an exception and return -1 on error. */
PyAPI_FUNC(int) _PyTime_Init(void);

/* Converts a timestamp to the Gregorian time, using the local time zone.
Return 0 on success, raise an exception and return -1 on error. */
PyAPI_FUNC(int) _PyTime_localtime(time_t t, struct tm *tm);
Expand All @@ -224,8 +225,11 @@ PyAPI_FUNC(int) _PyTime_gmtime(time_t t, struct tm *tm);
/* Get the performance counter: clock with the highest available resolution to
measure a short duration.

The function cannot fail. _PyTime_Init() ensures that the system clock
works. */
If the internal clock fails, silently ignore the error and return 0.
On integer overflow, silently ignore the overflow and truncated the clock to
_PyTime_MIN or _PyTime_MAX.

Use _PyTime_GetPerfCounterWithInfo() to check for failure. */
PyAPI_FUNC(_PyTime_t) _PyTime_GetPerfCounter(void);

/* Get the performance counter: clock with the highest available resolution to
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:func:`time.time()`, :func:`time.perf_counter()` and
:func:`time.monotonic()` functions can no longer fail with a Python fatal
error, instead raise a regular Python exception on failure.
87 changes: 65 additions & 22 deletions Modules/timemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
#define _Py_tzname tzname
#endif

#if defined(__APPLE__ ) && defined(__has_builtin)
#if defined(__APPLE__ ) && defined(__has_builtin)
# if __has_builtin(__builtin_available)
# define HAVE_CLOCK_GETTIME_RUNTIME __builtin_available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
# endif
Expand All @@ -74,10 +74,21 @@ _PyFloat_FromPyTime(_PyTime_t t)
}


static int
get_system_time(_PyTime_t *t)
{
// Avoid _PyTime_GetSystemClock() which silently ignores errors.
return _PyTime_GetSystemClockWithInfo(t, NULL);
}


static PyObject *
time_time(PyObject *self, PyObject *unused)
{
_PyTime_t t = _PyTime_GetSystemClock();
_PyTime_t t;
if (get_system_time(&t) < 0) {
return NULL;
}
return _PyFloat_FromPyTime(t);
}

Expand All @@ -91,7 +102,10 @@ Fractions of a second may be present if the system clock provides them.");
static PyObject *
time_time_ns(PyObject *self, PyObject *unused)
{
_PyTime_t t = _PyTime_GetSystemClock();
_PyTime_t t;
if (get_system_time(&t) < 0) {
return NULL;
}
return _PyTime_AsNanosecondsObject(t);
}

Expand Down Expand Up @@ -147,20 +161,11 @@ _PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
}
#endif /* HAVE_CLOCK */

static PyObject*
perf_counter(_Py_clock_info_t *info)
{
_PyTime_t t;
if (_PyTime_GetPerfCounterWithInfo(&t, info) < 0) {
return NULL;
}
return _PyFloat_FromPyTime(t);
}

#ifdef HAVE_CLOCK_GETTIME

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


static int
get_monotonic(_PyTime_t *t)
{
// Avoid _PyTime_GetMonotonicClock() which silently ignores errors.
return _PyTime_GetMonotonicClockWithInfo(t, NULL);
}


static PyObject *
time_monotonic(PyObject *self, PyObject *unused)
{
_PyTime_t t = _PyTime_GetMonotonicClock();
_PyTime_t t;
if (get_monotonic(&t) < 0) {
return NULL;
}
return _PyFloat_FromPyTime(t);
}

Expand All @@ -1111,7 +1128,10 @@ Monotonic clock, cannot go backward.");
static PyObject *
time_monotonic_ns(PyObject *self, PyObject *unused)
{
_PyTime_t t = _PyTime_GetMonotonicClock();
_PyTime_t t;
if (get_monotonic(&t) < 0) {
return NULL;
}
return _PyTime_AsNanosecondsObject(t);
}

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


static int
get_perf_counter(_PyTime_t *t)
{
// Avoid _PyTime_GetPerfCounter() which silently ignores errors.
return _PyTime_GetPerfCounterWithInfo(t, NULL);
}


static PyObject *
time_perf_counter(PyObject *self, PyObject *unused)
{
return perf_counter(NULL);
_PyTime_t t;
if (get_perf_counter(&t) < 0) {
return NULL;
}
return _PyFloat_FromPyTime(t);
}

PyDoc_STRVAR(perf_counter_doc,
"perf_counter() -> float\n\
\n\
Performance counter for benchmarking.");


static PyObject *
time_perf_counter_ns(PyObject *self, PyObject *unused)
{
_PyTime_t t = _PyTime_GetPerfCounter();
_PyTime_t t;
if (get_perf_counter(&t) < 0) {
return NULL;
}
return _PyTime_AsNanosecondsObject(t);
}

Expand Down Expand Up @@ -1421,7 +1458,7 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)

#if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability)
static int
_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
__attribute__((availability(macos, introduced=10.12)))
__attribute__((availability(ios, introduced=10.0)))
__attribute__((availability(tvos, introduced=10.0)))
Expand Down Expand Up @@ -1460,7 +1497,7 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)

#ifdef HAVE_THREAD_TIME
#ifdef __APPLE__
/*
/*
* The clock_* functions will be removed from the module
* dict entirely when the C API is not available.
*/
Expand Down Expand Up @@ -2025,7 +2062,10 @@ pysleep(_PyTime_t secs)
HANDLE hInterruptEvent;
#endif

deadline = _PyTime_GetMonotonicClock() + secs;
if (get_monotonic(&monotonic) < 0) {
return -1;
}
deadline = monotonic + secs;

do {
#ifndef MS_WINDOWS
Expand Down Expand Up @@ -2077,10 +2117,13 @@ pysleep(_PyTime_t secs)
if (PyErr_CheckSignals())
return -1;

monotonic = _PyTime_GetMonotonicClock();
if (get_monotonic(&monotonic) < 0) {
return -1;
}
secs = deadline - monotonic;
if (secs < 0)
if (secs < 0) {
break;
}
/* retry with the recomputed delay */
} while (1);

Expand Down
6 changes: 0 additions & 6 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -763,12 +763,6 @@ pycore_interp_init(PyThreadState *tstate)
goto done;
}

if (_Py_IsMainInterpreter(tstate)) {
if (_PyTime_Init() < 0) {
return _PyStatus_ERR("can't initialize time");
}
}

status = _PySys_Create(tstate, &sysmod);
if (_PyStatus_EXCEPTION(status)) {
goto done;
Expand Down
Loading