Commits

Armin Rigo committed 80d054b

Test and fix for "Ambiguous low-level helper specialization" when
the same RPython program contains several calls to start_new_thread().

Comments (0)

Files changed (2)

pypy/module/thread/ll_thread.py

 import py
 from pypy.rlib import jit, rgc
 from pypy.rlib.debug import ll_assert
-from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.objectmodel import we_are_translated, specialize
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.tool import rffi_platform
 from pypy.tool import autopath
 def allocate_lock():
     return Lock(allocate_ll_lock())
 
+@specialize.arg(0)
 def ll_start_new_thread(func):
     ident = c_thread_start(func)
     if ident == -1:
 def get_ident():
     return rffi.cast(lltype.Signed, c_thread_get_ident())
 
+@specialize.arg(0)
 def start_new_thread(x, y):
     """In RPython, no argument can be passed.  You have to use global
     variables to pass information to the new thread.  That's not very

pypy/module/thread/test/test_ll_thread.py

     use_threads = True
 
     def test_start_new_thread(self):
-        py.test.skip("xxx ideally, investigate why it fails randomly")
-        # xxx but in practice start_new_thread() is also tested by the
-        # next test, and it's a mess to test start_new_thread() without
-        # the proper GIL to protect the GC
         import time
 
         class State:
             pass
         state = State()
 
-        class Z:
-            def __init__(self, value):
-                self.value = value
-            def __del__(self):
-                state.freed_counter += 1
-
-        def bootstrap():
-            state.my_thread_ident = state.z.ident = get_ident()
-            assert state.my_thread_ident == get_ident()
-            assert get_ident() == state.z.ident
-            state.seen_value = state.z.value
-            state.z = None
-            # I think that we would need here a memory barrier in order
-            # to make the test pass reliably.  The issue is that the
-            # main thread may see 'state.done = 1' before seeing the
-            # effect of the other assignments done above.  For now let's
-            # emulate the write barrier by doing a system call and
-            # waiting a bit...
-            time.sleep(0.012)
-            state.done = 1
-
-        def g(i):
-            state.z = Z(i)
-            return start_new_thread(bootstrap, ())
-        g._dont_inline_ = True
+        def bootstrap1():
+            state.my_thread_ident1 = get_ident()
+        def bootstrap2():
+            state.my_thread_ident2 = get_ident()
 
         def f():
-            main_ident = get_ident()
-            assert main_ident == get_ident()
-            state.freed_counter = 0
-            for i in range(50):
-                state.done = 0
-                state.seen_value = 0
-                ident = g(i)
-                gc.collect()
-                willing_to_wait_more = 1000
-                while not state.done:
-                    willing_to_wait_more -= 1
-                    if not willing_to_wait_more:
-                        raise Exception("thread didn't start?")
-                    time.sleep(0.01)
-                assert state.my_thread_ident != main_ident
-                assert state.my_thread_ident == ident
-                assert state.seen_value == i
-            # try to force Boehm to do some freeing
-            for i in range(3):
-                gc.collect()
-            return state.freed_counter
+            state.my_thread_ident1 = get_ident()
+            state.my_thread_ident2 = get_ident()
+            start_new_thread(bootstrap1, ())
+            start_new_thread(bootstrap2, ())
+            willing_to_wait_more = 1000
+            while (state.my_thread_ident1 == get_ident() or
+                   state.my_thread_ident2 == get_ident()):
+                willing_to_wait_more -= 1
+                if not willing_to_wait_more:
+                    raise Exception("thread didn't start?")
+                time.sleep(0.01)
+            return 42
 
         fn = self.getcompiled(f, [])
-        freed_counter = fn()
-        print freed_counter
-        if self.gcpolicy == 'boehm':
-            assert freed_counter > 0
-        else:
-            assert freed_counter == 50
+        res = fn()
+        assert res == 42
 
     def test_gc_locking(self):
         import time