[issue12625] sporadic test_unittest failure

Charles-François Natali report at bugs.python.org
Sun Jul 24 14:32:31 CEST 2011


Charles-François Natali <neologix at free.fr> added the comment:

> No, it's a feature of the new GIL.

When I look at 2.7's code, I see something different - _Py_Ticker is
reset in Py_AddPendingCall():

int
Py_AddPendingCall(int (*func)(void *), void *arg)
{
[...]
    /* signal main loop */
    _Py_Ticker = 0;
    pendingcalls_to_do = 1;
[...]
}

And there's a comment in the main eval loop which confirms this:
        /* Do periodic things.  Doing this every time through
           the loop would add too much overhead, so we do it
           only every Nth instruction.  We also do it if
           ``pendingcalls_to_do'' is set, i.e. when an asynchronous
           event needs attention (e.g. a signal handler or
           async I/O handler); see Py_AddPendingCall() and
           Py_MakePendingCalls() above. */

So, AFAICT, signal handlers will get called right away (and if I
remove the _Py_Ticker reset from Py_AddPendingCall(), then those tests
fail consistently on Linux).
Or am I missing something?

Concerning the original problem, here's a patch implementing the second idea:
- getpid() is called after each kill(getpid(), <signum>), to "force"
the signal delivery
- the test is now re-enabled on FreeBSD6

I think this should fx the problem on both FreeBSD6 and OpenSolaris,
but since I don't have a FreeBSD or OpenSolaris box at hand, I
couldn't test it. Shall I try to commit it and see what the buildbots
say?

----------
Added file: http://bugs.python.org/file22743/kill_delayed_signal.diff

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue12625>
_______________________________________
-------------- next part --------------
diff -r cda93720c06d Lib/unittest/test/test_break.py
--- a/Lib/unittest/test/test_break.py	Sat Jul 23 18:15:43 2011 +0200
+++ b/Lib/unittest/test/test_break.py	Sun Jul 24 14:23:32 2011 +0200
@@ -10,8 +10,6 @@
 
 @unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill")
 @unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows")
- at unittest.skipIf(sys.platform == 'freebsd6', "Test kills regrtest on freebsd6 "
-    "if threads have been used")
 class TestBreak(unittest.TestCase):
 
     def setUp(self):
@@ -29,8 +27,15 @@
         self.assertNotEqual(signal.getsignal(signal.SIGINT), default_handler)
 
         try:
+            # When a process sends a signal to itself, POSIX states that the
+            # signal must be delivered before the kill() syscall returns. Some
+            # operating systems are known to delay signal delivery in this
+            # situation (see issues #12625, #8263 and #12469): to force the
+            # signal's delivery, we make a dummy getpid() syscall (signals are
+            # typically delivered when the process returns to user-space).
             pid = os.getpid()
             os.kill(pid, signal.SIGINT)
+            os.getpid()
         except KeyboardInterrupt:
             self.fail("KeyboardInterrupt not handled")
 
@@ -61,6 +66,7 @@
         def test(result):
             pid = os.getpid()
             os.kill(pid, signal.SIGINT)
+            os.getpid()
             result.breakCaught = True
             self.assertTrue(result.shouldStop)
 
@@ -79,9 +85,11 @@
         def test(result):
             pid = os.getpid()
             os.kill(pid, signal.SIGINT)
+            os.getpid()
             result.breakCaught = True
             self.assertTrue(result.shouldStop)
             os.kill(pid, signal.SIGINT)
+            os.getpid()
             self.fail("Second KeyboardInterrupt not raised")
 
         try:
@@ -109,6 +117,7 @@
         def test(result):
             pid = os.getpid()
             os.kill(pid, signal.SIGINT)
+            os.getpid()
 
         try:
             test(result)
@@ -134,6 +143,7 @@
         try:
             pid = os.getpid()
             os.kill(pid, signal.SIGINT)
+            os.getpid()
         except KeyboardInterrupt:
             pass
         else:
@@ -173,6 +183,7 @@
         try:
             pid = os.getpid()
             os.kill(pid, signal.SIGINT)
+            os.getpid()
         except KeyboardInterrupt:
             pass
 


More information about the Python-bugs-list mailing list