bpo-21302: Add _PyTime_AsNanoseconds() (GH-28350)

Refactor pytime.c:

* Add pytime_from_nanoseconds() and pytime_as_nanoseconds(),
  and use explicitly these functions
* Add two empty lines between functions
* PEP 7: add braces { ... }
* C99: declare variables where they are set
* Rename private functions to lowercase
* Rename error_time_t_overflow() to pytime_time_t_overflow()
* Rename win_perf_counter_frequency() to py_win_perf_counter_frequency()
* py_get_monotonic_clock(): add an assertion to detect overflow when
  mach_absolute_time() unsigned uint64_t is casted to _PyTime_t
  (signed int64_t).

_testcapi: use _PyTime_FromNanoseconds().
This commit is contained in:
Victor Stinner 2021-09-15 14:26:43 +02:00 committed by GitHub
parent 40d2ac92f9
commit b49263b698
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 233 additions and 171 deletions

View file

@ -111,6 +111,9 @@ PyAPI_FUNC(_PyTime_t) _PyTime_AsMilliseconds(_PyTime_t t,
PyAPI_FUNC(_PyTime_t) _PyTime_AsMicroseconds(_PyTime_t t, PyAPI_FUNC(_PyTime_t) _PyTime_AsMicroseconds(_PyTime_t t,
_PyTime_round_t round); _PyTime_round_t round);
/* Convert timestamp to a number of nanoseconds (10^-9 seconds). */
PyAPI_FUNC(_PyTime_t) _PyTime_AsNanoseconds(_PyTime_t t);
/* Convert timestamp to a number of nanoseconds (10^-9 seconds) as a Python int /* Convert timestamp to a number of nanoseconds (10^-9 seconds) as a Python int
object. */ object. */
PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t); PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t);

View file

@ -4623,11 +4623,10 @@ static PyObject *
test_pytime_fromseconds(PyObject *self, PyObject *args) test_pytime_fromseconds(PyObject *self, PyObject *args)
{ {
int seconds; int seconds;
_PyTime_t ts; if (!PyArg_ParseTuple(args, "i", &seconds)) {
if (!PyArg_ParseTuple(args, "i", &seconds))
return NULL; return NULL;
ts = _PyTime_FromSeconds(seconds); }
_PyTime_t ts = _PyTime_FromSeconds(seconds);
return _PyTime_AsNanosecondsObject(ts); return _PyTime_AsNanosecondsObject(ts);
} }
@ -4636,14 +4635,16 @@ test_pytime_fromsecondsobject(PyObject *self, PyObject *args)
{ {
PyObject *obj; PyObject *obj;
int round; int round;
if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) {
return NULL;
}
if (check_time_rounding(round) < 0) {
return NULL;
}
_PyTime_t ts; _PyTime_t ts;
if (_PyTime_FromSecondsObject(&ts, obj, round) == -1) {
if (!PyArg_ParseTuple(args, "Oi", &obj, &round))
return NULL;
if (check_time_rounding(round) < 0)
return NULL;
if (_PyTime_FromSecondsObject(&ts, obj, round) == -1)
return NULL; return NULL;
}
return _PyTime_AsNanosecondsObject(ts); return _PyTime_AsNanosecondsObject(ts);
} }
@ -4651,16 +4652,14 @@ static PyObject *
test_pytime_assecondsdouble(PyObject *self, PyObject *args) test_pytime_assecondsdouble(PyObject *self, PyObject *args)
{ {
PyObject *obj; PyObject *obj;
_PyTime_t ts;
double d;
if (!PyArg_ParseTuple(args, "O", &obj)) { if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL; return NULL;
} }
_PyTime_t ts;
if (_PyTime_FromNanosecondsObject(&ts, obj) < 0) { if (_PyTime_FromNanosecondsObject(&ts, obj) < 0) {
return NULL; return NULL;
} }
d = _PyTime_AsSecondsDouble(ts); double d = _PyTime_AsSecondsDouble(ts);
return PyFloat_FromDouble(d); return PyFloat_FromDouble(d);
} }
@ -4669,23 +4668,22 @@ test_PyTime_AsTimeval(PyObject *self, PyObject *args)
{ {
PyObject *obj; PyObject *obj;
int round; int round;
_PyTime_t t; if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) {
struct timeval tv;
PyObject *seconds;
if (!PyArg_ParseTuple(args, "Oi", &obj, &round))
return NULL; return NULL;
}
if (check_time_rounding(round) < 0) { if (check_time_rounding(round) < 0) {
return NULL; return NULL;
} }
_PyTime_t t;
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
return NULL; return NULL;
} }
struct timeval tv;
if (_PyTime_AsTimeval(t, &tv, round) < 0) { if (_PyTime_AsTimeval(t, &tv, round) < 0) {
return NULL; return NULL;
} }
seconds = PyLong_FromLongLong(tv.tv_sec); PyObject *seconds = PyLong_FromLongLong(tv.tv_sec);
if (seconds == NULL) { if (seconds == NULL) {
return NULL; return NULL;
} }
@ -4697,15 +4695,14 @@ static PyObject *
test_PyTime_AsTimespec(PyObject *self, PyObject *args) test_PyTime_AsTimespec(PyObject *self, PyObject *args)
{ {
PyObject *obj; PyObject *obj;
_PyTime_t t;
struct timespec ts;
if (!PyArg_ParseTuple(args, "O", &obj)) { if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL; return NULL;
} }
_PyTime_t t;
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
return NULL; return NULL;
} }
struct timespec ts;
if (_PyTime_AsTimespec(t, &ts) == -1) { if (_PyTime_AsTimespec(t, &ts) == -1) {
return NULL; return NULL;
} }
@ -4718,21 +4715,19 @@ test_PyTime_AsMilliseconds(PyObject *self, PyObject *args)
{ {
PyObject *obj; PyObject *obj;
int round; int round;
_PyTime_t t, ms;
if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) {
return NULL; return NULL;
} }
_PyTime_t t;
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
return NULL; return NULL;
} }
if (check_time_rounding(round) < 0) { if (check_time_rounding(round) < 0) {
return NULL; return NULL;
} }
ms = _PyTime_AsMilliseconds(t, round); _PyTime_t ms = _PyTime_AsMilliseconds(t, round);
/* This conversion rely on the fact that _PyTime_t is a number of _PyTime_t ns = _PyTime_FromNanoseconds(ms);
nanoseconds */ return _PyTime_AsNanosecondsObject(ns);
return _PyTime_AsNanosecondsObject(ms);
} }
static PyObject * static PyObject *
@ -4740,20 +4735,19 @@ test_PyTime_AsMicroseconds(PyObject *self, PyObject *args)
{ {
PyObject *obj; PyObject *obj;
int round; int round;
_PyTime_t t, ms; if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) {
if (!PyArg_ParseTuple(args, "Oi", &obj, &round))
return NULL; return NULL;
}
_PyTime_t t;
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
return NULL; return NULL;
} }
if (check_time_rounding(round) < 0) { if (check_time_rounding(round) < 0) {
return NULL; return NULL;
} }
ms = _PyTime_AsMicroseconds(t, round); _PyTime_t us = _PyTime_AsMicroseconds(t, round);
/* This conversion rely on the fact that _PyTime_t is a number of _PyTime_t ns = _PyTime_FromNanoseconds(us);
nanoseconds */ return _PyTime_AsNanosecondsObject(ns);
return _PyTime_AsNanosecondsObject(ms);
} }
static PyObject* static PyObject*

View file

@ -128,12 +128,11 @@ static int
_PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) _PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
{ {
static int initialized = 0; static int initialized = 0;
clock_t ticks;
if (!initialized) { if (!initialized) {
initialized = 1; initialized = 1;
/* must sure that _PyTime_MulDiv(ticks, SEC_TO_NS, CLOCKS_PER_SEC) /* Make sure that _PyTime_MulDiv(ticks, SEC_TO_NS, CLOCKS_PER_SEC)
above cannot overflow */ above cannot overflow */
if ((_PyTime_t)CLOCKS_PER_SEC > _PyTime_MAX / SEC_TO_NS) { if ((_PyTime_t)CLOCKS_PER_SEC > _PyTime_MAX / SEC_TO_NS) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
@ -149,14 +148,15 @@ _PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
info->adjustable = 0; info->adjustable = 0;
} }
ticks = clock(); clock_t ticks = clock();
if (ticks == (clock_t)-1) { if (ticks == (clock_t)-1) {
PyErr_SetString(PyExc_RuntimeError, PyErr_SetString(PyExc_RuntimeError,
"the processor time used is not available " "the processor time used is not available "
"or its value cannot be represented"); "or its value cannot be represented");
return -1; return -1;
} }
*tp = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)CLOCKS_PER_SEC); _PyTime_t ns = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)CLOCKS_PER_SEC);
*tp = _PyTime_FromNanoseconds(ns);
return 0; return 0;
} }
#endif /* HAVE_CLOCK */ #endif /* HAVE_CLOCK */
@ -1325,10 +1325,10 @@ _PyTime_GetProcessTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
info->resolution = 1.0 / (double)ticks_per_second; info->resolution = 1.0 / (double)ticks_per_second;
} }
_PyTime_t total; _PyTime_t ns;
total = _PyTime_MulDiv(t.tms_utime, SEC_TO_NS, ticks_per_second); ns = _PyTime_MulDiv(t.tms_utime, SEC_TO_NS, ticks_per_second);
total += _PyTime_MulDiv(t.tms_stime, SEC_TO_NS, ticks_per_second); ns += _PyTime_MulDiv(t.tms_stime, SEC_TO_NS, ticks_per_second);
*tp = total; *tp = _PyTime_FromNanoseconds(ns);
return 0; return 0;
} }
} }

View file

@ -34,21 +34,39 @@
#define NS_TO_MS (1000 * 1000) #define NS_TO_MS (1000 * 1000)
#define NS_TO_US (1000) #define NS_TO_US (1000)
static void static void
error_time_t_overflow(void) pytime_time_t_overflow(void)
{ {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"timestamp out of range for platform time_t"); "timestamp out of range for platform time_t");
} }
static void static void
_PyTime_overflow(void) pytime_overflow(void)
{ {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"timestamp too large to convert to C _PyTime_t"); "timestamp too large to convert to C _PyTime_t");
} }
static inline _PyTime_t
pytime_from_nanoseconds(_PyTime_t t)
{
// _PyTime_t is a number of nanoseconds
return t;
}
static inline _PyTime_t
pytime_as_nanoseconds(_PyTime_t t)
{
// _PyTime_t is a number of nanoseconds
return t;
}
_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)
{ {
@ -80,13 +98,14 @@ _PyLong_AsTime_t(PyObject *obj)
#endif #endif
if (val == -1 && PyErr_Occurred()) { if (val == -1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError)) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
error_time_t_overflow(); pytime_time_t_overflow();
} }
return -1; return -1;
} }
return (time_t)val; return (time_t)val;
} }
PyObject * PyObject *
_PyLong_FromTime_t(time_t t) _PyLong_FromTime_t(time_t t)
{ {
@ -98,28 +117,30 @@ _PyLong_FromTime_t(time_t t)
#endif #endif
} }
/* Round to nearest with ties going to nearest even integer /* Round to nearest with ties going to nearest even integer
(_PyTime_ROUND_HALF_EVEN) */ (_PyTime_ROUND_HALF_EVEN) */
static double static double
_PyTime_RoundHalfEven(double x) pytime_round_half_even(double x)
{ {
double rounded = round(x); double rounded = round(x);
if (fabs(x-rounded) == 0.5) { if (fabs(x-rounded) == 0.5) {
/* halfway case: round to even */ /* halfway case: round to even */
rounded = 2.0*round(x/2.0); rounded = 2.0 * round(x / 2.0);
} }
return rounded; return rounded;
} }
static double static double
_PyTime_Round(double x, _PyTime_round_t round) pytime_round(double x, _PyTime_round_t round)
{ {
/* volatile avoids optimization changing how numbers are rounded */ /* volatile avoids optimization changing how numbers are rounded */
volatile double d; volatile double d;
d = x; d = x;
if (round == _PyTime_ROUND_HALF_EVEN) { if (round == _PyTime_ROUND_HALF_EVEN) {
d = _PyTime_RoundHalfEven(d); d = pytime_round_half_even(d);
} }
else if (round == _PyTime_ROUND_CEILING) { else if (round == _PyTime_ROUND_CEILING) {
d = ceil(d); d = ceil(d);
@ -134,9 +155,10 @@ _PyTime_Round(double x, _PyTime_round_t round)
return d; return d;
} }
static int static int
_PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator, pytime_double_to_denominator(double d, time_t *sec, long *numerator,
long idenominator, _PyTime_round_t round) long idenominator, _PyTime_round_t round)
{ {
double denominator = (double)idenominator; double denominator = (double)idenominator;
double intpart; double intpart;
@ -146,7 +168,7 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
floatpart = modf(d, &intpart); floatpart = modf(d, &intpart);
floatpart *= denominator; floatpart *= denominator;
floatpart = _PyTime_Round(floatpart, round); floatpart = pytime_round(floatpart, round);
if (floatpart >= denominator) { if (floatpart >= denominator) {
floatpart -= denominator; floatpart -= denominator;
intpart += 1.0; intpart += 1.0;
@ -158,7 +180,7 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
assert(0.0 <= floatpart && floatpart < denominator); assert(0.0 <= floatpart && floatpart < denominator);
if (!_Py_InIntegralTypeRange(time_t, intpart)) { if (!_Py_InIntegralTypeRange(time_t, intpart)) {
error_time_t_overflow(); pytime_time_t_overflow();
return -1; return -1;
} }
*sec = (time_t)intpart; *sec = (time_t)intpart;
@ -167,9 +189,10 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
return 0; return 0;
} }
static int static int
_PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator, pytime_object_to_denominator(PyObject *obj, time_t *sec, long *numerator,
long denominator, _PyTime_round_t round) long denominator, _PyTime_round_t round)
{ {
assert(denominator >= 1); assert(denominator >= 1);
@ -180,8 +203,8 @@ _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator,
PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)"); PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)");
return -1; return -1;
} }
return _PyTime_DoubleToDenominator(d, sec, numerator, return pytime_double_to_denominator(d, sec, numerator,
denominator, round); denominator, round);
} }
else { else {
*sec = _PyLong_AsTime_t(obj); *sec = _PyLong_AsTime_t(obj);
@ -193,6 +216,7 @@ _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator,
} }
} }
int int
_PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round) _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round)
{ {
@ -207,11 +231,11 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round)
return -1; return -1;
} }
d = _PyTime_Round(d, round); d = pytime_round(d, round);
(void)modf(d, &intpart); (void)modf(d, &intpart);
if (!_Py_InIntegralTypeRange(time_t, intpart)) { if (!_Py_InIntegralTypeRange(time_t, intpart)) {
error_time_t_overflow(); pytime_time_t_overflow();
return -1; return -1;
} }
*sec = (time_t)intpart; *sec = (time_t)intpart;
@ -226,49 +250,50 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round)
} }
} }
int int
_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec, _PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec,
_PyTime_round_t round) _PyTime_round_t round)
{ {
return _PyTime_ObjectToDenominator(obj, sec, nsec, SEC_TO_NS, round); return pytime_object_to_denominator(obj, sec, nsec, SEC_TO_NS, round);
} }
int int
_PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec, _PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec,
_PyTime_round_t round) _PyTime_round_t round)
{ {
return _PyTime_ObjectToDenominator(obj, sec, usec, SEC_TO_US, round); return pytime_object_to_denominator(obj, sec, usec, SEC_TO_US, round);
} }
_PyTime_t _PyTime_t
_PyTime_FromSeconds(int seconds) _PyTime_FromSeconds(int seconds)
{ {
_PyTime_t t;
/* ensure that integer overflow cannot happen, int type should have 32 /* ensure that integer overflow cannot happen, int type should have 32
bits, whereas _PyTime_t type has at least 64 bits (SEC_TO_MS takes 30 bits, whereas _PyTime_t type has at least 64 bits (SEC_TO_MS takes 30
bits). */ bits). */
Py_BUILD_ASSERT(INT_MAX <= _PyTime_MAX / SEC_TO_NS); Py_BUILD_ASSERT(INT_MAX <= _PyTime_MAX / SEC_TO_NS);
Py_BUILD_ASSERT(INT_MIN >= _PyTime_MIN / SEC_TO_NS); Py_BUILD_ASSERT(INT_MIN >= _PyTime_MIN / SEC_TO_NS);
t = (_PyTime_t)seconds; _PyTime_t t = (_PyTime_t)seconds;
assert((t >= 0 && t <= _PyTime_MAX / SEC_TO_NS) assert((t >= 0 && t <= _PyTime_MAX / SEC_TO_NS)
|| (t < 0 && t >= _PyTime_MIN / SEC_TO_NS)); || (t < 0 && t >= _PyTime_MIN / SEC_TO_NS));
t *= SEC_TO_NS; t *= SEC_TO_NS;
return t; return pytime_from_nanoseconds(t);
} }
_PyTime_t _PyTime_t
_PyTime_FromNanoseconds(_PyTime_t ns) _PyTime_FromNanoseconds(_PyTime_t ns)
{ {
/* _PyTime_t already uses nanosecond resolution, no conversion needed */ return pytime_from_nanoseconds(ns);
return ns;
} }
int int
_PyTime_FromNanosecondsObject(_PyTime_t *tp, PyObject *obj) _PyTime_FromNanosecondsObject(_PyTime_t *tp, PyObject *obj)
{ {
long long nsec;
_PyTime_t t;
if (!PyLong_Check(obj)) { if (!PyLong_Check(obj)) {
PyErr_Format(PyExc_TypeError, "expect int, got %s", PyErr_Format(PyExc_TypeError, "expect int, got %s",
@ -277,25 +302,25 @@ _PyTime_FromNanosecondsObject(_PyTime_t *tp, PyObject *obj)
} }
Py_BUILD_ASSERT(sizeof(long long) == sizeof(_PyTime_t)); Py_BUILD_ASSERT(sizeof(long long) == sizeof(_PyTime_t));
nsec = PyLong_AsLongLong(obj); long long nsec = PyLong_AsLongLong(obj);
if (nsec == -1 && PyErr_Occurred()) { if (nsec == -1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError)) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
_PyTime_overflow(); pytime_overflow();
} }
return -1; return -1;
} }
/* _PyTime_t already uses nanosecond resolution, no conversion needed */ _PyTime_t t = (_PyTime_t)nsec;
t = (_PyTime_t)nsec; *tp = pytime_from_nanoseconds(t);
*tp = t;
return 0; return 0;
} }
#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)
{ {
_PyTime_t t, nsec; _PyTime_t t, tv_nsec;
int res = 0; int res = 0;
Py_BUILD_ASSERT(sizeof(ts->tv_sec) <= sizeof(_PyTime_t)); Py_BUILD_ASSERT(sizeof(ts->tv_sec) <= sizeof(_PyTime_t));
@ -303,7 +328,7 @@ pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise)
if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) { if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) {
if (raise) { if (raise) {
_PyTime_overflow(); pytime_overflow();
res = -1; res = -1;
} }
t = (t > 0) ? _PyTime_MAX : _PyTime_MIN; t = (t > 0) ? _PyTime_MAX : _PyTime_MIN;
@ -312,21 +337,21 @@ pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise)
t = t * SEC_TO_NS; t = t * SEC_TO_NS;
} }
nsec = ts->tv_nsec; tv_nsec = ts->tv_nsec;
/* The following test is written for positive only nsec */ /* The following test is written for positive only tv_nsec */
assert(nsec >= 0); assert(tv_nsec >= 0);
if (t > _PyTime_MAX - nsec) { if (t > _PyTime_MAX - tv_nsec) {
if (raise) { if (raise) {
_PyTime_overflow(); pytime_overflow();
res = -1; res = -1;
} }
t = _PyTime_MAX; t = _PyTime_MAX;
} }
else { else {
t += nsec; t += tv_nsec;
} }
*tp = t; *tp = pytime_from_nanoseconds(t);
return res; return res;
} }
@ -337,6 +362,7 @@ _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts)
} }
#endif #endif
#if !defined(MS_WINDOWS) #if !defined(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)
@ -349,7 +375,7 @@ pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise)
if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) { if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) {
if (raise) { if (raise) {
_PyTime_overflow(); pytime_overflow();
res = -1; res = -1;
} }
t = (t > 0) ? _PyTime_MAX : _PyTime_MIN; t = (t > 0) ? _PyTime_MAX : _PyTime_MIN;
@ -363,7 +389,7 @@ pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise)
assert(usec >= 0); assert(usec >= 0);
if (t > _PyTime_MAX - usec) { if (t > _PyTime_MAX - usec) {
if (raise) { if (raise) {
_PyTime_overflow(); pytime_overflow();
res = -1; res = -1;
} }
t = _PyTime_MAX; t = _PyTime_MAX;
@ -372,10 +398,11 @@ pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise)
t += usec; t += usec;
} }
*tp = t; *tp = pytime_from_nanoseconds(t);
return res; return res;
} }
int int
_PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv) _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv)
{ {
@ -383,8 +410,9 @@ _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv)
} }
#endif #endif
static int static int
_PyTime_FromDouble(_PyTime_t *t, double value, _PyTime_round_t round, pytime_from_double(_PyTime_t *tp, double value, _PyTime_round_t round,
long unit_to_ns) long unit_to_ns)
{ {
/* volatile avoids optimization changing how numbers are rounded */ /* volatile avoids optimization changing how numbers are rounded */
@ -393,18 +421,21 @@ _PyTime_FromDouble(_PyTime_t *t, double value, _PyTime_round_t round,
/* convert to a number of nanoseconds */ /* convert to a number of nanoseconds */
d = value; d = value;
d *= (double)unit_to_ns; d *= (double)unit_to_ns;
d = _PyTime_Round(d, round); d = pytime_round(d, round);
if (!_Py_InIntegralTypeRange(_PyTime_t, d)) { if (!_Py_InIntegralTypeRange(_PyTime_t, d)) {
_PyTime_overflow(); pytime_overflow();
return -1; return -1;
} }
*t = (_PyTime_t)d; _PyTime_t ns = (_PyTime_t)d;
*tp = pytime_from_nanoseconds(ns);
return 0; return 0;
} }
static int static int
_PyTime_FromObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round, pytime_from_object(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round,
long unit_to_ns) long unit_to_ns)
{ {
if (PyFloat_Check(obj)) { if (PyFloat_Check(obj)) {
@ -414,71 +445,77 @@ _PyTime_FromObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round,
PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)"); PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)");
return -1; return -1;
} }
return _PyTime_FromDouble(t, d, round, unit_to_ns); return pytime_from_double(tp, d, round, unit_to_ns);
} }
else { else {
long long sec;
Py_BUILD_ASSERT(sizeof(long long) <= sizeof(_PyTime_t)); Py_BUILD_ASSERT(sizeof(long long) <= sizeof(_PyTime_t));
long long sec = PyLong_AsLongLong(obj);
sec = PyLong_AsLongLong(obj);
if (sec == -1 && PyErr_Occurred()) { if (sec == -1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError)) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
_PyTime_overflow(); pytime_overflow();
} }
return -1; return -1;
} }
if (_PyTime_check_mul_overflow(sec, unit_to_ns)) { if (_PyTime_check_mul_overflow(sec, unit_to_ns)) {
_PyTime_overflow(); pytime_overflow();
return -1; return -1;
} }
*t = sec * unit_to_ns; _PyTime_t ns = sec * unit_to_ns;
*tp = pytime_from_nanoseconds(ns);
return 0; return 0;
} }
} }
int
_PyTime_FromSecondsObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round)
{
return _PyTime_FromObject(t, obj, round, SEC_TO_NS);
}
int int
_PyTime_FromMillisecondsObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round) _PyTime_FromSecondsObject(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round)
{ {
return _PyTime_FromObject(t, obj, round, MS_TO_NS); return pytime_from_object(tp, obj, round, SEC_TO_NS);
} }
int
_PyTime_FromMillisecondsObject(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round)
{
return pytime_from_object(tp, obj, round, MS_TO_NS);
}
double double
_PyTime_AsSecondsDouble(_PyTime_t t) _PyTime_AsSecondsDouble(_PyTime_t t)
{ {
/* volatile avoids optimization changing how numbers are rounded */ /* volatile avoids optimization changing how numbers are rounded */
volatile double d; volatile double d;
if (t % SEC_TO_NS == 0) { _PyTime_t ns = pytime_as_nanoseconds(t);
_PyTime_t secs; if (ns % SEC_TO_NS == 0) {
/* Divide using integers to avoid rounding issues on the integer part. /* Divide using integers to avoid rounding issues on the integer part.
1e-9 cannot be stored exactly in IEEE 64-bit. */ 1e-9 cannot be stored exactly in IEEE 64-bit. */
secs = t / SEC_TO_NS; _PyTime_t secs = ns / SEC_TO_NS;
d = (double)secs; d = (double)secs;
} }
else { else {
d = (double)t; d = (double)ns;
d /= 1e9; d /= 1e9;
} }
return d; return d;
} }
PyObject * PyObject *
_PyTime_AsNanosecondsObject(_PyTime_t t) _PyTime_AsNanosecondsObject(_PyTime_t t)
{ {
_PyTime_t ns = pytime_as_nanoseconds(t);
Py_BUILD_ASSERT(sizeof(long long) >= sizeof(_PyTime_t)); Py_BUILD_ASSERT(sizeof(long long) >= sizeof(_PyTime_t));
return PyLong_FromLongLong((long long)t); return PyLong_FromLongLong((long long)ns);
} }
static _PyTime_t static _PyTime_t
_PyTime_Divide(const _PyTime_t t, const _PyTime_t k, pytime_divide(const _PyTime_t t, const _PyTime_t k,
const _PyTime_round_t round) const _PyTime_round_t round)
{ {
assert(k > 1); assert(k > 1);
if (round == _PyTime_ROUND_HALF_EVEN) { if (round == _PyTime_ROUND_HALF_EVEN) {
@ -523,66 +560,77 @@ _PyTime_Divide(const _PyTime_t t, const _PyTime_t k,
} }
} }
_PyTime_t _PyTime_t
_PyTime_AsMilliseconds(_PyTime_t t, _PyTime_round_t round) _PyTime_AsNanoseconds(_PyTime_t t)
{ {
return _PyTime_Divide(t, NS_TO_MS, round); return pytime_as_nanoseconds(t);
} }
_PyTime_t _PyTime_t
_PyTime_AsMicroseconds(_PyTime_t t, _PyTime_round_t round) _PyTime_AsMicroseconds(_PyTime_t t, _PyTime_round_t round)
{ {
return _PyTime_Divide(t, NS_TO_US, round); _PyTime_t ns = pytime_as_nanoseconds(t);
return pytime_divide(ns, NS_TO_US, round);
} }
static int
_PyTime_AsTimeval_impl(_PyTime_t t, _PyTime_t *p_secs, int *p_us, _PyTime_t
_PyTime_round_t round) _PyTime_AsMilliseconds(_PyTime_t t, _PyTime_round_t round)
{ {
_PyTime_t secs, ns; _PyTime_t ns = pytime_as_nanoseconds(t);
int usec; return pytime_divide(ns, NS_TO_MS, round);
}
static int
pytime_as_timeval(_PyTime_t t, _PyTime_t *p_secs, int *p_us,
_PyTime_round_t round)
{
_PyTime_t ns, tv_sec;
ns = pytime_as_nanoseconds(t);
tv_sec = ns / SEC_TO_NS;
ns = ns % SEC_TO_NS;
int tv_usec = (int)pytime_divide(ns, US_TO_NS, round);
int res = 0; int res = 0;
if (tv_usec < 0) {
secs = t / SEC_TO_NS; tv_usec += SEC_TO_US;
ns = t % SEC_TO_NS; if (tv_sec != _PyTime_MIN) {
tv_sec -= 1;
usec = (int)_PyTime_Divide(ns, US_TO_NS, round);
if (usec < 0) {
usec += SEC_TO_US;
if (secs != _PyTime_MIN) {
secs -= 1;
} }
else { else {
res = -1; res = -1;
} }
} }
else if (usec >= SEC_TO_US) { else if (tv_usec >= SEC_TO_US) {
usec -= SEC_TO_US; tv_usec -= SEC_TO_US;
if (secs != _PyTime_MAX) { if (tv_sec != _PyTime_MAX) {
secs += 1; tv_sec += 1;
} }
else { else {
res = -1; res = -1;
} }
} }
assert(0 <= usec && usec < SEC_TO_US); assert(0 <= tv_usec && tv_usec < SEC_TO_US);
*p_secs = secs; *p_secs = tv_sec;
*p_us = usec; *p_us = tv_usec;
return res; return res;
} }
static int static int
_PyTime_AsTimevalStruct_impl(_PyTime_t t, struct timeval *tv, pytime_as_timeval_struct(_PyTime_t t, struct timeval *tv,
_PyTime_round_t round, int raise) _PyTime_round_t round, int raise)
{ {
_PyTime_t secs, secs2; _PyTime_t secs, secs2;
int us; int us;
int res; int res;
res = _PyTime_AsTimeval_impl(t, &secs, &us, round); res = pytime_as_timeval(t, &secs, &us, round);
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
tv->tv_sec = (long)secs; tv->tv_sec = (long)secs;
#else #else
@ -593,38 +641,39 @@ _PyTime_AsTimevalStruct_impl(_PyTime_t t, struct timeval *tv,
secs2 = (_PyTime_t)tv->tv_sec; secs2 = (_PyTime_t)tv->tv_sec;
if (res < 0 || secs2 != secs) { if (res < 0 || secs2 != secs) {
if (raise) { if (raise) {
error_time_t_overflow(); pytime_time_t_overflow();
} }
return -1; return -1;
} }
return 0; return 0;
} }
int int
_PyTime_AsTimeval(_PyTime_t t, struct timeval *tv, _PyTime_round_t round) _PyTime_AsTimeval(_PyTime_t t, struct timeval *tv, _PyTime_round_t round)
{ {
return _PyTime_AsTimevalStruct_impl(t, tv, round, 1); return pytime_as_timeval_struct(t, tv, round, 1);
} }
int int
_PyTime_AsTimeval_noraise(_PyTime_t t, struct timeval *tv, _PyTime_round_t round) _PyTime_AsTimeval_noraise(_PyTime_t t, struct timeval *tv, _PyTime_round_t round)
{ {
return _PyTime_AsTimevalStruct_impl(t, tv, round, 0); return pytime_as_timeval_struct(t, tv, round, 0);
} }
int int
_PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us, _PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us,
_PyTime_round_t round) _PyTime_round_t round)
{ {
_PyTime_t secs; _PyTime_t secs;
int res; int res = pytime_as_timeval(t, &secs, us, round);
res = _PyTime_AsTimeval_impl(t, &secs, us, round); *p_secs = (time_t)secs;
*p_secs = secs;
if (res < 0 || (_PyTime_t)*p_secs != secs) { if (res < 0 || (_PyTime_t)*p_secs != secs) {
error_time_t_overflow(); pytime_time_t_overflow();
return -1; return -1;
} }
return 0; return 0;
@ -635,26 +684,28 @@ _PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us,
int int
_PyTime_AsTimespec(_PyTime_t t, struct timespec *ts) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)
{ {
_PyTime_t secs, nsec; _PyTime_t tv_sec, tv_nsec;
secs = t / SEC_TO_NS; _PyTime_t ns = pytime_as_nanoseconds(t);
nsec = t % SEC_TO_NS; tv_sec = ns / SEC_TO_NS;
if (nsec < 0) { tv_nsec = ns % SEC_TO_NS;
nsec += SEC_TO_NS; if (tv_nsec < 0) {
secs -= 1; tv_nsec += SEC_TO_NS;
tv_sec -= 1;
} }
ts->tv_sec = (time_t)secs; ts->tv_sec = (time_t)tv_sec;
assert(0 <= nsec && nsec < SEC_TO_NS); assert(0 <= tv_nsec && tv_nsec < SEC_TO_NS);
ts->tv_nsec = nsec; ts->tv_nsec = tv_nsec;
if ((_PyTime_t)ts->tv_sec != secs) { if ((_PyTime_t)ts->tv_sec != tv_sec) {
error_time_t_overflow(); pytime_time_t_overflow();
return -1; return -1;
} }
return 0; return 0;
} }
#endif #endif
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)
{ {
@ -670,7 +721,8 @@ py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
/* 11,644,473,600,000,000,000: number of nanoseconds between /* 11,644,473,600,000,000,000: number of nanoseconds between
the 1st january 1601 and the 1st january 1970 (369 years + 89 leap the 1st january 1601 and the 1st january 1970 (369 years + 89 leap
days). */ days). */
*tp = large.QuadPart * 100 - 11644473600000000000; _PyTime_t ns = large.QuadPart * 100 - 11644473600000000000;
*tp = pytime_from_nanoseconds(ns);
if (info) { if (info) {
DWORD timeAdjustment, timeIncrement; DWORD timeAdjustment, timeIncrement;
BOOL isTimeAdjustmentDisabled, ok; BOOL isTimeAdjustmentDisabled, ok;
@ -730,7 +782,8 @@ py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
} }
#ifdef HAVE_CLOCK_GETTIME_RUNTIME #ifdef HAVE_CLOCK_GETTIME_RUNTIME
} else { }
else {
#endif #endif
#endif #endif
@ -765,6 +818,7 @@ py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
return 0; return 0;
} }
_PyTime_t _PyTime_t
_PyTime_GetSystemClock(void) _PyTime_GetSystemClock(void)
{ {
@ -777,12 +831,14 @@ _PyTime_GetSystemClock(void)
return t; return t;
} }
int int
_PyTime_GetSystemClockWithInfo(_PyTime_t *t, _Py_clock_info_t *info) _PyTime_GetSystemClockWithInfo(_PyTime_t *t, _Py_clock_info_t *info)
{ {
return py_get_system_clock(t, info, 1); return py_get_system_clock(t, info, 1);
} }
#if __APPLE__ #if __APPLE__
static int static int
py_mach_timebase_info(_PyTime_t *pnumer, _PyTime_t *pdenom, int raise) py_mach_timebase_info(_PyTime_t *pnumer, _PyTime_t *pdenom, int raise)
@ -848,7 +904,7 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
if (_PyTime_check_mul_overflow(t, MS_TO_NS)) { if (_PyTime_check_mul_overflow(t, MS_TO_NS)) {
if (raise) { if (raise) {
_PyTime_overflow(); pytime_overflow();
return -1; return -1;
} }
// Truncate to _PyTime_MAX silently. // Truncate to _PyTime_MAX silently.
@ -889,8 +945,13 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
info->adjustable = 0; info->adjustable = 0;
} }
uint64_t ticks = mach_absolute_time(); uint64_t uticks = mach_absolute_time();
*tp = _PyTime_MulDiv((_PyTime_t)ticks, timebase_numer, timebase_denom); // unsigned => signed
assert(uticks <= (uint64_t)_PyTime_MAX);
_PyTime_t ticks = (_PyTime_t)uticks;
_PyTime_t ns = _PyTime_MulDiv(ticks, timebase_numer, timebase_denom);
*tp = pytime_from_nanoseconds(ns);
#elif defined(__hpux) #elif defined(__hpux)
hrtime_t time; hrtime_t time;
@ -903,7 +964,7 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
return -1; return -1;
} }
*tp = time; *tp = pytime_from_nanoseconds(time);
if (info) { if (info) {
info->implementation = "gethrtime()"; info->implementation = "gethrtime()";
@ -950,6 +1011,7 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
return 0; return 0;
} }
_PyTime_t _PyTime_t
_PyTime_GetMonotonicClock(void) _PyTime_GetMonotonicClock(void)
{ {
@ -962,6 +1024,7 @@ _PyTime_GetMonotonicClock(void)
return t; return t;
} }
int int
_PyTime_GetMonotonicClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) _PyTime_GetMonotonicClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
{ {
@ -971,7 +1034,7 @@ _PyTime_GetMonotonicClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
static int static int
win_perf_counter_frequency(LONGLONG *pfrequency, int raise) py_win_perf_counter_frequency(LONGLONG *pfrequency, int raise)
{ {
LONGLONG frequency; LONGLONG frequency;
@ -1025,7 +1088,7 @@ py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
{ {
static LONGLONG frequency = 0; static LONGLONG frequency = 0;
if (frequency == 0) { if (frequency == 0) {
if (win_perf_counter_frequency(&frequency, raise) < 0) { if (py_win_perf_counter_frequency(&frequency, raise) < 0) {
return -1; return -1;
} }
} }
@ -1047,7 +1110,8 @@ py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
Py_BUILD_ASSERT(sizeof(ticksll) <= sizeof(ticks)); Py_BUILD_ASSERT(sizeof(ticksll) <= sizeof(ticks));
ticks = (_PyTime_t)ticksll; ticks = (_PyTime_t)ticksll;
*tp = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)frequency); _PyTime_t ns = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)frequency);
*tp = pytime_from_nanoseconds(ns);
return 0; return 0;
} }
#endif #endif
@ -1075,8 +1139,8 @@ _PyTime_GetPerfCounter(void)
res = py_get_monotonic_clock(&t, NULL, 0); res = py_get_monotonic_clock(&t, NULL, 0);
#endif #endif
if (res < 0) { if (res < 0) {
// If win_perf_counter_frequency() or py_get_monotonic_clock() fails: // If py_win_perf_counter_frequency() or py_get_monotonic_clock()
// silently ignore the failure and return 0. // fails: silently ignore the failure and return 0.
t = 0; t = 0;
} }
return t; return t;
@ -1121,6 +1185,7 @@ _PyTime_localtime(time_t t, struct tm *tm)
#endif /* MS_WINDOWS */ #endif /* MS_WINDOWS */
} }
int int
_PyTime_gmtime(time_t t, struct tm *tm) _PyTime_gmtime(time_t t, struct tm *tm)
{ {