[pypy-commit] pypy default: a failing test for the signals_enabled context manager's fork logic

bdkearns noreply at buildbot.pypy.org
Sat Feb 16 09:41:50 CET 2013


Author: Brian Kearns <bdkearns at gmail.com>
Branch: 
Changeset: r61304:320c4790eae6
Date: 2013-02-16 02:26 -0500
http://bitbucket.org/pypy/pypy/changeset/320c4790eae6/

Log:	a failing test for the signals_enabled context manager's fork logic

diff --git a/pypy/module/__pypy__/test/test_signal.py b/pypy/module/__pypy__/test/test_signal.py
--- a/pypy/module/__pypy__/test/test_signal.py
+++ b/pypy/module/__pypy__/test/test_signal.py
@@ -1,5 +1,7 @@
 import sys
 
+from pypy.module.thread.test.support import GenericTestThread
+
 
 class AppTestMinimal:
     spaceconfig = dict(usemodules=['__pypy__'])
@@ -11,7 +13,7 @@
         # assert did not crash
 
 
-class AppTestThreadSignal:
+class AppTestThreadSignal(GenericTestThread):
     spaceconfig = dict(usemodules=['__pypy__', 'thread', 'signal', 'time'])
 
     def test_enable_signals(self):
@@ -48,6 +50,37 @@
             finally:
                 __pypy__.thread._signals_enter()
 
+    def test_thread_fork_signals(self):
+        import __pypy__
+        import os, thread, signal
+
+        if not hasattr(os, 'fork'):
+            skip("No fork on this platform")
+
+        def fork():
+            with __pypy__.thread.signals_enabled:
+                return os.fork()
+
+        def threadfunction():
+            pid = fork()
+            if pid == 0:
+                print 'in child'
+                # signal() only works from the 'main' thread
+                signal.signal(signal.SIGUSR1, signal.SIG_IGN)
+                os._exit(42)
+            else:
+                self.timeout_killer(pid, 5)
+                exitcode = os.waitpid(pid, 0)[1]
+                feedback.append(exitcode)
+
+        feedback = []
+        thread.start_new_thread(threadfunction, ())
+        self.waitfor(lambda: feedback)
+        # if 0, an (unraisable) exception was raised from the forked thread.
+        # if 9, process was killed by timer.
+        # if 42<<8, os._exit(42) was correctly reached.
+        assert feedback == [42<<8]
+
 
 class AppTestThreadSignalLock:
     spaceconfig = dict(usemodules=['__pypy__', 'thread', 'signal'])
diff --git a/pypy/module/thread/threadlocals.py b/pypy/module/thread/threadlocals.py
--- a/pypy/module/thread/threadlocals.py
+++ b/pypy/module/thread/threadlocals.py
@@ -81,6 +81,16 @@
         # (which are now dead); and for the current thread, force an
         # enable_signals() if necessary.  That's a hack but I cannot
         # figure out a non-hackish way to handle thread+signal+fork :-(
+        """
+        TODO: this logic is currently flawed as we need to differentiate
+        between: 1) fork while in a main thread, in which case old should
+                    not be incremented
+                 2) fork while in a subthread that has an enable_threads
+                    context but is not main (in which case old should be
+                    incremented, as the thread should get a point for becoming
+                    the new 'main', so it remains in the dict when all its
+                    contexts exit)
+        """
         ident = rthread.get_ident()
         old = self._signalsenabled.get(ident, 0)
         self._signalsenabled.clear()


More information about the pypy-commit mailing list