| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8d3e7ef commit 09796f2
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,6 +16,7 @@ extern "C" { | |||
| 16 | 16 | typedef int64_t _PyTime_t; | |
| 17 | 17 | #define _PyTime_MIN INT64_MIN | |
| 18 | 18 | #define _PyTime_MAX INT64_MAX | |
| 19 | + #define _SIZEOF_PYTIME_T 8 | ||
| 19 | 20 | ||
| 20 | 21 | typedef enum { | |
| 21 | 22 | /* Round towards minus infinity (-inf). | |
@@ -136,8 +137,9 @@ PyAPI_FUNC(int) _PyTime_AsTimeval(_PyTime_t t, | |||
| 136 | 137 | struct timeval *tv, | |
| 137 | 138 | _PyTime_round_t round); | |
| 138 | 139 | ||
| 139 | - /* Similar to _PyTime_AsTimeval(), but don't raise an exception on error. */ | ||
| 140 | - PyAPI_FUNC(int) _PyTime_AsTimeval_noraise(_PyTime_t t, | ||
| 140 | + /* Similar to _PyTime_AsTimeval() but don't raise an exception on overflow. | ||
| 141 | + On overflow, clamp tv_sec to _PyTime_t min/max. */ | ||
| 142 | + PyAPI_FUNC(void) _PyTime_AsTimeval_clamp(_PyTime_t t, | ||
| 141 | 143 | struct timeval *tv, | |
| 142 | 144 | _PyTime_round_t round); | |
| 143 | 145 | ||
@@ -162,6 +164,10 @@ PyAPI_FUNC(int) _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts); | |||
| 162 | 164 | tv_nsec is always positive. | |
| 163 | 165 | Raise an exception and return -1 on error, return 0 on success. */ | |
| 164 | 166 | PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts); | |
| 167 | + | ||
| 168 | + /* Similar to _PyTime_AsTimespec() but don't raise an exception on overflow. | ||
| 169 | + On overflow, clamp tv_sec to _PyTime_t min/max. */ | ||
| 170 | + PyAPI_FUNC(void) _PyTime_AsTimespec_clamp(_PyTime_t t, struct timespec *ts); | ||
| 165 | 171 | #endif | |
| 166 | 172 | ||
| 167 | 173 | /* Compute ticks * mul / div. | |
@@ -181,7 +187,7 @@ typedef struct { | |||
| 181 | 187 | /* Get the current time from the system clock. | |
| 182 | 188 | ||
| 183 | 189 | If the internal clock fails, silently ignore the error and return 0. | |
| 184 | - On integer overflow, silently ignore the overflow and truncated the clock to | ||
| 190 | + On integer overflow, silently ignore the overflow and clamp the clock to | ||
| 185 | 191 | _PyTime_MIN or _PyTime_MAX. | |
| 186 | 192 | ||
| 187 | 193 | Use _PyTime_GetSystemClockWithInfo() to check for failure. */ | |
@@ -201,7 +207,7 @@ PyAPI_FUNC(int) _PyTime_GetSystemClockWithInfo( | |||
| 201 | 207 | results of consecutive calls is valid. | |
| 202 | 208 | ||
| 203 | 209 | If the internal clock fails, silently ignore the error and return 0. | |
| 204 | - On integer overflow, silently ignore the overflow and truncated the clock to | ||
| 210 | + On integer overflow, silently ignore the overflow and clamp the clock to | ||
| 205 | 211 | _PyTime_MIN or _PyTime_MAX. | |
| 206 | 212 | ||
| 207 | 213 | Use _PyTime_GetMonotonicClockWithInfo() to check for failure. */ | |
@@ -232,7 +238,7 @@ PyAPI_FUNC(int) _PyTime_gmtime(time_t t, struct tm *tm); | |||
| 232 | 238 | measure a short duration. | |
| 233 | 239 | ||
| 234 | 240 | If the internal clock fails, silently ignore the error and return 0. | |
| 235 | - On integer overflow, silently ignore the overflow and truncated the clock to | ||
| 241 | + On integer overflow, silently ignore the overflow and clamp the clock to | ||
| 236 | 242 | _PyTime_MIN or _PyTime_MAX. | |
| 237 | 243 | ||
| 238 | 244 | Use _PyTime_GetPerfCounterWithInfo() to check for failure. */ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -38,6 +38,10 @@ class _PyTime(enum.IntEnum): | |||
| 38 | 38 | # Round away from zero | |
| 39 | 39 | ROUND_UP = 3 | |
| 40 | 40 | ||
| 41 | + # _PyTime_t is int64_t | ||
| 42 | + _PyTime_MIN = -2 ** 63 | ||
| 43 | + _PyTime_MAX = 2 ** 63 - 1 | ||
| 44 | + | ||
| 41 | 45 | # Rounding modes supported by PyTime | |
| 42 | 46 | ROUNDING_MODES = ( | |
| 43 | 47 | # (PyTime rounding method, decimal rounding method) | |
@@ -960,6 +964,49 @@ def timespec_converter(ns): | |||
| 960 | 964 | NS_TO_SEC, | |
| 961 | 965 | value_filter=self.time_t_filter) | |
| 962 | 966 | ||
| 967 | + @unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimeval_clamp'), | ||
| 968 | + 'need _testcapi.PyTime_AsTimeval_clamp') | ||
| 969 | + def test_AsTimeval_clamp(self): | ||
| 970 | + from _testcapi import PyTime_AsTimeval_clamp | ||
| 971 | + | ||
| 972 | + if sys.platform == 'win32': | ||
| 973 | + from _testcapi import LONG_MIN, LONG_MAX | ||
| 974 | + tv_sec_max = LONG_MAX | ||
| 975 | + tv_sec_min = LONG_MIN | ||
| 976 | + else: | ||
| 977 | + tv_sec_max = self.time_t_max | ||
| 978 | + tv_sec_min = self.time_t_min | ||
| 979 | + | ||
| 980 | + for t in (_PyTime_MIN, _PyTime_MAX): | ||
| 981 | + ts = PyTime_AsTimeval_clamp(t, _PyTime.ROUND_CEILING) | ||
| 982 | + with decimal.localcontext() as context: | ||
| 983 | + context.rounding = decimal.ROUND_CEILING | ||
| 984 | + us = self.decimal_round(decimal.Decimal(t) / US_TO_NS) | ||
| 985 | + tv_sec, tv_usec = divmod(us, SEC_TO_US) | ||
| 986 | + if tv_sec_max < tv_sec: | ||
| 987 | + tv_sec = tv_sec_max | ||
| 988 | + tv_usec = 0 | ||
| 989 | + elif tv_sec < tv_sec_min: | ||
| 990 | + tv_sec = tv_sec_min | ||
| 991 | + tv_usec = 0 | ||
| 992 | + self.assertEqual(ts, (tv_sec, tv_usec)) | ||
| 993 | + | ||
| 994 | + @unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec_clamp'), | ||
| 995 | + 'need _testcapi.PyTime_AsTimespec_clamp') | ||
| 996 | + def test_AsTimespec_clamp(self): | ||
| 997 | + from _testcapi import PyTime_AsTimespec_clamp | ||
| 998 | + | ||
| 999 | + for t in (_PyTime_MIN, _PyTime_MAX): | ||
| 1000 | + ts = PyTime_AsTimespec_clamp(t) | ||
| 1001 | + tv_sec, tv_nsec = divmod(t, NS_TO_SEC) | ||
| 1002 | + if self.time_t_max < tv_sec: | ||
| 1003 | + tv_sec = self.time_t_max | ||
| 1004 | + tv_nsec = 0 | ||
| 1005 | + elif tv_sec < self.time_t_min: | ||
| 1006 | + tv_sec = self.time_t_min | ||
| 1007 | + tv_nsec = 0 | ||
| 1008 | + self.assertEqual(ts, (tv_sec, tv_nsec)) | ||
| 1009 | + | ||
| 963 | 1010 | def test_AsMilliseconds(self): | |
| 964 | 1011 | from _testcapi import PyTime_AsMilliseconds | |
| 965 | 1012 | ||
@@ -1062,7 +1109,7 @@ def test_clock_functions(self): | |||
| 1062 | 1109 | clock_names = [ | |
| 1063 | 1110 | "CLOCK_MONOTONIC", "clock_gettime", "clock_gettime_ns", "clock_settime", | |
| 1064 | 1111 | "clock_settime_ns", "clock_getres"] | |
| 1065 | - | ||
| 1112 | + | ||
| 1066 | 1113 | if mac_ver >= (10, 12): | |
| 1067 | 1114 | for name in clock_names: | |
| 1068 | 1115 | self.assertTrue(hasattr(time, name), f"time.{name} is not available") | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2264,7 +2264,7 @@ PySSL_select(PySocketSockObject *s, int writing, _PyTime_t timeout) | |||
| 2264 | 2264 | if (!_PyIsSelectable_fd(s->sock_fd)) | |
| 2265 | 2265 | return SOCKET_TOO_LARGE_FOR_SELECT; | |
| 2266 | 2266 | ||
| 2267 | - _PyTime_AsTimeval_noraise(timeout, &tv, _PyTime_ROUND_CEILING); | ||
| 2267 | + _PyTime_AsTimeval_clamp(timeout, &tv, _PyTime_ROUND_CEILING); | ||
| 2268 | 2268 | ||
| 2269 | 2269 | FD_ZERO(&fds); | |
| 2270 | 2270 | FD_SET(s->sock_fd, &fds); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4687,7 +4687,32 @@ test_PyTime_AsTimeval(PyObject *self, PyObject *args) | |||
| 4687 | 4687 | if (seconds == NULL) { | |
| 4688 | 4688 | return NULL; | |
| 4689 | 4689 | } | |
| 4690 | - return Py_BuildValue("Nl", seconds, tv.tv_usec); | ||
| 4690 | + return Py_BuildValue("Nl", seconds, (long)tv.tv_usec); | ||
| 4691 | + } | ||
| 4692 | + | ||
| 4693 | + static PyObject * | ||
| 4694 | + test_PyTime_AsTimeval_clamp(PyObject *self, PyObject *args) | ||
| 4695 | + { | ||
| 4696 | + PyObject *obj; | ||
| 4697 | + int round; | ||
| 4698 | + if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { | ||
| 4699 | + return NULL; | ||
| 4700 | + } | ||
| 4701 | + if (check_time_rounding(round) < 0) { | ||
| 4702 | + return NULL; | ||
| 4703 | + } | ||
| 4704 | + _PyTime_t t; | ||
| 4705 | + if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { | ||
| 4706 | + return NULL; | ||
| 4707 | + } | ||
| 4708 | + struct timeval tv; | ||
| 4709 | + _PyTime_AsTimeval_clamp(t, &tv, round); | ||
| 4710 | + | ||
| 4711 | + PyObject *seconds = PyLong_FromLongLong(tv.tv_sec); | ||
| 4712 | + if (seconds == NULL) { | ||
| 4713 | + return NULL; | ||
| 4714 | + } | ||
| 4715 | + return Py_BuildValue("Nl", seconds, (long)tv.tv_usec); | ||
| 4691 | 4716 | } | |
| 4692 | 4717 | ||
| 4693 | 4718 | #ifdef HAVE_CLOCK_GETTIME | |
@@ -4708,6 +4733,22 @@ test_PyTime_AsTimespec(PyObject *self, PyObject *args) | |||
| 4708 | 4733 | } | |
| 4709 | 4734 | return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec); | |
| 4710 | 4735 | } | |
| 4736 | + | ||
| 4737 | + static PyObject * | ||
| 4738 | + test_PyTime_AsTimespec_clamp(PyObject *self, PyObject *args) | ||
| 4739 | + { | ||
| 4740 | + PyObject *obj; | ||
| 4741 | + if (!PyArg_ParseTuple(args, "O", &obj)) { | ||
| 4742 | + return NULL; | ||
| 4743 | + } | ||
| 4744 | + _PyTime_t t; | ||
| 4745 | + if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { | ||
| 4746 | + return NULL; | ||
| 4747 | + } | ||
| 4748 | + struct timespec ts; | ||
| 4749 | + _PyTime_AsTimespec_clamp(t, &ts); | ||
| 4750 | + return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec); | ||
| 4751 | + } | ||
| 4711 | 4752 | #endif | |
| 4712 | 4753 | ||
| 4713 | 4754 | static PyObject * | |
@@ -5872,8 +5913,10 @@ static PyMethodDef TestMethods[] = { | |||
| 5872 | 5913 | {"PyTime_FromSecondsObject", test_pytime_fromsecondsobject, METH_VARARGS}, | |
| 5873 | 5914 | {"PyTime_AsSecondsDouble", test_pytime_assecondsdouble, METH_VARARGS}, | |
| 5874 | 5915 | {"PyTime_AsTimeval", test_PyTime_AsTimeval, METH_VARARGS}, | |
| 5916 | + {"PyTime_AsTimeval_clamp", test_PyTime_AsTimeval_clamp, METH_VARARGS}, | ||
| 5875 | 5917 | #ifdef HAVE_CLOCK_GETTIME | |
| 5876 | 5918 | {"PyTime_AsTimespec", test_PyTime_AsTimespec, METH_VARARGS}, | |
| 5919 | + {"PyTime_AsTimespec_clamp", test_PyTime_AsTimespec_clamp, METH_VARARGS}, | ||
| 5877 | 5920 | #endif | |
| 5878 | 5921 | {"PyTime_AsMilliseconds", test_PyTime_AsMilliseconds, METH_VARARGS}, | |
| 5879 | 5922 | {"PyTime_AsMicroseconds", test_PyTime_AsMicroseconds, METH_VARARGS}, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -344,7 +344,7 @@ select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist, | |||
| 344 | 344 | n = 0; | |
| 345 | 345 | break; | |
| 346 | 346 | } | |
| 347 | - _PyTime_AsTimeval_noraise(timeout, &tv, _PyTime_ROUND_CEILING); | ||
| 347 | + _PyTime_AsTimeval_clamp(timeout, &tv, _PyTime_ROUND_CEILING); | ||
| 348 | 348 | /* retry select() with the recomputed timeout */ | |
| 349 | 349 | } | |
| 350 | 350 | } while (1); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -758,7 +758,7 @@ internal_select(PySocketSockObject *s, int writing, _PyTime_t interval, | |||
| 758 | 758 | Py_END_ALLOW_THREADS; | |
| 759 | 759 | #else | |
| 760 | 760 | if (interval >= 0) { | |
| 761 | - _PyTime_AsTimeval_noraise(interval, &tv, _PyTime_ROUND_CEILING); | ||
| 761 | + _PyTime_AsTimeval_clamp(interval, &tv, _PyTime_ROUND_CEILING); | ||
| 762 | 762 | tvp = &tv; | |
| 763 | 763 | } | |
| 764 | 764 | else | |
| Back | FazBrowse Home | New Git URL |
0 commit comments