Commit 34dc0f46 authored by Victor Stinner's avatar Victor Stinner

Issue #22117: The signal modules uses the new _PyTime_t API

* Add _PyTime_AsTimespec()
* Add unit tests for _PyTime_AsTimespec()
parent 7181dec3
...@@ -145,6 +145,12 @@ PyAPI_FUNC(int) _PyTime_AsTimeval(_PyTime_t t, ...@@ -145,6 +145,12 @@ PyAPI_FUNC(int) _PyTime_AsTimeval(_PyTime_t t,
struct timeval *tv, struct timeval *tv,
_PyTime_round_t round); _PyTime_round_t round);
#ifdef HAVE_CLOCK_GETTIME
/* Convert a timestamp to a timespec structure (nanosecond resolution).
Raise an exception and return -1 on error, return 0 on success. */
PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts);
#endif
/* Get the current time from the system clock. /* Get the current time from the system clock.
* Fill clock information if info is not NULL. * Fill clock information if info is not NULL.
* Raise an exception and return -1 on error, return 0 on success. * Raise an exception and return -1 on error, return 0 on success.
......
...@@ -10,6 +10,11 @@ try: ...@@ -10,6 +10,11 @@ try:
import threading import threading
except ImportError: except ImportError:
threading = None threading = None
try:
import _testcapi
except ImportError:
_testcapi = None
# Max year is only limited by the size of C int. # Max year is only limited by the size of C int.
SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4 SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4
...@@ -768,7 +773,8 @@ class TestPytime(unittest.TestCase): ...@@ -768,7 +773,8 @@ class TestPytime(unittest.TestCase):
self.assertIs(lt.tm_zone, None) self.assertIs(lt.tm_zone, None)
@support.cpython_only @unittest.skipUnless(_testcapi is not None,
'need the _testcapi module')
class TestPyTime_t(unittest.TestCase): class TestPyTime_t(unittest.TestCase):
def test_FromSecondsObject(self): def test_FromSecondsObject(self):
from _testcapi import PyTime_FromSecondsObject from _testcapi import PyTime_FromSecondsObject
...@@ -896,6 +902,27 @@ class TestPyTime_t(unittest.TestCase): ...@@ -896,6 +902,27 @@ class TestPyTime_t(unittest.TestCase):
self.assertEqual(PyTime_AsSecondsDouble(nanoseconds), self.assertEqual(PyTime_AsSecondsDouble(nanoseconds),
seconds) seconds)
@unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec'),
'need _testcapi.PyTime_AsTimespec')
def test_timespec(self):
from _testcapi import PyTime_AsTimespec
for ns, ts in (
# nanoseconds
(0, (0, 0)),
(1, (0, 1)),
(-1, (-1, 999999999)),
# seconds
(2 * SEC_TO_NS, (2, 0)),
(-3 * SEC_TO_NS, (-3, 0)),
# seconds + nanoseconds
(1234567890, (1, 234567890)),
(-1234567890, (-2, 765432110)),
):
with self.subTest(nanoseconds=ns, timespec=ts):
self.assertEqual(PyTime_AsTimespec(ns), ts)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()
...@@ -3408,6 +3408,23 @@ test_pytime_assecondsdouble(PyObject *self, PyObject *args) ...@@ -3408,6 +3408,23 @@ test_pytime_assecondsdouble(PyObject *self, PyObject *args)
return PyFloat_FromDouble(d); return PyFloat_FromDouble(d);
} }
#ifdef HAVE_CLOCK_GETTIME
static PyObject *
test_PyTime_AsTimespec(PyObject *self, PyObject *args)
{
PY_LONG_LONG ns;
_PyTime_t t;
struct timespec ts;
if (!PyArg_ParseTuple(args, "L", &ns))
return NULL;
t = _PyTime_FromNanoseconds(ns);
if (_PyTime_AsTimespec(t, &ts) == -1)
return NULL;
return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec);
}
#endif
static PyMethodDef TestMethods[] = { static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS},
...@@ -3573,6 +3590,9 @@ static PyMethodDef TestMethods[] = { ...@@ -3573,6 +3590,9 @@ static PyMethodDef TestMethods[] = {
return_result_with_error, METH_NOARGS}, return_result_with_error, METH_NOARGS},
{"PyTime_FromSecondsObject", test_pytime_fromsecondsobject, METH_VARARGS}, {"PyTime_FromSecondsObject", test_pytime_fromsecondsobject, METH_VARARGS},
{"PyTime_AsSecondsDouble", test_pytime_assecondsdouble, METH_VARARGS}, {"PyTime_AsSecondsDouble", test_pytime_assecondsdouble, METH_VARARGS},
#ifdef HAVE_CLOCK_GETTIME
{"PyTime_AsTimespec", test_PyTime_AsTimespec, METH_VARARGS},
#endif
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
......
...@@ -966,16 +966,18 @@ Returns a struct_siginfo containing information about the signal."); ...@@ -966,16 +966,18 @@ Returns a struct_siginfo containing information about the signal.");
static PyObject * static PyObject *
signal_sigtimedwait(PyObject *self, PyObject *args) signal_sigtimedwait(PyObject *self, PyObject *args)
{ {
PyObject *signals; PyObject *signals, *timeout_obj;
double timeout, frac;
struct timespec ts; struct timespec ts;
sigset_t set; sigset_t set;
siginfo_t si; siginfo_t si;
int res; int res;
_PyTime_timeval deadline, monotonic; _PyTime_t timeout, deadline, monotonic;
if (!PyArg_ParseTuple(args, "OO:sigtimedwait",
&signals, &timeout_obj))
return NULL;
if (!PyArg_ParseTuple(args, "Od:sigtimedwait", if (_PyTime_FromSecondsObject(&timeout, timeout_obj, _PyTime_ROUND_UP) < 0)
&signals, &timeout))
return NULL; return NULL;
if (timeout < 0) { if (timeout < 0) {
...@@ -986,14 +988,11 @@ signal_sigtimedwait(PyObject *self, PyObject *args) ...@@ -986,14 +988,11 @@ signal_sigtimedwait(PyObject *self, PyObject *args)
if (iterable_to_sigset(signals, &set)) if (iterable_to_sigset(signals, &set))
return NULL; return NULL;
_PyTime_monotonic(&deadline); deadline = _PyTime_GetMonotonicClock() + timeout;
_PyTime_AddDouble(&deadline, timeout, _PyTime_ROUND_UP);
do { do {
frac = fmod(timeout, 1.0); if (_PyTime_AsTimespec(timeout, &ts) < 0)
timeout = floor(timeout); return NULL;
ts.tv_sec = (long)timeout;
ts.tv_nsec = (long)(frac*1e9);
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
res = sigtimedwait(&set, &si, &ts); res = sigtimedwait(&set, &si, &ts);
...@@ -1013,9 +1012,9 @@ signal_sigtimedwait(PyObject *self, PyObject *args) ...@@ -1013,9 +1012,9 @@ signal_sigtimedwait(PyObject *self, PyObject *args)
if (PyErr_CheckSignals()) if (PyErr_CheckSignals())
return NULL; return NULL;
_PyTime_monotonic(&monotonic); monotonic = _PyTime_GetMonotonicClock();
timeout = _PyTime_INTERVAL(monotonic, deadline); timeout = deadline - monotonic;
if (timeout <= 0.0) if (timeout <= 0)
break; break;
} while (1); } while (1);
......
...@@ -572,6 +572,27 @@ _PyTime_AsTimeval(_PyTime_t t, struct timeval *tv, _PyTime_round_t round) ...@@ -572,6 +572,27 @@ _PyTime_AsTimeval(_PyTime_t t, struct timeval *tv, _PyTime_round_t round)
return 0; return 0;
} }
#ifdef HAVE_CLOCK_GETTIME
int
_PyTime_AsTimespec(_PyTime_t t, struct timespec *ts)
{
_PyTime_t sec, nsec;
sec = t / SEC_TO_NS;
nsec = t % SEC_TO_NS;
if (nsec < 0) {
nsec += SEC_TO_NS;
sec -= 1;
}
ts->tv_sec = (time_t)sec;
if ((_PyTime_t)ts->tv_sec != sec) {
_PyTime_overflow();
return -1;
}
ts->tv_nsec = nsec;
return 0;
}
#endif
static int static int
pygettimeofday_new(_PyTime_t *tp, _Py_clock_info_t *info, int raise) pygettimeofday_new(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment