[Python-3000-checkins] r61848 - in python/branches/py3k: Doc/library/signal.rst Lib/test/test_signal.py Misc/ACKS Modules/signalmodule.c Tools/scripts/2to3 configure configure.in pyconfig.h.in setup.py

martin.v.loewis python-3000-checkins at python.org
Mon Mar 24 14:39:55 CET 2008


Author: martin.v.loewis
Date: Mon Mar 24 14:39:54 2008
New Revision: 61848

Added:
   python/branches/py3k/Tools/scripts/2to3
      - copied unchanged from r61847, python/trunk/Tools/scripts/2to3
Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Doc/library/signal.rst
   python/branches/py3k/Lib/test/test_signal.py
   python/branches/py3k/Misc/ACKS
   python/branches/py3k/Modules/signalmodule.c
   python/branches/py3k/configure
   python/branches/py3k/configure.in
   python/branches/py3k/pyconfig.h.in
   python/branches/py3k/setup.py
Log:
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.
........


Modified: python/branches/py3k/Doc/library/signal.rst
==============================================================================
--- python/branches/py3k/Doc/library/signal.rst	(original)
+++ python/branches/py3k/Doc/library/signal.rst	Mon Mar 24 14:39:54 2008
@@ -39,12 +39,13 @@
 * 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 @@
 
    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 @@
    :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 @@
    exception to be raised.
 
 
-
 .. function:: siginterrupt(signalnum, flag)
 
    Change system call restart behaviour: if *flag* is :const:`False`, system calls

Modified: python/branches/py3k/Lib/test/test_signal.py
==============================================================================
--- python/branches/py3k/Lib/test/test_signal.py	(original)
+++ python/branches/py3k/Lib/test/test_signal.py	Mon Mar 24 14:39:54 2008
@@ -258,9 +258,93 @@
         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__":

Modified: python/branches/py3k/Misc/ACKS
==============================================================================
--- python/branches/py3k/Misc/ACKS	(original)
+++ python/branches/py3k/Misc/ACKS	Mon Mar 24 14:39:54 2008
@@ -531,6 +531,7 @@
 Zach Pincus
 Michael Piotrowski
 Antoine Pitrou
+Guilherme Polo
 Michael Pomraning
 Iustin Pop
 John Popplewell

Modified: python/branches/py3k/Modules/signalmodule.c
==============================================================================
--- python/branches/py3k/Modules/signalmodule.c	(original)
+++ python/branches/py3k/Modules/signalmodule.c	Mon Mar 24 14:39:54 2008
@@ -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 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 @@
 }
 
 
+#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 @@
 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 @@
 	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;
 

Modified: python/branches/py3k/configure
==============================================================================
--- python/branches/py3k/configure	(original)
+++ python/branches/py3k/configure	Mon Mar 24 14:39:54 2008
@@ -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 @@
 
 
 
-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 \

Modified: python/branches/py3k/configure.in
==============================================================================
--- python/branches/py3k/configure.in	(original)
+++ python/branches/py3k/configure.in	Mon Mar 24 14:39:54 2008
@@ -2274,8 +2274,8 @@
 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 \

Modified: python/branches/py3k/pyconfig.h.in
==============================================================================
--- python/branches/py3k/pyconfig.h.in	(original)
+++ python/branches/py3k/pyconfig.h.in	Mon Mar 24 14:39:54 2008
@@ -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
 

Modified: python/branches/py3k/setup.py
==============================================================================
--- python/branches/py3k/setup.py	(original)
+++ python/branches/py3k/setup.py	Mon Mar 24 14:39:54 2008
@@ -1632,6 +1632,7 @@
 
           # Scripts to install
           scripts = ['Tools/scripts/pydoc', 'Tools/scripts/idle',
+                     'Tools/scripts/2to3',
                      'Lib/smtpd.py']
         )
 


More information about the Python-3000-checkins mailing list