From ef611c96eab0ab667ebb43fdf429b319f6d99890 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 13 Oct 2017 13:49:43 -0700 Subject: [PATCH] bpo-30807: signal.setitimer() now uses _PyTime API (GH-3865) The _PyTime API handles detects overflow and is well tested. Document that the signal will only be sent once if internal is equal to zero. --- Doc/library/signal.rst | 7 +++--- Modules/clinic/signalmodule.c.h | 12 +++++----- Modules/signalmodule.c | 40 ++++++++++++++++++++------------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst index 46d71def08a..2bc39d9f133 100644 --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -273,13 +273,14 @@ The :mod:`signal` module defines the following functions: .. versionadded:: 3.3 -.. function:: setitimer(which, seconds[, interval]) +.. function:: setitimer(which, seconds, interval=0.0) Sets given interval timer (one of :const:`signal.ITIMER_REAL`, :const:`signal.ITIMER_VIRTUAL` or :const:`signal.ITIMER_PROF`) specified by *which* to fire after *seconds* (float is accepted, different from - :func:`alarm`) and after that every *interval* seconds. The interval - timer specified by *which* can be cleared by setting seconds to zero. + :func:`alarm`) and after that every *interval* seconds (if *interval* + is non-zero). The interval timer specified by *which* can be cleared by + setting *seconds* to zero. When an interval timer fires, a signal is sent to the process. The signal sent is dependent on the timer being used; diff --git a/Modules/clinic/signalmodule.c.h b/Modules/clinic/signalmodule.c.h index a4542cc45a0..cc3e64002bc 100644 --- a/Modules/clinic/signalmodule.c.h +++ b/Modules/clinic/signalmodule.c.h @@ -182,18 +182,18 @@ PyDoc_STRVAR(signal_setitimer__doc__, {"setitimer", (PyCFunction)signal_setitimer, METH_FASTCALL, signal_setitimer__doc__}, static PyObject * -signal_setitimer_impl(PyObject *module, int which, double seconds, - double interval); +signal_setitimer_impl(PyObject *module, int which, PyObject *seconds, + PyObject *interval); static PyObject * signal_setitimer(PyObject *module, PyObject **args, Py_ssize_t nargs) { PyObject *return_value = NULL; int which; - double seconds; - double interval = 0.0; + PyObject *seconds; + PyObject *interval = NULL; - if (!_PyArg_ParseStack(args, nargs, "id|d:setitimer", + if (!_PyArg_ParseStack(args, nargs, "iO|O:setitimer", &which, &seconds, &interval)) { goto exit; } @@ -440,4 +440,4 @@ exit: #ifndef SIGNAL_PTHREAD_KILL_METHODDEF #define SIGNAL_PTHREAD_KILL_METHODDEF #endif /* !defined(SIGNAL_PTHREAD_KILL_METHODDEF) */ -/*[clinic end generated code: output=3f6e6298696f1b75 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a003d3fea9a33daa input=a9049054013a1b77]*/ diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 66331088176..d470727fb62 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -131,16 +131,21 @@ static HANDLE sigint_event = NULL; #ifdef HAVE_GETITIMER static PyObject *ItimerError; -/* auxiliary functions for setitimer/getitimer */ -static void -timeval_from_double(double d, struct timeval *tv) +/* auxiliary functions for setitimer */ +static int +timeval_from_double(PyObject *obj, struct timeval *tv) { - tv->tv_sec = floor(d); - tv->tv_usec = fmod(d, 1.0) * 1000000.0; - /* Don't disable the timer if the computation above rounds down to zero. */ - if (d > 0.0 && tv->tv_sec == 0 && tv->tv_usec == 0) { - tv->tv_usec = 1; + if (obj == NULL) { + tv->tv_sec = 0; + tv->tv_usec = 0; + return 0; } + + _PyTime_t t; + if (_PyTime_FromSecondsObject(&t, obj, _PyTime_ROUND_CEILING) < 0) { + return -1; + } + return _PyTime_AsTimeval(t, tv, _PyTime_ROUND_CEILING); } Py_LOCAL_INLINE(double) @@ -677,8 +682,8 @@ PySignal_SetWakeupFd(int fd) signal.setitimer which: int - seconds: double - interval: double = 0.0 + seconds: object + interval: object(c_default="NULL") = 0.0 / Sets given itimer (one of ITIMER_REAL, ITIMER_VIRTUAL or ITIMER_PROF). @@ -690,14 +695,19 @@ Returns old values as a tuple: (delay, interval). [clinic start generated code]*/ static PyObject * -signal_setitimer_impl(PyObject *module, int which, double seconds, - double interval) -/*[clinic end generated code: output=6f51da0fe0787f2c input=0d27d417cfcbd51a]*/ +signal_setitimer_impl(PyObject *module, int which, PyObject *seconds, + PyObject *interval) +/*[clinic end generated code: output=65f9dcbddc35527b input=de43daf194e6f66f]*/ { struct itimerval new, old; - timeval_from_double(seconds, &new.it_value); - timeval_from_double(interval, &new.it_interval); + if (timeval_from_double(seconds, &new.it_value) < 0) { + return NULL; + } + if (timeval_from_double(interval, &new.it_interval) < 0) { + return NULL; + } + /* Let OS check "which" value */ if (setitimer(which, &new, &old) != 0) { PyErr_SetFromErrno(ItimerError);