[pypy-svn] pypy default: Fix siginterrupt(). Previously, the state would be reset

arigo commits-noreply at bitbucket.org
Sun Feb 13 11:25:38 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r41870:a944602ffc05
Date: 2011-02-13 11:25 +0100
http://bitbucket.org/pypy/pypy/changeset/a944602ffc05/

Log:	Fix siginterrupt(). Previously, the state would be reset to default
	after the first time the signal was received.

diff --git a/pypy/module/signal/test/test_signal.py b/pypy/module/signal/test/test_signal.py
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -197,11 +197,35 @@
         signal.signal(signal.SIGUSR1, signal.SIG_DFL)
 
     def test_siginterrupt(self):
-        import signal
+        import signal, os, time
         signum = signal.SIGUSR1
+        def readpipe_is_not_interrupted():
+            # from CPython's test_signal.readpipe_interrupted()
+            r, w = os.pipe()
+            ppid = os.getpid()
+            pid = os.fork()
+            if pid == 0:
+                try:
+                    time.sleep(1)
+                    os.kill(ppid, signum)
+                    time.sleep(1)
+                finally:
+                    os._exit(0)
+            else:
+                try:
+                    os.close(w)
+                    # we expect not to be interrupted.  If we are, the
+                    # following line raises OSError(EINTR).
+                    os.read(r, 1)
+                finally:
+                    os.waitpid(pid, 0)
+                    os.close(r)
+        #
         oldhandler = signal.signal(signum, lambda x,y: None)
         try:
             signal.siginterrupt(signum, 0)
+            readpipe_is_not_interrupted()
+            readpipe_is_not_interrupted()
         finally:
             signal.signal(signum, oldhandler)
 

diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -35,6 +35,7 @@
     include_dirs = [str(py.path.local(autopath.pypydir).join('translator', 'c'))],
     export_symbols = ['pypysig_poll', 'pypysig_default',
                       'pypysig_ignore', 'pypysig_setflag',
+                      'pypysig_reinstall',
                       'pypysig_set_wakeup_fd',
                       'pypysig_getaddr_occurred'],
 )
@@ -65,6 +66,7 @@
 pypysig_ignore = external('pypysig_ignore', [rffi.INT], lltype.Void)
 pypysig_default = external('pypysig_default', [rffi.INT], lltype.Void)
 pypysig_setflag = external('pypysig_setflag', [rffi.INT], lltype.Void)
+pypysig_reinstall = external('pypysig_reinstall', [rffi.INT], lltype.Void)
 pypysig_set_wakeup_fd = external('pypysig_set_wakeup_fd', [rffi.INT], rffi.INT)
 pypysig_poll = external('pypysig_poll', [], rffi.INT, threadsafe=False)
 # don't bother releasing the GIL around a call to pypysig_poll: it's
@@ -150,7 +152,7 @@
         except KeyError:
             return    # no handler, ignore signal
         # re-install signal handler, for OSes that clear it
-        pypysig_setflag(n)
+        pypysig_reinstall(n)
         # invoke the app-level handler
         space = self.space
         ec = space.getexecutioncontext()

diff --git a/pypy/translator/c/src/signals.h b/pypy/translator/c/src/signals.h
--- a/pypy/translator/c/src/signals.h
+++ b/pypy/translator/c/src/signals.h
@@ -143,6 +143,21 @@
 #endif
 }
 
+void pypysig_reinstall(int signum)
+{
+#ifdef SA_RESTART
+    /* Assume sigaction was used.  We did not pass SA_RESETHAND to
+       sa_flags, so there is nothing to do here. */
+#else
+# ifdef SIGCHLD
+    /* To avoid infinite recursion, this signal remains
+       reset until explicitly re-instated.  (Copied from CPython) */
+    if (signum != SIGCHLD)
+# endif
+    pypysig_setflag(signum);
+#endif
+}
+
 int pypysig_poll(void)
 {
   if (pypysig_occurred)


More information about the Pypy-commit mailing list