gdb/testsuite: fix race in gdb.server/stop-reply-no-thread-multi.exp

Message ID 20221018011958.1113124-1-simon.marchi@polymtl.ca
State New
Headers
Series gdb/testsuite: fix race in gdb.server/stop-reply-no-thread-multi.exp |

Commit Message

Simon Marchi Oct. 18, 2022, 1:19 a.m. UTC
  I got a random failure on my CI for this test:

    set scheduler-locking on^M
    (gdb) PASS: gdb.server/stop-reply-no-thread-multi.exp: target-non-stop=off: to_disable=T: set scheduler-locking on
    stepi^M
    0x00005555555551d1      35      }^M
    (gdb) FAIL: gdb.server/stop-reply-no-thread-multi.exp: target-non-stop=off: to_disable=T: stepi

The expected execution looks like:

 - the worker thread unlocks the main thread, and goes wait on the
   `while (worker_blocked)` line
 - the main thread, now unblocked, calls unlock_worker, where a
   breakpoint is hit, and everything stops
 - the test does a stepi on the worker thread, expecting it to land
   again on the `while (worker_blocked)` line, as it's an empty loop

The problem is if the worker thread is slow and doesn't manage to reach
the `while (worker_blocked)` line by the time everything stops.  The
stepi will work fine, but the thread will land at a different line than
what the test expects.  This can easily be reproduced by adding a
`sleep (1)` at the end of unlock_worker.

Fix this by inserting a temporary breakpoint in the
`while (worker_blocked)` loop and continuing, rather than doing a stepi.
This way, the worker thread will always stop on the expected line,
regardless of where it started.  Re-use the breakpt function, which I
believe was not useful prior to this patch.

I think this keeps the original intent of the test, which is to test
what happens if a stop-reply comes back without a thread identifier, in
a multi-threaded program.  Because scheduler-locking is "on", only
thread 2 is resumed, just like before with the stepi.  The stop-reply
will maybe be missing the thread identifier, depending on the iteration
of the test.  If the fix introduced in 8f66807b98f76 ("gdb: better
handling of 'S' packets") was reverted, GDB would assume the stop-reply
is for thread 1, make thread 1 current, and the "info threads" test just
after would fail.

Change-Id: I4aff9e4c7d53d74e87c59a4f8b44ea5171014459
---
 .../gdb.server/stop-reply-no-thread-multi.c     |  4 +---
 .../gdb.server/stop-reply-no-thread-multi.exp   | 17 ++++++-----------
 2 files changed, 7 insertions(+), 14 deletions(-)


base-commit: 02a8b5c25806339f801c80a5a364a963b2ece080
  

Patch

diff --git a/gdb/testsuite/gdb.server/stop-reply-no-thread-multi.c b/gdb/testsuite/gdb.server/stop-reply-no-thread-multi.c
index e7da33dcf616..a0cf9044064d 100644
--- a/gdb/testsuite/gdb.server/stop-reply-no-thread-multi.c
+++ b/gdb/testsuite/gdb.server/stop-reply-no-thread-multi.c
@@ -46,9 +46,7 @@  worker (void *data)
   unlock_main ();
 
   while (worker_blocked)
-    ;
-
-  breakpt ();
+    breakpt ();
 
   return NULL;
 }
diff --git a/gdb/testsuite/gdb.server/stop-reply-no-thread-multi.exp b/gdb/testsuite/gdb.server/stop-reply-no-thread-multi.exp
index 3bc7cbed52e2..cd096445bf41 100644
--- a/gdb/testsuite/gdb.server/stop-reply-no-thread-multi.exp
+++ b/gdb/testsuite/gdb.server/stop-reply-no-thread-multi.exp
@@ -103,26 +103,21 @@  proc run_test { target_non_stop disable_feature } {
     # Switch threads.
     gdb_test "thread 2" ".*" "switch to second thread"
 
-    # Now turn on scheduler-locking so that when we step thread 2 only
+    # Now turn on scheduler-locking so that when we resume thread 2 only
     # that one thread will be set running.
     gdb_test_no_output "set scheduler-locking on"
 
-    # Single step thread 2.  Only the one thread will step.  When the
+    gdb_test "tbreak breakpt"
+
+    # Resume thread 2.  Only the one thread will execute.  When the
     # thread stops, if the stop packet doesn't include a thread-id
     # then GDB should still understand which thread stopped.
-    gdb_test_multiple "stepi" "" {
-	-re -wrap "Thread 1 received signal SIGTRAP.*" {
-	    fail $gdb_test_name
-	}
-	-re -wrap "$hex.*$decimal.*while \\(worker_blocked\\).*" {
-	    pass $gdb_test_name
-	}
-    }
+    gdb_test "continue" "Thread 2 hit Temporary breakpoint $::decimal, breakpt.*"
 
     # Check that thread 2 is still selected.
     gdb_test "info threads" \
 	"  1\[\t \]*Thread\[^\r\n\]*\r\n\\\* 2\[\t \]*Thread\[^\r\n\]*" \
-	"second thread should still be selected after stepi"
+	"second thread should still be selected after continue"
 
     # Turn scheduler locking off again so that when we continue all
     # threads will be set running.