mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
bpo-41710: Add pytime_add() and pytime_mul() (GH-28642)
Add pytime_add() and pytime_mul() functions to pytime.c to compute t+t2 and t*k with clamping to [_PyTime_MIN; _PyTime_MAX]. Fix pytime.h: _PyTime_FromTimeval() is not implemented on Windows.
This commit is contained in:
parent
09796f2f14
commit
d62d925823
2 changed files with 101 additions and 102 deletions
|
@ -125,9 +125,11 @@ PyAPI_FUNC(_PyTime_t) _PyTime_As100Nanoseconds(_PyTime_t t,
|
||||||
object. */
|
object. */
|
||||||
PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t);
|
PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t);
|
||||||
|
|
||||||
|
#ifndef MS_WINDOWS
|
||||||
/* Create a timestamp from a timeval structure.
|
/* Create a timestamp from a timeval structure.
|
||||||
Raise an exception and return -1 on overflow, return 0 on success. */
|
Raise an exception and return -1 on overflow, return 0 on success. */
|
||||||
PyAPI_FUNC(int) _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv);
|
PyAPI_FUNC(int) _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Convert a timestamp to a timeval structure (microsecond resolution).
|
/* Convert a timestamp to a timeval structure (microsecond resolution).
|
||||||
tv_usec is always positive.
|
tv_usec is always positive.
|
||||||
|
@ -188,7 +190,7 @@ typedef struct {
|
||||||
|
|
||||||
If the internal clock fails, silently ignore the error and return 0.
|
If the internal clock fails, silently ignore the error and return 0.
|
||||||
On integer overflow, silently ignore the overflow and clamp the clock to
|
On integer overflow, silently ignore the overflow and clamp the clock to
|
||||||
_PyTime_MIN or _PyTime_MAX.
|
[_PyTime_MIN; _PyTime_MAX].
|
||||||
|
|
||||||
Use _PyTime_GetSystemClockWithInfo() to check for failure. */
|
Use _PyTime_GetSystemClockWithInfo() to check for failure. */
|
||||||
PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void);
|
PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void);
|
||||||
|
@ -208,7 +210,7 @@ PyAPI_FUNC(int) _PyTime_GetSystemClockWithInfo(
|
||||||
|
|
||||||
If the internal clock fails, silently ignore the error and return 0.
|
If the internal clock fails, silently ignore the error and return 0.
|
||||||
On integer overflow, silently ignore the overflow and clamp the clock to
|
On integer overflow, silently ignore the overflow and clamp the clock to
|
||||||
_PyTime_MIN or _PyTime_MAX.
|
[_PyTime_MIN; _PyTime_MAX].
|
||||||
|
|
||||||
Use _PyTime_GetMonotonicClockWithInfo() to check for failure. */
|
Use _PyTime_GetMonotonicClockWithInfo() to check for failure. */
|
||||||
PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void);
|
PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void);
|
||||||
|
@ -239,7 +241,7 @@ PyAPI_FUNC(int) _PyTime_gmtime(time_t t, struct tm *tm);
|
||||||
|
|
||||||
If the internal clock fails, silently ignore the error and return 0.
|
If the internal clock fails, silently ignore the error and return 0.
|
||||||
On integer overflow, silently ignore the overflow and clamp the clock to
|
On integer overflow, silently ignore the overflow and clamp the clock to
|
||||||
_PyTime_MIN or _PyTime_MAX.
|
[_PyTime_MIN; _PyTime_MAX].
|
||||||
|
|
||||||
Use _PyTime_GetPerfCounterWithInfo() to check for failure. */
|
Use _PyTime_GetPerfCounterWithInfo() to check for failure. */
|
||||||
PyAPI_FUNC(_PyTime_t) _PyTime_GetPerfCounter(void);
|
PyAPI_FUNC(_PyTime_t) _PyTime_GetPerfCounter(void);
|
||||||
|
|
195
Python/pytime.c
195
Python/pytime.c
|
@ -13,11 +13,6 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define _PyTime_check_mul_overflow(a, b) \
|
|
||||||
(assert(b > 0), \
|
|
||||||
(_PyTime_t)(a) < _PyTime_MIN / (_PyTime_t)(b) \
|
|
||||||
|| _PyTime_MAX / (_PyTime_t)(b) < (_PyTime_t)(a))
|
|
||||||
|
|
||||||
/* To millisecond (10^-3) */
|
/* To millisecond (10^-3) */
|
||||||
#define SEC_TO_MS 1000
|
#define SEC_TO_MS 1000
|
||||||
|
|
||||||
|
@ -78,6 +73,49 @@ pytime_as_nanoseconds(_PyTime_t t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Compute t + t2. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow.
|
||||||
|
static inline _PyTime_t
|
||||||
|
pytime_add(_PyTime_t *t, _PyTime_t t2)
|
||||||
|
{
|
||||||
|
if (t2 > 0 && *t > _PyTime_MAX - t2) {
|
||||||
|
*t = _PyTime_MAX;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (t2 < 0 && *t < _PyTime_MIN - t2) {
|
||||||
|
*t = _PyTime_MIN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*t += t2;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
_PyTime_check_mul_overflow(_PyTime_t a, _PyTime_t b)
|
||||||
|
{
|
||||||
|
assert(b > 0);
|
||||||
|
return ((a < _PyTime_MIN / b) || (_PyTime_MAX / b < a));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Compute t * k. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow.
|
||||||
|
static inline _PyTime_t
|
||||||
|
pytime_mul(_PyTime_t *t, _PyTime_t k)
|
||||||
|
{
|
||||||
|
assert(k > 0);
|
||||||
|
if (_PyTime_check_mul_overflow(*t, k)) {
|
||||||
|
*t = (*t >= 0) ? _PyTime_MAX : _PyTime_MIN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*t *= k;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_PyTime_t
|
_PyTime_t
|
||||||
_PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div)
|
_PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div)
|
||||||
{
|
{
|
||||||
|
@ -371,41 +409,25 @@ _PyTime_FromNanosecondsObject(_PyTime_t *tp, PyObject *obj)
|
||||||
|
|
||||||
#ifdef HAVE_CLOCK_GETTIME
|
#ifdef HAVE_CLOCK_GETTIME
|
||||||
static int
|
static int
|
||||||
pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise)
|
pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise_exc)
|
||||||
{
|
{
|
||||||
_PyTime_t t, tv_nsec;
|
_PyTime_t t, tv_nsec;
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
Py_BUILD_ASSERT(sizeof(ts->tv_sec) <= sizeof(_PyTime_t));
|
Py_BUILD_ASSERT(sizeof(ts->tv_sec) <= sizeof(_PyTime_t));
|
||||||
t = (_PyTime_t)ts->tv_sec;
|
t = (_PyTime_t)ts->tv_sec;
|
||||||
|
|
||||||
if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) {
|
int res1 = pytime_mul(&t, SEC_TO_NS);
|
||||||
if (raise) {
|
|
||||||
pytime_overflow();
|
|
||||||
res = -1;
|
|
||||||
}
|
|
||||||
t = (t > 0) ? _PyTime_MAX : _PyTime_MIN;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
t = t * SEC_TO_NS;
|
|
||||||
}
|
|
||||||
|
|
||||||
tv_nsec = ts->tv_nsec;
|
tv_nsec = ts->tv_nsec;
|
||||||
/* The following test is written for positive only tv_nsec */
|
int res2 = pytime_add(&t, tv_nsec);
|
||||||
assert(tv_nsec >= 0);
|
|
||||||
if (t > _PyTime_MAX - tv_nsec) {
|
|
||||||
if (raise) {
|
|
||||||
pytime_overflow();
|
|
||||||
res = -1;
|
|
||||||
}
|
|
||||||
t = _PyTime_MAX;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
t += tv_nsec;
|
|
||||||
}
|
|
||||||
|
|
||||||
*tp = pytime_from_nanoseconds(t);
|
*tp = pytime_from_nanoseconds(t);
|
||||||
return res;
|
|
||||||
|
if (raise_exc && (res1 < 0 || res2 < 0)) {
|
||||||
|
pytime_overflow();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -416,43 +438,25 @@ _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if !defined(MS_WINDOWS)
|
#ifndef MS_WINDOWS
|
||||||
static int
|
static int
|
||||||
pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise)
|
pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise_exc)
|
||||||
{
|
{
|
||||||
_PyTime_t t, usec;
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
Py_BUILD_ASSERT(sizeof(tv->tv_sec) <= sizeof(_PyTime_t));
|
Py_BUILD_ASSERT(sizeof(tv->tv_sec) <= sizeof(_PyTime_t));
|
||||||
t = (_PyTime_t)tv->tv_sec;
|
_PyTime_t t = (_PyTime_t)tv->tv_sec;
|
||||||
|
|
||||||
if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) {
|
int res1 = pytime_mul(&t, SEC_TO_NS);
|
||||||
if (raise) {
|
|
||||||
pytime_overflow();
|
|
||||||
res = -1;
|
|
||||||
}
|
|
||||||
t = (t > 0) ? _PyTime_MAX : _PyTime_MIN;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
t = t * SEC_TO_NS;
|
|
||||||
}
|
|
||||||
|
|
||||||
usec = (_PyTime_t)tv->tv_usec * US_TO_NS;
|
_PyTime_t usec = (_PyTime_t)tv->tv_usec * US_TO_NS;
|
||||||
/* The following test is written for positive only usec */
|
int res2 = pytime_add(&t, usec);
|
||||||
assert(usec >= 0);
|
|
||||||
if (t > _PyTime_MAX - usec) {
|
|
||||||
if (raise) {
|
|
||||||
pytime_overflow();
|
|
||||||
res = -1;
|
|
||||||
}
|
|
||||||
t = _PyTime_MAX;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
t += usec;
|
|
||||||
}
|
|
||||||
|
|
||||||
*tp = pytime_from_nanoseconds(t);
|
*tp = pytime_from_nanoseconds(t);
|
||||||
return res;
|
|
||||||
|
if (raise_exc && (res1 < 0 || res2 < 0)) {
|
||||||
|
pytime_overflow();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -572,7 +576,7 @@ pytime_divide_round_up(const _PyTime_t t, const _PyTime_t k)
|
||||||
assert(k > 1);
|
assert(k > 1);
|
||||||
if (t >= 0) {
|
if (t >= 0) {
|
||||||
// Don't use (t + k - 1) / k to avoid integer overflow
|
// Don't use (t + k - 1) / k to avoid integer overflow
|
||||||
// if t=_PyTime_MAX
|
// if t is equal to _PyTime_MAX
|
||||||
_PyTime_t q = t / k;
|
_PyTime_t q = t / k;
|
||||||
if (t % k) {
|
if (t % k) {
|
||||||
q += 1;
|
q += 1;
|
||||||
|
@ -581,7 +585,7 @@ pytime_divide_round_up(const _PyTime_t t, const _PyTime_t k)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Don't use (t - (k - 1)) / k to avoid integer overflow
|
// Don't use (t - (k - 1)) / k to avoid integer overflow
|
||||||
// if t=_PyTime_MIN
|
// if t is equals to _PyTime_MIN.
|
||||||
_PyTime_t q = t / k;
|
_PyTime_t q = t / k;
|
||||||
if (t % k) {
|
if (t % k) {
|
||||||
q -= 1;
|
q -= 1;
|
||||||
|
@ -804,14 +808,14 @@ _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc)
|
||||||
{
|
{
|
||||||
|
assert(info == NULL || raise_exc);
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
FILETIME system_time;
|
FILETIME system_time;
|
||||||
ULARGE_INTEGER large;
|
ULARGE_INTEGER large;
|
||||||
|
|
||||||
assert(info == NULL || raise);
|
|
||||||
|
|
||||||
GetSystemTimeAsFileTime(&system_time);
|
GetSystemTimeAsFileTime(&system_time);
|
||||||
large.u.LowPart = system_time.dwLowDateTime;
|
large.u.LowPart = system_time.dwLowDateTime;
|
||||||
large.u.HighPart = system_time.dwHighDateTime;
|
large.u.HighPart = system_time.dwHighDateTime;
|
||||||
|
@ -846,8 +850,6 @@ py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(info == NULL || raise);
|
|
||||||
|
|
||||||
#ifdef HAVE_CLOCK_GETTIME
|
#ifdef HAVE_CLOCK_GETTIME
|
||||||
|
|
||||||
#ifdef HAVE_CLOCK_GETTIME_RUNTIME
|
#ifdef HAVE_CLOCK_GETTIME_RUNTIME
|
||||||
|
@ -856,12 +858,12 @@ py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
||||||
|
|
||||||
err = clock_gettime(CLOCK_REALTIME, &ts);
|
err = clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (raise) {
|
if (raise_exc) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (pytime_fromtimespec(tp, &ts, raise) < 0) {
|
if (pytime_fromtimespec(tp, &ts, raise_exc) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -890,12 +892,12 @@ py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
||||||
/* test gettimeofday() */
|
/* test gettimeofday() */
|
||||||
err = gettimeofday(&tv, (struct timezone *)NULL);
|
err = gettimeofday(&tv, (struct timezone *)NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (raise) {
|
if (raise_exc) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (pytime_fromtimeval(tp, &tv, raise) < 0) {
|
if (pytime_fromtimeval(tp, &tv, raise_exc) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,28 +989,21 @@ py_mach_timebase_info(_PyTime_t *pnumer, _PyTime_t *pdenom, int raise)
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc)
|
||||||
{
|
{
|
||||||
|
assert(info == NULL || raise_exc);
|
||||||
|
|
||||||
#if defined(MS_WINDOWS)
|
#if defined(MS_WINDOWS)
|
||||||
ULONGLONG ticks;
|
ULONGLONG ticks = GetTickCount64();
|
||||||
_PyTime_t t;
|
|
||||||
|
|
||||||
assert(info == NULL || raise);
|
|
||||||
|
|
||||||
ticks = GetTickCount64();
|
|
||||||
Py_BUILD_ASSERT(sizeof(ticks) <= sizeof(_PyTime_t));
|
Py_BUILD_ASSERT(sizeof(ticks) <= sizeof(_PyTime_t));
|
||||||
t = (_PyTime_t)ticks;
|
_PyTime_t t = (_PyTime_t)ticks;
|
||||||
|
|
||||||
if (_PyTime_check_mul_overflow(t, MS_TO_NS)) {
|
int res = pytime_mul(&t, MS_TO_NS);
|
||||||
if (raise) {
|
*tp = t;
|
||||||
pytime_overflow();
|
|
||||||
return -1;
|
if (raise_exc && res < 0) {
|
||||||
}
|
pytime_overflow();
|
||||||
// Clamp to _PyTime_MAX silently.
|
return -1;
|
||||||
*tp = _PyTime_MAX;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*tp = t * MS_TO_NS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info) {
|
if (info) {
|
||||||
|
@ -1030,7 +1025,7 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
||||||
static _PyTime_t timebase_numer = 0;
|
static _PyTime_t timebase_numer = 0;
|
||||||
static _PyTime_t timebase_denom = 0;
|
static _PyTime_t timebase_denom = 0;
|
||||||
if (timebase_denom == 0) {
|
if (timebase_denom == 0) {
|
||||||
if (py_mach_timebase_info(&timebase_numer, &timebase_denom, raise) < 0) {
|
if (py_mach_timebase_info(&timebase_numer, &timebase_denom, raise_exc) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1055,7 +1050,7 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
||||||
|
|
||||||
time = gethrtime();
|
time = gethrtime();
|
||||||
if (time == -1) {
|
if (time == -1) {
|
||||||
if (raise) {
|
if (raise_exc) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1071,7 +1066,7 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
struct timespec ts;
|
|
||||||
#ifdef CLOCK_HIGHRES
|
#ifdef CLOCK_HIGHRES
|
||||||
const clockid_t clk_id = CLOCK_HIGHRES;
|
const clockid_t clk_id = CLOCK_HIGHRES;
|
||||||
const char *implementation = "clock_gettime(CLOCK_HIGHRES)";
|
const char *implementation = "clock_gettime(CLOCK_HIGHRES)";
|
||||||
|
@ -1080,30 +1075,30 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
||||||
const char *implementation = "clock_gettime(CLOCK_MONOTONIC)";
|
const char *implementation = "clock_gettime(CLOCK_MONOTONIC)";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(info == NULL || raise);
|
struct timespec ts;
|
||||||
|
|
||||||
if (clock_gettime(clk_id, &ts) != 0) {
|
if (clock_gettime(clk_id, &ts) != 0) {
|
||||||
if (raise) {
|
if (raise_exc) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pytime_fromtimespec(tp, &ts, raise_exc) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (info) {
|
if (info) {
|
||||||
struct timespec res;
|
|
||||||
info->monotonic = 1;
|
info->monotonic = 1;
|
||||||
info->implementation = implementation;
|
info->implementation = implementation;
|
||||||
info->adjustable = 0;
|
info->adjustable = 0;
|
||||||
|
struct timespec res;
|
||||||
if (clock_getres(clk_id, &res) != 0) {
|
if (clock_getres(clk_id, &res) != 0) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
|
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
|
||||||
}
|
}
|
||||||
if (pytime_fromtimespec(tp, &ts, raise) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1169,6 +1164,8 @@ py_win_perf_counter_frequency(LONGLONG *pfrequency, int raise)
|
||||||
static int
|
static int
|
||||||
py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
||||||
{
|
{
|
||||||
|
assert(info == NULL || raise_exc);
|
||||||
|
|
||||||
static LONGLONG frequency = 0;
|
static LONGLONG frequency = 0;
|
||||||
if (frequency == 0) {
|
if (frequency == 0) {
|
||||||
if (py_win_perf_counter_frequency(&frequency, raise) < 0) {
|
if (py_win_perf_counter_frequency(&frequency, raise) < 0) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue