Fix a pendning children and side effects bug sandbox/pcoval/on/master/review
authorPhilippe Coval <philippe.coval@osg.samsung.com>
Sun, 27 Aug 2017 13:10:01 +0000 (15:10 +0200)
committerPhilippe Coval <philippe.coval@osg.samsung.com>
Tue, 10 Oct 2017 09:24:00 +0000 (11:24 +0200)
Bug: http://scons.tigris.org/issues/show_bug.cgi?id=2777O
Change-Id: Iafa328a0430c675d52cdba50e6984e4c3e74e29e
Credit-to: Emil Stanchev <estanchev@tigris.org>
Origin: http://scons.tigris.org/nonav/issues/showattachment.cgi/894/Fix-a-pending-children-and-side-effects-bug_v3.patch

src/engine/SCons/Taskmaster.py
src/engine/SCons/TaskmasterTests.py

index 17507a6ff15381980db220590cbaa990efebc809..b77c375a06fed294dc0cf6b9bf81ad78d3402851 100644 (file)
@@ -1016,6 +1016,27 @@ class Taskmaster(object):
                 to_visit = to_visit | parents
                 pending_children = pending_children - parents
 
+                # Clean up the other branches of side effect
+                for se in node.get_side_effects():
+                    waiting_s_e = se.get_waiting_s_e()
+                    pending_children = pending_children - waiting_s_e
+                    stack = set(waiting_s_e)
+                    if T:
+                        for n in waiting_s_e:
+                            T.write(self.trace_message('       removing side effect parent %s from the pending children set\n' %
+                                    self.trace_node(n)))
+                    while stack:
+                        n = stack.pop()
+                        waiting_parents = n.waiting_parents
+                        n.waiting_parents = set()
+                        stack = stack | waiting_parents
+                        pending_children = pending_children - waiting_parents
+
+                    for p in waiting_parents:
+                        p.ref_count = p.ref_count - 1
+                        if T: T.write(self.trace_message('       removing parent %s from the pending children set\n' %
+                                                           self.trace_node(p)))
+
                 for p in parents:
                     p.ref_count = p.ref_count - 1
                     if T: T.write(self.trace_message('       removing parent %s from the pending children set\n' %
index d237d60a8ebcba51e3a920a4ed1ae2207f2d2163..430b56d00461f661337028a54508aa928fd95a68 100644 (file)
@@ -34,6 +34,7 @@ import TestUnit
 
 import SCons.Taskmaster
 import SCons.Errors
+import SCons.Job
 
 
 built_text = None
@@ -181,8 +182,17 @@ class Node(object):
         wp.add(node)
         return 1
 
+    def add_to_waiting_s_e(self, node):
+        self.waiting_s_e.add(node)
+    
     def get_state(self):
         return self.state
+    
+    def get_side_effects(self):
+        return self.side_effects
+
+    def get_waiting_s_e(self):
+        return self.waiting_s_e
 
     def set_state(self, state):
         self.state = state
@@ -235,7 +245,7 @@ class Node(object):
                 def get_all_prerequisites(self):
                     return []
                 def get_action_side_effects(self):
-                    return []
+                    return [se for t in self.targets for se in t.side_effects]
             self.executor = Executor()
             self.executor.targets = self.targets
         return self.executor
@@ -1007,6 +1017,26 @@ class TaskmasterTestCase(unittest.TestCase):
         t.execute()
         assert built_text is None, built_text
         assert cache_text == ["n7 retrieved", "n8 retrieved"], cache_text
+    
+    def test_pending_children_side_effects(self):
+        n1 = Node("n1")
+        n2 = Node("n2")
+        n3 = Node("n3")
+        n4 = Node("n4")
+        side_effect = Node("se")
+
+        def build_error():
+            import time; time.sleep(2)
+            raise SystemError("Node failed.")
+        n1.build = build_error
+        n1.side_effects = [side_effect]
+        n2.side_effects = [side_effect]
+
+        n3.kids = [n2]
+        n4.kids = [n1, n2, n3]
+        tm = SCons.Taskmaster.Taskmaster([n4])
+        jobs = SCons.Job.Jobs(2, tm)
+        jobs.run()
 
     def test_cached_execute(self):
         """Test executing a task with cached targets