Issue #22117: The signal modules uses the new _PyTime_t API
* Add _PyTime_AsTimespec() * Add unit tests for _PyTime_AsTimespec()
This commit is contained in:
parent
7181dec3f1
commit
34dc0f46ae
|
@ -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:
|
||||||
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):
|
||||||
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):
|
||||||
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)
|
||||||
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[] = {
|
||||||
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.");
|
||||||
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, "Od:sigtimedwait",
|
if (!PyArg_ParseTuple(args, "OO:sigtimedwait",
|
||||||
&signals, &timeout))
|
&signals, &timeout_obj))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (_PyTime_FromSecondsObject(&timeout, timeout_obj, _PyTime_ROUND_UP) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue