* [PATCH] Ignore the last EXIT_THREAD_DEBUG_EVENT on Windows
@ 2026-08-21 16:18 Tom Tromey
2026-08-21 17:53 ` Eli Zaretskii
0 siblings, 1 reply; 5+ messages in thread
From: Tom Tromey @ 2026-08-21 16:18 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
The Windows non-stop series caused some regressions in the internal
AdaCore test suite. I filed this as PR tdep/34195. I finally found
some time to look into the problem, and this patch is the result.
The symptom of the problem is that some fairly ordinary tests -- like
a test to simply run a do-nothing program to completion -- would fail
because gdb would print "No unwaited-for children left."
I bisected the problem to commit ae2f226d ("Windows gdb: Add non-stop
support").
Instrumenting the test suite to enable logging showed something
strange: in the failing case, we'd see and EXIT_THREAD_DEBUG_EVENT for
each thread, but never an EXIT_PROCESS_DEBUG_EVENT.
And, since gdb didn't see or handle an EXIT_PROCESS_DEBUG_EVENT, the
process would remain live -- one of the internal AdaCore tests checks
this (via some "ps" equivalent), causing a separate failure.
After a lot of experimentation I came up with this patch. It changes
gdb to ignore the final EXIT_THREAD_DEBUG_EVENT, waiting instead for
an EXIT_PROCESS_DEBUG_EVENT to do the cleanup. This fixed the
regressions in my testing.
I still don't fully understand this bug, though:
1. It only happened under load, I was never able to reproduce it by
running a single test case. It's worth noting, though, that I ran
the test suite against gdb 17 on the same Windows instance, and
that always worked flawlessly -- so it seems like it's definitely a
gdb bug and not an OS bug.
2. Windows supposedly shouldn't even issue an EXIT_THREAD_DEBUG_EVENT
for the final thread, only EXIT_PROCESS_DEBUG_EVENT. At least
IIUC. So, the fact that we're even seeing this seems mysterious.
However it's worth noting that the patch only affects this case, so
if Windows does not emit that final thread-exit event, everything
should still work fine.
I've marked this bug as blocking gdb 18 because it is a regression.
If approved I plan to apply the patch to that branch as well.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34195
---
gdb/windows-nat.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index def8fa606f4..0e958ea8186 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -1570,6 +1570,32 @@ windows_nat_target::get_windows_debug_event
case EXIT_THREAD_DEBUG_EVENT:
{
+ /* If we see the last thread-exited event, and then we go
+ ahead and delete the thread, this might cause gdb to stop
+ issuing calls to ContinueDebugEvent. See PR dept/34195.
+ This has two bad effects.
+
+ First, the EXIT_PROCESS_DEBUG_EVENT is never handled, so
+ the process doesn't truly exit -- something that can be
+ detected by examining the running processes on the system
+ (i.e., using the equivalent of "ps").
+
+ Second, gdb will tell the user "No unwaited-for children
+ left", which is not really something users do or should
+ understand.
+
+ This stanza works around this problem: we treat the exit of
+ the last remaining thread as a spurious event, causing gdb
+ to call ContinueDebugEvent; the thread exit is then handled
+ by the EXIT_PROCESS_DEBUG_EVENT. */
+ inferior *inf = find_inferior_pid (this, current_event->dwProcessId);
+ auto rng = inf->non_exited_threads ();
+ if (std::distance (rng.begin (), rng.end ()) == 1)
+ {
+ ourstatus->set_spurious ();
+ return null_ptid;
+ }
+
ourstatus->set_thread_exited
(current_event->u.ExitThread.dwExitCode);
thread_id = current_event->dwThreadId;
base-commit: a3a56294a7c5e5898309c04cc3b1e490cca76ef7
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Ignore the last EXIT_THREAD_DEBUG_EVENT on Windows
2026-08-21 16:18 [PATCH] Ignore the last EXIT_THREAD_DEBUG_EVENT on Windows Tom Tromey
@ 2026-08-21 17:53 ` Eli Zaretskii
2026-08-21 18:18 ` Tom Tromey
0 siblings, 1 reply; 5+ messages in thread
From: Eli Zaretskii @ 2026-08-21 17:53 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> From: Tom Tromey <tromey@adacore.com>
> Cc: Tom Tromey <tromey@adacore.com>
> Date: Fri, 21 Aug 2026 10:18:28 -0600
>
> The Windows non-stop series caused some regressions in the internal
> AdaCore test suite. I filed this as PR tdep/34195. I finally found
> some time to look into the problem, and this patch is the result.
>
> The symptom of the problem is that some fairly ordinary tests -- like
> a test to simply run a do-nothing program to completion -- would fail
> because gdb would print "No unwaited-for children left."
>
> I bisected the problem to commit ae2f226d ("Windows gdb: Add non-stop
> support").
>
> Instrumenting the test suite to enable logging showed something
> strange: in the failing case, we'd see and EXIT_THREAD_DEBUG_EVENT for
> each thread, but never an EXIT_PROCESS_DEBUG_EVENT.
>
> And, since gdb didn't see or handle an EXIT_PROCESS_DEBUG_EVENT, the
> process would remain live -- one of the internal AdaCore tests checks
> this (via some "ps" equivalent), causing a separate failure.
>
> After a lot of experimentation I came up with this patch. It changes
> gdb to ignore the final EXIT_THREAD_DEBUG_EVENT, waiting instead for
> an EXIT_PROCESS_DEBUG_EVENT to do the cleanup. This fixed the
> regressions in my testing.
How can we know that a given thread is a "final" one, when Windows is
known to start its own threads for the program being debugged? Are
you sure there are no such threads left running after all the threads
known to GDB exit, and cause this issue?
> 1. It only happened under load, I was never able to reproduce it by
> running a single test case.
What do you mean by "load" in this case? what kind of load?
Thanks.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Ignore the last EXIT_THREAD_DEBUG_EVENT on Windows
2026-08-21 17:53 ` Eli Zaretskii
@ 2026-08-21 18:18 ` Tom Tromey
2026-08-22 5:47 ` Eli Zaretskii
0 siblings, 1 reply; 5+ messages in thread
From: Tom Tromey @ 2026-08-21 18:18 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Tom Tromey, gdb-patches
>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:
Eli> How can we know that a given thread is a "final" one, when Windows is
Eli> known to start its own threads for the program being debugged?
We track when threads are created and destroyed, and only apply this
behavior when there is a single thread remaining.
Eli> Are you sure there are no such threads left running after all the
Eli> threads known to GDB exit, and cause this issue?
Yes, extracted from the log in the bug, here are all the thread and
process events:
[windows events] get_windows_debug_event: kernel event for pid=1604 tid=0x89c code=CREATE_PROCESS_DEBUG_EVENT
[windows events] get_windows_debug_event: kernel event for pid=1604 tid=0xc20 code=CREATE_THREAD_DEBUG_EVENT
[windows events] get_windows_debug_event: kernel event for pid=1604 tid=0xc20 code=EXIT_THREAD_DEBUG_EVENT
[windows events] get_windows_debug_event: kernel event for pid=1604 tid=0x89c code=EXIT_THREAD_DEBUG_EVENT
>> 1. It only happened under load, I was never able to reproduce it by
>> running a single test case.
Eli> What do you mean by "load" in this case? what kind of load?
If I run one test case in isolation, it never fails. However if I run
the whole test suite, which defaults to running as many tests as there
are CPUs, I do see some failures. Frequently -- but not always -- the
same tests fail.
Tom
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Ignore the last EXIT_THREAD_DEBUG_EVENT on Windows
2026-08-21 18:18 ` Tom Tromey
@ 2026-08-22 5:47 ` Eli Zaretskii
2026-08-27 15:27 ` Tom Tromey
0 siblings, 1 reply; 5+ messages in thread
From: Eli Zaretskii @ 2026-08-22 5:47 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> From: Tom Tromey <tromey@adacore.com>
> Cc: Tom Tromey <tromey@adacore.com>, gdb-patches@sourceware.org
> Date: Fri, 21 Aug 2026 12:18:05 -0600
>
> >>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:
>
> Eli> How can we know that a given thread is a "final" one, when Windows is
> Eli> known to start its own threads for the program being debugged?
>
> We track when threads are created and destroyed, and only apply this
> behavior when there is a single thread remaining.
Is there no possibility whatsoever that another thread will be created
while we handle the termination of what we consider to be "the last
thread"? Even though GDB supports scheduler-locking and non-stop mode
on Windows?
Also, doesn't EXIT_PROCESS_DEBUG_EVENT provide to us data about the
process (like its exit code) that EXIT_THREAD_DEBUG_EVENT does not?
> Eli> Are you sure there are no such threads left running after all the
> Eli> threads known to GDB exit, and cause this issue?
>
> Yes, extracted from the log in the bug, here are all the thread and
> process events:
>
> [windows events] get_windows_debug_event: kernel event for pid=1604 tid=0x89c code=CREATE_PROCESS_DEBUG_EVENT
> [windows events] get_windows_debug_event: kernel event for pid=1604 tid=0xc20 code=CREATE_THREAD_DEBUG_EVENT
> [windows events] get_windows_debug_event: kernel event for pid=1604 tid=0xc20 code=EXIT_THREAD_DEBUG_EVENT
> [windows events] get_windows_debug_event: kernel event for pid=1604 tid=0x89c code=EXIT_THREAD_DEBUG_EVENT
Did you succeed in capturing EXIT_THREAD_DEBUG_EVENT after receiving
EXIT_PROCESS_DEBUG_EVENT this way?
> >> 1. It only happened under load, I was never able to reproduce it by
> >> running a single test case.
>
> Eli> What do you mean by "load" in this case? what kind of load?
>
> If I run one test case in isolation, it never fails. However if I run
> the whole test suite, which defaults to running as many tests as there
> are CPUs, I do see some failures. Frequently -- but not always -- the
> same tests fail.
Then this could be a problem due to effect of previous/other tests,
which run before or in parallel with this test. In which case I'm not
sure we should install this change. As you say, the OS should handle
this issue for us, and the OS always knows better which thread is the
last one. I worry that we could introduce a possibility of
regressions if we install this workaround for a problem for which we
have only insufficient understanding.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Ignore the last EXIT_THREAD_DEBUG_EVENT on Windows
2026-08-22 5:47 ` Eli Zaretskii
@ 2026-08-27 15:27 ` Tom Tromey
0 siblings, 0 replies; 5+ messages in thread
From: Tom Tromey @ 2026-08-27 15:27 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Tom Tromey, gdb-patches
Eli> Is there no possibility whatsoever that another thread will be created
Eli> while we handle the termination of what we consider to be "the last
Eli> thread"? Even though GDB supports scheduler-locking and non-stop mode
Eli> on Windows?
I don't see how it could, because at relevant point there are no other
threads in existence. So, there's nothing to run.
Anyway it's moot because I've approved a different patch for this bug.
Eli> Then this could be a problem due to effect of previous/other tests,
Eli> which run before or in parallel with this test.
It is not, because my testing was not done with the gdb test suite, but
with the AdaCore internal test suite, which does not have this problem.
In the AdaCore test suite, the tests are isolated from one another.
Tom
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-27 15:28 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-21 16:18 [PATCH] Ignore the last EXIT_THREAD_DEBUG_EVENT on Windows Tom Tromey
2026-08-21 17:53 ` Eli Zaretskii
2026-08-21 18:18 ` Tom Tromey
2026-08-22 5:47 ` Eli Zaretskii
2026-08-27 15:27 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox