[pypy-svn] r56149 - in pypy/branch/async-del/pypy/module/thread: . test

arigo at codespeak.net arigo at codespeak.net
Sat Jun 28 13:03:58 CEST 2008


Author: arigo
Date: Sat Jun 28 13:03:57 2008
New Revision: 56149

Modified:
   pypy/branch/async-del/pypy/module/thread/gil.py
   pypy/branch/async-del/pypy/module/thread/test/test_ll_thread.py
Log:
Fix the test.  Threads are not fun.


Modified: pypy/branch/async-del/pypy/module/thread/gil.py
==============================================================================
--- pypy/branch/async-del/pypy/module/thread/gil.py	(original)
+++ pypy/branch/async-del/pypy/module/thread/gil.py	Sat Jun 28 13:03:57 2008
@@ -101,3 +101,10 @@
     spacestate.after_thread_switch()
     set_errno(e)
 after_external_call._gctransformer_hint_cannot_collect_ = True
+
+# The _gctransformer_hint_cannot_collect_ hack is needed for
+# translations in which the *_external_call() functions are not inlined.
+# They tell the gctransformer not to save and restore the local GC
+# pointers in the shadow stack.  This is necessary because the GIL is
+# not held after the call to before_external_call() or before the call
+# to after_external_call().

Modified: pypy/branch/async-del/pypy/module/thread/test/test_ll_thread.py
==============================================================================
--- pypy/branch/async-del/pypy/module/thread/test/test_ll_thread.py	(original)
+++ pypy/branch/async-del/pypy/module/thread/test/test_ll_thread.py	Sat Jun 28 13:03:57 2008
@@ -7,7 +7,8 @@
 def setup_module(mod):
     # Hack to avoid a deadlock if the module is run after other test files :-(
     # In this module, we assume that ll_thread.start_new_thread() is not
-    # providing us with a GIL equivalent.
+    # providing us with a GIL equivalent, except in test_gc_locking
+    # which installs its own aroundstate.
     rffi.aroundstate._freeze_()
 
 def test_lock():
@@ -89,6 +90,9 @@
 
     def test_gc_locking(self):
         import time
+        from pypy.rlib.objectmodel import invoke_around_extcall
+        from pypy.rlib.objectmodel import we_are_translated
+        from pypy.rlib.debug import ll_assert
 
         class State:
             pass
@@ -102,63 +106,82 @@
                 j = self.j
                 if self.i > 1:
                     g(self.i-1, self.j * 2)
-                    assert j == self.j
+                    ll_assert(j == self.j, "1: bad j")
                     g(self.i-2, self.j * 2 + 1)
                 else:
                     if len(state.answers) % 7 == 5:
                         gc.collect()
                     state.answers.append(self.j)
-                assert j == self.j
+                ll_assert(j == self.j, "2: bad j")
             run._dont_inline_ = True
 
-        def bootstrap():
+        def before_extcall():
+            release_NOAUTO(state.gil)
+        before_extcall._gctransformer_hint_cannot_collect_ = True
+        # ^^^ see comments in gil.py about this hint
+
+        def after_extcall():
             acquire_NOAUTO(state.gil, True)
             gc_thread_run()
+        after_extcall._gctransformer_hint_cannot_collect_ = True
+        # ^^^ see comments in gil.py about this hint
+
+        def bootstrap():
+            # after_extcall() is called before we arrive here.
+            # We can't just acquire and release the GIL manually here,
+            # because it is unsafe: bootstrap() is called from a rffi
+            # callback which checks for and reports exceptions after
+            # bootstrap() returns.  The exception checking code must be
+            # protected by the GIL too.
             z = state.z
             state.z = None
+            state.bootstrapping.release()
             z.run()
             gc_thread_die()
-            release_NOAUTO(state.gil)
+            # before_extcall() is called after we leave here
 
         def g(i, j):
+            state.bootstrapping.acquire(True)
             state.z = Z(i, j)
             gc_thread_prepare()
             start_new_thread(bootstrap, ())
-            # now wait until the new thread really started and consumed 'z'
-            willing_to_wait_more = 1000
-            while state.z is not None:
-                assert willing_to_wait_more > 0
-                willing_to_wait_more -= 1
-                release_NOAUTO(state.gil)
-                time.sleep(0.005)
-                acquire_NOAUTO(state.gil, True)
-                gc_thread_run()
 
         def f():
             state.gil = allocate_ll_lock()
             acquire_NOAUTO(state.gil, True)
+            state.bootstrapping = allocate_lock()
             state.answers = []
             state.finished = 0
-            g(7, 1)
+            # the next line installs before_extcall() and after_extcall()
+            # to be called automatically around external function calls.
+            # When not translated it does not work around time.sleep(),
+            # so we have to call them manually for this test.
+            invoke_around_extcall(before_extcall, after_extcall)
+
+            g(10, 1)
             done = False
-            willing_to_wait_more = 1000
+            willing_to_wait_more = 2000
             while not done:
                 if not willing_to_wait_more:
-                    raise Exception("didn't get enough answers: got %d,"
-                                    " expected %d" % (len(state.answers),
-                                                      expected))
+                    break
                 willing_to_wait_more -= 1
                 done = len(state.answers) == expected
-                release_NOAUTO(state.gil)
+
+                if not we_are_translated(): before_extcall()
                 time.sleep(0.01)
-                acquire_NOAUTO(state.gil, True)
-                gc_thread_run()
-            release_NOAUTO(state.gil)
+                if not we_are_translated(): after_extcall()
+
+            if not we_are_translated(): before_extcall()
             time.sleep(0.1)
+            if not we_are_translated(): after_extcall()
+
             return len(state.answers)
 
-        expected = 21
-        fn = self.getcompiled(f, [])
+        expected = 89
+        try:
+            fn = self.getcompiled(f, [])
+        finally:
+            rffi.aroundstate._freeze_()
         answers = fn()
         assert answers == expected
 



More information about the Pypy-commit mailing list