[Python-checkins] bpo-37205: time.time() cannot fail with fatal error (GH-23314)

vstinner webhook-mailer at python.org
Mon Nov 16 10:08:18 EST 2020


https://github.com/python/cpython/commit/ae6cd7cfdab0599139002c526953d907696d9eef
commit: ae6cd7cfdab0599139002c526953d907696d9eef
branch: master
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2020年11月16日T16:08:05+01:00
summary:
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.
files:
A Misc/NEWS.d/next/Library/2020-11-16-15-08-12.bpo-37205.Wh5svI.rst
M Include/pytime.h
M Modules/timemodule.c
M Python/pylifecycle.c
M Python/pytime.c
diff --git a/Include/pytime.h b/Include/pytime.h
index bdda1da2e6b8f..944170f7d0c4c 100644
--- a/Include/pytime.h
+++ b/Include/pytime.h
@@ -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;
@@ -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
@@ -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);
@@ -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
diff --git a/Misc/NEWS.d/next/Library/2020-11-16-15-08-12.bpo-37205.Wh5svI.rst b/Misc/NEWS.d/next/Library/2020-11-16-15-08-12.bpo-37205.Wh5svI.rst
new file mode 100644
index 0000000000000..9268f2d77f72f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-11-16-15-08-12.bpo-37205.Wh5svI.rst
@@ -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.
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index 80eab30c95d6f..4caacc3b64d7c 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -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
@@ -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);
 }
 
@@ -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);
 }
 
@@ -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.
 */
@@ -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);
 }
 
@@ -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);
 }
 
@@ -1120,10 +1140,23 @@ 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,
@@ -1131,10 +1164,14 @@ PyDoc_STRVAR(perf_counter_doc,
 \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);
 }
 
@@ -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)))
@@ -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.
 */
@@ -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
@@ -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);
 
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 2d43e016efd50..33deafbc0a215 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -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;
diff --git a/Python/pytime.c b/Python/pytime.c
index 179bced1ac68f..1ef99aee74846 100644
--- a/Python/pytime.c
+++ b/Python/pytime.c
@@ -304,8 +304,8 @@ pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise)
 if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) {
 if (raise) {
 _PyTime_overflow();
+ res = -1;
 }
- res = -1;
 t = (t > 0) ? _PyTime_MAX : _PyTime_MIN;
 }
 else {
@@ -318,8 +318,8 @@ pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise)
 if (t > _PyTime_MAX - nsec) {
 if (raise) {
 _PyTime_overflow();
+ res = -1;
 }
- res = -1;
 t = _PyTime_MAX;
 }
 else {
@@ -350,8 +350,8 @@ pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise)
 if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) {
 if (raise) {
 _PyTime_overflow();
+ res = -1;
 }
- res = -1;
 t = (t > 0) ? _PyTime_MAX : _PyTime_MIN;
 }
 else {
@@ -364,8 +364,8 @@ pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise)
 if (t > _PyTime_MAX - usec) {
 if (raise) {
 _PyTime_overflow();
+ res = -1;
 }
- res = -1;
 t = _PyTime_MAX;
 }
 else {
@@ -656,7 +656,7 @@ _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)
 #endif
 
 static int
-pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
+py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
 {
 #ifdef MS_WINDOWS
 FILETIME system_time;
@@ -769,9 +769,10 @@ _PyTime_t
 _PyTime_GetSystemClock(void)
 {
 _PyTime_t t;
- if (pygettimeofday(&t, NULL, 0) < 0) {
- /* should not happen, _PyTime_Init() checked the clock at startup */
- Py_FatalError("pygettimeofday() failed");
+ if (py_get_system_clock(&t, NULL, 0) < 0) {
+ // If clock_gettime(CLOCK_REALTIME) or gettimeofday() fails:
+ // silently ignore the failure and return 0.
+ t = 0;
 }
 return t;
 }
@@ -779,11 +780,61 @@ _PyTime_GetSystemClock(void)
 int
 _PyTime_GetSystemClockWithInfo(_PyTime_t *t, _Py_clock_info_t *info)
 {
- return pygettimeofday(t, info, 1);
+ return py_get_system_clock(t, info, 1);
+}
+
+#if __APPLE__
+static int
+py_mach_timebase_info(_PyTime_t *pnumer, _PyTime_t *pdenom, int raise)
+{
+ static mach_timebase_info_data_t timebase;
+ /* According to the Technical Q&A QA1398, mach_timebase_info() cannot
+ fail: https://developer.apple.com/library/mac/#qa/qa1398/ */
+ (void)mach_timebase_info(&timebase);
+
+ /* Sanity check: should never occur in practice */
+ if (timebase.numer < 1 || timebase.denom < 1) {
+ if (raise) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "invalid mach_timebase_info");
+ }
+ return -1;
+ }
+
+ /* Check that timebase.numer and timebase.denom can be casted to
+ _PyTime_t. In practice, timebase uses uint32_t, so casting cannot
+ overflow. At the end, only make sure that the type is uint32_t
+ (_PyTime_t is 64-bit long). */
+ Py_BUILD_ASSERT(sizeof(timebase.numer) < sizeof(_PyTime_t));
+ Py_BUILD_ASSERT(sizeof(timebase.denom) < sizeof(_PyTime_t));
+
+ /* Make sure that (ticks * timebase.numer) cannot overflow in
+ _PyTime_MulDiv(), with ticks < timebase.denom.
+
+ Known time bases:
+
+ * always (1, 1) on Intel
+ * (1000000000, 33333335) or (1000000000, 25000000) on PowerPC
+
+ None of these time bases can overflow with 64-bit _PyTime_t, but
+ check for overflow, just in case. */
+ if ((_PyTime_t)timebase.numer > _PyTime_MAX / (_PyTime_t)timebase.denom) {
+ if (raise) {
+ PyErr_SetString(PyExc_OverflowError,
+ "mach_timebase_info is too large");
+ }
+ return -1;
+ }
+
+ *pnumer = (_PyTime_t)timebase.numer;
+ *pdenom = (_PyTime_t)timebase.denom;
+ return 0;
 }
+#endif
+
 
 static int
-pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
+py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
 {
 #if defined(MS_WINDOWS)
 ULONGLONG ticks;
@@ -800,10 +851,12 @@ pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
 _PyTime_overflow();
 return -1;
 }
- /* Hello, time traveler! */
- Py_FatalError("pymonotonic: integer overflow");
+ // Truncate to _PyTime_MAX silently.
+ *tp = _PyTime_MAX;
+ }
+ else {
+ *tp = t * MS_TO_NS;
 }
- *tp = t * MS_TO_NS;
 
 if (info) {
 DWORD timeAdjustment, timeIncrement;
@@ -821,56 +874,23 @@ pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
 }
 
 #elif defined(__APPLE__)
- static mach_timebase_info_data_t timebase;
- uint64_t ticks;
-
- if (timebase.denom == 0) {
- /* According to the Technical Q&A QA1398, mach_timebase_info() cannot
- fail: https://developer.apple.com/library/mac/#qa/qa1398/ */
- (void)mach_timebase_info(&timebase);
-
- /* Sanity check: should never occur in practice */
- if (timebase.numer < 1 || timebase.denom < 1) {
- PyErr_SetString(PyExc_RuntimeError,
- "invalid mach_timebase_info");
- return -1;
- }
-
- /* Check that timebase.numer and timebase.denom can be casted to
- _PyTime_t. In practice, timebase uses uint32_t, so casting cannot
- overflow. At the end, only make sure that the type is uint32_t
- (_PyTime_t is 64-bit long). */
- assert(sizeof(timebase.numer) < sizeof(_PyTime_t));
- assert(sizeof(timebase.denom) < sizeof(_PyTime_t));
-
- /* Make sure that (ticks * timebase.numer) cannot overflow in
- _PyTime_MulDiv(), with ticks < timebase.denom.
-
- Known time bases:
-
- * always (1, 1) on Intel
- * (1000000000, 33333335) or (1000000000, 25000000) on PowerPC
-
- None of these time bases can overflow with 64-bit _PyTime_t, but
- check for overflow, just in case. */
- if ((_PyTime_t)timebase.numer > _PyTime_MAX / (_PyTime_t)timebase.denom) {
- PyErr_SetString(PyExc_OverflowError,
- "mach_timebase_info is too large");
+ static _PyTime_t timebase_numer = 0;
+ static _PyTime_t timebase_denom = 0;
+ if (timebase_denom == 0) {
+ if (py_mach_timebase_info(&timebase_numer, &timebase_denom, raise) < 0) {
 return -1;
 }
 }
 
 if (info) {
 info->implementation = "mach_absolute_time()";
- info->resolution = (double)timebase.numer / (double)timebase.denom * 1e-9;
+ info->resolution = (double)timebase_numer / (double)timebase_denom * 1e-9;
 info->monotonic = 1;
 info->adjustable = 0;
 }
 
- ticks = mach_absolute_time();
- *tp = _PyTime_MulDiv(ticks,
- (_PyTime_t)timebase.numer,
- (_PyTime_t)timebase.denom);
+ uint64_t ticks = mach_absolute_time();
+ *tp = _PyTime_MulDiv((_PyTime_t)ticks, timebase_numer, timebase_denom);
 
 #elif defined(__hpux)
 hrtime_t time;
@@ -934,10 +954,10 @@ _PyTime_t
 _PyTime_GetMonotonicClock(void)
 {
 _PyTime_t t;
- if (pymonotonic(&t, NULL, 0) < 0) {
- /* should not happen, _PyTime_Init() checked that monotonic clock at
- startup */
- Py_FatalError("pymonotonic() failed");
+ if (py_get_monotonic_clock(&t, NULL, 0) < 0) {
+ // If mach_timebase_info(), clock_gettime() or gethrtime() fails:
+ // silently ignore the failure and return 0.
+ t = 0;
 }
 return t;
 }
@@ -945,54 +965,69 @@ _PyTime_GetMonotonicClock(void)
 int
 _PyTime_GetMonotonicClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
 {
- return pymonotonic(tp, info, 1);
+ return py_get_monotonic_clock(tp, info, 1);
 }
 
 
 #ifdef MS_WINDOWS
 static int
-win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info)
+win_perf_counter_frequency(LONGLONG *pfrequency, int raise)
 {
- static LONGLONG frequency = 0;
- LARGE_INTEGER now;
- LONGLONG ticksll;
- _PyTime_t ticks;
+ LONGLONG frequency;
 
- if (frequency == 0) {
- LARGE_INTEGER freq;
- if (!QueryPerformanceFrequency(&freq)) {
+ LARGE_INTEGER freq;
+ if (!QueryPerformanceFrequency(&freq)) {
+ if (raise) {
 PyErr_SetFromWindowsErr(0);
- return -1;
 }
- frequency = freq.QuadPart;
+ return -1;
+ }
+ frequency = freq.QuadPart;
 
- /* Sanity check: should never occur in practice */
- if (frequency < 1) {
+ /* Sanity check: should never occur in practice */
+ if (frequency < 1) {
+ if (raise) {
 PyErr_SetString(PyExc_RuntimeError,
 "invalid QueryPerformanceFrequency");
- return -1;
 }
+ return -1;
+ }
 
- /* Check that frequency can be casted to _PyTime_t.
+ /* Check that frequency can be casted to _PyTime_t.
 
- Make also sure that (ticks * SEC_TO_NS) cannot overflow in
- _PyTime_MulDiv(), with ticks < frequency.
+ Make also sure that (ticks * SEC_TO_NS) cannot overflow in
+ _PyTime_MulDiv(), with ticks < frequency.
 
- Known QueryPerformanceFrequency() values:
+ Known QueryPerformanceFrequency() values:
 
- * 10,000,000 (10 MHz): 100 ns resolution
- * 3,579,545 Hz (3.6 MHz): 279 ns resolution
+ * 10,000,000 (10 MHz): 100 ns resolution
+ * 3,579,545 Hz (3.6 MHz): 279 ns resolution
 
- None of these frequencies can overflow with 64-bit _PyTime_t, but
- check for overflow, just in case. */
- if (frequency > _PyTime_MAX
- || frequency > (LONGLONG)_PyTime_MAX / (LONGLONG)SEC_TO_NS) {
+ None of these frequencies can overflow with 64-bit _PyTime_t, but
+ check for overflow, just in case. */
+ if (frequency > _PyTime_MAX
+ || frequency > (LONGLONG)_PyTime_MAX / (LONGLONG)SEC_TO_NS)
+ {
+ if (raise) {
 PyErr_SetString(PyExc_OverflowError,
 "QueryPerformanceFrequency is too large");
- return -1;
 }
+ return -1;
+ }
 
- QueryPerformanceCounter(&now);
+ *pfrequency = frequency;
+ return 0;
+}
+
+
+static int
+py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
+{
+ static LONGLONG frequency = 0;
+ if (frequency == 0) {
+ if (win_perf_counter_frequency(&frequency, raise) < 0) {
+ return -1;
+ }
 }
 
 if (info) {
@@ -1002,11 +1037,13 @@ win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info)
 info->adjustable = 0;
 }
 
+ LARGE_INTEGER now;
 QueryPerformanceCounter(&now);
- ticksll = now.QuadPart;
+ LONGLONG ticksll = now.QuadPart;
 
 /* Make sure that casting LONGLONG to _PyTime_t cannot overflow,
 both types are signed */
+ _PyTime_t ticks;
 Py_BUILD_ASSERT(sizeof(ticksll) <= sizeof(ticks));
 ticks = (_PyTime_t)ticksll;
 
@@ -1020,7 +1057,7 @@ int
 _PyTime_GetPerfCounterWithInfo(_PyTime_t *t, _Py_clock_info_t *info)
 {
 #ifdef MS_WINDOWS
- return win_perf_counter(t, info);
+ return py_get_win_perf_counter(t, info, 1);
 #else
 return _PyTime_GetMonotonicClockWithInfo(t, info);
 #endif
@@ -1031,32 +1068,21 @@ _PyTime_t
 _PyTime_GetPerfCounter(void)
 {
 _PyTime_t t;
- if (_PyTime_GetPerfCounterWithInfo(&t, NULL)) {
- Py_FatalError("_PyTime_GetPerfCounterWithInfo() failed");
+ int res;
+#ifdef MS_WINDOWS
+ res = py_get_win_perf_counter(&t, NULL, 0);
+#else
+ res = py_get_monotonic_clock(&t, NULL, 0);
+#endif
+ if (res < 0) {
+ // If win_perf_counter_frequency() or py_get_monotonic_clock() fails:
+ // silently ignore the failure and return 0.
+ t = 0;
 }
 return t;
 }
 
 
-int
-_PyTime_Init(void)
-{
- /* check that time.time(), time.monotonic() and time.perf_counter() clocks
- are working properly to not have to check for exceptions at runtime. If
- a clock works once, it cannot fail in next calls. */
- _PyTime_t t;
- if (_PyTime_GetSystemClockWithInfo(&t, NULL) < 0) {
- return -1;
- }
- if (_PyTime_GetMonotonicClockWithInfo(&t, NULL) < 0) {
- return -1;
- }
- if (_PyTime_GetPerfCounterWithInfo(&t, NULL) < 0) {
- return -1;
- }
- return 0;
-}
-
 int
 _PyTime_localtime(time_t t, struct tm *tm)
 {


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /