Author: Antonio Cuni <[email protected]>
Branch: gc-hooks
Changeset: r94248:df2490d5d814
Date: 2018-04-05 13:41 +0200
http://bitbucket.org/pypy/pypy/changeset/df2490d5d814/

Log:    argh, this was a bad bug: make sure to clear action._next after
        perform(), else the next time we put it in the queue, the ._next
        link will point to a spurious action

diff --git a/pypy/interpreter/executioncontext.py 
b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -430,6 +430,7 @@
 
     @rgc.no_collect
     def _fired_actions_append(self, action):
+        assert action._next is None
         if self._fired_actions_first is None:
             self._fired_actions_first = action
             self._fired_actions_last = action
@@ -494,7 +495,7 @@
                 while action is not None:
                     action._fired = False
                     action.perform(ec, frame)
-                    action = action._next
+                    action._next, action = None, action._next
 
         self.action_dispatcher = action_dispatcher
 
diff --git a/pypy/interpreter/test/test_executioncontext.py 
b/pypy/interpreter/test/test_executioncontext.py
--- a/pypy/interpreter/test/test_executioncontext.py
+++ b/pypy/interpreter/test/test_executioncontext.py
@@ -37,6 +37,37 @@
             pass
         assert i == 9
 
+    def test_action_queue(self):
+        events = []
+
+        class Action1(executioncontext.AsyncAction):
+            def perform(self, ec, frame):
+                events.append('one')
+        
+        class Action2(executioncontext.AsyncAction):
+            def perform(self, ec, frame):
+                events.append('two')
+
+        space = self.space
+        a1 = Action1(space)
+        a2 = Action2(space)
+        a1.fire()
+        a2.fire()
+        space.appexec([], """():
+            n = 5
+            return n + 2
+        """)
+        assert events == ['one', 'two']
+        #
+        events[:] = []
+        a1.fire()
+        space.appexec([], """():
+            n = 5
+            return n + 2
+        """)
+        assert events == ['one']
+
+
     def test_periodic_action(self):
         from pypy.interpreter.executioncontext import ActionFlag
 
diff --git a/pypy/module/gc/test/test_hook.py b/pypy/module/gc/test/test_hook.py
--- a/pypy/module/gc/test/test_hook.py
+++ b/pypy/module/gc/test/test_hook.py
@@ -21,9 +21,16 @@
         def fire_gc_collect(space, a, b, c, d, e, f):
             gchooks.fire_gc_collect(a, b, c, d, e, f)
 
+        @unwrap_spec(ObjSpace)
+        def fire_many(space):
+            gchooks.fire_gc_minor(0, 0)
+            gchooks.fire_gc_collect_step(0, 0)
+            gchooks.fire_gc_collect(1, 2, 3, 4, 5, 6)
+
         cls.w_fire_gc_minor = space.wrap(interp2app(fire_gc_minor))
         cls.w_fire_gc_collect_step = 
space.wrap(interp2app(fire_gc_collect_step))
         cls.w_fire_gc_collect = space.wrap(interp2app(fire_gc_collect))
+        cls.w_fire_many = space.wrap(interp2app(fire_many))
 
     def test_on_gc_minor(self):
         import gc
@@ -98,3 +105,19 @@
         assert S.STATE_SWEEPING == 2
         assert S.STATE_FINALIZING == 3
         assert S.GC_STATES == ('SCANNING', 'MARKING', 'SWEEPING', 'FINALIZING')
+
+    def test_clear_queue(self):
+        import gc
+        lst = []
+        def on_gc_minor(stats):        lst.append('minor')
+        def on_gc_collect_step(stats): lst.append('step')
+        def on_gc_collect(stats):      lst.append('collect')
+        gc.set_hooks(on_gc_minor=on_gc_minor,
+                     on_gc_collect_step=on_gc_collect_step,
+                     on_gc_collect=on_gc_collect)
+        #
+        self.fire_many()
+        assert lst == ['minor', 'step', 'collect']
+        lst[:] = []
+        self.fire_gc_minor(0, 0)
+        assert lst == ['minor']
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to