[Python-checkins] cpython: Issue #13964: signal.sigtimedwait() timeout is now a float instead of a tuple

victor.stinner python-checkins at python.org
Fri Mar 2 22:54:43 CET 2012


http://hg.python.org/cpython/rev/67d9595a833c
changeset: 75372:67d9595a833c
user: Victor Stinner <victor.stinner at gmail.com>
date: Fri Mar 02 22:54:03 2012 +0100
summary:
 Issue #13964: signal.sigtimedwait() timeout is now a float instead of a tuple
Add a private API to convert an int or float to a C timespec structure.
files:
 Doc/library/signal.rst | 9 ++---
 Include/pytime.h | 11 ++++++
 Lib/test/test_signal.py | 10 ++---
 Lib/test/test_time.py | 21 ++++++++++++-
 Modules/_testcapimodule.c | 19 +++++++++++
 Modules/signalmodule.c | 11 +----
 Python/pytime.c | 45 +++++++++++++++++++++++++++
 7 files changed, 106 insertions(+), 20 deletions(-)
diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst
--- a/Doc/library/signal.rst
+++ b/Doc/library/signal.rst
@@ -369,12 +369,11 @@
 .. versionadded:: 3.3
 
 
-.. function:: sigtimedwait(sigset, (timeout_sec, timeout_nsec))
+.. function:: sigtimedwait(sigset, timeout)
 
- Like :func:`sigtimedwait`, but takes a tuple of ``(seconds, nanoseconds)``
- as an additional argument specifying a timeout. If both *timeout_sec* and
- *timeout_nsec* are specified as :const:`0`, a poll is performed. Returns
- :const:`None` if a timeout occurs.
+ Like :func:`sigwaitinfo`, but takes an additional *timeout* argument
+ specifying a timeout. If *timeout* is specified as :const:`0`, a poll is
+ performed. Returns :const:`None` if a timeout occurs.
 
 Availability: Unix (see the man page :manpage:`sigtimedwait(2)` for further
 information).
diff --git a/Include/pytime.h b/Include/pytime.h
--- a/Include/pytime.h
+++ b/Include/pytime.h
@@ -3,6 +3,7 @@
 #define Py_PYTIME_H
 
 #include "pyconfig.h" /* include for defines */
+#include "object.h"
 
 /**************************************************************************
 Symbols and macros to supply platform-independent interfaces to time related
@@ -37,6 +38,16 @@
 ((tv_end.tv_sec - tv_start.tv_sec) + \
 (tv_end.tv_usec - tv_start.tv_usec) * 0.000001)
 
+#ifndef Py_LIMITED_API
+/* Convert a number of seconds, int or float, to a timespec structure.
+ nsec is always in the range [0; 999999999]. For example, -1.2 is converted
+ to (-2, 800000000). */
+PyAPI_FUNC(int) _PyTime_ObjectToTimespec(
+ PyObject *obj,
+ time_t *sec,
+ long *nsec);
+#endif
+
 /* Dummy to force linking. */
 PyAPI_FUNC(void) _PyTime_Init(void);
 
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -662,7 +662,7 @@
 self.wait_helper(signal.SIGALRM, '''
 def test(signum):
 signal.alarm(1)
- info = signal.sigtimedwait([signum], (10, 1000))
+ info = signal.sigtimedwait([signum], 10.1000)
 if info.si_signo != signum:
 raise Exception('info.si_signo != %s' % signum)
 ''')
@@ -675,7 +675,7 @@
 def test(signum):
 import os
 os.kill(os.getpid(), signum)
- info = signal.sigtimedwait([signum], (0, 0))
+ info = signal.sigtimedwait([signum], 0)
 if info.si_signo != signum:
 raise Exception('info.si_signo != %s' % signum)
 ''')
@@ -685,7 +685,7 @@
 def test_sigtimedwait_timeout(self):
 self.wait_helper(signal.SIGALRM, '''
 def test(signum):
- received = signal.sigtimedwait([signum], (1, 0))
+ received = signal.sigtimedwait([signum], 1.0)
 if received is not None:
 raise Exception("received=%r" % (received,))
 ''')
@@ -694,9 +694,7 @@
 'need signal.sigtimedwait()')
 def test_sigtimedwait_negative_timeout(self):
 signum = signal.SIGALRM
- self.assertRaises(ValueError, signal.sigtimedwait, [signum], (-1, -1))
- self.assertRaises(ValueError, signal.sigtimedwait, [signum], (0, -1))
- self.assertRaises(ValueError, signal.sigtimedwait, [signum], (-1, 0))
+ self.assertRaises(ValueError, signal.sigtimedwait, [signum], -1.0)
 
 @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'),
 'need signal.sigwaitinfo()')
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
@@ -497,12 +497,31 @@
 pass
 
 
+class TestPytime(unittest.TestCase):
+ def test_timespec(self):
+ from _testcapi import pytime_object_to_timespec
+ for obj, timespec in (
+ (0, (0, 0)),
+ (-1, (-1, 0)),
+ (-1.0, (-1, 0)),
+ (-1e-9, (-1, 999999999)),
+ (-1.2, (-2, 800000000)),
+ (1.123456789, (1, 123456789)),
+ ):
+ self.assertEqual(pytime_object_to_timespec(obj), timespec)
+
+ for invalid in (-(2 ** 100), -(2.0 ** 100.0), 2 ** 100, 2.0 ** 100.0):
+ self.assertRaises(OverflowError, pytime_object_to_timespec, invalid)
+
+
+
 def test_main():
 support.run_unittest(
 TimeTestCase,
 TestLocale,
 TestAsctime4dyear,
- TestStrftime4dyear)
+ TestStrftime4dyear,
+ TestPytime)
 
 if __name__ == "__main__":
 test_main()
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2323,6 +2323,24 @@
 return PyLong_FromLong(r);
 }
 
+static PyObject *
+test_pytime_object_to_timespec(PyObject *self, PyObject *args)
+{
+ PyObject *obj;
+ time_t sec;
+ long nsec;
+ if (!PyArg_ParseTuple(args, "O:pytime_object_to_timespec", &obj))
+ return NULL;
+ if (_PyTime_ObjectToTimespec(obj, &sec, &nsec) == -1)
+ return NULL;
+#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG
+ return Py_BuildValue("Ll", (PY_LONG_LONG)sec, nsec);
+#else
+ assert(sizeof(time_t) <= sizeof(long));
+ return Py_BuildValue("ll", (long)sec, nsec);
+#endif
+}
+
 
 static PyMethodDef TestMethods[] = {
 {"raise_exception", raise_exception, METH_VARARGS},
@@ -2412,6 +2430,7 @@
 METH_NOARGS},
 {"crash_no_current_thread", (PyCFunction)crash_no_current_thread, METH_NOARGS},
 {"run_in_subinterp", run_in_subinterp, METH_VARARGS},
+ {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS},
 {NULL, NULL} /* sentinel */
 };
 
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -783,16 +783,11 @@
 siginfo_t si;
 int err;
 
- if (!PyArg_ParseTuple(args, "OO:sigtimedwait", &signals, &timeout))
+ if (!PyArg_ParseTuple(args, "OO:sigtimedwait",
+ &signals, &timeout))
 return NULL;
 
- if (!PyTuple_Check(timeout) || PyTuple_Size(timeout) != 2) {
- PyErr_SetString(PyExc_TypeError,
- "sigtimedwait() arg 2 must be a tuple "
- "(timeout_sec, timeout_nsec)");
- return NULL;
- } else if (!PyArg_ParseTuple(timeout, "ll:sigtimedwait",
- &(buf.tv_sec), &(buf.tv_nsec)))
+ if (_PyTime_ObjectToTimespec(timeout, &buf.tv_sec, &buf.tv_nsec) == -1)
 return NULL;
 
 if (buf.tv_sec < 0 || buf.tv_nsec < 0) {
diff --git a/Python/pytime.c b/Python/pytime.c
--- a/Python/pytime.c
+++ b/Python/pytime.c
@@ -70,6 +70,51 @@
 #endif /* MS_WINDOWS */
 }
 
+int
+_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec)
+{
+ if (PyFloat_Check(obj)) {
+ double d, intpart, floatpart, err;
+
+ d = PyFloat_AsDouble(obj);
+ floatpart = modf(d, &intpart);
+ if (floatpart < 0) {
+ floatpart = 1.0 + floatpart;
+ intpart -= 1.0;
+ }
+
+ *sec = (time_t)intpart;
+ err = intpart - (double)*sec;
+ if (err <= -1.0 || err >= 1.0)
+ goto overflow;
+
+ floatpart *= 1e9;
+ *nsec = (long)floatpart;
+ return 0;
+ }
+ else {
+#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG
+ *sec = PyLong_AsLongLong(obj);
+#else
+ assert(sizeof(time_t) <= sizeof(long));
+ *sec = PyLong_AsLong(obj);
+#endif
+ if (*sec == -1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ goto overflow;
+ else
+ return -1;
+ }
+ *nsec = 0;
+ return 0;
+ }
+
+overflow:
+ PyErr_SetString(PyExc_OverflowError,
+ "timestamp out of range for platform time_t");
+ return -1;
+}
+
 void
 _PyTime_Init()
 {
-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list

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