[Python-checkins] cpython: Issue #22117: The signal modules uses the new _PyTime_t API

victor.stinner python-checkins at python.org
Fri Mar 27 22:39:15 CET 2015


https://hg.python.org/cpython/rev/a3c5e05d2cef
changeset: 95230:a3c5e05d2cef
user: Victor Stinner <victor.stinner at gmail.com>
date: Fri Mar 27 18:19:03 2015 +0100
summary:
 Issue #22117: The signal modules uses the new _PyTime_t API
* Add _PyTime_AsTimespec()
* Add unit tests for _PyTime_AsTimespec()
files:
 Include/pytime.h | 6 +++++
 Lib/test/test_time.py | 29 ++++++++++++++++++++++++++-
 Modules/_testcapimodule.c | 20 ++++++++++++++++++
 Modules/signalmodule.c | 27 ++++++++++++-------------
 Python/pytime.c | 21 +++++++++++++++++++
 5 files changed, 88 insertions(+), 15 deletions(-)
diff --git a/Include/pytime.h b/Include/pytime.h
--- a/Include/pytime.h
+++ b/Include/pytime.h
@@ -145,6 +145,12 @@
 struct timeval *tv,
 _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.
 * Fill clock information if info is not NULL.
 * Raise an exception and return -1 on error, return 0 on success.
diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -10,6 +10,11 @@
 import threading
 except ImportError:
 threading = None
+try:
+ import _testcapi
+except ImportError:
+ _testcapi = None
+
 
 # Max year is only limited by the size of C int.
 SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4
@@ -768,7 +773,8 @@
 self.assertIs(lt.tm_zone, None)
 
 
- at support.cpython_only
+ at unittest.skipUnless(_testcapi is not None,
+ 'need the _testcapi module')
 class TestPyTime_t(unittest.TestCase):
 def test_FromSecondsObject(self):
 from _testcapi import PyTime_FromSecondsObject
@@ -896,6 +902,27 @@
 self.assertEqual(PyTime_AsSecondsDouble(nanoseconds),
 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__":
 unittest.main()
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3408,6 +3408,23 @@
 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[] = {
 {"raise_exception", raise_exception, METH_VARARGS},
@@ -3573,6 +3590,9 @@
 return_result_with_error, METH_NOARGS},
 {"PyTime_FromSecondsObject", test_pytime_fromsecondsobject, METH_VARARGS},
 {"PyTime_AsSecondsDouble", test_pytime_assecondsdouble, METH_VARARGS},
+#ifdef HAVE_CLOCK_GETTIME
+ {"PyTime_AsTimespec", test_PyTime_AsTimespec, METH_VARARGS},
+#endif
 {NULL, NULL} /* sentinel */
 };
 
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -966,16 +966,18 @@
 static PyObject *
 signal_sigtimedwait(PyObject *self, PyObject *args)
 {
- PyObject *signals;
- double timeout, frac;
+ PyObject *signals, *timeout_obj;
 struct timespec ts;
 sigset_t set;
 siginfo_t si;
 int res;
- _PyTime_timeval deadline, monotonic;
+ _PyTime_t timeout, deadline, monotonic;
 
- if (!PyArg_ParseTuple(args, "Od:sigtimedwait",
- &signals, &timeout))
+ if (!PyArg_ParseTuple(args, "OO:sigtimedwait",
+ &signals, &timeout_obj))
+ return NULL;
+
+ if (_PyTime_FromSecondsObject(&timeout, timeout_obj, _PyTime_ROUND_UP) < 0)
 return NULL;
 
 if (timeout < 0) {
@@ -986,14 +988,11 @@
 if (iterable_to_sigset(signals, &set))
 return NULL;
 
- _PyTime_monotonic(&deadline);
- _PyTime_AddDouble(&deadline, timeout, _PyTime_ROUND_UP);
+ deadline = _PyTime_GetMonotonicClock() + timeout;
 
 do {
- frac = fmod(timeout, 1.0);
- timeout = floor(timeout);
- ts.tv_sec = (long)timeout;
- ts.tv_nsec = (long)(frac*1e9);
+ if (_PyTime_AsTimespec(timeout, &ts) < 0)
+ return NULL;
 
 Py_BEGIN_ALLOW_THREADS
 res = sigtimedwait(&set, &si, &ts);
@@ -1013,9 +1012,9 @@
 if (PyErr_CheckSignals())
 return NULL;
 
- _PyTime_monotonic(&monotonic);
- timeout = _PyTime_INTERVAL(monotonic, deadline);
- if (timeout <= 0.0)
+ monotonic = _PyTime_GetMonotonicClock();
+ timeout = deadline - monotonic;
+ if (timeout <= 0)
 break;
 } while (1);
 
diff --git a/Python/pytime.c b/Python/pytime.c
--- a/Python/pytime.c
+++ b/Python/pytime.c
@@ -572,6 +572,27 @@
 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
 pygettimeofday_new(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
 {
-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /