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).
diff --git a/Include/pytime.h b/Include/pytime.h
index bf237c8..bf0dcd8 100644
--- a/Include/pytime.h
+++ b/Include/pytime.h
@@ -66,7 +66,10 @@
_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 a9f6fd8..0891834 100644
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -731,6 +731,13 @@
@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 7b4f239..d6eb6d4 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3383,6 +3383,18 @@
}
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)
{
PyObject *obj;
@@ -3651,6 +3663,7 @@
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 323447f..812c8a3 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -101,7 +101,7 @@
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 38543e0..bab3a2f 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -405,15 +405,15 @@
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 491bbea..02a9374 100644
--- a/Python/pytime.c
+++ b/Python/pytime.c
@@ -159,6 +159,19 @@
}
_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)
{
_PyTime_t t;
@@ -657,5 +670,9 @@
/* 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;
}