Commit ef611c96 authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

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.
parent a505ecdc
...@@ -273,13 +273,14 @@ The :mod:`signal` module defines the following functions: ...@@ -273,13 +273,14 @@ The :mod:`signal` module defines the following functions:
.. versionadded:: 3.3 .. 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`, Sets given interval timer (one of :const:`signal.ITIMER_REAL`,
:const:`signal.ITIMER_VIRTUAL` or :const:`signal.ITIMER_PROF`) specified :const:`signal.ITIMER_VIRTUAL` or :const:`signal.ITIMER_PROF`) specified
by *which* to fire after *seconds* (float is accepted, different from by *which* to fire after *seconds* (float is accepted, different from
:func:`alarm`) and after that every *interval* seconds. The interval :func:`alarm`) and after that every *interval* seconds (if *interval*
timer specified by *which* can be cleared by setting seconds to zero. 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. When an interval timer fires, a signal is sent to the process.
The signal sent is dependent on the timer being used; The signal sent is dependent on the timer being used;
......
...@@ -182,18 +182,18 @@ PyDoc_STRVAR(signal_setitimer__doc__, ...@@ -182,18 +182,18 @@ PyDoc_STRVAR(signal_setitimer__doc__,
{"setitimer", (PyCFunction)signal_setitimer, METH_FASTCALL, signal_setitimer__doc__}, {"setitimer", (PyCFunction)signal_setitimer, METH_FASTCALL, signal_setitimer__doc__},
static PyObject * static PyObject *
signal_setitimer_impl(PyObject *module, int which, double seconds, signal_setitimer_impl(PyObject *module, int which, PyObject *seconds,
double interval); PyObject *interval);
static PyObject * static PyObject *
signal_setitimer(PyObject *module, PyObject **args, Py_ssize_t nargs) signal_setitimer(PyObject *module, PyObject **args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
int which; int which;
double seconds; PyObject *seconds;
double interval = 0.0; PyObject *interval = NULL;
if (!_PyArg_ParseStack(args, nargs, "id|d:setitimer", if (!_PyArg_ParseStack(args, nargs, "iO|O:setitimer",
&which, &seconds, &interval)) { &which, &seconds, &interval)) {
goto exit; goto exit;
} }
...@@ -440,4 +440,4 @@ exit: ...@@ -440,4 +440,4 @@ exit:
#ifndef SIGNAL_PTHREAD_KILL_METHODDEF #ifndef SIGNAL_PTHREAD_KILL_METHODDEF
#define SIGNAL_PTHREAD_KILL_METHODDEF #define SIGNAL_PTHREAD_KILL_METHODDEF
#endif /* !defined(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]*/
...@@ -131,16 +131,21 @@ static HANDLE sigint_event = NULL; ...@@ -131,16 +131,21 @@ static HANDLE sigint_event = NULL;
#ifdef HAVE_GETITIMER #ifdef HAVE_GETITIMER
static PyObject *ItimerError; static PyObject *ItimerError;
/* auxiliary functions for setitimer/getitimer */ /* auxiliary functions for setitimer */
static void static int
timeval_from_double(double d, struct timeval *tv) timeval_from_double(PyObject *obj, struct timeval *tv)
{ {
tv->tv_sec = floor(d); if (obj == NULL) {
tv->tv_usec = fmod(d, 1.0) * 1000000.0; tv->tv_sec = 0;
/* Don't disable the timer if the computation above rounds down to zero. */ tv->tv_usec = 0;
if (d > 0.0 && tv->tv_sec == 0 && tv->tv_usec == 0) { return 0;
tv->tv_usec = 1; }
_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) Py_LOCAL_INLINE(double)
...@@ -677,8 +682,8 @@ PySignal_SetWakeupFd(int fd) ...@@ -677,8 +682,8 @@ PySignal_SetWakeupFd(int fd)
signal.setitimer signal.setitimer
which: int which: int
seconds: double seconds: object
interval: double = 0.0 interval: object(c_default="NULL") = 0.0
/ /
Sets given itimer (one of ITIMER_REAL, ITIMER_VIRTUAL or ITIMER_PROF). Sets given itimer (one of ITIMER_REAL, ITIMER_VIRTUAL or ITIMER_PROF).
...@@ -690,14 +695,19 @@ Returns old values as a tuple: (delay, interval). ...@@ -690,14 +695,19 @@ Returns old values as a tuple: (delay, interval).
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
signal_setitimer_impl(PyObject *module, int which, double seconds, signal_setitimer_impl(PyObject *module, int which, PyObject *seconds,
double interval) PyObject *interval)
/*[clinic end generated code: output=6f51da0fe0787f2c input=0d27d417cfcbd51a]*/ /*[clinic end generated code: output=65f9dcbddc35527b input=de43daf194e6f66f]*/
{ {
struct itimerval new, old; struct itimerval new, old;
timeval_from_double(seconds, &new.it_value); if (timeval_from_double(seconds, &new.it_value) < 0) {
timeval_from_double(interval, &new.it_interval); return NULL;
}
if (timeval_from_double(interval, &new.it_interval) < 0) {
return NULL;
}
/* Let OS check "which" value */ /* Let OS check "which" value */
if (setitimer(which, &new, &old) != 0) { if (setitimer(which, &new, &old) != 0) {
PyErr_SetFromErrno(ItimerError); PyErr_SetFromErrno(ItimerError);
......
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