summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin v. Löwis <martin@v.loewis.de>2008-03-24 13:39:54 (GMT)
committerMartin v. Löwis <martin@v.loewis.de>2008-03-24 13:39:54 (GMT)
commit823725e93cdd85371eae53352dd83fc634e95694 (patch)
tree9c9a313f8f0859aaf6790aa4b4900adb6d1b3e60
parent6cf49cf10689bf2ff23fff05928daa23ecdf6fc2 (diff)
downloadcpython-823725e93cdd85371eae53352dd83fc634e95694.zip
cpython-823725e93cdd85371eae53352dd83fc634e95694.tar.gz
cpython-823725e93cdd85371eae53352dd83fc634e95694.tar.bz2
Merged revisions 61846-61847 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r61846 | martin.v.loewis | 2008-03-24 13:57:53 +0100 (Mo, 24 Mär 2008) | 2 lines Install 2to3 script. ........ r61847 | martin.v.loewis | 2008-03-24 14:31:16 +0100 (Mo, 24 Mär 2008) | 2 lines Patch #2240: Implement signal.setitimer and signal.getitimer. ........
-rw-r--r--Doc/library/signal.rst67
-rw-r--r--Lib/test/test_signal.py86
-rw-r--r--Misc/ACKS1
-rw-r--r--Modules/signalmodule.c152
-rwxr-xr-xTools/scripts/2to35
-rwxr-xr-xconfigure8
-rw-r--r--configure.in4
-rw-r--r--pyconfig.h.in6
-rw-r--r--setup.py1
9 files changed, 314 insertions, 16 deletions
diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst
index 2e5cae5..94863e1 100644
--- a/Doc/library/signal.rst
+++ b/Doc/library/signal.rst
@@ -39,12 +39,13 @@ rules for working with signals and their handlers:
* Some care must be taken if both signals and threads are used in the same
program. The fundamental thing to remember in using signals and threads
simultaneously is: always perform :func:`signal` operations in the main thread
- of execution. Any thread can perform an :func:`alarm`, :func:`getsignal`, or
- :func:`pause`; only the main thread can set a new signal handler, and the main
- thread will be the only one to receive signals (this is enforced by the Python
- :mod:`signal` module, even if the underlying thread implementation supports
- sending signals to individual threads). This means that signals can't be used
- as a means of inter-thread communication. Use locks instead.
+ of execution. Any thread can perform an :func:`alarm`, :func:`getsignal`,
+ :func:`pause`, :func:`setitimer` or :func:`getitimer`; only the main thread
+ can set a new signal handler, and the main thread will be the only one to
+ receive signals (this is enforced by the Python :mod:`signal` module, even
+ if the underlying thread implementation supports sending signals to
+ individual threads). This means that signals can't be used as a means of
+ inter-thread communication. Use locks instead.
The variables defined in the :mod:`signal` module are:
@@ -78,6 +79,36 @@ The variables defined in the :mod:`signal` module are:
One more than the number of the highest signal number.
+
+.. data:: ITIMER_REAL
+
+ Decrements interval timer in real time, and delivers SIGALRM upon expiration.
+
+
+.. data:: ITIMER_VIRTUAL
+
+ Decrements interval timer only when the process is executing, and delivers
+ SIGVTALRM upon expiration.
+
+
+.. data:: ITIMER_PROF
+
+ Decrements interval timer both when the process executes and when the
+ system is executing on behalf of the process. Coupled with ITIMER_VIRTUAL,
+ this timer is usually used to profile the time spent by the application
+ in user and kernel space. SIGPROF is delivered upon expiration.
+
+
+The :mod:`signal` module defines one exception:
+
+.. exception:: ItimerError
+
+ Raised to signal an error from the underlying :func:`setitimer` or
+ :func:`getitimer` implementation. Expect this error if an invalid
+ interval timer or a negative time is passed to :func:`setitimer`.
+ This error is a subtype of :exc:`IOError`.
+
+
The :mod:`signal` module defines the following functions:
@@ -110,6 +141,29 @@ The :mod:`signal` module defines the following functions:
:manpage:`signal(2)`.)
+.. function:: setitimer(which, seconds[, interval])
+
+ Sets given itimer (one of :const:`signal.ITIMER_REAL`,
+ :const:`signal.ITIMER_VIRTUAL` or :const:`signal.ITIMER_PROF`) especified
+ 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.
+
+ The old values are returned as a tuple: (delay, interval).
+
+ Attempting to pass an invalid interval timer will cause a
+ :exc:`ItimerError`.
+
+ .. versionadded:: 2.6
+
+
+.. function:: getitimer(which)
+
+ Returns current value of a given itimer especified by *which*.
+
+ .. versionadded:: 2.6
+
+
.. function:: set_wakeup_fd(fd)
Set the wakeup fd to *fd*. When a signal is received, a ``'\0'`` byte is
@@ -124,7 +178,6 @@ The :mod:`signal` module defines the following functions:
exception to be raised.
-
.. function:: siginterrupt(signalnum, flag)
Change system call restart behaviour: if *flag* is :const:`False`, system calls
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index 2834076..2cee626 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -258,9 +258,93 @@ class SiginterruptTest(unittest.TestCase):
i=self.readpipe_interrupted(lambda: signal.siginterrupt(self.signum, 0))
self.assertEquals(i, False)
+class ItimerTest(unittest.TestCase):
+ def setUp(self):
+ self.hndl_called = False
+ self.hndl_count = 0
+ self.itimer = None
+
+ def tearDown(self):
+ if self.itimer is not None: # test_itimer_exc doesn't change this attr
+ # just ensure that itimer is stopped
+ signal.setitimer(self.itimer, 0)
+
+ def sig_alrm(self, *args):
+ self.hndl_called = True
+ if test_support.verbose:
+ print("SIGALRM handler invoked", args)
+
+ def sig_vtalrm(self, *args):
+ self.hndl_called = True
+
+ if self.hndl_count > 3:
+ # it shouldn't be here, because it should have been disabled.
+ raise signal.ItimerError("setitimer didn't disable ITIMER_VIRTUAL "
+ "timer.")
+ elif self.hndl_count == 3:
+ # disable ITIMER_VIRTUAL, this function shouldn't be called anymore
+ signal.setitimer(signal.ITIMER_VIRTUAL, 0)
+ if test_support.verbose:
+ print("last SIGVTALRM handler call")
+
+ self.hndl_count += 1
+
+ if test_support.verbose:
+ print("SIGVTALRM handler invoked", args)
+
+ def sig_prof(self, *args):
+ self.hndl_called = True
+ signal.setitimer(signal.ITIMER_PROF, 0)
+
+ if test_support.verbose:
+ print("SIGPROF handler invoked", args)
+
+ def test_itimer_exc(self):
+ # XXX I'm assuming -1 is an invalid itimer, but maybe some platform
+ # defines it ?
+ self.assertRaises(signal.ItimerError, signal.setitimer, -1, 0)
+ # negative time
+ self.assertRaises(signal.ItimerError, signal.setitimer,
+ signal.ITIMER_REAL, -1)
+
+ def test_itimer_real(self):
+ self.itimer = signal.ITIMER_REAL
+ signal.signal(signal.SIGALRM, self.sig_alrm)
+ signal.setitimer(self.itimer, 1.0)
+ if test_support.verbose:
+ print("\ncall pause()...")
+ signal.pause()
+
+ self.assertEqual(self.hndl_called, True)
+
+ def test_itimer_virtual(self):
+ self.itimer = signal.ITIMER_VIRTUAL
+ signal.signal(signal.SIGVTALRM, self.sig_vtalrm)
+ signal.setitimer(self.itimer, 0.3, 0.2)
+
+ for i in range(100000000):
+ if signal.getitimer(self.itimer) == (0.0, 0.0):
+ break # sig_vtalrm handler stopped this itimer
+
+ # virtual itimer should be (0.0, 0.0) now
+ self.assertEquals(signal.getitimer(self.itimer), (0.0, 0.0))
+ # and the handler should have been called
+ self.assertEquals(self.hndl_called, True)
+
+ def test_itimer_prof(self):
+ self.itimer = signal.ITIMER_PROF
+ signal.signal(signal.SIGPROF, self.sig_prof)
+ signal.setitimer(self.itimer, 0.2)
+
+ for i in range(100000000):
+ if signal.getitimer(self.itimer) == (0.0, 0.0):
+ break # sig_prof handler stopped this itimer
+
+ self.assertEqual(self.hndl_called, True)
+
def test_main():
test_support.run_unittest(BasicSignalTests, InterProcessSignalTests,
- WakeupSignalTests, SiginterruptTest)
+ WakeupSignalTests, SiginterruptTest, ItimerTest)
if __name__ == "__main__":
diff --git a/Misc/ACKS b/Misc/ACKS
index dbc86df..7f6e3db 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -531,6 +531,7 @@ François Pinard
Zach Pincus
Michael Piotrowski
Antoine Pitrou
+Guilherme Polo
Michael Pomraning
Iustin Pop
John Popplewell
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index 18f1b52..9b7f7bb 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -13,6 +13,7 @@
#include <signal.h>
#include <sys/stat.h>
+#include <sys/time.h>
#ifndef SIG_ERR
#define SIG_ERR ((PyOS_sighandler_t)(-1))
@@ -93,6 +94,49 @@ static PyObject *IntHandler;
static PyOS_sighandler_t old_siginthandler = SIG_DFL;
+#ifdef HAVE_GETITIMER
+static PyObject *ItimerError;
+
+/* auxiliary functions for setitimer/getitimer */
+static void
+timeval_from_double(double d, struct timeval *tv)
+{
+ tv->tv_sec = floor(d);
+ tv->tv_usec = fmod(d, 1.0) * 1000000.0;
+}
+
+static inline double
+double_from_timeval(struct timeval *tv)
+{
+ return tv->tv_sec + (double)(tv->tv_usec / 1000000.0);
+}
+
+static PyObject *
+itimer_retval(struct itimerval *iv)
+{
+ PyObject *r, *v;
+
+ r = PyTuple_New(2);
+ if (r == NULL)
+ return NULL;
+
+ if(!(v = PyFloat_FromDouble(double_from_timeval(&iv->it_value)))) {
+ Py_DECREF(r);
+ return NULL;
+ }
+
+ PyTuple_SET_ITEM(r, 0, v);
+
+ if(!(v = PyFloat_FromDouble(double_from_timeval(&iv->it_interval)))) {
+ Py_DECREF(r);
+ return NULL;
+ }
+
+ PyTuple_SET_ITEM(r, 1, v);
+
+ return r;
+}
+#endif
static PyObject *
signal_default_int_handler(PyObject *self, PyObject *args)
@@ -347,11 +391,77 @@ PySignal_SetWakeupFd(int fd)
}
+#ifdef HAVE_SETITIMER
+static PyObject *
+signal_setitimer(PyObject *self, PyObject *args)
+{
+ double first;
+ double interval = 0;
+ int which;
+ struct itimerval new, old;
+
+ if(!PyArg_ParseTuple(args, "id|d:setitimer", &which, &first, &interval))
+ return NULL;
+
+ timeval_from_double(first, &new.it_value);
+ timeval_from_double(interval, &new.it_interval);
+ /* Let OS check "which" value */
+ if (setitimer(which, &new, &old) != 0) {
+ PyErr_SetFromErrno(ItimerError);
+ return NULL;
+ }
+
+ return itimer_retval(&old);
+}
+
+PyDoc_STRVAR(setitimer_doc,
+"setitimer(which, seconds[, interval])\n\
+\n\
+Sets given itimer (one of ITIMER_REAL, ITIMER_VIRTUAL\n\
+or ITIMER_PROF) to fire after value seconds and after\n\
+that every interval seconds.\n\
+The itimer can be cleared by setting seconds to zero.\n\
+\n\
+Returns old values as a tuple: (delay, interval).");
+#endif
+
+
+#ifdef HAVE_GETITIMER
+static PyObject *
+signal_getitimer(PyObject *self, PyObject *args)
+{
+ int which;
+ struct itimerval old;
+
+ if (!PyArg_ParseTuple(args, "i:getitimer", &which))
+ return NULL;
+
+ if (getitimer(which, &old) != 0) {
+ PyErr_SetFromErrno(ItimerError);
+ return NULL;
+ }
+
+ return itimer_retval(&old);
+}
+
+PyDoc_STRVAR(getitimer_doc,
+"getitimer(which)\n\
+\n\
+Returns current value of given itimer.");
+#endif
+
+
/* List of functions defined in the module */
static PyMethodDef signal_methods[] = {
#ifdef HAVE_ALARM
{"alarm", signal_alarm, METH_VARARGS, alarm_doc},
#endif
+#ifdef HAVE_SETITIMER
+ {"setitimer", signal_setitimer, METH_VARARGS, setitimer_doc},
+#endif
+#ifdef HAVE_GETITIMER
+ {"getitimer", signal_getitimer, METH_VARARGS, getitimer_doc},
+#endif
{"signal", signal_signal, METH_VARARGS, signal_doc},
{"getsignal", signal_getsignal, METH_VARARGS, getsignal_doc},
{"set_wakeup_fd", signal_set_wakeup_fd, METH_VARARGS, set_wakeup_fd_doc},
@@ -374,19 +484,32 @@ PyDoc_STRVAR(module_doc,
Functions:\n\
\n\
alarm() -- cause SIGALRM after a specified time [Unix only]\n\
+setitimer() -- cause a signal (described below) after a specified\n\
+ float time and the timer may restart then [Unix only]\n\
+getitimer() -- get current value of timer [Unix only]\n\
signal() -- set the action for a given signal\n\
getsignal() -- get the signal action for a given signal\n\
pause() -- wait until a signal arrives [Unix only]\n\
default_int_handler() -- default SIGINT handler\n\
\n\
-Constants:\n\
-\n\
+signal constants:\n\
SIG_DFL -- used to refer to the system default handler\n\
SIG_IGN -- used to ignore the signal\n\
NSIG -- number of defined signals\n\
-\n\
SIGINT, SIGTERM, etc. -- signal numbers\n\
\n\
+itimer constants:\n\
+ITIMER_REAL -- decrements in real time, and delivers SIGALRM upon\n\
+ expiration\n\
+ITIMER_VIRTUAL -- decrements only when the process is executing,\n\
+ and delivers SIGVTALRM upon expiration\n\
+ITIMER_PROF -- decrements both when the process is executing and\n\
+ when the system is executing on behalf of the process.\n\
+ Coupled with ITIMER_VIRTUAL, this timer is usually\n\
+ used to profile the time spent by the application\n\
+ in user and kernel space. SIGPROF is delivered upon\n\
+ expiration.\n\
+\n\n\
*** IMPORTANT NOTICE ***\n\
A signal handler function is called with two arguments:\n\
the first is the signal number, the second is the interrupted stack frame.");
@@ -639,6 +762,29 @@ initsignal(void)
PyDict_SetItemString(d, "SIGINFO", x);
Py_XDECREF(x);
#endif
+
+#ifdef ITIMER_REAL
+ x = PyLong_FromLong(ITIMER_REAL);
+ PyDict_SetItemString(d, "ITIMER_REAL", x);
+ Py_DECREF(x);
+#endif
+#ifdef ITIMER_VIRTUAL
+ x = PyLong_FromLong(ITIMER_VIRTUAL);
+ PyDict_SetItemString(d, "ITIMER_VIRTUAL", x);
+ Py_DECREF(x);
+#endif
+#ifdef ITIMER_PROF
+ x = PyLong_FromLong(ITIMER_PROF);
+ PyDict_SetItemString(d, "ITIMER_PROF", x);
+ Py_DECREF(x);
+#endif
+
+#if defined (HAVE_SETITIMER) || defined (HAVE_GETITIMER)
+ ItimerError = PyErr_NewException("signal.ItimerError",
+ PyExc_IOError, NULL);
+ PyDict_SetItemString(d, "ItimerError", ItimerError);
+#endif
+
if (!PyErr_Occurred())
return;
diff --git a/Tools/scripts/2to3 b/Tools/scripts/2to3
new file mode 100755
index 0000000..251c291
--- /dev/null
+++ b/Tools/scripts/2to3
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+from lib2to3 import refactor
+import sys
+
+sys.exit(refactor.main())
diff --git a/configure b/configure
index 3a4dc7c..7fa106f 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.in Revision: 61306 .
+# From configure.in Revision: 61728 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61 for python 3.0.
#
@@ -15719,8 +15719,10 @@ echo "${ECHO_T}MACHDEP_OBJS" >&6; }
-for ac_func in alarm bind_textdomain_codeset chown clock confstr \
- ctermid execv fchmod fchown fork fpathconf ftime ftruncate \
+
+
+for ac_func in alarm setitimer getitimer bind_textdomain_codeset chown \
+ clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \
gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \
getpriority getpwent getspnam getspent getsid getwd \
kill killpg lchmod lchown lstat mkfifo mknod mktime \
diff --git a/configure.in b/configure.in
index c1c25ff..664c965 100644
--- a/configure.in
+++ b/configure.in
@@ -2274,8 +2274,8 @@ fi
AC_MSG_RESULT(MACHDEP_OBJS)
# checks for library functions
-AC_CHECK_FUNCS(alarm bind_textdomain_codeset chown clock confstr \
- ctermid execv fchmod fchown fork fpathconf ftime ftruncate \
+AC_CHECK_FUNCS(alarm setitimer getitimer bind_textdomain_codeset chown \
+ clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \
gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \
getpriority getpwent getspnam getspent getsid getwd \
kill killpg lchmod lchown lstat mkfifo mknod mktime \
diff --git a/pyconfig.h.in b/pyconfig.h.in
index f533de2..732b8ff 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -240,6 +240,9 @@
/* Define this if you have the 6-arg version of gethostbyname_r(). */
#undef HAVE_GETHOSTBYNAME_R_6_ARG
+/* Define to 1 if you have the `getitimer' function. */
+#undef HAVE_GETITIMER
+
/* Define to 1 if you have the `getloadavg' function. */
#undef HAVE_GETLOADAVG
@@ -501,6 +504,9 @@
/* Define if you have the 'setgroups' function. */
#undef HAVE_SETGROUPS
+/* Define to 1 if you have the `setitimer' function. */
+#undef HAVE_SETITIMER
+
/* Define to 1 if you have the `setlocale' function. */
#undef HAVE_SETLOCALE
diff --git a/setup.py b/setup.py
index 2bfa91b..759a85c 100644
--- a/setup.py
+++ b/setup.py
@@ -1632,6 +1632,7 @@ def main():
# Scripts to install
scripts = ['Tools/scripts/pydoc', 'Tools/scripts/idle',
+ 'Tools/scripts/2to3',
'Lib/smtpd.py']
)