[pypy-commit] pypy stmgc-c7: Fight fight until I can reliably get a failure mode for weakrefs

arigo noreply at buildbot.pypy.org
Mon Feb 2 23:38:59 CET 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c7
Changeset: r75670:5b9137e56e6b
Date: 2015-02-02 23:38 +0100
http://bitbucket.org/pypy/pypy/changeset/5b9137e56e6b/

Log:	Fight fight until I can reliably get a failure mode for weakrefs

diff --git a/pypy/module/pypystm/test_pypy_c/support.py b/pypy/module/pypystm/test_pypy_c/support.py
--- a/pypy/module/pypystm/test_pypy_c/support.py
+++ b/pypy/module/pypystm/test_pypy_c/support.py
@@ -8,27 +8,66 @@
     HEADER = """
 import thread, pypystm
 
-def _run(lock, result, function, args):
+NUM_THREADS = 3
+
+_b_to_go = NUM_THREADS
+_b_done = False
+_b_lock = thread.allocate_lock()
+_b_locks = [thread.allocate_lock() for _i in range(NUM_THREADS)]
+for _bl in _b_locks:
+    _bl.acquire()
+
+class BarrierThreadsDone(Exception):
+    pass
+
+def barrier(tnum, done=False):
+    '''Waits until NUM_THREADS call this function, and then returns
+    in all these threads at once.'''
+    global _b_to_go, _b_done
+    _b_lock.acquire()
+    if done:
+        _b_done = True
+    _b_to_go -= 1
+    if _b_to_go > 0:
+        _b_lock.release()
+        _b_locks[tnum].acquire()
+    else:
+        _b_to_go = NUM_THREADS
+        for i in range(NUM_THREADS):
+            if i != tnum:
+                _b_locks[i].release()
+        _b_lock.release()
+    if _b_done:
+        raise BarrierThreadsDone
+
+def _run(tnum, lock, result, function, args):
     start = pypystm.time()
     try:
-        while True:
-            function(*args)
-            if pypystm.time() - start >= 3.0:
-                break
+        try:
+            while True:
+                function(*args)
+                if pypystm.time() - start >= 3.0:
+                    break
+        except BarrierThreadsDone:
+            pass
         result.append(1)
     finally:
         lock.release()
+    while len(result) != NUM_THREADS:
+        barrier(tnum, done=True)
 
-def run_in_threads(function, arg_thread_num=False):
+def run_in_threads(function, arg_thread_num=False, arg_class=None):
     locks = []
     result = []
-    for i in range(3):
+    for i in range(NUM_THREADS):
         lock = thread.allocate_lock()
         lock.acquire()
         args = ()
         if arg_thread_num:
             args += (i,)
-        thread.start_new_thread(_run, (lock, result, function, args))
+        if arg_class:
+            args += (arg_class(),)
+        thread.start_new_thread(_run, (i, lock, result, function, args))
         locks.append(lock)
     for lock in locks:
         lock._py3k_acquire(timeout=30)
@@ -98,6 +137,10 @@
         count = self._check_count_conflicts(*args)
         assert count < 500
 
-    def check_many_conflicts(self, *args):
+    def check_MANY_conflicts(self, *args):
         count = self._check_count_conflicts(*args)
         assert count > 20000
+
+    def check_SOME_conflicts(self, *args):
+        count = self._check_count_conflicts(*args)
+        assert count > 1000
diff --git a/pypy/module/pypystm/test_pypy_c/test_conflict.py b/pypy/module/pypystm/test_pypy_c/test_conflict.py
--- a/pypy/module/pypystm/test_pypy_c/test_conflict.py
+++ b/pypy/module/pypystm/test_pypy_c/test_conflict.py
@@ -13,7 +13,7 @@
                 x.a += 1
             run_in_threads(g)
         #
-        self.check_many_conflicts(f)
+        self.check_MANY_conflicts(f)
 
     def test_plain_dict_access(self):
         def f():
@@ -22,4 +22,25 @@
                 d[n] = d.get(n, 0) + 1
             run_in_threads(g, arg_thread_num=True)
         #
-        self.check_many_conflicts(f)
+        self.check_MANY_conflicts(f)
+
+    def test_write_to_many_objects_in_order(self):
+        def f():
+            import weakref
+
+            class X(object):
+                pass
+
+            lst = []     # shared
+
+            def g(tnum):
+                if tnum == 0:
+                    lst[:] = [X() for i in range(1000)]
+                barrier(tnum)
+                for x in lst:
+                    x.a = 5
+                barrier(tnum)
+
+            run_in_threads(g, arg_thread_num=True)
+        #
+        self.check_SOME_conflicts(f)
diff --git a/pypy/module/pypystm/test_pypy_c/test_no_conflict.py b/pypy/module/pypystm/test_pypy_c/test_no_conflict.py
--- a/pypy/module/pypystm/test_pypy_c/test_no_conflict.py
+++ b/pypy/module/pypystm/test_pypy_c/test_no_conflict.py
@@ -1,3 +1,4 @@
+import py
 from pypy.module.pypystm.test_pypy_c.support import BaseTestSTM
 
 
@@ -27,3 +28,25 @@
             run_in_threads(g, arg_thread_num=True)
         #
         self.check_almost_no_conflict(f)
+
+    def test_weakrefs(self):
+        py.test.skip("next issue")
+        def f():
+            import weakref
+
+            class X(object):
+                pass
+
+            lst = []     # shared
+
+            def g(tnum):
+                if tnum == 0:
+                    lst[:] = [X() for i in range(1000)]
+                barrier(tnum)
+                for x in lst:
+                    weakref.ref(x)
+                barrier(tnum)
+
+            run_in_threads(g, arg_thread_num=True)
+        #
+        self.check_almost_no_conflict(f)


More information about the pypy-commit mailing list