Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 0/2] [gdb/testsuite] Two gdb.threads patches
@ 2026-07-23 11:40 Tom de Vries
  2026-07-23 11:40 ` [PATCH 1/2] [gdb/testsuite] Fix race in gdb.threads/leader-exit.exp Tom de Vries
  2026-07-23 11:40 ` [PATCH 2/2] [gdb/testsuite] Fix timeout in gdb.threads/vfork-multi-inferior.exp Tom de Vries
  0 siblings, 2 replies; 6+ messages in thread
From: Tom de Vries @ 2026-07-23 11:40 UTC (permalink / raw)
  To: gdb-patches

Two patches fixing gdb.threads test-cases.

Tom de Vries (2):
  [gdb/testsuite] Fix race in gdb.threads/leader-exit.exp
  [gdb/testsuite] Fix timeout in gdb.threads/vfork-multi-inferior.exp

 gdb/testsuite/gdb.threads/leader-exit.c       |  4 ++++
 gdb/testsuite/gdb.threads/leader-exit.exp     | 22 +++++++++++++++++++
 gdb/testsuite/gdb.threads/non-ldr-exc-2.c     |  5 +++++
 gdb/testsuite/gdb.threads/non-ldr-exc-2.exp   | 22 +++++++++++++++++++
 .../gdb.threads/vfork-multi-inferior.exp      |  2 +-
 5 files changed, 54 insertions(+), 1 deletion(-)


base-commit: 39fc0cc4aa6f82a73b9eac6b8739895484ab269f
-- 
2.51.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] [gdb/testsuite] Fix race in gdb.threads/leader-exit.exp
  2026-07-23 11:40 [PATCH 0/2] [gdb/testsuite] Two gdb.threads patches Tom de Vries
@ 2026-07-23 11:40 ` Tom de Vries
  2026-07-24 17:49   ` Keith Seitz
  2026-07-23 11:40 ` [PATCH 2/2] [gdb/testsuite] Fix timeout in gdb.threads/vfork-multi-inferior.exp Tom de Vries
  1 sibling, 1 reply; 6+ messages in thread
From: Tom de Vries @ 2026-07-23 11:40 UTC (permalink / raw)
  To: gdb-patches

On aarch64-linux, when running test-case gdb.threads/leader-exit.exp with
"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))]

Thread 2 "leader-exit" hit Breakpoint 2, start (arg=0x0) at leader-exit.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/libc.so.6
* 2    Thread 0xfffff7d1f160 (LWP 62010) "leader-exit" \
         start (arg=0x0) at leader-exit.c:32
(gdb) FAIL: gdb.threads/leader-exit.exp: single thread has been left
...

In a passing version, the continue produces a "Thread exited" message, but
that's missing here.

The problem is that after the pthread_join is executed:
...
  i = pthread_join (main_thread, NULL);
  ...

  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.

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

Likewise in gdb.threads/non-ldr-exc-2.exp.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34425
---
 gdb/testsuite/gdb.threads/leader-exit.c     |  4 ++++
 gdb/testsuite/gdb.threads/leader-exit.exp   | 22 +++++++++++++++++++++
 gdb/testsuite/gdb.threads/non-ldr-exc-2.c   |  5 +++++
 gdb/testsuite/gdb.threads/non-ldr-exc-2.exp | 22 +++++++++++++++++++++
 4 files changed, 53 insertions(+)

diff --git a/gdb/testsuite/gdb.threads/leader-exit.c b/gdb/testsuite/gdb.threads/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 @@
 
 static volatile pthread_t main_thread;
 
+static volatile int wait_for_exit = 1;
+
 static void *
 start (void *arg)
 {
@@ -28,6 +30,8 @@ start (void *arg)
 
   i = pthread_join (main_thread, NULL);
   assert (i == 0);
+  while (wait_for_exit)
+    usleep (100 * 1000);
 
   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..22f27d2d6e8 100644
--- a/gdb/testsuite/gdb.threads/leader-exit.exp
+++ b/gdb/testsuite/gdb.threads/leader-exit.exp
@@ -30,6 +30,28 @@ if {![runto_main]} {
     return
 }
 
+# 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 to exit the wait_for_exit loop.
+gdb_test_no_output "set var wait_for_exit = 0"
+
 gdb_breakpoint [gdb_get_line_number "break-here"]
 gdb_continue_to_breakpoint "break-here" ".* break-here .*"
 
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 = "go away";
 
+static volatile int wait_for_exit = 1;
+
 static void *
 thread_execler (void *arg)
 {
@@ -34,6 +36,9 @@ thread_execler (void *arg)
   i = pthread_join (main_thread, NULL);
   assert (i == 0);
 
+  while (wait_for_exit)
+    usleep (100 * 1000);
+
   /* Exec ourselves again.  */
   if (execl (image, image, argv1, NULL) == -1) /* break-here */
     {
diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp
index ead262cc2b5..dfc34f42afe 100644
--- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp
+++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp
@@ -37,6 +37,28 @@ proc do_test { lock_sched nonstop } {
 	return -1
     }
 
+    # 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 to exit the wait_for_exit loop.
+    gdb_test_no_output "set var wait_for_exit = 0"
+
     gdb_breakpoint [gdb_get_line_number "break-here"]
     gdb_continue_to_breakpoint "break-here" ".* break-here .*"
 
-- 
2.51.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/2] [gdb/testsuite] Fix timeout in gdb.threads/vfork-multi-inferior.exp
  2026-07-23 11:40 [PATCH 0/2] [gdb/testsuite] Two gdb.threads patches Tom de Vries
  2026-07-23 11:40 ` [PATCH 1/2] [gdb/testsuite] Fix race in gdb.threads/leader-exit.exp Tom de Vries
@ 2026-07-23 11:40 ` Tom de Vries
  2026-07-24 17:52   ` Keith Seitz
  1 sibling, 1 reply; 6+ messages in thread
From: Tom de Vries @ 2026-07-23 11:40 UTC (permalink / raw)
  To: gdb-patches

With test-case gdb.threads/vfork-multi-inferior.exp I get either:
...
(gdb) run &
Starting program: vfork-multi-inferior-sleep
(gdb) PASS: $exp: method=non-stop: run inferior 2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
inferior 1
[Switching to inferior 1 [<null>] (<noexec>)]
(gdb) PASS: $exp: method=non-stop: inferior 1
...
or:
...
(gdb) run &
Starting program: vfork-multi-inferior-sleep
(gdb) PASS: $exp: method=non-stop: run inferior 2
inferior 1^M
[Switching to inferior 1 [<null>] (<noexec>)]^M
(gdb) PASS: $exp: method=non-stop: inferior 1
[Thread debugging using libthread_db enabled]^M
Using host libthread_db library "/lib64/libthread_db.so.1".^M
...

With a 16.3-based package on aarch64-linux, I ran into:
...
(gdb) run &
Starting program: vfork-multi-inferior-sleep
(gdb) PASS: $exp: method=non-stop: run inferior 2
inferior 1
[Switching to inferior 1 [<null>] (<noexec>)]
(gdb) [Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
FAIL: $exp: method=non-stop: inferior 1
(timeout)
...

Unfortunately I have not been able to reproduce this.

Fix this using -no-prompt-anchor.

See also commit 5f69c00a6e0 ("[gdb/testsuite] Fix timeout in
gdb.base/async-shell.exp").

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34427
---
 gdb/testsuite/gdb.threads/vfork-multi-inferior.exp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gdb/testsuite/gdb.threads/vfork-multi-inferior.exp b/gdb/testsuite/gdb.threads/vfork-multi-inferior.exp
index e258ec719e9..f6c90bf0655 100644
--- a/gdb/testsuite/gdb.threads/vfork-multi-inferior.exp
+++ b/gdb/testsuite/gdb.threads/vfork-multi-inferior.exp
@@ -86,7 +86,7 @@ proc do_test {method} {
     }
 
     # Start the first inferior.
-    gdb_test "inferior 1" "Switching to inferior 1 .*"
+    gdb_test -no-prompt-anchor "inferior 1" "Switching to inferior 1 .*"
     gdb_file_cmd ${::binfile}
     gdb_test "break should_break_here" "Breakpoint $::decimal at .*"
     gdb_test "start" "Thread 1.1 .* hit Temporary breakpoint.*" \
-- 
2.51.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] [gdb/testsuite] Fix race in gdb.threads/leader-exit.exp
  2026-07-23 11:40 ` [PATCH 1/2] [gdb/testsuite] Fix race in gdb.threads/leader-exit.exp Tom de Vries
@ 2026-07-24 17:49   ` Keith Seitz
  2026-07-25  7:03     ` Tom de Vries
  0 siblings, 1 reply; 6+ messages in thread
From: Keith Seitz @ 2026-07-24 17:49 UTC (permalink / raw)
  To: Tom de Vries, gdb-patches

Hi,

On 7/23/26 4:40 AM, Tom de Vries wrote:
> 
> The problem is that after the pthread_join is executed:
> ...
>    i = pthread_join (main_thread, NULL);
>    ...
> 
>    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.

While I cannot reproduce this on my local hardware, your analysis
is sound.

> 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
> 
> Likewise in gdb.threads/non-ldr-exc-2.exp.

Sounds like a plan!

> diff --git a/gdb/testsuite/gdb.threads/leader-exit.exp b/gdb/testsuite/gdb.threads/leader-exit.exp
> index b5e6f558ac7..22f27d2d6e8 100644
> --- a/gdb/testsuite/gdb.threads/leader-exit.exp
> +++ b/gdb/testsuite/gdb.threads/leader-exit.exp
> @@ -30,6 +30,28 @@ if {![runto_main]} {
>       return
>   }
>   
> +# 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 to exit the wait_for_exit loop.

This comment got a bit jumbled. Superfluous "to"?

> +gdb_test_no_output "set var wait_for_exit = 0"
> +
>   gdb_breakpoint [gdb_get_line_number "break-here"]
>   gdb_continue_to_breakpoint "break-here" ".* break-here .*"
>   
> diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp
> index ead262cc2b5..dfc34f42afe 100644
> --- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp
> +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp
> @@ -37,6 +37,28 @@ proc do_test { lock_sched nonstop } {
>   	return -1
>       }
>   
> +    # 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 to exit the wait_for_exit loop.

Same nit in this comment.

Question: Since this test file now relies on sending the target
an interrupt, does it also need the same "require" on gdb,nointerrupts
that leader-exit.exp has?

Reviewed-By: Keith Seitz <keiths@redhat.com>

Keith

> +    gdb_test_no_output "set var wait_for_exit = 0"
> +
>       gdb_breakpoint [gdb_get_line_number "break-here"]
>       gdb_continue_to_breakpoint "break-here" ".* break-here .*"
>   


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] [gdb/testsuite] Fix timeout in gdb.threads/vfork-multi-inferior.exp
  2026-07-23 11:40 ` [PATCH 2/2] [gdb/testsuite] Fix timeout in gdb.threads/vfork-multi-inferior.exp Tom de Vries
@ 2026-07-24 17:52   ` Keith Seitz
  0 siblings, 0 replies; 6+ messages in thread
From: Keith Seitz @ 2026-07-24 17:52 UTC (permalink / raw)
  To: Tom de Vries, gdb-patches

Hi,

On 7/23/26 4:40 AM, Tom de Vries wrote:
> Unfortunately I have not been able to reproduce this.
> 

Nor am I...

> Fix this using -no-prompt-anchor.
> 
> See also commit 5f69c00a6e0 ("[gdb/testsuite] Fix timeout in
> gdb.base/async-shell.exp").

I agree this is an established paradigm and harmless enough.

Thank you for your tireless efforts to clean up the test suite.

Reviewed-By: Keith Seitz <keiths@redhat.com>

Keith


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] [gdb/testsuite] Fix race in gdb.threads/leader-exit.exp
  2026-07-24 17:49   ` Keith Seitz
@ 2026-07-25  7:03     ` Tom de Vries
  0 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-07-25  7:03 UTC (permalink / raw)
  To: Keith Seitz, gdb-patches

On 7/24/26 7:49 PM, Keith Seitz wrote:
> Hi,
> 
> On 7/23/26 4:40 AM, Tom de Vries wrote:
>>
>> The problem is that after the pthread_join is executed:
>> ...
>>    i = pthread_join (main_thread, NULL);
>>    ...
>>
>>    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.
> 
> While I cannot reproduce this on my local hardware, your analysis
> is sound.
> 
>> 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
>>
>> Likewise in gdb.threads/non-ldr-exc-2.exp.
> 
> Sounds like a plan!
> 
>> diff --git a/gdb/testsuite/gdb.threads/leader-exit.exp b/gdb/ 
>> testsuite/gdb.threads/leader-exit.exp
>> index b5e6f558ac7..22f27d2d6e8 100644
>> --- a/gdb/testsuite/gdb.threads/leader-exit.exp
>> +++ b/gdb/testsuite/gdb.threads/leader-exit.exp
>> @@ -30,6 +30,28 @@ if {![runto_main]} {
>>       return
>>   }
>> +# 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 to exit the wait_for_exit loop.
> 
> This comment got a bit jumbled. Superfluous "to"?
> 
>> +gdb_test_no_output "set var wait_for_exit = 0"
>> +
>>   gdb_breakpoint [gdb_get_line_number "break-here"]
>>   gdb_continue_to_breakpoint "break-here" ".* break-here .*"
>> diff --git a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp b/gdb/ 
>> testsuite/gdb.threads/non-ldr-exc-2.exp
>> index ead262cc2b5..dfc34f42afe 100644
>> --- a/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp
>> +++ b/gdb/testsuite/gdb.threads/non-ldr-exc-2.exp
>> @@ -37,6 +37,28 @@ proc do_test { lock_sched nonstop } {
>>       return -1
>>       }
>> +    # 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 to exit the wait_for_exit loop.
> 
> Same nit in this comment.
> 

Hi Keith,

fixed both nits.

> Question: Since this test file now relies on sending the target
> an interrupt, does it also need the same "require" on gdb,nointerrupts
> that leader-exit.exp has?
> 

Thanks for spotting that.  I've added this, and pushed.

Thanks for the reviews,
- Tom

> Reviewed-By: Keith Seitz <keiths@redhat.com>
> 
> Keith
> 
>> +    gdb_test_no_output "set var wait_for_exit = 0"
>> +
>>       gdb_breakpoint [gdb_get_line_number "break-here"]
>>       gdb_continue_to_breakpoint "break-here" ".* break-here .*"
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-07-25  7:04 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-23 11:40 [PATCH 0/2] [gdb/testsuite] Two gdb.threads patches Tom de Vries
2026-07-23 11:40 ` [PATCH 1/2] [gdb/testsuite] Fix race in gdb.threads/leader-exit.exp Tom de Vries
2026-07-24 17:49   ` Keith Seitz
2026-07-25  7:03     ` Tom de Vries
2026-07-23 11:40 ` [PATCH 2/2] [gdb/testsuite] Fix timeout in gdb.threads/vfork-multi-inferior.exp Tom de Vries
2026-07-24 17:52   ` Keith Seitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox