[binutils-gdb] [gdb/testsuite] Fix race in gdb.threads/leader-exit.exp

Tom de Vries via Gdb-cvs <[email protected]> Sat, 25 Jul 2026 06:59:55 +0000 (GMT)
Newsgroups gmane.comp.gdb.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D1fba9bb362c6=
ca7a0ae30f0fff7d8c1d68f8bdb4

commit 1fba9bb362c6ca7a0ae30f0fff7d8c1d68f8bdb4
Author: Tom de Vries <[email protected]>
Date:   Sat Jul 25 08:59:51 2026 +0200

    [gdb/testsuite] Fix race in gdb.threads/leader-exit.exp
   =20
    On aarch64-linux, when running test-case gdb.threads/leader-exit.exp wi=
th
    "taskset -c 0", 3 out of 10 times I run into:
    ...
    (gdb) continue
    Continuing.
    [New Thread 0xfffff7d1f160 (LWP 62010) (id 2)]
    [Switching to thread 2 (Thread 0xfffff7d1f160 (LWP 62010))]
   =20
    Thread 2 "leader-exit" hit Breakpoint 2, start (arg=3D0x0) at leader-ex=
it.c:32
    32        sleep (10);  /* break-here */
    (gdb) PASS: gdb.threads/leader-exit.exp: continue to breakpoint: break-=
here
    info threads
      Id   Target Id                                                 Frame
      1    Thread 0xfffff7fe8020 (LWP 62008) "leader-exit" (Exiting) \
             0x0000fffff7d46fa0 in __libc_start_call_main () from /lib64/li=
bc.so.6
    * 2    Thread 0xfffff7d1f160 (LWP 62010) "leader-exit" \
             start (arg=3D0x0) at leader-exit.c:32
    (gdb) FAIL: gdb.threads/leader-exit.exp: single thread has been left
    ...
   =20
    In a passing version, the continue produces a "Thread exited" message, =
but
    that's missing here.
   =20
    The problem is that after the pthread_join is executed:
    ...
      i =3D pthread_join (main_thread, NULL);
      ...
   =20
      sleep (10);  /* break-here */
    ...
    there's a race between:
    - the breakpoint at break-here triggering, and
    - the "Thread exited" message for the main thread being reported.
   =20
    Fix this by:
    - adding a loop before the break location
    - waiting in the loop until the "Thread exited" message is seen
    - sending ^C to get a prompt
    - setting a variable to exit the loop
   =20
    Likewise in gdb.threads/non-ldr-exc-2.exp.
   =20
    Reviewed-By: Keith Seitz <[email protected]>
    Approved-By: Kevin Buettner <[email protected]>
   =20
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=3D34425

Diff:
---
 gdb/testsuite/gdb.threads/leader-exit.c     |  4 ++++
 gdb/testsuite/gdb.threads/leader-exit.exp   | 24 +++++++++++++++++++++++-
 gdb/testsuite/gdb.threads/non-ldr-exc-2.c   |  5 +++++
 gdb/testsuite/gdb.threads/non-ldr-exc-2.exp | 26 +++++++++++++++++++++++++-
 4 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/gdb/testsuite/gdb.threads/leader-exit.c b/gdb/testsuite/gdb.th=
reads/leader-exit.c
index bd546d009cd..b24817e8a14 100644
--- a/gdb/testsuite/gdb.threads/leader-exit.c
+++ b/gdb/testsuite/gdb.threads/leader-exit.c
@@ -21,6 +21,8 @@
=20
 static volatile pthread_t main_thread;
=20
+static volatile int wait_for_exit =3D 1;
+
 static void *
 start (void *arg)
 {
@@ -28,6 +30,8 @@ start (void *arg)
=20
   i =3D pthread_join (main_thread, NULL);
   assert (i =3D=3D 0);
+  while (wait_for_exit)
+    usleep (100 * 1000);
=20
   sleep (10);  /* break-here */
   return arg;
diff --git a/gdb/testsuite/gdb.threads/leader-exit.exp b/gdb/testsuite/gdb.=
threads/leader-exit.exp
index b5e6f558ac7..fb2f6980c2a 100644
--- a/gdb/testsuite/gdb.threads/leader-exit.exp
+++ b/gdb/testsuite/gdb.threads/leader-exit.exp
@@ -30,7 +30,29 @@ if {![runto_main]} {
     return
 }
=20
-gdb_breakpoint [gdb_get_line_number "break-here"]
+# Wait for the "Thread exited" message.
+set re_thread_exited {\[Thread [^\r\n]+ exited\]}
+set saw_thread_exited 0
+gdb_test_multiple "continue" "continue to thread exited" {
+    -re $re_thread_exited {
+	set saw_thread_exited 1
+	# Get a prompt.
+	send_gdb "\003"
+	exp_continue
+    }
+    -re -wrap "" {
+	pass $gdb_test_name
+    }
+}
+gdb_assert {$saw_thread_exited} "thread exited"
+if {!$saw_thread_exited} {
+    return
+}
+
+# Let the inferior exit the wait_for_exit loop.
+gdb_test_no_output "set var wait_for_exit =3D 0"
+
+gdb_breakpoint $srcfile:[gdb_get_line_number "break-here"]
 gdb_continue_to_breakpoint "break-here" ".* break-here .*"
=20
 gdb_test "info threads" \
diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.c b/gdb/testsuite/gdb.=
threads/non-ldr-exc-2.c
index b05479be01f..a9e81dfa495 100644
--- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.c
+++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.c
@@ -26,6 +26,8 @@ static const char *image;
 static volatile pthread_t main_thread;
 static char *argv1 =3D "go away";
=20
+static volatile int wait_for_exit =3D 1;
+
 static void *
 thread_execler (void *arg)
 {
@@ -34,6 +36,9 @@ thread_execler (void *arg)
   i =3D pthread_join (main_thread, NULL);
   assert (i =3D=3D 0);
=20
+  while (wait_for_exit)
+    usleep (100 * 1000);
+
   /* Exec ourselves again.  */
   if (execl (image, image, argv1, NULL) =3D=3D -1) /* break-here */
     {
diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp b/gdb/testsuite/gd=
b.threads/non-ldr-exc-2.exp
index ead262cc2b5..3f465e10159 100644
--- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp
+++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp
@@ -17,6 +17,8 @@
 # through to the new incarnation of the main thread, even if the main
 # thread had already exited before the exec.
=20
+require {!target_info exists gdb,nointerrupts}
+
 standard_testfile
 set executable ${testfile}
=20
@@ -37,7 +39,29 @@ proc do_test { lock_sched nonstop } {
 	return -1
     }
=20
-    gdb_breakpoint [gdb_get_line_number "break-here"]
+    # Wait for the "Thread exited" message.
+    set re_thread_exited {\[Thread [^\r\n]+ exited\]}
+    set saw_thread_exited 0
+    gdb_test_multiple "continue" "continue to thread exited" {
+	-re $re_thread_exited {
+	    set saw_thread_exited 1
+	    # Get a prompt.
+	    send_gdb "\003"
+	    exp_continue
+	}
+	-re -wrap "" {
+	    pass $gdb_test_name
+	}
+    }
+    gdb_assert {$saw_thread_exited} "thread exited"
+    if {!$saw_thread_exited} {
+	return
+    }
+
+    # Let the inferior exit the wait_for_exit loop.
+    gdb_test_no_output "set var wait_for_exit =3D 0"
+
+    gdb_breakpoint $::srcfile:[gdb_get_line_number "break-here"]
     gdb_continue_to_breakpoint "break-here" ".* break-here .*"
=20
     if { $nonstop =3D=3D "on" } {