mirror of https://github.com/python/cpython
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:
parent
40d2ac92f9
commit
b49263b698
|
@ -111,6 +111,9 @@ PyAPI_FUNC(_PyTime_t) _PyTime_AsMilliseconds(_PyTime_t t,
|
|||
PyAPI_FUNC(_PyTime_t) _PyTime_AsMicroseconds(_PyTime_t t,
|
||||
_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
|
||||
object. */
|
||||
PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t);
|
||||
|
|
|
@ -4623,11 +4623,10 @@ static PyObject *
|
|||
test_pytime_fromseconds(PyObject *self, PyObject *args)
|
||||
{
|
||||
int seconds;
|
||||
_PyTime_t ts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i", &seconds))
|
||||
if (!PyArg_ParseTuple(args, "i", &seconds)) {
|
||||
return NULL;
|
||||
ts = _PyTime_FromSeconds(seconds);
|
||||
}
|
||||
_PyTime_t ts = _PyTime_FromSeconds(seconds);
|
||||
return _PyTime_AsNanosecondsObject(ts);
|
||||
}
|
||||
|
||||
|
@ -4636,14 +4635,16 @@ test_pytime_fromsecondsobject(PyObject *self, PyObject *args)
|
|||
{
|
||||
PyObject *obj;
|
||||
int round;
|
||||
if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) {
|
||||
return NULL;
|
||||
}
|
||||
if (check_time_rounding(round) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
_PyTime_t ts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "Oi", &obj, &round))
|
||||
return NULL;
|
||||
if (check_time_rounding(round) < 0)
|
||||
return NULL;
|
||||
if (_PyTime_FromSecondsObject(&ts, obj, round) == -1)
|
||||
if (_PyTime_FromSecondsObject(&ts, obj, round) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
return _PyTime_AsNanosecondsObject(ts);
|
||||
}
|
||||
|
||||
|
@ -4651,16 +4652,14 @@ static PyObject *
|
|||
test_pytime_assecondsdouble(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *obj;
|
||||
_PyTime_t ts;
|
||||
double d;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O", &obj)) {
|
||||
return NULL;
|
||||
}
|
||||
_PyTime_t ts;
|
||||
if (_PyTime_FromNanosecondsObject(&ts, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
d = _PyTime_AsSecondsDouble(ts);
|
||||
double d = _PyTime_AsSecondsDouble(ts);
|
||||
return PyFloat_FromDouble(d);
|
||||
}
|
||||
|
||||
|
@ -4669,23 +4668,22 @@ test_PyTime_AsTimeval(PyObject *self, PyObject *args)
|
|||
{
|
||||
PyObject *obj;
|
||||
int round;
|
||||
_PyTime_t t;
|
||||
struct timeval tv;
|
||||
PyObject *seconds;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "Oi", &obj, &round))
|
||||
if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) {
|
||||
return NULL;
|
||||
}
|
||||
if (check_time_rounding(round) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
_PyTime_t t;
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
struct timeval tv;
|
||||
if (_PyTime_AsTimeval(t, &tv, round) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
seconds = PyLong_FromLongLong(tv.tv_sec);
|
||||
PyObject *seconds = PyLong_FromLongLong(tv.tv_sec);
|
||||
if (seconds == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -4697,15 +4695,14 @@ static PyObject *
|
|||
test_PyTime_AsTimespec(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *obj;
|
||||
_PyTime_t t;
|
||||
struct timespec ts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O", &obj)) {
|
||||
return NULL;
|
||||
}
|
||||
_PyTime_t t;
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
struct timespec ts;
|
||||
if (_PyTime_AsTimespec(t, &ts) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -4718,21 +4715,19 @@ test_PyTime_AsMilliseconds(PyObject *self, PyObject *args)
|
|||
{
|
||||
PyObject *obj;
|
||||
int round;
|
||||
_PyTime_t t, ms;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) {
|
||||
return NULL;
|
||||
}
|
||||
_PyTime_t t;
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (check_time_rounding(round) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
ms = _PyTime_AsMilliseconds(t, round);
|
||||
/* This conversion rely on the fact that _PyTime_t is a number of
|
||||
nanoseconds */
|
||||
return _PyTime_AsNanosecondsObject(ms);
|
||||
_PyTime_t ms = _PyTime_AsMilliseconds(t, round);
|
||||
_PyTime_t ns = _PyTime_FromNanoseconds(ms);
|
||||
return _PyTime_AsNanosecondsObject(ns);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -4740,20 +4735,19 @@ test_PyTime_AsMicroseconds(PyObject *self, PyObject *args)
|
|||
{
|
||||
PyObject *obj;
|
||||
int round;
|
||||
_PyTime_t t, ms;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "Oi", &obj, &round))
|
||||
if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) {
|
||||
return NULL;
|
||||
}
|
||||
_PyTime_t t;
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (check_time_rounding(round) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
ms = _PyTime_AsMicroseconds(t, round);
|
||||
/* This conversion rely on the fact that _PyTime_t is a number of
|
||||
nanoseconds */
|
||||
return _PyTime_AsNanosecondsObject(ms);
|
||||
_PyTime_t us = _PyTime_AsMicroseconds(t, round);
|
||||
_PyTime_t ns = _PyTime_FromNanoseconds(us);
|
||||
return _PyTime_AsNanosecondsObject(ns);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
|
|
|
@ -128,12 +128,11 @@ static int
|
|||
_PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
|
||||
{
|
||||
static int initialized = 0;
|
||||
clock_t ticks;
|
||||
|
||||
if (!initialized) {
|
||||
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 */
|
||||
if ((_PyTime_t)CLOCKS_PER_SEC > _PyTime_MAX / SEC_TO_NS) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
|
@ -149,14 +148,15 @@ _PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
|
|||
info->adjustable = 0;
|
||||
}
|
||||
|
||||
ticks = clock();
|
||||
clock_t ticks = clock();
|
||||
if (ticks == (clock_t)-1) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"the processor time used is not available "
|
||||
"or its value cannot be represented");
|
||||
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;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
_PyTime_t total;
|
||||
total = _PyTime_MulDiv(t.tms_utime, SEC_TO_NS, ticks_per_second);
|
||||
total += _PyTime_MulDiv(t.tms_stime, SEC_TO_NS, ticks_per_second);
|
||||
*tp = total;
|
||||
_PyTime_t ns;
|
||||
ns = _PyTime_MulDiv(t.tms_utime, SEC_TO_NS, ticks_per_second);
|
||||
ns += _PyTime_MulDiv(t.tms_stime, SEC_TO_NS, ticks_per_second);
|
||||
*tp = _PyTime_FromNanoseconds(ns);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
319
Python/pytime.c
319
Python/pytime.c
|
@ -34,21 +34,39 @@
|
|||
#define NS_TO_MS (1000 * 1000)
|
||||
#define NS_TO_US (1000)
|
||||
|
||||
|
||||
static void
|
||||
error_time_t_overflow(void)
|
||||
pytime_time_t_overflow(void)
|
||||
{
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"timestamp out of range for platform time_t");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_PyTime_overflow(void)
|
||||
pytime_overflow(void)
|
||||
{
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"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_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div)
|
||||
{
|
||||
|
@ -80,13 +98,14 @@ _PyLong_AsTime_t(PyObject *obj)
|
|||
#endif
|
||||
if (val == -1 && PyErr_Occurred()) {
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
|
||||
error_time_t_overflow();
|
||||
pytime_time_t_overflow();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return (time_t)val;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
_PyLong_FromTime_t(time_t t)
|
||||
{
|
||||
|
@ -98,28 +117,30 @@ _PyLong_FromTime_t(time_t t)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Round to nearest with ties going to nearest even integer
|
||||
(_PyTime_ROUND_HALF_EVEN) */
|
||||
static double
|
||||
_PyTime_RoundHalfEven(double x)
|
||||
pytime_round_half_even(double x)
|
||||
{
|
||||
double rounded = round(x);
|
||||
if (fabs(x-rounded) == 0.5) {
|
||||
/* halfway case: round to even */
|
||||
rounded = 2.0*round(x/2.0);
|
||||
rounded = 2.0 * round(x / 2.0);
|
||||
}
|
||||
return rounded;
|
||||
}
|
||||
|
||||
|
||||
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 double d;
|
||||
|
||||
d = x;
|
||||
if (round == _PyTime_ROUND_HALF_EVEN) {
|
||||
d = _PyTime_RoundHalfEven(d);
|
||||
d = pytime_round_half_even(d);
|
||||
}
|
||||
else if (round == _PyTime_ROUND_CEILING) {
|
||||
d = ceil(d);
|
||||
|
@ -134,9 +155,10 @@ _PyTime_Round(double x, _PyTime_round_t round)
|
|||
return d;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
|
||||
long idenominator, _PyTime_round_t round)
|
||||
pytime_double_to_denominator(double d, time_t *sec, long *numerator,
|
||||
long idenominator, _PyTime_round_t round)
|
||||
{
|
||||
double denominator = (double)idenominator;
|
||||
double intpart;
|
||||
|
@ -146,7 +168,7 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
|
|||
floatpart = modf(d, &intpart);
|
||||
|
||||
floatpart *= denominator;
|
||||
floatpart = _PyTime_Round(floatpart, round);
|
||||
floatpart = pytime_round(floatpart, round);
|
||||
if (floatpart >= denominator) {
|
||||
floatpart -= denominator;
|
||||
intpart += 1.0;
|
||||
|
@ -158,7 +180,7 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
|
|||
assert(0.0 <= floatpart && floatpart < denominator);
|
||||
|
||||
if (!_Py_InIntegralTypeRange(time_t, intpart)) {
|
||||
error_time_t_overflow();
|
||||
pytime_time_t_overflow();
|
||||
return -1;
|
||||
}
|
||||
*sec = (time_t)intpart;
|
||||
|
@ -167,9 +189,10 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator,
|
||||
long denominator, _PyTime_round_t round)
|
||||
pytime_object_to_denominator(PyObject *obj, time_t *sec, long *numerator,
|
||||
long denominator, _PyTime_round_t round)
|
||||
{
|
||||
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)");
|
||||
return -1;
|
||||
}
|
||||
return _PyTime_DoubleToDenominator(d, sec, numerator,
|
||||
denominator, round);
|
||||
return pytime_double_to_denominator(d, sec, numerator,
|
||||
denominator, round);
|
||||
}
|
||||
else {
|
||||
*sec = _PyLong_AsTime_t(obj);
|
||||
|
@ -193,6 +216,7 @@ _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_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;
|
||||
}
|
||||
|
||||
d = _PyTime_Round(d, round);
|
||||
d = pytime_round(d, round);
|
||||
(void)modf(d, &intpart);
|
||||
|
||||
if (!_Py_InIntegralTypeRange(time_t, intpart)) {
|
||||
error_time_t_overflow();
|
||||
pytime_time_t_overflow();
|
||||
return -1;
|
||||
}
|
||||
*sec = (time_t)intpart;
|
||||
|
@ -226,49 +250,50 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec,
|
||||
_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
|
||||
_PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec,
|
||||
_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_FromSeconds(int seconds)
|
||||
{
|
||||
_PyTime_t t;
|
||||
/* 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). */
|
||||
Py_BUILD_ASSERT(INT_MAX <= _PyTime_MAX / 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)
|
||||
|| (t < 0 && t >= _PyTime_MIN / SEC_TO_NS));
|
||||
t *= SEC_TO_NS;
|
||||
return t;
|
||||
return pytime_from_nanoseconds(t);
|
||||
}
|
||||
|
||||
|
||||
_PyTime_t
|
||||
_PyTime_FromNanoseconds(_PyTime_t ns)
|
||||
{
|
||||
/* _PyTime_t already uses nanosecond resolution, no conversion needed */
|
||||
return ns;
|
||||
return pytime_from_nanoseconds(ns);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyTime_FromNanosecondsObject(_PyTime_t *tp, PyObject *obj)
|
||||
{
|
||||
long long nsec;
|
||||
_PyTime_t t;
|
||||
|
||||
if (!PyLong_Check(obj)) {
|
||||
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));
|
||||
nsec = PyLong_AsLongLong(obj);
|
||||
long long nsec = PyLong_AsLongLong(obj);
|
||||
if (nsec == -1 && PyErr_Occurred()) {
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
|
||||
_PyTime_overflow();
|
||||
pytime_overflow();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* _PyTime_t already uses nanosecond resolution, no conversion needed */
|
||||
t = (_PyTime_t)nsec;
|
||||
*tp = t;
|
||||
_PyTime_t t = (_PyTime_t)nsec;
|
||||
*tp = pytime_from_nanoseconds(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
static int
|
||||
pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise)
|
||||
{
|
||||
_PyTime_t t, nsec;
|
||||
_PyTime_t t, tv_nsec;
|
||||
int res = 0;
|
||||
|
||||
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 (raise) {
|
||||
_PyTime_overflow();
|
||||
pytime_overflow();
|
||||
res = -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
nsec = ts->tv_nsec;
|
||||
/* The following test is written for positive only nsec */
|
||||
assert(nsec >= 0);
|
||||
if (t > _PyTime_MAX - nsec) {
|
||||
tv_nsec = ts->tv_nsec;
|
||||
/* The following test is written for positive only tv_nsec */
|
||||
assert(tv_nsec >= 0);
|
||||
if (t > _PyTime_MAX - tv_nsec) {
|
||||
if (raise) {
|
||||
_PyTime_overflow();
|
||||
pytime_overflow();
|
||||
res = -1;
|
||||
}
|
||||
t = _PyTime_MAX;
|
||||
}
|
||||
else {
|
||||
t += nsec;
|
||||
t += tv_nsec;
|
||||
}
|
||||
|
||||
*tp = t;
|
||||
*tp = pytime_from_nanoseconds(t);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -337,6 +362,7 @@ _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(MS_WINDOWS)
|
||||
static int
|
||||
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 (raise) {
|
||||
_PyTime_overflow();
|
||||
pytime_overflow();
|
||||
res = -1;
|
||||
}
|
||||
t = (t > 0) ? _PyTime_MAX : _PyTime_MIN;
|
||||
|
@ -363,7 +389,7 @@ pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise)
|
|||
assert(usec >= 0);
|
||||
if (t > _PyTime_MAX - usec) {
|
||||
if (raise) {
|
||||
_PyTime_overflow();
|
||||
pytime_overflow();
|
||||
res = -1;
|
||||
}
|
||||
t = _PyTime_MAX;
|
||||
|
@ -372,10 +398,11 @@ pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise)
|
|||
t += usec;
|
||||
}
|
||||
|
||||
*tp = t;
|
||||
*tp = pytime_from_nanoseconds(t);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv)
|
||||
{
|
||||
|
@ -383,8 +410,9 @@ _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
/* 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 */
|
||||
d = value;
|
||||
d *= (double)unit_to_ns;
|
||||
d = _PyTime_Round(d, round);
|
||||
d = pytime_round(d, round);
|
||||
|
||||
if (!_Py_InIntegralTypeRange(_PyTime_t, d)) {
|
||||
_PyTime_overflow();
|
||||
pytime_overflow();
|
||||
return -1;
|
||||
}
|
||||
*t = (_PyTime_t)d;
|
||||
_PyTime_t ns = (_PyTime_t)d;
|
||||
|
||||
*tp = pytime_from_nanoseconds(ns);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
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)");
|
||||
return -1;
|
||||
}
|
||||
return _PyTime_FromDouble(t, d, round, unit_to_ns);
|
||||
return pytime_from_double(tp, d, round, unit_to_ns);
|
||||
}
|
||||
else {
|
||||
long long sec;
|
||||
Py_BUILD_ASSERT(sizeof(long long) <= sizeof(_PyTime_t));
|
||||
|
||||
sec = PyLong_AsLongLong(obj);
|
||||
long long sec = PyLong_AsLongLong(obj);
|
||||
if (sec == -1 && PyErr_Occurred()) {
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
|
||||
_PyTime_overflow();
|
||||
pytime_overflow();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_PyTime_check_mul_overflow(sec, unit_to_ns)) {
|
||||
_PyTime_overflow();
|
||||
pytime_overflow();
|
||||
return -1;
|
||||
}
|
||||
*t = sec * unit_to_ns;
|
||||
_PyTime_t ns = sec * unit_to_ns;
|
||||
|
||||
*tp = pytime_from_nanoseconds(ns);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
_PyTime_FromSecondsObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round)
|
||||
{
|
||||
return _PyTime_FromObject(t, obj, round, SEC_TO_NS);
|
||||
}
|
||||
|
||||
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
|
||||
_PyTime_AsSecondsDouble(_PyTime_t t)
|
||||
{
|
||||
/* volatile avoids optimization changing how numbers are rounded */
|
||||
volatile double d;
|
||||
|
||||
if (t % SEC_TO_NS == 0) {
|
||||
_PyTime_t secs;
|
||||
_PyTime_t ns = pytime_as_nanoseconds(t);
|
||||
if (ns % SEC_TO_NS == 0) {
|
||||
/* Divide using integers to avoid rounding issues on the integer part.
|
||||
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;
|
||||
}
|
||||
else {
|
||||
d = (double)t;
|
||||
d = (double)ns;
|
||||
d /= 1e9;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
_PyTime_AsNanosecondsObject(_PyTime_t t)
|
||||
{
|
||||
_PyTime_t ns = pytime_as_nanoseconds(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
|
||||
_PyTime_Divide(const _PyTime_t t, const _PyTime_t k,
|
||||
const _PyTime_round_t round)
|
||||
pytime_divide(const _PyTime_t t, const _PyTime_t k,
|
||||
const _PyTime_round_t round)
|
||||
{
|
||||
assert(k > 1);
|
||||
if (round == _PyTime_ROUND_HALF_EVEN) {
|
||||
|
@ -523,66 +560,77 @@ _PyTime_Divide(const _PyTime_t t, const _PyTime_t k,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
_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_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_round_t round)
|
||||
|
||||
_PyTime_t
|
||||
_PyTime_AsMilliseconds(_PyTime_t t, _PyTime_round_t round)
|
||||
{
|
||||
_PyTime_t secs, ns;
|
||||
int usec;
|
||||
_PyTime_t ns = pytime_as_nanoseconds(t);
|
||||
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;
|
||||
|
||||
secs = t / SEC_TO_NS;
|
||||
ns = t % SEC_TO_NS;
|
||||
|
||||
usec = (int)_PyTime_Divide(ns, US_TO_NS, round);
|
||||
if (usec < 0) {
|
||||
usec += SEC_TO_US;
|
||||
if (secs != _PyTime_MIN) {
|
||||
secs -= 1;
|
||||
if (tv_usec < 0) {
|
||||
tv_usec += SEC_TO_US;
|
||||
if (tv_sec != _PyTime_MIN) {
|
||||
tv_sec -= 1;
|
||||
}
|
||||
else {
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
else if (usec >= SEC_TO_US) {
|
||||
usec -= SEC_TO_US;
|
||||
if (secs != _PyTime_MAX) {
|
||||
secs += 1;
|
||||
else if (tv_usec >= SEC_TO_US) {
|
||||
tv_usec -= SEC_TO_US;
|
||||
if (tv_sec != _PyTime_MAX) {
|
||||
tv_sec += 1;
|
||||
}
|
||||
else {
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
assert(0 <= usec && usec < SEC_TO_US);
|
||||
assert(0 <= tv_usec && tv_usec < SEC_TO_US);
|
||||
|
||||
*p_secs = secs;
|
||||
*p_us = usec;
|
||||
*p_secs = tv_sec;
|
||||
*p_us = tv_usec;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_PyTime_AsTimevalStruct_impl(_PyTime_t t, struct timeval *tv,
|
||||
_PyTime_round_t round, int raise)
|
||||
pytime_as_timeval_struct(_PyTime_t t, struct timeval *tv,
|
||||
_PyTime_round_t round, int raise)
|
||||
{
|
||||
_PyTime_t secs, secs2;
|
||||
int us;
|
||||
int res;
|
||||
|
||||
res = _PyTime_AsTimeval_impl(t, &secs, &us, round);
|
||||
|
||||
res = pytime_as_timeval(t, &secs, &us, round);
|
||||
#ifdef MS_WINDOWS
|
||||
tv->tv_sec = (long)secs;
|
||||
#else
|
||||
|
@ -593,38 +641,39 @@ _PyTime_AsTimevalStruct_impl(_PyTime_t t, struct timeval *tv,
|
|||
secs2 = (_PyTime_t)tv->tv_sec;
|
||||
if (res < 0 || secs2 != secs) {
|
||||
if (raise) {
|
||||
error_time_t_overflow();
|
||||
pytime_time_t_overflow();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_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
|
||||
_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
|
||||
_PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us,
|
||||
_PyTime_round_t round)
|
||||
{
|
||||
_PyTime_t secs;
|
||||
int res;
|
||||
int res = pytime_as_timeval(t, &secs, us, round);
|
||||
|
||||
res = _PyTime_AsTimeval_impl(t, &secs, us, round);
|
||||
|
||||
*p_secs = secs;
|
||||
*p_secs = (time_t)secs;
|
||||
|
||||
if (res < 0 || (_PyTime_t)*p_secs != secs) {
|
||||
error_time_t_overflow();
|
||||
pytime_time_t_overflow();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -635,26 +684,28 @@ _PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us,
|
|||
int
|
||||
_PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)
|
||||
{
|
||||
_PyTime_t secs, nsec;
|
||||
_PyTime_t tv_sec, tv_nsec;
|
||||
|
||||
secs = t / SEC_TO_NS;
|
||||
nsec = t % SEC_TO_NS;
|
||||
if (nsec < 0) {
|
||||
nsec += SEC_TO_NS;
|
||||
secs -= 1;
|
||||
_PyTime_t ns = pytime_as_nanoseconds(t);
|
||||
tv_sec = ns / SEC_TO_NS;
|
||||
tv_nsec = ns % SEC_TO_NS;
|
||||
if (tv_nsec < 0) {
|
||||
tv_nsec += SEC_TO_NS;
|
||||
tv_sec -= 1;
|
||||
}
|
||||
ts->tv_sec = (time_t)secs;
|
||||
assert(0 <= nsec && nsec < SEC_TO_NS);
|
||||
ts->tv_nsec = nsec;
|
||||
ts->tv_sec = (time_t)tv_sec;
|
||||
assert(0 <= tv_nsec && tv_nsec < SEC_TO_NS);
|
||||
ts->tv_nsec = tv_nsec;
|
||||
|
||||
if ((_PyTime_t)ts->tv_sec != secs) {
|
||||
error_time_t_overflow();
|
||||
if ((_PyTime_t)ts->tv_sec != tv_sec) {
|
||||
pytime_time_t_overflow();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int
|
||||
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
|
||||
the 1st january 1601 and the 1st january 1970 (369 years + 89 leap
|
||||
days). */
|
||||
*tp = large.QuadPart * 100 - 11644473600000000000;
|
||||
_PyTime_t ns = large.QuadPart * 100 - 11644473600000000000;
|
||||
*tp = pytime_from_nanoseconds(ns);
|
||||
if (info) {
|
||||
DWORD timeAdjustment, timeIncrement;
|
||||
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
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -765,6 +818,7 @@ py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
_PyTime_t
|
||||
_PyTime_GetSystemClock(void)
|
||||
{
|
||||
|
@ -777,12 +831,14 @@ _PyTime_GetSystemClock(void)
|
|||
return t;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyTime_GetSystemClockWithInfo(_PyTime_t *t, _Py_clock_info_t *info)
|
||||
{
|
||||
return py_get_system_clock(t, info, 1);
|
||||
}
|
||||
|
||||
|
||||
#if __APPLE__
|
||||
static int
|
||||
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 (raise) {
|
||||
_PyTime_overflow();
|
||||
pytime_overflow();
|
||||
return -1;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
uint64_t ticks = mach_absolute_time();
|
||||
*tp = _PyTime_MulDiv((_PyTime_t)ticks, timebase_numer, timebase_denom);
|
||||
uint64_t uticks = mach_absolute_time();
|
||||
// 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)
|
||||
hrtime_t time;
|
||||
|
@ -903,7 +964,7 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
|||
return -1;
|
||||
}
|
||||
|
||||
*tp = time;
|
||||
*tp = pytime_from_nanoseconds(time);
|
||||
|
||||
if (info) {
|
||||
info->implementation = "gethrtime()";
|
||||
|
@ -950,6 +1011,7 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
_PyTime_t
|
||||
_PyTime_GetMonotonicClock(void)
|
||||
{
|
||||
|
@ -962,6 +1024,7 @@ _PyTime_GetMonotonicClock(void)
|
|||
return t;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_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
|
||||
static int
|
||||
win_perf_counter_frequency(LONGLONG *pfrequency, int raise)
|
||||
py_win_perf_counter_frequency(LONGLONG *pfrequency, int raise)
|
||||
{
|
||||
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;
|
||||
if (frequency == 0) {
|
||||
if (win_perf_counter_frequency(&frequency, raise) < 0) {
|
||||
if (py_win_perf_counter_frequency(&frequency, raise) < 0) {
|
||||
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));
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
@ -1075,8 +1139,8 @@ _PyTime_GetPerfCounter(void)
|
|||
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.
|
||||
// If py_win_perf_counter_frequency() or py_get_monotonic_clock()
|
||||
// fails: silently ignore the failure and return 0.
|
||||
t = 0;
|
||||
}
|
||||
return t;
|
||||
|
@ -1121,6 +1185,7 @@ _PyTime_localtime(time_t t, struct tm *tm)
|
|||
#endif /* MS_WINDOWS */
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyTime_gmtime(time_t t, struct tm *tm)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue