mirror of https://github.com/python/cpython
bpo-41710: Add _PyTime_AsTimespec_clamp() (GH-28629)
Add the _PyTime_AsTimespec_clamp() function: similar to _PyTime_AsTimespec(), but clamp to _PyTime_t min/max and don't raise an exception. PyThread_acquire_lock_timed() now uses _PyTime_AsTimespec_clamp() to remove the Py_UNREACHABLE() code path. * Add _PyTime_AsTime_t() function. * Add PY_TIME_T_MIN and PY_TIME_T_MAX constants. * Replace _PyTime_AsTimeval_noraise() with _PyTime_AsTimeval_clamp(). * Add pytime_divide_round_up() function. * Fix integer overflow in pytime_divide(). * Add pytime_divmod() function.
This commit is contained in:
parent
8d3e7eff09
commit
09796f2f14
|
@ -16,6 +16,7 @@ extern "C" {
|
|||
typedef int64_t _PyTime_t;
|
||||
#define _PyTime_MIN INT64_MIN
|
||||
#define _PyTime_MAX INT64_MAX
|
||||
#define _SIZEOF_PYTIME_T 8
|
||||
|
||||
typedef enum {
|
||||
/* Round towards minus infinity (-inf).
|
||||
|
@ -136,8 +137,9 @@ PyAPI_FUNC(int) _PyTime_AsTimeval(_PyTime_t t,
|
|||
struct timeval *tv,
|
||||
_PyTime_round_t round);
|
||||
|
||||
/* Similar to _PyTime_AsTimeval(), but don't raise an exception on error. */
|
||||
PyAPI_FUNC(int) _PyTime_AsTimeval_noraise(_PyTime_t t,
|
||||
/* Similar to _PyTime_AsTimeval() but don't raise an exception on overflow.
|
||||
On overflow, clamp tv_sec to _PyTime_t min/max. */
|
||||
PyAPI_FUNC(void) _PyTime_AsTimeval_clamp(_PyTime_t t,
|
||||
struct timeval *tv,
|
||||
_PyTime_round_t round);
|
||||
|
||||
|
@ -162,6 +164,10 @@ PyAPI_FUNC(int) _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts);
|
|||
tv_nsec is always positive.
|
||||
Raise an exception and return -1 on error, return 0 on success. */
|
||||
PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts);
|
||||
|
||||
/* Similar to _PyTime_AsTimespec() but don't raise an exception on overflow.
|
||||
On overflow, clamp tv_sec to _PyTime_t min/max. */
|
||||
PyAPI_FUNC(void) _PyTime_AsTimespec_clamp(_PyTime_t t, struct timespec *ts);
|
||||
#endif
|
||||
|
||||
/* Compute ticks * mul / div.
|
||||
|
@ -181,7 +187,7 @@ typedef struct {
|
|||
/* Get the current time from the system clock.
|
||||
|
||||
If the internal clock fails, silently ignore the error and return 0.
|
||||
On integer overflow, silently ignore the overflow and truncated the clock to
|
||||
On integer overflow, silently ignore the overflow and clamp the clock to
|
||||
_PyTime_MIN or _PyTime_MAX.
|
||||
|
||||
Use _PyTime_GetSystemClockWithInfo() to check for failure. */
|
||||
|
@ -201,7 +207,7 @@ PyAPI_FUNC(int) _PyTime_GetSystemClockWithInfo(
|
|||
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
|
||||
On integer overflow, silently ignore the overflow and clamp the clock to
|
||||
_PyTime_MIN or _PyTime_MAX.
|
||||
|
||||
Use _PyTime_GetMonotonicClockWithInfo() to check for failure. */
|
||||
|
@ -232,7 +238,7 @@ PyAPI_FUNC(int) _PyTime_gmtime(time_t t, struct tm *tm);
|
|||
measure a short duration.
|
||||
|
||||
If the internal clock fails, silently ignore the error and return 0.
|
||||
On integer overflow, silently ignore the overflow and truncated the clock to
|
||||
On integer overflow, silently ignore the overflow and clamp the clock to
|
||||
_PyTime_MIN or _PyTime_MAX.
|
||||
|
||||
Use _PyTime_GetPerfCounterWithInfo() to check for failure. */
|
||||
|
|
|
@ -38,6 +38,10 @@ class _PyTime(enum.IntEnum):
|
|||
# Round away from zero
|
||||
ROUND_UP = 3
|
||||
|
||||
# _PyTime_t is int64_t
|
||||
_PyTime_MIN = -2 ** 63
|
||||
_PyTime_MAX = 2 ** 63 - 1
|
||||
|
||||
# Rounding modes supported by PyTime
|
||||
ROUNDING_MODES = (
|
||||
# (PyTime rounding method, decimal rounding method)
|
||||
|
@ -960,6 +964,49 @@ class TestCPyTime(CPyTimeTestCase, unittest.TestCase):
|
|||
NS_TO_SEC,
|
||||
value_filter=self.time_t_filter)
|
||||
|
||||
@unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimeval_clamp'),
|
||||
'need _testcapi.PyTime_AsTimeval_clamp')
|
||||
def test_AsTimeval_clamp(self):
|
||||
from _testcapi import PyTime_AsTimeval_clamp
|
||||
|
||||
if sys.platform == 'win32':
|
||||
from _testcapi import LONG_MIN, LONG_MAX
|
||||
tv_sec_max = LONG_MAX
|
||||
tv_sec_min = LONG_MIN
|
||||
else:
|
||||
tv_sec_max = self.time_t_max
|
||||
tv_sec_min = self.time_t_min
|
||||
|
||||
for t in (_PyTime_MIN, _PyTime_MAX):
|
||||
ts = PyTime_AsTimeval_clamp(t, _PyTime.ROUND_CEILING)
|
||||
with decimal.localcontext() as context:
|
||||
context.rounding = decimal.ROUND_CEILING
|
||||
us = self.decimal_round(decimal.Decimal(t) / US_TO_NS)
|
||||
tv_sec, tv_usec = divmod(us, SEC_TO_US)
|
||||
if tv_sec_max < tv_sec:
|
||||
tv_sec = tv_sec_max
|
||||
tv_usec = 0
|
||||
elif tv_sec < tv_sec_min:
|
||||
tv_sec = tv_sec_min
|
||||
tv_usec = 0
|
||||
self.assertEqual(ts, (tv_sec, tv_usec))
|
||||
|
||||
@unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec_clamp'),
|
||||
'need _testcapi.PyTime_AsTimespec_clamp')
|
||||
def test_AsTimespec_clamp(self):
|
||||
from _testcapi import PyTime_AsTimespec_clamp
|
||||
|
||||
for t in (_PyTime_MIN, _PyTime_MAX):
|
||||
ts = PyTime_AsTimespec_clamp(t)
|
||||
tv_sec, tv_nsec = divmod(t, NS_TO_SEC)
|
||||
if self.time_t_max < tv_sec:
|
||||
tv_sec = self.time_t_max
|
||||
tv_nsec = 0
|
||||
elif tv_sec < self.time_t_min:
|
||||
tv_sec = self.time_t_min
|
||||
tv_nsec = 0
|
||||
self.assertEqual(ts, (tv_sec, tv_nsec))
|
||||
|
||||
def test_AsMilliseconds(self):
|
||||
from _testcapi import PyTime_AsMilliseconds
|
||||
|
||||
|
@ -1062,7 +1109,7 @@ class TestTimeWeaklinking(unittest.TestCase):
|
|||
clock_names = [
|
||||
"CLOCK_MONOTONIC", "clock_gettime", "clock_gettime_ns", "clock_settime",
|
||||
"clock_settime_ns", "clock_getres"]
|
||||
|
||||
|
||||
if mac_ver >= (10, 12):
|
||||
for name in clock_names:
|
||||
self.assertTrue(hasattr(time, name), f"time.{name} is not available")
|
||||
|
|
|
@ -2264,7 +2264,7 @@ PySSL_select(PySocketSockObject *s, int writing, _PyTime_t timeout)
|
|||
if (!_PyIsSelectable_fd(s->sock_fd))
|
||||
return SOCKET_TOO_LARGE_FOR_SELECT;
|
||||
|
||||
_PyTime_AsTimeval_noraise(timeout, &tv, _PyTime_ROUND_CEILING);
|
||||
_PyTime_AsTimeval_clamp(timeout, &tv, _PyTime_ROUND_CEILING);
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(s->sock_fd, &fds);
|
||||
|
|
|
@ -4687,7 +4687,32 @@ test_PyTime_AsTimeval(PyObject *self, PyObject *args)
|
|||
if (seconds == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return Py_BuildValue("Nl", seconds, tv.tv_usec);
|
||||
return Py_BuildValue("Nl", seconds, (long)tv.tv_usec);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_PyTime_AsTimeval_clamp(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 t;
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
struct timeval tv;
|
||||
_PyTime_AsTimeval_clamp(t, &tv, round);
|
||||
|
||||
PyObject *seconds = PyLong_FromLongLong(tv.tv_sec);
|
||||
if (seconds == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return Py_BuildValue("Nl", seconds, (long)tv.tv_usec);
|
||||
}
|
||||
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
|
@ -4708,6 +4733,22 @@ test_PyTime_AsTimespec(PyObject *self, PyObject *args)
|
|||
}
|
||||
return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_PyTime_AsTimespec_clamp(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *obj;
|
||||
if (!PyArg_ParseTuple(args, "O", &obj)) {
|
||||
return NULL;
|
||||
}
|
||||
_PyTime_t t;
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
struct timespec ts;
|
||||
_PyTime_AsTimespec_clamp(t, &ts);
|
||||
return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec);
|
||||
}
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
|
@ -5872,8 +5913,10 @@ static PyMethodDef TestMethods[] = {
|
|||
{"PyTime_FromSecondsObject", test_pytime_fromsecondsobject, METH_VARARGS},
|
||||
{"PyTime_AsSecondsDouble", test_pytime_assecondsdouble, METH_VARARGS},
|
||||
{"PyTime_AsTimeval", test_PyTime_AsTimeval, METH_VARARGS},
|
||||
{"PyTime_AsTimeval_clamp", test_PyTime_AsTimeval_clamp, METH_VARARGS},
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
{"PyTime_AsTimespec", test_PyTime_AsTimespec, METH_VARARGS},
|
||||
{"PyTime_AsTimespec_clamp", test_PyTime_AsTimespec_clamp, METH_VARARGS},
|
||||
#endif
|
||||
{"PyTime_AsMilliseconds", test_PyTime_AsMilliseconds, METH_VARARGS},
|
||||
{"PyTime_AsMicroseconds", test_PyTime_AsMicroseconds, METH_VARARGS},
|
||||
|
|
|
@ -344,7 +344,7 @@ select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist,
|
|||
n = 0;
|
||||
break;
|
||||
}
|
||||
_PyTime_AsTimeval_noraise(timeout, &tv, _PyTime_ROUND_CEILING);
|
||||
_PyTime_AsTimeval_clamp(timeout, &tv, _PyTime_ROUND_CEILING);
|
||||
/* retry select() with the recomputed timeout */
|
||||
}
|
||||
} while (1);
|
||||
|
|
|
@ -758,7 +758,7 @@ internal_select(PySocketSockObject *s, int writing, _PyTime_t interval,
|
|||
Py_END_ALLOW_THREADS;
|
||||
#else
|
||||
if (interval >= 0) {
|
||||
_PyTime_AsTimeval_noraise(interval, &tv, _PyTime_ROUND_CEILING);
|
||||
_PyTime_AsTimeval_clamp(interval, &tv, _PyTime_ROUND_CEILING);
|
||||
tvp = &tv;
|
||||
}
|
||||
else
|
||||
|
|
240
Python/pytime.c
240
Python/pytime.c
|
@ -35,6 +35,16 @@
|
|||
#define NS_TO_US (1000)
|
||||
#define NS_TO_100NS (100)
|
||||
|
||||
#if SIZEOF_TIME_T == SIZEOF_LONG_LONG
|
||||
# define PY_TIME_T_MAX LLONG_MAX
|
||||
# define PY_TIME_T_MIN LLONG_MIN
|
||||
#elif SIZEOF_TIME_T == SIZEOF_LONG
|
||||
# define PY_TIME_T_MAX LONG_MAX
|
||||
# define PY_TIME_T_MIN LONG_MIN
|
||||
#else
|
||||
# error "unsupported time_t size"
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
pytime_time_t_overflow(void)
|
||||
|
@ -63,7 +73,7 @@ pytime_from_nanoseconds(_PyTime_t t)
|
|||
static inline _PyTime_t
|
||||
pytime_as_nanoseconds(_PyTime_t t)
|
||||
{
|
||||
// _PyTime_t is a number of nanoseconds
|
||||
// _PyTime_t is a number of nanoseconds: see pytime_from_nanoseconds()
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -119,6 +129,48 @@ _PyLong_FromTime_t(time_t t)
|
|||
}
|
||||
|
||||
|
||||
// Convert _PyTime_t to time_t.
|
||||
// Return 0 on success. Return -1 and clamp the value on overflow.
|
||||
static int
|
||||
_PyTime_AsTime_t(_PyTime_t t, time_t *t2)
|
||||
{
|
||||
#if SIZEOF_TIME_T < _SIZEOF_PYTIME_T
|
||||
if ((_PyTime_t)PY_TIME_T_MAX < t) {
|
||||
*t2 = PY_TIME_T_MAX;
|
||||
return -1;
|
||||
}
|
||||
if (t < (_PyTime_t)PY_TIME_T_MIN) {
|
||||
*t2 = PY_TIME_T_MIN;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
*t2 = (time_t)t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
// Convert _PyTime_t to long.
|
||||
// Return 0 on success. Return -1 and clamp the value on overflow.
|
||||
static int
|
||||
_PyTime_AsLong(_PyTime_t t, long *t2)
|
||||
{
|
||||
#if SIZEOF_LONG < _SIZEOF_PYTIME_T
|
||||
if ((_PyTime_t)LONG_MAX < t) {
|
||||
*t2 = LONG_MAX;
|
||||
return -1;
|
||||
}
|
||||
if (t < (_PyTime_t)LONG_MIN) {
|
||||
*t2 = LONG_MIN;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
*t2 = (long)t;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Round to nearest with ties going to nearest even integer
|
||||
(_PyTime_ROUND_HALF_EVEN) */
|
||||
static double
|
||||
|
@ -514,16 +566,40 @@ _PyTime_AsNanosecondsObject(_PyTime_t t)
|
|||
}
|
||||
|
||||
|
||||
static _PyTime_t
|
||||
pytime_divide_round_up(const _PyTime_t t, const _PyTime_t k)
|
||||
{
|
||||
assert(k > 1);
|
||||
if (t >= 0) {
|
||||
// Don't use (t + k - 1) / k to avoid integer overflow
|
||||
// if t=_PyTime_MAX
|
||||
_PyTime_t q = t / k;
|
||||
if (t % k) {
|
||||
q += 1;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
else {
|
||||
// Don't use (t - (k - 1)) / k to avoid integer overflow
|
||||
// if t=_PyTime_MIN
|
||||
_PyTime_t q = t / k;
|
||||
if (t % k) {
|
||||
q -= 1;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static _PyTime_t
|
||||
pytime_divide(const _PyTime_t t, const _PyTime_t k,
|
||||
const _PyTime_round_t round)
|
||||
{
|
||||
assert(k > 1);
|
||||
if (round == _PyTime_ROUND_HALF_EVEN) {
|
||||
_PyTime_t x, r, abs_r;
|
||||
x = t / k;
|
||||
r = t % k;
|
||||
abs_r = Py_ABS(r);
|
||||
_PyTime_t x = t / k;
|
||||
_PyTime_t r = t % k;
|
||||
_PyTime_t abs_r = Py_ABS(r);
|
||||
if (abs_r > k / 2 || (abs_r == k / 2 && (Py_ABS(x) & 1))) {
|
||||
if (t >= 0) {
|
||||
x++;
|
||||
|
@ -536,7 +612,7 @@ pytime_divide(const _PyTime_t t, const _PyTime_t k,
|
|||
}
|
||||
else if (round == _PyTime_ROUND_CEILING) {
|
||||
if (t >= 0) {
|
||||
return (t + k - 1) / k;
|
||||
return pytime_divide_round_up(t, k);
|
||||
}
|
||||
else {
|
||||
return t / k;
|
||||
|
@ -547,21 +623,44 @@ pytime_divide(const _PyTime_t t, const _PyTime_t k,
|
|||
return t / k;
|
||||
}
|
||||
else {
|
||||
return (t - (k - 1)) / k;
|
||||
return pytime_divide_round_up(t, k);
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(round == _PyTime_ROUND_UP);
|
||||
if (t >= 0) {
|
||||
return (t + k - 1) / k;
|
||||
}
|
||||
else {
|
||||
return (t - (k - 1)) / k;
|
||||
}
|
||||
return pytime_divide_round_up(t, k);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Compute (t / k, t % k) in (pq, pr).
|
||||
// Make sure that 0 <= pr < k.
|
||||
// Return 0 on success.
|
||||
// Return -1 on underflow and store (_PyTime_MIN, 0) in (pq, pr).
|
||||
static int
|
||||
pytime_divmod(const _PyTime_t t, const _PyTime_t k,
|
||||
_PyTime_t *pq, _PyTime_t *pr)
|
||||
{
|
||||
assert(k > 1);
|
||||
_PyTime_t q = t / k;
|
||||
_PyTime_t r = t % k;
|
||||
if (r < 0) {
|
||||
if (q == _PyTime_MIN) {
|
||||
*pq = _PyTime_MIN;
|
||||
*pr = 0;
|
||||
return -1;
|
||||
}
|
||||
r += k;
|
||||
q -= 1;
|
||||
}
|
||||
assert(0 <= r && r < k);
|
||||
|
||||
*pq = q;
|
||||
*pr = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
_PyTime_t
|
||||
_PyTime_AsNanoseconds(_PyTime_t t)
|
||||
{
|
||||
|
@ -596,64 +695,41 @@ _PyTime_AsMilliseconds(_PyTime_t t, _PyTime_round_t round)
|
|||
|
||||
|
||||
static int
|
||||
pytime_as_timeval(_PyTime_t t, _PyTime_t *p_secs, int *p_us,
|
||||
pytime_as_timeval(_PyTime_t t, _PyTime_t *ptv_sec, int *ptv_usec,
|
||||
_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;
|
||||
if (tv_usec < 0) {
|
||||
tv_usec += SEC_TO_US;
|
||||
if (tv_sec != _PyTime_MIN) {
|
||||
tv_sec -= 1;
|
||||
}
|
||||
else {
|
||||
res = -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 <= tv_usec && tv_usec < SEC_TO_US);
|
||||
|
||||
*p_secs = tv_sec;
|
||||
*p_us = tv_usec;
|
||||
_PyTime_t ns = pytime_as_nanoseconds(t);
|
||||
_PyTime_t us = pytime_divide(ns, US_TO_NS, round);
|
||||
|
||||
_PyTime_t tv_sec, tv_usec;
|
||||
int res = pytime_divmod(us, SEC_TO_US, &tv_sec, &tv_usec);
|
||||
*ptv_sec = tv_sec;
|
||||
*ptv_usec = (int)tv_usec;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pytime_as_timeval_struct(_PyTime_t t, struct timeval *tv,
|
||||
_PyTime_round_t round, int raise)
|
||||
_PyTime_round_t round, int raise_exc)
|
||||
{
|
||||
_PyTime_t secs, secs2;
|
||||
int us;
|
||||
int res;
|
||||
|
||||
res = pytime_as_timeval(t, &secs, &us, round);
|
||||
_PyTime_t tv_sec;
|
||||
int tv_usec;
|
||||
int res = pytime_as_timeval(t, &tv_sec, &tv_usec, round);
|
||||
int res2;
|
||||
#ifdef MS_WINDOWS
|
||||
tv->tv_sec = (long)secs;
|
||||
// On Windows, timeval.tv_sec type is long
|
||||
res2 = _PyTime_AsLong(tv_sec, &tv->tv_sec);
|
||||
#else
|
||||
tv->tv_sec = secs;
|
||||
res2 = _PyTime_AsTime_t(tv_sec, &tv->tv_sec);
|
||||
#endif
|
||||
tv->tv_usec = us;
|
||||
if (res2 < 0) {
|
||||
tv_usec = 0;
|
||||
}
|
||||
tv->tv_usec = tv_usec;
|
||||
|
||||
secs2 = (_PyTime_t)tv->tv_sec;
|
||||
if (res < 0 || secs2 != secs) {
|
||||
if (raise) {
|
||||
pytime_time_t_overflow();
|
||||
}
|
||||
if (raise_exc && (res < 0 || res2 < 0)) {
|
||||
pytime_time_t_overflow();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -667,10 +743,10 @@ _PyTime_AsTimeval(_PyTime_t t, struct timeval *tv, _PyTime_round_t round)
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
_PyTime_AsTimeval_noraise(_PyTime_t t, struct timeval *tv, _PyTime_round_t round)
|
||||
void
|
||||
_PyTime_AsTimeval_clamp(_PyTime_t t, struct timeval *tv, _PyTime_round_t round)
|
||||
{
|
||||
return pytime_as_timeval_struct(t, tv, round, 0);
|
||||
(void)pytime_as_timeval_struct(t, tv, round, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -679,11 +755,12 @@ _PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us,
|
|||
_PyTime_round_t round)
|
||||
{
|
||||
_PyTime_t secs;
|
||||
int res = pytime_as_timeval(t, &secs, us, round);
|
||||
if (pytime_as_timeval(t, &secs, us, round) < 0) {
|
||||
pytime_time_t_overflow();
|
||||
return -1;
|
||||
}
|
||||
|
||||
*p_secs = (time_t)secs;
|
||||
|
||||
if (res < 0 || (_PyTime_t)*p_secs != secs) {
|
||||
if (_PyTime_AsTime_t(secs, p_secs) < 0) {
|
||||
pytime_time_t_overflow();
|
||||
return -1;
|
||||
}
|
||||
|
@ -692,28 +769,37 @@ _PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us,
|
|||
|
||||
|
||||
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE)
|
||||
int
|
||||
_PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)
|
||||
static int
|
||||
pytime_as_timespec(_PyTime_t t, struct timespec *ts, int raise_exc)
|
||||
{
|
||||
_PyTime_t tv_sec, tv_nsec;
|
||||
|
||||
_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;
|
||||
_PyTime_t tv_sec, tv_nsec;
|
||||
int res = pytime_divmod(ns, SEC_TO_NS, &tv_sec, &tv_nsec);
|
||||
|
||||
int res2 = _PyTime_AsTime_t(tv_sec, &ts->tv_sec);
|
||||
if (res2 < 0) {
|
||||
tv_nsec = 0;
|
||||
}
|
||||
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 != tv_sec) {
|
||||
if (raise_exc && (res < 0 || res2 < 0)) {
|
||||
pytime_time_t_overflow();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_PyTime_AsTimespec_clamp(_PyTime_t t, struct timespec *ts)
|
||||
{
|
||||
(void)pytime_as_timespec(t, ts, 0);
|
||||
}
|
||||
|
||||
int
|
||||
_PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)
|
||||
{
|
||||
return pytime_as_timespec(t, ts, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -918,7 +1004,7 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
|||
pytime_overflow();
|
||||
return -1;
|
||||
}
|
||||
// Truncate to _PyTime_MAX silently.
|
||||
// Clamp to _PyTime_MAX silently.
|
||||
*tp = _PyTime_MAX;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -481,11 +481,7 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
|
|||
}
|
||||
else if (dt > 0) {
|
||||
_PyTime_t realtime_deadline = _PyTime_GetSystemClock() + dt;
|
||||
if (_PyTime_AsTimespec(realtime_deadline, &ts) < 0) {
|
||||
/* Cannot occur thanks to (microseconds > PY_TIMEOUT_MAX)
|
||||
check done above */
|
||||
Py_UNREACHABLE();
|
||||
}
|
||||
_PyTime_AsTimespec_clamp(realtime_deadline, &ts);
|
||||
/* no need to update microseconds value, the code only care
|
||||
if (microseconds > 0 or (microseconds == 0). */
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue