From 13019fdef3b6d589f8d7602943c76fcc637114ea Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 3 Apr 2015 13:10:54 +0200 Subject: [PATCH] Issue #22117: Add a new _PyTime_FromSeconds() function Fix also _Py_InitializeEx_Private(): initialize time before initializing import, import_init() uses the _PyTime API (for thread locks). --- Include/pytime.h | 5 ++++- Lib/test/test_time.py | 7 +++++++ Modules/_testcapimodule.c | 13 +++++++++++++ Modules/_threadmodule.c | 2 +- Python/pylifecycle.c | 6 +++--- Python/pytime.c | 17 +++++++++++++++++ 6 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Include/pytime.h b/Include/pytime.h index bf237c8655b..bf0dcd86577 100644 --- a/Include/pytime.h +++ b/Include/pytime.h @@ -66,7 +66,10 @@ PyAPI_FUNC(int) _PyTime_ObjectToTimespec( _PyTime_round_t); -/* Create a timestamp from a number of nanoseconds (C long). */ +/* Create a timestamp from a number of seconds. */ +PyAPI_FUNC(_PyTime_t) _PyTime_FromSeconds(int ns); + +/* Create a timestamp from a number of nanoseconds. */ PyAPI_FUNC(_PyTime_t) _PyTime_FromNanoseconds(PY_LONG_LONG ns); /* Convert a number of seconds (Python float or int) to a timetamp. diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index a9f6fd87edb..0891834c154 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -731,6 +731,13 @@ class TestPytime(unittest.TestCase): @unittest.skipUnless(_testcapi is not None, 'need the _testcapi module') class TestPyTime_t(unittest.TestCase): + def test_FromSeconds(self): + from _testcapi import PyTime_FromSeconds + for seconds in (0, 3, -456, _testcapi.INT_MAX, _testcapi.INT_MIN): + with self.subTest(seconds=seconds): + self.assertEqual(PyTime_FromSeconds(seconds), + seconds * SEC_TO_NS) + def test_FromSecondsObject(self): from _testcapi import PyTime_FromSecondsObject diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 7b4f2396378..d6eb6d4509a 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3382,6 +3382,18 @@ return_result_with_error(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +test_pytime_fromseconds(PyObject *self, PyObject *args) +{ + int seconds; + _PyTime_t ts; + + if (!PyArg_ParseTuple(args, "i", &seconds)) + return NULL; + ts = _PyTime_FromSeconds(seconds); + return _PyTime_AsNanosecondsObject(ts); +} + static PyObject * test_pytime_fromsecondsobject(PyObject *self, PyObject *args) { @@ -3651,6 +3663,7 @@ static PyMethodDef TestMethods[] = { return_null_without_error, METH_NOARGS}, {"return_result_with_error", return_result_with_error, METH_NOARGS}, + {"PyTime_FromSeconds", test_pytime_fromseconds, METH_VARARGS}, {"PyTime_FromSecondsObject", test_pytime_fromsecondsobject, METH_VARARGS}, {"PyTime_AsSecondsDouble", test_pytime_assecondsdouble, METH_VARARGS}, {"PyTime_AsTimeval", test_PyTime_AsTimeval, METH_VARARGS}, diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 323447f9daa..812c8a3b6a3 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -101,7 +101,7 @@ lock_acquire_parse_args(PyObject *args, PyObject *kwds, char *kwlist[] = {"blocking", "timeout", NULL}; int blocking = 1; PyObject *timeout_obj = NULL; - const _PyTime_t unset_timeout = _PyTime_FromNanoseconds(-1000000000); + const _PyTime_t unset_timeout = _PyTime_FromSeconds(-1); *timeout = unset_timeout ; diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 38543e05efa..bab3a2f38a8 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -405,15 +405,15 @@ _Py_InitializeEx_Private(int install_sigs, int install_importlib) if (!install_importlib) return; + if (_PyTime_Init() < 0) + Py_FatalError("Py_Initialize: can't initialize time"); + import_init(interp, sysmod); /* initialize the faulthandler module */ if (_PyFaulthandler_Init()) Py_FatalError("Py_Initialize: can't initialize faulthandler"); - if (_PyTime_Init() < 0) - Py_FatalError("Py_Initialize: can't initialize time"); - if (initfsencoding(interp) < 0) Py_FatalError("Py_Initialize: unable to load the file system codec"); diff --git a/Python/pytime.c b/Python/pytime.c index 491bbea6112..02a93749c71 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -158,6 +158,19 @@ _PyTime_overflow(void) "timestamp too large to convert to C _PyTime_t"); } +_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). */ + assert((seconds >= 0 && seconds <= _PyTime_MAX / SEC_TO_NS) + || (seconds < 0 && seconds >= _PyTime_MIN / SEC_TO_NS)); + t = (_PyTime_t)seconds * SEC_TO_NS; + return t; +} + _PyTime_t _PyTime_FromNanoseconds(PY_LONG_LONG ns) { @@ -657,5 +670,9 @@ _PyTime_Init(void) /* ensure that the operating system provides a monotonic clock */ if (_PyTime_GetMonotonicClockWithInfo(&t, NULL) < 0) return -1; + + /* check that _PyTime_FromSeconds() cannot overflow */ + assert(INT_MAX <= _PyTime_MAX / SEC_TO_NS); + assert(INT_MIN >= _PyTime_MIN / SEC_TO_NS); return 0; }