Fix MulticoreRegTest.
authorTim Newsome <tim@sifive.com>
Wed, 1 Nov 2017 18:43:04 +0000 (11:43 -0700)
committerTim Newsome <tim@sifive.com>
Wed, 1 Nov 2017 18:43:04 +0000 (11:43 -0700)
This test would fail intermittently if gdb on the first hart managed to
set a breakpoint, resume, halt, and clear the breakpoint before the
second hart got a chance to resume.

debug/gdbserver.py
debug/testlib.py

index 51c6ab6b09d550e2d1fbce5d4b8ee81ef09c5d35..4d8d99a2276debf89f0cf2e30868bc3c25c4cc0a 100755 (executable)
@@ -465,64 +465,60 @@ class InterruptTest(GdbSingleHartTest):
         self.gdb.p("interrupt_count")
         self.gdb.p("local")
 
-# Fails nondeterministically.
-#class MulticoreRegTest(GdbTest):
-#    compile_args = ("programs/infinite_loop.S", "-DMULTICORE")
-#
-#    def early_applicable(self):
-#        return len(self.target.harts) > 1
-#
-#    def setup(self):
-#        self.gdb.load()
-#        for hart in self.target.harts:
-#            self.gdb.select_hart(hart)
-#            self.gdb.p("$pc=_start")
-#
-#    def test(self):
-#        # Run to main
-#        # Hart 0 is the first to be resumed, so we have to set the breakpoint
-#        # there. gdb won't actually set the breakpoint until we tell it to
-#        # resume.
-#        self.gdb.select_hart(self.target.harts[0])
-#        self.gdb.b("main")
-#        self.gdb.c_all()
-#        for hart in self.target.harts:
-#            self.gdb.select_hart(hart)
-#            assertIn("main", self.gdb.where())
-#        self.gdb.select_hart(self.target.harts[0])
-#        self.gdb.command("delete breakpoints")
-#
-#        # Run through the entire loop.
-#        self.gdb.b("main_end")
-#        self.gdb.c_all()
-#
-#        hart_ids = []
-#        for hart in self.target.harts:
-#            self.gdb.select_hart(hart)
-#            assertIn("main_end", self.gdb.where())
-#            # Check register values.
-#            hart_id = self.gdb.p("$x1")
-#            assertNotIn(hart_id, hart_ids)
-#            hart_ids.append(hart_id)
-#            for n in range(2, 32):
-#                value = self.gdb.p("$x%d" % n)
-#                assertEqual(value, hart_ids[-1] + n - 1)
-#
-#        # Confirmed that we read different register values for different harts.
-#        # Write a new value to x1, and run through the add sequence again.
-#
-#        for hart in self.target.harts:
-#            self.gdb.select_hart(hart)
-#            self.gdb.p("$x1=0x%x" % (hart.index * 0x800))
-#            self.gdb.p("$pc=main_post_csrr")
-#        self.gdb.c_all()
-#        for hart in self.target.harts:
-#            self.gdb.select_hart(hart)
-#            assertIn("main", self.gdb.where())
-#            # Check register values.
-#            for n in range(1, 32):
-#                value = self.gdb.p("$x%d" % n)
-#                assertEqual(value, hart.index * 0x800 + n - 1)
+class MulticoreRegTest(GdbTest):
+    compile_args = ("programs/infinite_loop.S", "-DMULTICORE")
+
+    def early_applicable(self):
+        return len(self.target.harts) > 1
+
+    def setup(self):
+        self.gdb.load()
+        for hart in self.target.harts:
+            self.gdb.select_hart(hart)
+            self.gdb.p("$pc=_start")
+
+    def test(self):
+        # Run to main
+        for hart in self.target.harts:
+            self.gdb.select_hart(hart)
+            self.gdb.b("main")
+            self.gdb.c()
+            assertIn("main", self.gdb.where())
+            self.gdb.command("delete breakpoints")
+
+        # Run through the entire loop.
+        for hart in self.target.harts:
+            self.gdb.select_hart(hart)
+            self.gdb.b("main_end")
+            self.gdb.c()
+            assertIn("main_end", self.gdb.where())
+
+        hart_ids = []
+        for hart in self.target.harts:
+            self.gdb.select_hart(hart)
+            # Check register values.
+            hart_id = self.gdb.p("$x1")
+            assertNotIn(hart_id, hart_ids)
+            hart_ids.append(hart_id)
+            for n in range(2, 32):
+                value = self.gdb.p("$x%d" % n)
+                assertEqual(value, hart_ids[-1] + n - 1)
+
+        # Confirmed that we read different register values for different harts.
+        # Write a new value to x1, and run through the add sequence again.
+
+        for hart in self.target.harts:
+            self.gdb.select_hart(hart)
+            self.gdb.p("$x1=0x%x" % (hart.index * 0x800))
+            self.gdb.p("$pc=main_post_csrr")
+            self.gdb.c()
+        for hart in self.target.harts:
+            self.gdb.select_hart(hart)
+            assertIn("main", self.gdb.where())
+            # Check register values.
+            for n in range(1, 32):
+                value = self.gdb.p("$x%d" % n)
+                assertEqual(value, hart.index * 0x800 + n - 1)
 
 class MulticoreRunHaltStepiTest(GdbTest):
     compile_args = ("programs/multicore.c", "-DMULTICORE")
index 66b7b388879e34098c3294e18e6f0fd3ffeecc4c..e1be100f41ad3288eddb7ae41b09160b121c5cfa 100644 (file)
@@ -420,7 +420,17 @@ class Gdb(object):
             self.active_child.expect("Continuing")
 
     def c_all(self):
-        """Resume every hart."""
+        """
+        Resume every hart.
+
+        This function works fine when using multiple gdb sessions, but the
+        caller must be careful when using it nonetheless. gdb's behavior is to
+        not set breakpoints until just before the hart is resumed, and then
+        clears them as soon as the hart halts. That means that you can't set
+        one software breakpoint, and expect multiple harts to hit it. It's
+        possible that the first hart completes set/run/halt/clear before the
+        second hart even gets to resume, so it will never hit the breakpoint.
+        """
         with PrivateState(self):
             for child in self.children:
                 child.sendline("c")