gdb/testsuite: fix race in gdb.server/stop-reply-no-thread-multi.exp
Commit Message
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
@@ -46,9 +46,7 @@ worker (void *data)
unlock_main ();
while (worker_blocked)
- ;
-
- breakpt ();
+ breakpt ();
return NULL;
}
@@ -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.