* [PATCH] gdb: notify of inferior switch when needed from 'thread' command
@ 2025-10-08 8:48 Andrew Burgess
2025-10-09 18:59 ` Pedro Alves
2026-01-26 13:58 ` [PATCHv2] " Andrew Burgess
0 siblings, 2 replies; 10+ messages in thread
From: Andrew Burgess @ 2025-10-08 8:48 UTC (permalink / raw)
To: gdb-patches; +Cc: Andrew Burgess
While working on the commit:
commit 9959019545d8d6d71d927f20f088efba944b1e9c
Date: Sun Sep 28 16:16:53 2025 +0100
gdb: fix for 'set suppress-cli-notifications on' missed case
I spotted this message in the gdb.mi/user-selected-context-sync.exp
test script:
# Idea for the future: selecting a thread in a different inferior. For now,
# GDB doesn't show an inferior switch, but if it did, it would be a nice
# place to test it.
What this message is talking about is this behaviour:
(gdb) info threads
Id Target Id Frame
1.1 Thread 0xf7dbc700 (LWP 818430) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
1.2 Thread 0xf7dbbb40 (LWP 818433) "thr" 0xf7fd0579 in __kernel_vsyscall ()
1.3 Thread 0xf73ffb40 (LWP 818434) "thr" breakpt () at thr.c:19
2.1 Thread 0xf7dbc700 (LWP 818456) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
2.2 Thread 0xf7dbbb40 (LWP 818457) "thr" breakpt () at thr.c:19
* 2.3 Thread 0xf73ffb40 (LWP 818458) "thr" breakpt () at thr.c:19
(gdb) inferior 1
[Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
[Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))]
#0 0xf7eb2888 in clone () from /lib/libc.so.6
(gdb) thread 2.2
[Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))]
#0 breakpt () at thr.c:19
19 while (stop)
(gdb)
Notice that when we switch from thread 2.3 to 1.1 using the 'inferior
1' command, GDB tells us that the inferior has changed, and that the
thread has changed (and also that the frame has changed).
But, when we switch from 1.1 to 2.2 using the 'thread 2.2' command, we
are only told about the thread change.
The 'Switching to inferior ...' line includes some useful information,
the process PID and the executable name, and I think it is a shame
that these are not presented when using the 'thread' command to switch
inferior.
So, this commit addresses this issue.
There are changes in basically two areas. The easy part is in
thread_command (thread.c). Here we spot when the inferior has changed
as a result of the 'thread' command, and included
USER_SELECTED_INFERIOR in the set of state passed to the
notify_user_selected_context_changed function.
The change in mi/mi-main.c is a little more involved. In the
mi_cmd_execute function we use an instance of user_selected_context to
spot if any inferior state (frame, thread, or inferior) changes after
an MI command, this is then used to decide if there should be a call
to notify_user_selected_context_changed.
Currently, in mi_cmd_execute, notify_user_selected_context_changed is
always passed 'USER_SELECTED_THREAD | USER_SELECTED_FRAME'. This
makes sense, the MI doesn't allow "switching inferiors" as a command,
instead, an MI frontend must switch threads, and the inferior is
switched as a consequence. But this does mean that if a user has a
CLI and MI interpreter running, and the MI switches threads, the CLI
will only receive the thread switch style notifications, that is,
there will be no "Switching to inferior ..." line.
What I've done is rename user_selected_context::has_changed to
user_selected_context::what_changed, this function is now responsible
for returning the set of USER_SELECTED_* flags that indicate what
changed.
If anything has changed then we always return USER_SELECTED_THREAD |
USER_SELECTED_FRAME as a minimum. This retains the existing
behaviour, but is possibly more aggressive that we need to be; the
-stack-select-frame command can only change the frame, so maybe in
this case we should only return USER_SELECTED_FRAME? I've left that
for the future though.
However, the important change is that in ::what_changed, I now spot
when the inferior has changed and include USER_SELECTED_INFERIOR in
the set of flags that are returned.
In mi_cmd_execute we now call the new what_changed function, and use
the set of flags returned when calling
notify_user_selected_context_changed. This means that the CLI will
now receive inferior changed notifications when appropriate.
The gdb.mi/user-selected-context-sync.exp script has been updated,
replacing the comment I quoted above with an actual test that the
inferior change is announced correctly.
---
gdb/mi/mi-main.c | 44 ++++++++++++---
.../gdb.mi/user-selected-context-sync.exp | 56 ++++++++++++++++---
gdb/thread.c | 13 ++++-
3 files changed, 93 insertions(+), 20 deletions(-)
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index bf1070030e2..3a5cbb27966 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -538,6 +538,11 @@ mi_cmd_thread_select (const char *command, const char *const *argv, int argc)
thread_select (argv[0], thr);
+ /* We don't call print_selected_inferior here as this never prints
+ anything when the output is MI like (as it is now). MI consumers are
+ expected to derive the inferior change from the global thread-id
+ included in the print_selected_thread_frame output. */
+
print_selected_thread_frame (current_uiout,
USER_SELECTED_THREAD | USER_SELECTED_FRAME);
}
@@ -1968,12 +1973,30 @@ struct user_selected_context
/* Return true if the user selected context has changed since this object
was created. */
- bool has_changed () const
+ user_selected_what what_changed () const
{
+ /* If anything changed then we report both the thread and frame at a
+ minimum. We optionally add the inferior if we know that it
+ changed.
+
+ This means that for pure frame changes, e.g. -stack-select-frame, we
+ still report both a thread and a frame, which isn't ideal, but
+ there's also the cases where -thread-select is used to re-select the
+ current thread, in this case we'd still like to see the thread
+ reported, at least, that's what we have historically done. */
+ user_selected_what state
+ = USER_SELECTED_THREAD | USER_SELECTED_FRAME;
+
/* Did the selected thread change? */
if (m_previous_ptid != null_ptid && inferior_ptid != null_ptid
&& m_previous_ptid != inferior_ptid)
- return true;
+ {
+ /* Did the inferior change too? */
+ if (m_previous_ptid.pid () != inferior_ptid.pid ())
+ state |= USER_SELECTED_INFERIOR;
+
+ return state;
+ }
/* Grab details of the currently selected frame, for comparison. */
frame_id current_frame_id;
@@ -1982,7 +2005,7 @@ struct user_selected_context
/* Did the selected frame level change? */
if (current_frame_level != m_previous_frame_level)
- return true;
+ return state;
/* Did the selected frame id change? If the innermost frame is
selected then the level will be -1, and the frame-id will be
@@ -1991,10 +2014,10 @@ struct user_selected_context
other than the innermost frame selected. */
if (current_frame_level != -1
&& current_frame_id != m_previous_frame_id)
- return true;
+ return state;
/* Nothing changed! */
- return false;
+ return 0;
}
private:
/* The previously selected thread. This might be null_ptid if there was
@@ -2098,10 +2121,13 @@ mi_cmd_execute (struct mi_parse *parse)
parse->cmd->invoke (parse);
- if (!parse->cmd->preserve_user_selected_context ()
- && current_user_selected_context.has_changed ())
- interps_notify_user_selected_context_changed
- (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
+ if (!parse->cmd->preserve_user_selected_context ())
+ {
+ user_selected_what what
+ = current_user_selected_context.what_changed ();
+ if (what != 0)
+ notify_user_selected_context_changed (what);
+ }
}
/* See mi-main.h. */
diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
index 8a4827fd4a8..36792ee8293 100644
--- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
+++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
@@ -698,9 +698,21 @@ proc_with_prefix test_cli_thread { mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set mi_re [make_mi_re $mode 5 0 event]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $gdb_main_spawn_id {
+ gdb_test "thread 2.2" $cli_re "select thread"
+ }
+
+ with_spawn_id $mi_spawn_id {
+ match_re_or_ensure_no_output $mi_re "select thread, event on MI"
+ }
+ }
}
# Test frame selection from CLI.
@@ -995,9 +1007,22 @@ proc_with_prefix test_mi_thread_select { mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set mi_re [make_mi_re $mode 5 0 response]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $mi_spawn_id {
+ mi_gdb_test "-thread-select 5" $mi_re "-thread-select"
+ }
+
+ with_spawn_id $gdb_main_spawn_id {
+ match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on CLI"
+ }
+
+ }
}
proc_with_prefix test_mi_stack_select_frame { mode } {
@@ -1290,9 +1315,22 @@ proc_with_prefix test_cli_in_mi_thread { mode cli_in_mi_mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set command [make_cli_in_mi_command $cli_in_mi_mode "thread 2.2"]
+ set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 2 2.2 5 0]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $mi_spawn_id {
+ mi_gdb_test $command $mi_re "select thread"
+ }
+
+ with_spawn_id $gdb_main_spawn_id {
+ match_re_or_ensure_no_output "$cli_re\r\n" "select thread, event on CLI"
+ }
+ }
}
# Test selecting the frame using a CLI command in the MI channel.
diff --git a/gdb/thread.c b/gdb/thread.c
index 472f41969cf..fc9b3d0ccde 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1977,10 +1977,19 @@ thread_command (const char *tidstr, int from_tty)
}
else
{
+ inferior *previous_inferior = current_inferior ();
+
thread_select (tidstr, parse_thread_id (tidstr, NULL));
- notify_user_selected_context_changed
- (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
+ user_selected_what selection = (USER_SELECTED_THREAD
+ | USER_SELECTED_FRAME);
+
+ /* If the inferior changed as a consequence of the thread change,
+ then let the user know. */
+ if (previous_inferior != current_inferior ())
+ selection |= USER_SELECTED_INFERIOR;
+
+ notify_user_selected_context_changed (selection);
}
}
base-commit: 9959019545d8d6d71d927f20f088efba944b1e9c
--
2.47.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] gdb: notify of inferior switch when needed from 'thread' command
2025-10-08 8:48 [PATCH] gdb: notify of inferior switch when needed from 'thread' command Andrew Burgess
@ 2025-10-09 18:59 ` Pedro Alves
2025-10-10 14:47 ` Andrew Burgess
2026-01-26 13:58 ` [PATCHv2] " Andrew Burgess
1 sibling, 1 reply; 10+ messages in thread
From: Pedro Alves @ 2025-10-09 18:59 UTC (permalink / raw)
To: Andrew Burgess, gdb-patches
Hi!
On 2025-10-08 09:48, Andrew Burgess wrote:
> What this message is talking about is this behaviour:
>
> (gdb) info threads
> Id Target Id Frame
> 1.1 Thread 0xf7dbc700 (LWP 818430) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
> 1.2 Thread 0xf7dbbb40 (LWP 818433) "thr" 0xf7fd0579 in __kernel_vsyscall ()
> 1.3 Thread 0xf73ffb40 (LWP 818434) "thr" breakpt () at thr.c:19
> 2.1 Thread 0xf7dbc700 (LWP 818456) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
> 2.2 Thread 0xf7dbbb40 (LWP 818457) "thr" breakpt () at thr.c:19
> * 2.3 Thread 0xf73ffb40 (LWP 818458) "thr" breakpt () at thr.c:19
> (gdb) inferior 1
> [Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
> [Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))]
> #0 0xf7eb2888 in clone () from /lib/libc.so.6
> (gdb) thread 2.2
> [Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))]
> #0 breakpt () at thr.c:19
> 19 while (stop)
> (gdb)
>
> Notice that when we switch from thread 2.3 to 1.1 using the 'inferior
> 1' command, GDB tells us that the inferior has changed, and that the
> thread has changed (and also that the frame has changed).
>
> But, when we switch from 1.1 to 2.2 using the 'thread 2.2' command, we
> are only told about the thread change.
>
> The 'Switching to inferior ...' line includes some useful information,
> the process PID and the executable name, and I think it is a shame
> that these are not presented when using the 'thread' command to switch
> inferior.
AMD and Intel have been having discussions about settling on how to
expose GPU lane debugging in GDB for the past year, and this very detail
came up there.
(There was a presentation/BoF about the topic at the Cauldron and videos/slides
are already up:
https://conf.gnu-tools-cauldron.org/opo25/talk/FN7FKL/ )
For lane debugging support, we're going to propose a new "lane" command (along with
'info lanes', 'lane find', 'break foo lane N' etc.), where "lane" is new level of
execution context. Currently an inferior has threads. And with lane debugging,
a thread has lanes. So inferior has threads, thread has lanes. A lane has
a fully-qualified ID like "I.T.L" (inferior.thread.lane), just like threads have a
fully qualified ID like "I.T".
For the issue at hand, it works like this:
(gdb) inferior 1
[Switching to inferior 1 [process 3286570] (/home/pedro/rocm/gdb/build/gdb/testsuite/outputs/gdb.rocm/simple/simple)]
[Switching to thread 1.7 (AMDGPU Wave 1:2:1:1 (0,0,0)/0)]
[Switching to lane 1.7.0 (AMDGPU Lane 1:2:1:1/0 (0,0,0)[0,0,0])]
#0 do_an_addition (a=1, b=2, out=0x7ffee3e00000) at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
24 *out = a + b;
(gdb) thread 7
[Switching to thread 1.7 (AMDGPU Wave 1:2:1:1 (0,0,0)/0)]
[Switching to lane 1.7.0 (AMDGPU Lane 1:2:1:1/0 (0,0,0)[0,0,0])]
#0 do_an_addition (a=1, b=2, out=0x7ffee3e00000) at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
24 *out = a + b;
(gdb) lane 0
[Switching to lane 1.7.0 (AMDGPU Lane 1:2:1:1/0 (0,0,0)[0,0,0])]
#0 do_an_addition (a=1, b=2, out=0x7ffee3e00000) at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
24 *out = a + b;
Note this is just reusing the logic of the current behavior you observed
with "inferior" and "thread".
There is a logic/pattern to it that I think is the right balance.
Let me explain.
When you do "inferior 1", GDB also switches to some thread of inferior 1.
Reusing your example, if GDB didn't print about what thread it switched
to, and just said:
(gdb) inferior 1
[Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
#0 0xf7eb2888 in clone () from /lib/libc.so.6
then the user would have no way to know what thread is now current,
and would be forced to issue the "thread" command to get it. So
that's why current GDB prints the "Switch to thread" part too:
(gdb) inferior 1
[Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
[Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))]
#0 0xf7eb2888 in clone () from /lib/libc.so.6
This however, does not apply when you use the "thread" command instead
of the "inferior" command, as in, you are not _forced_ to use the
"inferior" command. That is because in that case, the
"Switching to thread 2.2" part, as in your example:
(gdb) thread 2.2
[Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))]
#0 breakpt () at thr.c:19
19 while (stop)
... that "thread 2.2" part already tells you which inferior it is
GDB switched to. It's inferior 2, from "2.2", which is "I.T".
That is why in my example above, when I switch to lane 0 with the
"lane" command, GDB only needs to tell me about the lane switch and
not the "inferior" and "thread" switching:
(gdb) lane 0
[Switching to lane 1.7.0 (AMDGPU Lane 1:2:1:1/0 (0,0,0)[0,0,0])]
#0 do_an_addition (a=1, b=2, out=0x7ffee3e00000) at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
24 *out = a + b;
From "lane 1.7.0", I already know the inferior (1) and the thread (7), so
GDB doesn't need to say it. I _can_ use the "inferior" and "thread"
commands to get more information if I want, but I'm not _forced_ to.
So the current logic, extended to lanes, is I think simple -- when you
switch to an execution object using a "FOO" command, then GDB informs
you about the current FOO it switched to, as well as any finer
execution object context below FOO. I.e.,
- if you use the "inferior" command, GDB tells you about
"inferior", "thread" and "lane" (if lanes exist).
- if you use the "thread" command, GDB tells you about
"thread" and "lane" (if lanes exist).
- if you use the "lane" command, GDB tells you about
"lane".
This reduces noise for a set of core commands that are used all the time.
When you're focused on switching threads around to debug something, you don't
need to be told what is the current program the inferior is running.
IMHO, it ends up being noise after a short while, like:
(gdb) lane 0
[Switching to inferior 1 [process 3286570] (/home/pedro/rocm/gdb/build/gdb/testsuite/outputs/gdb.rocm/simple/simple)]
[Switching to thread 1.7 (AMDGPU Wave 1:2:1:1 (0,0,0)/0)]
[Switching to lane 1.7.0 (AMDGPU Lane 1:2:1:1/0 (0,0,0)[0,0,0])]
#0 do_an_addition (a=1, b=2, out=0x7ffee3e00000) at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
24 *out = a + b;
(gdb) lane 1
[Switching to inferior 1 [process 3286570] (/home/pedro/rocm/gdb/build/gdb/testsuite/outputs/gdb.rocm/simple/simple)]
[Switching to thread 1.7 (AMDGPU Wave 1:2:1:1 (0,0,0)/0)]
[Switching to lane 1.7.1 (AMDGPU Lane 1:2:1:1/1 (0,0,0)[0,0,1])]
#0 do_an_addition (a=<lane inactive>, b=<lane inactive>, out=<lane inactive>)
at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
24 *out = a + b;
etc., etc.
IOW, even though you could argue that the "Switching to inferior ..."
information could be useful when you use the "thread" command, that is
information that the user can easily retrieve with the "inferior"
command. I think reducing noise is more important here, especially when
we start adding other levels of execution objects, like lanes.
(If you happen to have an AMD GPU, you can play with my examples above
using this branch:
https://github.com/ROCm/ROCgdb/tree/users/palves/lane-debugging)
Pedro Alves
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] gdb: notify of inferior switch when needed from 'thread' command
2025-10-09 18:59 ` Pedro Alves
@ 2025-10-10 14:47 ` Andrew Burgess
2025-11-03 16:12 ` Aktemur, Tankut Baris
2026-01-06 13:37 ` Andrew Burgess
0 siblings, 2 replies; 10+ messages in thread
From: Andrew Burgess @ 2025-10-10 14:47 UTC (permalink / raw)
To: Pedro Alves, gdb-patches
Pedro Alves <pedro@palves.net> writes:
> Hi!
>
> On 2025-10-08 09:48, Andrew Burgess wrote:
>
>> What this message is talking about is this behaviour:
>>
>> (gdb) info threads
>> Id Target Id Frame
>> 1.1 Thread 0xf7dbc700 (LWP 818430) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
>> 1.2 Thread 0xf7dbbb40 (LWP 818433) "thr" 0xf7fd0579 in __kernel_vsyscall ()
>> 1.3 Thread 0xf73ffb40 (LWP 818434) "thr" breakpt () at thr.c:19
>> 2.1 Thread 0xf7dbc700 (LWP 818456) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
>> 2.2 Thread 0xf7dbbb40 (LWP 818457) "thr" breakpt () at thr.c:19
>> * 2.3 Thread 0xf73ffb40 (LWP 818458) "thr" breakpt () at thr.c:19
>> (gdb) inferior 1
>> [Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
>> [Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))]
>> #0 0xf7eb2888 in clone () from /lib/libc.so.6
>> (gdb) thread 2.2
>> [Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))]
>> #0 breakpt () at thr.c:19
>> 19 while (stop)
>> (gdb)
>>
>> Notice that when we switch from thread 2.3 to 1.1 using the 'inferior
>> 1' command, GDB tells us that the inferior has changed, and that the
>> thread has changed (and also that the frame has changed).
>>
>> But, when we switch from 1.1 to 2.2 using the 'thread 2.2' command, we
>> are only told about the thread change.
>>
>> The 'Switching to inferior ...' line includes some useful information,
>> the process PID and the executable name, and I think it is a shame
>> that these are not presented when using the 'thread' command to switch
>> inferior.
>
> AMD and Intel have been having discussions about settling on how to
> expose GPU lane debugging in GDB for the past year, and this very detail
> came up there.
>
> (There was a presentation/BoF about the topic at the Cauldron and videos/slides
> are already up:
> https://conf.gnu-tools-cauldron.org/opo25/talk/FN7FKL/ )
>
> For lane debugging support, we're going to propose a new "lane" command (along with
> 'info lanes', 'lane find', 'break foo lane N' etc.), where "lane" is new level of
> execution context. Currently an inferior has threads. And with lane debugging,
> a thread has lanes. So inferior has threads, thread has lanes. A lane has
> a fully-qualified ID like "I.T.L" (inferior.thread.lane), just like threads have a
> fully qualified ID like "I.T".
>
> For the issue at hand, it works like this:
>
> (gdb) inferior 1
> [Switching to inferior 1 [process 3286570] (/home/pedro/rocm/gdb/build/gdb/testsuite/outputs/gdb.rocm/simple/simple)]
> [Switching to thread 1.7 (AMDGPU Wave 1:2:1:1 (0,0,0)/0)]
> [Switching to lane 1.7.0 (AMDGPU Lane 1:2:1:1/0 (0,0,0)[0,0,0])]
> #0 do_an_addition (a=1, b=2, out=0x7ffee3e00000) at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
> 24 *out = a + b;
> (gdb) thread 7
> [Switching to thread 1.7 (AMDGPU Wave 1:2:1:1 (0,0,0)/0)]
> [Switching to lane 1.7.0 (AMDGPU Lane 1:2:1:1/0 (0,0,0)[0,0,0])]
> #0 do_an_addition (a=1, b=2, out=0x7ffee3e00000) at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
> 24 *out = a + b;
> (gdb) lane 0
> [Switching to lane 1.7.0 (AMDGPU Lane 1:2:1:1/0 (0,0,0)[0,0,0])]
> #0 do_an_addition (a=1, b=2, out=0x7ffee3e00000) at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
> 24 *out = a + b;
>
>
> Note this is just reusing the logic of the current behavior you observed
> with "inferior" and "thread".
>
> There is a logic/pattern to it that I think is the right balance.
>
> Let me explain.
>
> When you do "inferior 1", GDB also switches to some thread of inferior 1.
> Reusing your example, if GDB didn't print about what thread it switched
> to, and just said:
>
> (gdb) inferior 1
> [Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
> #0 0xf7eb2888 in clone () from /lib/libc.so.6
>
> then the user would have no way to know what thread is now current,
> and would be forced to issue the "thread" command to get it. So
> that's why current GDB prints the "Switch to thread" part too:
>
> (gdb) inferior 1
> [Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
> [Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))]
> #0 0xf7eb2888 in clone () from /lib/libc.so.6
>
> This however, does not apply when you use the "thread" command instead
> of the "inferior" command, as in, you are not _forced_ to use the
> "inferior" command. That is because in that case, the
> "Switching to thread 2.2" part, as in your example:
>
> (gdb) thread 2.2
> [Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))]
> #0 breakpt () at thr.c:19
> 19 while (stop)
>
> ... that "thread 2.2" part already tells you which inferior it is
> GDB switched to. It's inferior 2, from "2.2", which is "I.T".
>
> That is why in my example above, when I switch to lane 0 with the
> "lane" command, GDB only needs to tell me about the lane switch and
> not the "inferior" and "thread" switching:
>
> (gdb) lane 0
> [Switching to lane 1.7.0 (AMDGPU Lane 1:2:1:1/0 (0,0,0)[0,0,0])]
> #0 do_an_addition (a=1, b=2, out=0x7ffee3e00000) at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
> 24 *out = a + b;
>
> From "lane 1.7.0", I already know the inferior (1) and the thread (7), so
> GDB doesn't need to say it. I _can_ use the "inferior" and "thread"
> commands to get more information if I want, but I'm not _forced_ to.
>
> So the current logic, extended to lanes, is I think simple -- when you
> switch to an execution object using a "FOO" command, then GDB informs
> you about the current FOO it switched to, as well as any finer
> execution object context below FOO. I.e.,
>
> - if you use the "inferior" command, GDB tells you about
> "inferior", "thread" and "lane" (if lanes exist).
>
> - if you use the "thread" command, GDB tells you about
> "thread" and "lane" (if lanes exist).
>
> - if you use the "lane" command, GDB tells you about
> "lane".
I like this list, because I think it perfectly explains why I disagree
with your position. But lets first take a quick look at your next
example...
> This reduces noise for a set of core commands that are used all the time.
> When you're focused on switching threads around to debug something, you don't
> need to be told what is the current program the inferior is running.
> IMHO, it ends up being noise after a short while, like:
>
> (gdb) lane 0
> [Switching to inferior 1 [process 3286570] (/home/pedro/rocm/gdb/build/gdb/testsuite/outputs/gdb.rocm/simple/simple)]
> [Switching to thread 1.7 (AMDGPU Wave 1:2:1:1 (0,0,0)/0)]
> [Switching to lane 1.7.0 (AMDGPU Lane 1:2:1:1/0 (0,0,0)[0,0,0])]
> #0 do_an_addition (a=1, b=2, out=0x7ffee3e00000) at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
> 24 *out = a + b;
>
> (gdb) lane 1
> [Switching to inferior 1 [process 3286570] (/home/pedro/rocm/gdb/build/gdb/testsuite/outputs/gdb.rocm/simple/simple)]
> [Switching to thread 1.7 (AMDGPU Wave 1:2:1:1 (0,0,0)/0)]
> [Switching to lane 1.7.1 (AMDGPU Lane 1:2:1:1/1 (0,0,0)[0,0,1])]
> #0 do_an_addition (a=<lane inactive>, b=<lane inactive>, out=<lane inactive>)
> at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.rocm/simple.cpp:24
> 24 *out = a + b;
I agree with your conclusion that the "Switching to inferior..." output
is unnecessary in the example you just gave. But given you mentioned it
in response to my patch, but didn't really touch on how my patch is
different, I think it's worth mentioning, just in case this was missed.
The above does not represent what I'm proposing, and is not what the
patch I posted implements; obviously I'm talking inferiors and threads
only here, but I would be against implementing the above behaviour for
lanes too, which I think is your position.
Notice that in the above case the inferior and thread didn't change.
That's the important distinction, which is maybe missing from this
discussion. I'm not suggesting that we should display the inferior
during a thread change if the inferior doesn't actually change. Nor
would I suggest that you display the inferior and thread when switching
lane, if the inferior and/or thread didn't change.
I'll try rewriting one of your examples by handle to more closely match
what I'm actually proposing (or would propose in the future when lane's
exist):
(gdb) lane 2.3.1
[Switching to inferior 2 [process 3286570] (/home/pedro/rocm/gdb/build/gdb/testsuite/outputs/gdb.rocm/blah/blah)]
[Switching to thread 2.3 (AMDGPU Wave ... snip ...]
[Switching to lane 2.3.1 (AMDGPU Lane ... snip ...]
#0 some_function (...snip...) file.c:23
24 // ... some code ...
Here the user used the lane command to change inferior, thread, and
lane. Now I think GDB should display all the things that changed. Why
I hear you ask, lets revisit your list from above:
> - if you use the "inferior" command, GDB tells you about
> "inferior", "thread" and "lane" (if lanes exist).
>
> - if you use the "thread" command, GDB tells you about
> "thread" and "lane" (if lanes exist).
>
> - if you use the "lane" command, GDB tells you about
> "lane".
You argument seems to be that if I'm in thread 1.1 and use the command
'thread 2.2' to switch both inferior and thread, then I don't need to be
told about the inferior change, that information is given in the command
already.
But by this argument, why does the "inferior" command show the inferior?
Surely that information is present in the command, and is just "noise".
So the inferior command should only show the thread and lane.
Similarly, the thread command should only show the lane being switched
too, not which thread was selected.
And the lane command should only show the ... well, nothing (actually
all of the above show the frame too, but lets ignore that for now). As
the lane being selected is right there in the command.
I'm not seriously suggesting we change GDB inline with what I just
wrote. My position is that when something changes we should print what
it is we just switched too. Just like you say in your list above.
Switching inferior? Print the new inferior details, along with the
thread, lane, and frame. Switching thread _only_, print thread, lane,
and frame. Etc.
I actually feel that 'thread 2.2' really should be thought of as short
hand for "inferior 2; thread 2", and as such should act just as an
inferior command followed by a thread command would.
Is this noise? Sure. But is this overwhelming? I don't feel so. I
think letting the user know when something changes is OK.
>
> etc., etc.
>
>
> IOW, even though you could argue that the "Switching to inferior ..."
> information could be useful when you use the "thread" command, that is
> information that the user can easily retrieve with the "inferior"
> command. I think reducing noise is more important here, especially when
> we start adding other levels of execution objects, like lanes.
I was actually doubting myself so much by this point that I went and
retested my patch. Here's it in action:
(gdb) info threads
Id Target Id Frame
1.1 Thread 0xf7dbc700 (LWP 1750862) "thr_a" breakpt () at thr.c:19
1.2 Thread 0xf7dbbb40 (LWP 1750865) "thr_a" breakpt () at thr.c:19
1.3 Thread 0xf75bab40 (LWP 1750866) "thr_a" breakpt () at thr.c:19
1.4 Thread 0xf6bffb40 (LWP 1750867) "thr_a" breakpt () at thr.c:19
* 2.1 Thread 0xf7dbc700 (LWP 1750910) "thr_b" breakpt () at thr.c:19
2.2 Thread 0xf7dbbb40 (LWP 1750911) "thr_b" 0xf7fd0579 in __kernel_vsyscall ()
2.3 Thread 0xf73ffb40 (LWP 1750912) "thr_b" breakpt () at thr.c:19
2.4 Thread 0xf6bfeb40 (LWP 1750913) "thr_b" breakpt () at thr.c:19
(gdb) thread 2
[Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 1750911))]
#0 0xf7fd0579 in __kernel_vsyscall ()
(gdb) thread 1.3
[Switching to inferior 1 [process 1750862] (/tmp/thr_a)]
[Switching to thread 1.3 (Thread 0xf75bab40 (LWP 1750866))]
#0 breakpt () at thr.c:19
19 while (stop)
(gdb) thread 1.2
[Switching to thread 1.2 (Thread 0xf7dbbb40 (LWP 1750865))]
#0 breakpt () at thr.c:19
19 while (stop)
(gdb)
GDB only printed the "Switching to inferior ..." line when we actually
switched inferiors.
>
> (If you happen to have an AMD GPU, you can play with my examples above
> using this branch:
> https://github.com/ROCm/ROCgdb/tree/users/palves/lane-debugging)
Sadly not.
I'd also like to draw you attention to the gdb/mi/* changes in this
patch as you didn't give your thoughts on that aspect of the change.
That part of the patch handles the case where a user as an MI and CLI
interpreter running, and the inferior/thread changes as a result of an
MI action.
In this case, the MI action might be a click, or miss-click in a UI, or
might even be some automated action by the MI frontend that the user
didn't (knowingly) perform. In this case, currently, the CLI will
receive a thread/frame change notification (i.e. the CLI interpreter
prints the new thread and frame), but the inferior notification is
missing. My patch changed GDB so the CLI would (when appropriate) also
receive an inferior changed notification, and so also print a "Switching
to inferior..." line.
Surely in that case, your "the inferior change is known from the
command" argument doesn't apply, right?
But then there's a whole argument about consistency. If I change
inferior and thread via the MI the CLI gets a "Switching to inferior"
line, but if I do the same switch via the CLI, I wouldn't. Which I
dislike.
Anyway, I still feel like this change is the right thing to do. I'd
love to hear your thoughts on the points I've raised.
Clearly though, my original patch did a poor job of explaining that the
extra "Switching to inferior" line would only appear when necessary, so
if I can get you on board with this change, I'll rewrite the commit
message to make that _much_ clearer.
Thanks,
Andrew
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH] gdb: notify of inferior switch when needed from 'thread' command
2025-10-10 14:47 ` Andrew Burgess
@ 2025-11-03 16:12 ` Aktemur, Tankut Baris
2025-11-03 17:57 ` Andrew Burgess
2026-01-06 13:37 ` Andrew Burgess
1 sibling, 1 reply; 10+ messages in thread
From: Aktemur, Tankut Baris @ 2025-11-03 16:12 UTC (permalink / raw)
To: Andrew Burgess, Pedro Alves, gdb-patches
Hello Andrew,
> I'd also like to draw you attention to the gdb/mi/* changes in this
> patch as you didn't give your thoughts on that aspect of the change.
>
> That part of the patch handles the case where a user as an MI and CLI
> interpreter running, and the inferior/thread changes as a result of an
> MI action.
>
> In this case, the MI action might be a click, or miss-click in a UI, or
> might even be some automated action by the MI frontend that the user
> didn't (knowingly) perform. In this case, currently, the CLI will
> receive a thread/frame change notification (i.e. the CLI interpreter
> prints the new thread and frame), but the inferior notification is
> missing. My patch changed GDB so the CLI would (when appropriate) also
> receive an inferior changed notification, and so also print a "Switching
> to inferior..." line.
>
> Surely in that case, your "the inferior change is known from the
> command" argument doesn't apply, right?
>
> But then there's a whole argument about consistency. If I change
> inferior and thread via the MI the CLI gets a "Switching to inferior"
> line, but if I do the same switch via the CLI, I wouldn't. Which I
> dislike.
Something is not clear to me. Suppose there is an internal switch because
of a breakpoint hit. E.g. My selected thread is 2.2. I resume all inferiors.
Thread 1.1 hits a breakpoint. GDB switches. With your patch, the output is
[Switching to Thread 0x7ffff7d85740 (LWP 1279258)]
Thread 1.1 "test" hit Breakpoint ...
Should we have seen a "Switching to inferior 1 ...", too?
Best regards,
-Baris
> Anyway, I still feel like this change is the right thing to do. I'd
> love to hear your thoughts on the points I've raised.
>
> Clearly though, my original patch did a poor job of explaining that the
> extra "Switching to inferior" line would only appear when necessary, so
> if I can get you on board with this change, I'll rewrite the commit
> message to make that _much_ clearer.
>
> Thanks,
> Andrew
Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH] gdb: notify of inferior switch when needed from 'thread' command
2025-11-03 16:12 ` Aktemur, Tankut Baris
@ 2025-11-03 17:57 ` Andrew Burgess
0 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2025-11-03 17:57 UTC (permalink / raw)
To: Aktemur, Tankut Baris, Pedro Alves, gdb-patches
"Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com> writes:
> Hello Andrew,
>
>> I'd also like to draw you attention to the gdb/mi/* changes in this
>> patch as you didn't give your thoughts on that aspect of the change.
>>
>> That part of the patch handles the case where a user as an MI and CLI
>> interpreter running, and the inferior/thread changes as a result of an
>> MI action.
>>
>> In this case, the MI action might be a click, or miss-click in a UI, or
>> might even be some automated action by the MI frontend that the user
>> didn't (knowingly) perform. In this case, currently, the CLI will
>> receive a thread/frame change notification (i.e. the CLI interpreter
>> prints the new thread and frame), but the inferior notification is
>> missing. My patch changed GDB so the CLI would (when appropriate) also
>> receive an inferior changed notification, and so also print a "Switching
>> to inferior..." line.
>>
>> Surely in that case, your "the inferior change is known from the
>> command" argument doesn't apply, right?
>>
>> But then there's a whole argument about consistency. If I change
>> inferior and thread via the MI the CLI gets a "Switching to inferior"
>> line, but if I do the same switch via the CLI, I wouldn't. Which I
>> dislike.
>
> Something is not clear to me. Suppose there is an internal switch because
> of a breakpoint hit. E.g. My selected thread is 2.2. I resume all inferiors.
> Thread 1.1 hits a breakpoint. GDB switches. With your patch, the output is
>
> [Switching to Thread 0x7ffff7d85740 (LWP 1279258)]
>
> Thread 1.1 "test" hit Breakpoint ...
>
> Should we have seen a "Switching to inferior 1 ...", too?
Just to clarify, this behaviour is unchanged by my patch. But I'd
certainly think there's an argument to be made that the message should
be printed in this case.
For now, I'm just hoping that Pedro might get back to me as I'd like to
see the initial patch merged first.
Thanks,
Andrew
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] gdb: notify of inferior switch when needed from 'thread' command
2025-10-10 14:47 ` Andrew Burgess
2025-11-03 16:12 ` Aktemur, Tankut Baris
@ 2026-01-06 13:37 ` Andrew Burgess
1 sibling, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2026-01-06 13:37 UTC (permalink / raw)
To: Pedro Alves, gdb-patches
Ping!
Hi Pedro, I wonder if you have any thoughts on my feedback here. I
interpreted your initial reply as a NAK, which I'd usually just accept.
But in this case I do feel there was some misunderstanding about this
patch, which might change how you feel.
I rebased the patch to current HEAD, and added some additional text to
the commit message which might address your concerns.
Would be great to hear your thoughts.
Thanks,
Andrew
---
commit cf68b707614acbebd3b7525fd11784013adc8a92
Author: Andrew Burgess <aburgess@redhat.com>
Date: Tue Sep 30 13:14:11 2025 +0100
gdb: notify of inferior switch when needed from 'thread' command
While working on the commit:
commit 9959019545d8d6d71d927f20f088efba944b1e9c
Date: Sun Sep 28 16:16:53 2025 +0100
gdb: fix for 'set suppress-cli-notifications on' missed case
I spotted this message in the gdb.mi/user-selected-context-sync.exp
test script:
# Idea for the future: selecting a thread in a different inferior. For now,
# GDB doesn't show an inferior switch, but if it did, it would be a nice
# place to test it.
What this message is talking about is this behaviour:
(gdb) info threads
Id Target Id Frame
1.1 Thread 0xf7dbc700 (LWP 818430) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
1.2 Thread 0xf7dbbb40 (LWP 818433) "thr" 0xf7fd0579 in __kernel_vsyscall ()
1.3 Thread 0xf73ffb40 (LWP 818434) "thr" breakpt () at thr.c:19
2.1 Thread 0xf7dbc700 (LWP 818456) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
2.2 Thread 0xf7dbbb40 (LWP 818457) "thr" breakpt () at thr.c:19
* 2.3 Thread 0xf73ffb40 (LWP 818458) "thr" breakpt () at thr.c:19
(gdb) inferior 1
[Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
[Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))]
#0 0xf7eb2888 in clone () from /lib/libc.so.6
(gdb) thread 2.2
[Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))]
#0 breakpt () at thr.c:19
19 while (stop)
(gdb)
Notice that when we switch from thread 2.3 to 1.1 using the 'inferior
1' command, GDB tells us that the inferior has changed, and that the
thread has changed (and also that the frame has changed).
But, when we switch from 1.1 to 2.2 using the 'thread 2.2' command, we
are only told about the thread change.
The 'Switching to inferior ...' line includes some useful information,
the process PID and the executable name, and I think it is a shame
that these are not presented when using the 'thread' command to switch
inferior.
So, this commit addresses this issue.
A question that came up during review, and which I'm clarifying here:
this change only effects the output of GDB when the thread command is
also used to switch inferiors. I am (in effect) arguing that the
command 'thread 2.2' should be treated as a shorthand for 'inferior 2;
thread 2', and should display all of the associated output. If the
user is only switching threads within a single inferior then it is not
necessary to re-display the inferior information.
I acknowledge that this does mean the output of the 'thread' command
will now be different depending on whether the user changes inferior
or not. However, I think this is better than the alternative, having
the 'thread' command always re-print the inferior information. I
think this would introduce excess noise that is not useful.
There are changes in basically two areas. The easy part is in
thread_command (thread.c). Here we spot when the inferior has changed
as a result of the 'thread' command, and included
USER_SELECTED_INFERIOR in the set of state passed to the
notify_user_selected_context_changed function.
The change in mi/mi-main.c is a little more involved. In the
mi_cmd_execute function we use an instance of user_selected_context to
spot if any inferior state (frame, thread, or inferior) changes after
an MI command, this is then used to decide if there should be a call
to notify_user_selected_context_changed.
Currently, in mi_cmd_execute, notify_user_selected_context_changed is
always passed 'USER_SELECTED_THREAD | USER_SELECTED_FRAME'. This
makes sense, the MI doesn't allow "switching inferiors" as a command,
instead, an MI frontend must switch threads, and the inferior is
switched as a consequence. But this does mean that if a user has a
CLI and MI interpreter running, and the MI switches threads, the CLI
will only receive the thread switch style notifications, that is,
there will be no "Switching to inferior ..." line.
What I've done is rename user_selected_context::has_changed to
user_selected_context::what_changed, this function is now responsible
for returning the set of USER_SELECTED_* flags that indicate what
changed.
If anything has changed then we always return USER_SELECTED_THREAD |
USER_SELECTED_FRAME as a minimum. This retains the existing
behaviour, but is possibly more aggressive that we need to be; the
-stack-select-frame command can only change the frame, so maybe in
this case we should only return USER_SELECTED_FRAME? I've left that
for the future though.
However, the important change is that in ::what_changed, I now spot
when the inferior has changed and include USER_SELECTED_INFERIOR in
the set of flags that are returned.
In mi_cmd_execute we now call the new what_changed function, and use
the set of flags returned when calling
notify_user_selected_context_changed. This means that the CLI will
now receive inferior changed notifications when appropriate.
The gdb.mi/user-selected-context-sync.exp script has been updated,
replacing the comment I quoted above with an actual test that the
inferior change is announced correctly.
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 77e56bc9fc8..a18209366ff 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -538,6 +538,11 @@ mi_cmd_thread_select (const char *command, const char *const *argv, int argc)
thread_select (argv[0], thr);
+ /* We don't call print_selected_inferior here as this never prints
+ anything when the output is MI like (as it is now). MI consumers are
+ expected to derive the inferior change from the global thread-id
+ included in the print_selected_thread_frame output. */
+
print_selected_thread_frame (current_uiout,
USER_SELECTED_THREAD | USER_SELECTED_FRAME);
}
@@ -1968,12 +1973,30 @@ struct user_selected_context
/* Return true if the user selected context has changed since this object
was created. */
- bool has_changed () const
+ user_selected_what what_changed () const
{
+ /* If anything changed then we report both the thread and frame at a
+ minimum. We optionally add the inferior if we know that it
+ changed.
+
+ This means that for pure frame changes, e.g. -stack-select-frame, we
+ still report both a thread and a frame, which isn't ideal, but
+ there's also the cases where -thread-select is used to re-select the
+ current thread, in this case we'd still like to see the thread
+ reported, at least, that's what we have historically done. */
+ user_selected_what state
+ = USER_SELECTED_THREAD | USER_SELECTED_FRAME;
+
/* Did the selected thread change? */
if (m_previous_ptid != null_ptid && inferior_ptid != null_ptid
&& m_previous_ptid != inferior_ptid)
- return true;
+ {
+ /* Did the inferior change too? */
+ if (m_previous_ptid.pid () != inferior_ptid.pid ())
+ state |= USER_SELECTED_INFERIOR;
+
+ return state;
+ }
/* Grab details of the currently selected frame, for comparison. */
frame_id current_frame_id;
@@ -1982,7 +2005,7 @@ struct user_selected_context
/* Did the selected frame level change? */
if (current_frame_level != m_previous_frame_level)
- return true;
+ return state;
/* Did the selected frame id change? If the innermost frame is
selected then the level will be -1, and the frame-id will be
@@ -1991,10 +2014,10 @@ struct user_selected_context
other than the innermost frame selected. */
if (current_frame_level != -1
&& current_frame_id != m_previous_frame_id)
- return true;
+ return state;
/* Nothing changed! */
- return false;
+ return 0;
}
private:
/* The previously selected thread. This might be null_ptid if there was
@@ -2098,10 +2121,13 @@ mi_cmd_execute (struct mi_parse *parse)
parse->cmd->invoke (parse);
- if (!parse->cmd->preserve_user_selected_context ()
- && current_user_selected_context.has_changed ())
- interps_notify_user_selected_context_changed
- (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
+ if (!parse->cmd->preserve_user_selected_context ())
+ {
+ user_selected_what what
+ = current_user_selected_context.what_changed ();
+ if (what != 0)
+ notify_user_selected_context_changed (what);
+ }
}
/* See mi-main.h. */
diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
index 3434ffa2a46..4f02b950f6e 100644
--- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
+++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
@@ -698,9 +698,21 @@ proc_with_prefix test_cli_thread { mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set mi_re [make_mi_re $mode 5 0 event]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $gdb_main_spawn_id {
+ gdb_test "thread 2.2" $cli_re "select thread"
+ }
+
+ with_spawn_id $mi_spawn_id {
+ match_re_or_ensure_no_output $mi_re "select thread, event on MI"
+ }
+ }
}
# Test frame selection from CLI.
@@ -995,9 +1007,22 @@ proc_with_prefix test_mi_thread_select { mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set mi_re [make_mi_re $mode 5 0 response]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $mi_spawn_id {
+ mi_gdb_test "-thread-select 5" $mi_re "-thread-select"
+ }
+
+ with_spawn_id $gdb_main_spawn_id {
+ match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on CLI"
+ }
+
+ }
}
proc_with_prefix test_mi_stack_select_frame { mode } {
@@ -1290,9 +1315,22 @@ proc_with_prefix test_cli_in_mi_thread { mode cli_in_mi_mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set command [make_cli_in_mi_command $cli_in_mi_mode "thread 2.2"]
+ set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 2 2.2 5 0]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $mi_spawn_id {
+ mi_gdb_test $command $mi_re "select thread"
+ }
+
+ with_spawn_id $gdb_main_spawn_id {
+ match_re_or_ensure_no_output "$cli_re\r\n" "select thread, event on CLI"
+ }
+ }
}
# Test selecting the frame using a CLI command in the MI channel.
diff --git a/gdb/thread.c b/gdb/thread.c
index 2c5292d24b7..0f44eacd1f4 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1977,10 +1977,19 @@ thread_command (const char *tidstr, int from_tty)
}
else
{
+ inferior *previous_inferior = current_inferior ();
+
thread_select (tidstr, parse_thread_id (tidstr, NULL));
- notify_user_selected_context_changed
- (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
+ user_selected_what selection = (USER_SELECTED_THREAD
+ | USER_SELECTED_FRAME);
+
+ /* If the inferior changed as a consequence of the thread change,
+ then let the user know. */
+ if (previous_inferior != current_inferior ())
+ selection |= USER_SELECTED_INFERIOR;
+
+ notify_user_selected_context_changed (selection);
}
}
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCHv2] gdb: notify of inferior switch when needed from 'thread' command
2025-10-08 8:48 [PATCH] gdb: notify of inferior switch when needed from 'thread' command Andrew Burgess
2025-10-09 18:59 ` Pedro Alves
@ 2026-01-26 13:58 ` Andrew Burgess
2026-03-17 19:41 ` Guinevere Larsen
2026-04-17 14:54 ` [PATCHv3] " Andrew Burgess
1 sibling, 2 replies; 10+ messages in thread
From: Andrew Burgess @ 2026-01-26 13:58 UTC (permalink / raw)
To: gdb-patches; +Cc: Andrew Burgess
In v2:
- Rebased and retested.
- Reworked commit message to try and address Pedro's concerns.
Thanks,
Andrew
---
While working on the commit:
commit 9959019545d8d6d71d927f20f088efba944b1e9c
Date: Sun Sep 28 16:16:53 2025 +0100
gdb: fix for 'set suppress-cli-notifications on' missed case
I spotted this message in the gdb.mi/user-selected-context-sync.exp
test script:
# Idea for the future: selecting a thread in a different inferior. For now,
# GDB doesn't show an inferior switch, but if it did, it would be a nice
# place to test it.
What this message is talking about is this behaviour:
(gdb) info threads
Id Target Id Frame
1.1 Thread 0xf7dbc700 (LWP 818430) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
1.2 Thread 0xf7dbbb40 (LWP 818433) "thr" 0xf7fd0579 in __kernel_vsyscall ()
1.3 Thread 0xf73ffb40 (LWP 818434) "thr" breakpt () at thr.c:19
2.1 Thread 0xf7dbc700 (LWP 818456) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
2.2 Thread 0xf7dbbb40 (LWP 818457) "thr" breakpt () at thr.c:19
* 2.3 Thread 0xf73ffb40 (LWP 818458) "thr" breakpt () at thr.c:19
(gdb) inferior 1
[Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
[Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))]
#0 0xf7eb2888 in clone () from /lib/libc.so.6
(gdb) thread 2.2
[Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))]
#0 breakpt () at thr.c:19
19 while (stop)
(gdb)
Notice that when we switch from thread 2.3 to 1.1 using the 'inferior
1' command, GDB tells us that the inferior has changed, and that the
thread has changed (and also that the frame has changed).
But, when we switch from 1.1 to 2.2 using the 'thread 2.2' command, we
are only told about the thread change.
The 'Switching to inferior ...' line includes some useful information,
the process PID and the executable name, and I think it is a shame
that these are not presented when using the 'thread' command to switch
inferior.
So, this commit addresses this issue.
A question that came up during review, and which I'm clarifying here:
this change only effects the output of GDB when the thread command is
also used to switch inferiors. I am (in effect) arguing that the
command 'thread 2.2' should be treated as a shorthand for 'inferior 2;
thread 2', and should display all of the associated output. If the
user is only switching threads within a single inferior then it is not
necessary to re-display the inferior information.
I acknowledge that this does mean the output of the 'thread' command
will now be different depending on whether the user changes inferior
or not. However, I think this is better than the alternative, having
the 'thread' command always re-print the inferior information. I
think this would introduce excess noise that is not useful.
There are changes in basically two areas. The easy part is in
thread_command (thread.c). Here we spot when the inferior has changed
as a result of the 'thread' command, and included
USER_SELECTED_INFERIOR in the set of state passed to the
notify_user_selected_context_changed function.
The change in mi/mi-main.c is a little more involved. In the
mi_cmd_execute function we use an instance of user_selected_context to
spot if any inferior state (frame, thread, or inferior) changes after
an MI command, this is then used to decide if there should be a call
to notify_user_selected_context_changed.
Currently, in mi_cmd_execute, notify_user_selected_context_changed is
always passed 'USER_SELECTED_THREAD | USER_SELECTED_FRAME'. This
makes sense, the MI doesn't allow "switching inferiors" as a command,
instead, an MI frontend must switch threads, and the inferior is
switched as a consequence. But this does mean that if a user has a
CLI and MI interpreter running, and the MI switches threads, the CLI
will only receive the thread switch style notifications, that is,
there will be no "Switching to inferior ..." line.
What I've done is rename user_selected_context::has_changed to
user_selected_context::what_changed, this function is now responsible
for returning the set of USER_SELECTED_* flags that indicate what
changed.
If anything has changed then we always return USER_SELECTED_THREAD |
USER_SELECTED_FRAME as a minimum. This retains the existing
behaviour, but is possibly more aggressive that we need to be; the
-stack-select-frame command can only change the frame, so maybe in
this case we should only return USER_SELECTED_FRAME? I've left that
for the future though.
However, the important change is that in ::what_changed, I now spot
when the inferior has changed and include USER_SELECTED_INFERIOR in
the set of flags that are returned.
In mi_cmd_execute we now call the new what_changed function, and use
the set of flags returned when calling
notify_user_selected_context_changed. This means that the CLI will
now receive inferior changed notifications when appropriate.
The gdb.mi/user-selected-context-sync.exp script has been updated,
replacing the comment I quoted above with an actual test that the
inferior change is announced correctly.
---
gdb/mi/mi-main.c | 44 ++++++++++++---
.../gdb.mi/user-selected-context-sync.exp | 56 ++++++++++++++++---
gdb/thread.c | 13 ++++-
3 files changed, 93 insertions(+), 20 deletions(-)
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 77e56bc9fc8..a18209366ff 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -538,6 +538,11 @@ mi_cmd_thread_select (const char *command, const char *const *argv, int argc)
thread_select (argv[0], thr);
+ /* We don't call print_selected_inferior here as this never prints
+ anything when the output is MI like (as it is now). MI consumers are
+ expected to derive the inferior change from the global thread-id
+ included in the print_selected_thread_frame output. */
+
print_selected_thread_frame (current_uiout,
USER_SELECTED_THREAD | USER_SELECTED_FRAME);
}
@@ -1968,12 +1973,30 @@ struct user_selected_context
/* Return true if the user selected context has changed since this object
was created. */
- bool has_changed () const
+ user_selected_what what_changed () const
{
+ /* If anything changed then we report both the thread and frame at a
+ minimum. We optionally add the inferior if we know that it
+ changed.
+
+ This means that for pure frame changes, e.g. -stack-select-frame, we
+ still report both a thread and a frame, which isn't ideal, but
+ there's also the cases where -thread-select is used to re-select the
+ current thread, in this case we'd still like to see the thread
+ reported, at least, that's what we have historically done. */
+ user_selected_what state
+ = USER_SELECTED_THREAD | USER_SELECTED_FRAME;
+
/* Did the selected thread change? */
if (m_previous_ptid != null_ptid && inferior_ptid != null_ptid
&& m_previous_ptid != inferior_ptid)
- return true;
+ {
+ /* Did the inferior change too? */
+ if (m_previous_ptid.pid () != inferior_ptid.pid ())
+ state |= USER_SELECTED_INFERIOR;
+
+ return state;
+ }
/* Grab details of the currently selected frame, for comparison. */
frame_id current_frame_id;
@@ -1982,7 +2005,7 @@ struct user_selected_context
/* Did the selected frame level change? */
if (current_frame_level != m_previous_frame_level)
- return true;
+ return state;
/* Did the selected frame id change? If the innermost frame is
selected then the level will be -1, and the frame-id will be
@@ -1991,10 +2014,10 @@ struct user_selected_context
other than the innermost frame selected. */
if (current_frame_level != -1
&& current_frame_id != m_previous_frame_id)
- return true;
+ return state;
/* Nothing changed! */
- return false;
+ return 0;
}
private:
/* The previously selected thread. This might be null_ptid if there was
@@ -2098,10 +2121,13 @@ mi_cmd_execute (struct mi_parse *parse)
parse->cmd->invoke (parse);
- if (!parse->cmd->preserve_user_selected_context ()
- && current_user_selected_context.has_changed ())
- interps_notify_user_selected_context_changed
- (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
+ if (!parse->cmd->preserve_user_selected_context ())
+ {
+ user_selected_what what
+ = current_user_selected_context.what_changed ();
+ if (what != 0)
+ notify_user_selected_context_changed (what);
+ }
}
/* See mi-main.h. */
diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
index 3434ffa2a46..4f02b950f6e 100644
--- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
+++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
@@ -698,9 +698,21 @@ proc_with_prefix test_cli_thread { mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set mi_re [make_mi_re $mode 5 0 event]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $gdb_main_spawn_id {
+ gdb_test "thread 2.2" $cli_re "select thread"
+ }
+
+ with_spawn_id $mi_spawn_id {
+ match_re_or_ensure_no_output $mi_re "select thread, event on MI"
+ }
+ }
}
# Test frame selection from CLI.
@@ -995,9 +1007,22 @@ proc_with_prefix test_mi_thread_select { mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set mi_re [make_mi_re $mode 5 0 response]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $mi_spawn_id {
+ mi_gdb_test "-thread-select 5" $mi_re "-thread-select"
+ }
+
+ with_spawn_id $gdb_main_spawn_id {
+ match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on CLI"
+ }
+
+ }
}
proc_with_prefix test_mi_stack_select_frame { mode } {
@@ -1290,9 +1315,22 @@ proc_with_prefix test_cli_in_mi_thread { mode cli_in_mi_mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set command [make_cli_in_mi_command $cli_in_mi_mode "thread 2.2"]
+ set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 2 2.2 5 0]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $mi_spawn_id {
+ mi_gdb_test $command $mi_re "select thread"
+ }
+
+ with_spawn_id $gdb_main_spawn_id {
+ match_re_or_ensure_no_output "$cli_re\r\n" "select thread, event on CLI"
+ }
+ }
}
# Test selecting the frame using a CLI command in the MI channel.
diff --git a/gdb/thread.c b/gdb/thread.c
index 0788bea235a..9ca1a8d973a 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1983,10 +1983,19 @@ thread_command (const char *tidstr, int from_tty)
}
else
{
+ inferior *previous_inferior = current_inferior ();
+
thread_select (tidstr, parse_thread_id (tidstr, NULL));
- notify_user_selected_context_changed
- (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
+ user_selected_what selection = (USER_SELECTED_THREAD
+ | USER_SELECTED_FRAME);
+
+ /* If the inferior changed as a consequence of the thread change,
+ then let the user know. */
+ if (previous_inferior != current_inferior ())
+ selection |= USER_SELECTED_INFERIOR;
+
+ notify_user_selected_context_changed (selection);
}
}
base-commit: 449035c35f2169e0c690d83f28306275ab7f7463
--
2.25.4
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCHv2] gdb: notify of inferior switch when needed from 'thread' command
2026-01-26 13:58 ` [PATCHv2] " Andrew Burgess
@ 2026-03-17 19:41 ` Guinevere Larsen
2026-03-18 14:34 ` Andrew Burgess
2026-04-17 14:54 ` [PATCHv3] " Andrew Burgess
1 sibling, 1 reply; 10+ messages in thread
From: Guinevere Larsen @ 2026-03-17 19:41 UTC (permalink / raw)
To: Andrew Burgess, gdb-patches
On 1/26/26 10:58 AM, Andrew Burgess wrote:
> In v2:
>
> - Rebased and retested.
>
> - Reworked commit message to try and address Pedro's concerns.
>
> Thanks,
> Andrew
>
> ---
Hi Andrew!
I've taken a look at this patch and it looks pretty good, and I think it
is a good change.
I know you're waiting for Pedro's feedback, but hopefully this message
acts as a ping for him as well as a review for you
Reviewed-By: Guinevere Larsen <guinevere@redhat.com>
>
> While working on the commit:
>
> commit 9959019545d8d6d71d927f20f088efba944b1e9c
> Date: Sun Sep 28 16:16:53 2025 +0100
>
> gdb: fix for 'set suppress-cli-notifications on' missed case
>
> I spotted this message in the gdb.mi/user-selected-context-sync.exp
> test script:
>
> # Idea for the future: selecting a thread in a different inferior. For now,
> # GDB doesn't show an inferior switch, but if it did, it would be a nice
> # place to test it.
>
> What this message is talking about is this behaviour:
>
> (gdb) info threads
> Id Target Id Frame
> 1.1 Thread 0xf7dbc700 (LWP 818430) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
> 1.2 Thread 0xf7dbbb40 (LWP 818433) "thr" 0xf7fd0579 in __kernel_vsyscall ()
> 1.3 Thread 0xf73ffb40 (LWP 818434) "thr" breakpt () at thr.c:19
> 2.1 Thread 0xf7dbc700 (LWP 818456) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
> 2.2 Thread 0xf7dbbb40 (LWP 818457) "thr" breakpt () at thr.c:19
> * 2.3 Thread 0xf73ffb40 (LWP 818458) "thr" breakpt () at thr.c:19
> (gdb) inferior 1
> [Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
> [Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))]
> #0 0xf7eb2888 in clone () from /lib/libc.so.6
> (gdb) thread 2.2
> [Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))]
> #0 breakpt () at thr.c:19
> 19 while (stop)
> (gdb)
>
> Notice that when we switch from thread 2.3 to 1.1 using the 'inferior
> 1' command, GDB tells us that the inferior has changed, and that the
> thread has changed (and also that the frame has changed).
>
> But, when we switch from 1.1 to 2.2 using the 'thread 2.2' command, we
> are only told about the thread change.
>
> The 'Switching to inferior ...' line includes some useful information,
> the process PID and the executable name, and I think it is a shame
> that these are not presented when using the 'thread' command to switch
> inferior.
>
> So, this commit addresses this issue.
>
> A question that came up during review, and which I'm clarifying here:
> this change only effects the output of GDB when the thread command is
> also used to switch inferiors. I am (in effect) arguing that the
> command 'thread 2.2' should be treated as a shorthand for 'inferior 2;
> thread 2', and should display all of the associated output. If the
> user is only switching threads within a single inferior then it is not
> necessary to re-display the inferior information.
>
> I acknowledge that this does mean the output of the 'thread' command
> will now be different depending on whether the user changes inferior
> or not. However, I think this is better than the alternative, having
> the 'thread' command always re-print the inferior information. I
> think this would introduce excess noise that is not useful.
>
> There are changes in basically two areas. The easy part is in
> thread_command (thread.c). Here we spot when the inferior has changed
> as a result of the 'thread' command, and included
> USER_SELECTED_INFERIOR in the set of state passed to the
> notify_user_selected_context_changed function.
>
> The change in mi/mi-main.c is a little more involved. In the
> mi_cmd_execute function we use an instance of user_selected_context to
> spot if any inferior state (frame, thread, or inferior) changes after
> an MI command, this is then used to decide if there should be a call
> to notify_user_selected_context_changed.
>
> Currently, in mi_cmd_execute, notify_user_selected_context_changed is
> always passed 'USER_SELECTED_THREAD | USER_SELECTED_FRAME'. This
> makes sense, the MI doesn't allow "switching inferiors" as a command,
> instead, an MI frontend must switch threads, and the inferior is
> switched as a consequence. But this does mean that if a user has a
> CLI and MI interpreter running, and the MI switches threads, the CLI
> will only receive the thread switch style notifications, that is,
> there will be no "Switching to inferior ..." line.
>
> What I've done is rename user_selected_context::has_changed to
> user_selected_context::what_changed, this function is now responsible
> for returning the set of USER_SELECTED_* flags that indicate what
> changed.
>
> If anything has changed then we always return USER_SELECTED_THREAD |
> USER_SELECTED_FRAME as a minimum. This retains the existing
> behaviour, but is possibly more aggressive that we need to be; the
> -stack-select-frame command can only change the frame, so maybe in
> this case we should only return USER_SELECTED_FRAME? I've left that
> for the future though.
>
> However, the important change is that in ::what_changed, I now spot
> when the inferior has changed and include USER_SELECTED_INFERIOR in
> the set of flags that are returned.
>
> In mi_cmd_execute we now call the new what_changed function, and use
> the set of flags returned when calling
> notify_user_selected_context_changed. This means that the CLI will
> now receive inferior changed notifications when appropriate.
>
> The gdb.mi/user-selected-context-sync.exp script has been updated,
> replacing the comment I quoted above with an actual test that the
> inferior change is announced correctly.
> ---
> gdb/mi/mi-main.c | 44 ++++++++++++---
> .../gdb.mi/user-selected-context-sync.exp | 56 ++++++++++++++++---
> gdb/thread.c | 13 ++++-
> 3 files changed, 93 insertions(+), 20 deletions(-)
>
> diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
> index 77e56bc9fc8..a18209366ff 100644
> --- a/gdb/mi/mi-main.c
> +++ b/gdb/mi/mi-main.c
> @@ -538,6 +538,11 @@ mi_cmd_thread_select (const char *command, const char *const *argv, int argc)
>
> thread_select (argv[0], thr);
>
> + /* We don't call print_selected_inferior here as this never prints
> + anything when the output is MI like (as it is now). MI consumers are
> + expected to derive the inferior change from the global thread-id
> + included in the print_selected_thread_frame output. */
> +
> print_selected_thread_frame (current_uiout,
> USER_SELECTED_THREAD | USER_SELECTED_FRAME);
> }
> @@ -1968,12 +1973,30 @@ struct user_selected_context
>
> /* Return true if the user selected context has changed since this object
> was created. */
> - bool has_changed () const
> + user_selected_what what_changed () const
> {
> + /* If anything changed then we report both the thread and frame at a
> + minimum. We optionally add the inferior if we know that it
> + changed.
> +
> + This means that for pure frame changes, e.g. -stack-select-frame, we
> + still report both a thread and a frame, which isn't ideal, but
> + there's also the cases where -thread-select is used to re-select the
> + current thread, in this case we'd still like to see the thread
> + reported, at least, that's what we have historically done. */
> + user_selected_what state
> + = USER_SELECTED_THREAD | USER_SELECTED_FRAME;
> +
> /* Did the selected thread change? */
> if (m_previous_ptid != null_ptid && inferior_ptid != null_ptid
> && m_previous_ptid != inferior_ptid)
> - return true;
> + {
> + /* Did the inferior change too? */
> + if (m_previous_ptid.pid () != inferior_ptid.pid ())
> + state |= USER_SELECTED_INFERIOR;
> +
> + return state;
> + }
>
> /* Grab details of the currently selected frame, for comparison. */
> frame_id current_frame_id;
> @@ -1982,7 +2005,7 @@ struct user_selected_context
>
> /* Did the selected frame level change? */
> if (current_frame_level != m_previous_frame_level)
> - return true;
> + return state;
>
> /* Did the selected frame id change? If the innermost frame is
> selected then the level will be -1, and the frame-id will be
> @@ -1991,10 +2014,10 @@ struct user_selected_context
> other than the innermost frame selected. */
> if (current_frame_level != -1
> && current_frame_id != m_previous_frame_id)
> - return true;
> + return state;
>
> /* Nothing changed! */
> - return false;
> + return 0;
> }
> private:
> /* The previously selected thread. This might be null_ptid if there was
> @@ -2098,10 +2121,13 @@ mi_cmd_execute (struct mi_parse *parse)
>
> parse->cmd->invoke (parse);
>
> - if (!parse->cmd->preserve_user_selected_context ()
> - && current_user_selected_context.has_changed ())
> - interps_notify_user_selected_context_changed
> - (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
> + if (!parse->cmd->preserve_user_selected_context ())
> + {
> + user_selected_what what
> + = current_user_selected_context.what_changed ();
> + if (what != 0)
> + notify_user_selected_context_changed (what);
> + }
> }
>
> /* See mi-main.h. */
> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> index 3434ffa2a46..4f02b950f6e 100644
> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
> @@ -698,9 +698,21 @@ proc_with_prefix test_cli_thread { mode } {
> }
> }
>
> - # Idea for the future: selecting a thread in a different inferior. For now,
> - # GDB doesn't show an inferior switch, but if it did, it would be a nice
> - # place to test it.
> + with_test_prefix "thread 2.2" {
> + # Select a thread in a different inferior. This should trigger an
> + # 'inferior changed' and 'thread changed' notification on the CLI,
> + # and a single MI async notification.
> + set mi_re [make_mi_re $mode 5 0 event]
> + set cli_re [make_cli_re $mode 2 2.2 0]
> +
> + with_spawn_id $gdb_main_spawn_id {
> + gdb_test "thread 2.2" $cli_re "select thread"
> + }
> +
> + with_spawn_id $mi_spawn_id {
> + match_re_or_ensure_no_output $mi_re "select thread, event on MI"
> + }
> + }
> }
>
> # Test frame selection from CLI.
> @@ -995,9 +1007,22 @@ proc_with_prefix test_mi_thread_select { mode } {
> }
> }
>
> - # Idea for the future: selecting a thread in a different inferior. For now,
> - # GDB doesn't show an inferior switch, but if it did, it would be a nice
> - # place to test it.
> + with_test_prefix "thread 2.2" {
> + # Select a thread in a different inferior. This should trigger an
> + # 'inferior changed' and 'thread changed' notification on the CLI,
> + # and a single MI async notification.
> + set mi_re [make_mi_re $mode 5 0 response]
> + set cli_re [make_cli_re $mode 2 2.2 0]
> +
> + with_spawn_id $mi_spawn_id {
> + mi_gdb_test "-thread-select 5" $mi_re "-thread-select"
> + }
> +
> + with_spawn_id $gdb_main_spawn_id {
> + match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on CLI"
> + }
> +
> + }
> }
>
> proc_with_prefix test_mi_stack_select_frame { mode } {
> @@ -1290,9 +1315,22 @@ proc_with_prefix test_cli_in_mi_thread { mode cli_in_mi_mode } {
> }
> }
>
> - # Idea for the future: selecting a thread in a different inferior. For now,
> - # GDB doesn't show an inferior switch, but if it did, it would be a nice
> - # place to test it.
> + with_test_prefix "thread 2.2" {
> + # Select a thread in a different inferior. This should trigger an
> + # 'inferior changed' and 'thread changed' notification on the CLI,
> + # and a single MI async notification.
> + set command [make_cli_in_mi_command $cli_in_mi_mode "thread 2.2"]
> + set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 2 2.2 5 0]
> + set cli_re [make_cli_re $mode 2 2.2 0]
> +
> + with_spawn_id $mi_spawn_id {
> + mi_gdb_test $command $mi_re "select thread"
> + }
> +
> + with_spawn_id $gdb_main_spawn_id {
> + match_re_or_ensure_no_output "$cli_re\r\n" "select thread, event on CLI"
> + }
> + }
> }
>
> # Test selecting the frame using a CLI command in the MI channel.
> diff --git a/gdb/thread.c b/gdb/thread.c
> index 0788bea235a..9ca1a8d973a 100644
> --- a/gdb/thread.c
> +++ b/gdb/thread.c
> @@ -1983,10 +1983,19 @@ thread_command (const char *tidstr, int from_tty)
> }
> else
> {
> + inferior *previous_inferior = current_inferior ();
> +
> thread_select (tidstr, parse_thread_id (tidstr, NULL));
>
> - notify_user_selected_context_changed
> - (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
> + user_selected_what selection = (USER_SELECTED_THREAD
> + | USER_SELECTED_FRAME);
> +
> + /* If the inferior changed as a consequence of the thread change,
> + then let the user know. */
> + if (previous_inferior != current_inferior ())
> + selection |= USER_SELECTED_INFERIOR;
> +
> + notify_user_selected_context_changed (selection);
> }
> }
>
>
> base-commit: 449035c35f2169e0c690d83f28306275ab7f7463
--
Cheers,
Guinevere Larsen
It/she
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCHv2] gdb: notify of inferior switch when needed from 'thread' command
2026-03-17 19:41 ` Guinevere Larsen
@ 2026-03-18 14:34 ` Andrew Burgess
0 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2026-03-18 14:34 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches, Pedro Alves
Guinevere Larsen <guinevere@redhat.com> writes:
> On 1/26/26 10:58 AM, Andrew Burgess wrote:
>> In v2:
>>
>> - Rebased and retested.
>>
>> - Reworked commit message to try and address Pedro's concerns.
>>
>> Thanks,
>> Andrew
>>
>> ---
>
> Hi Andrew!
>
> I've taken a look at this patch and it looks pretty good, and I think it
> is a good change.
>
> I know you're waiting for Pedro's feedback, but hopefully this message
> acts as a ping for him as well as a review for you
>
> Reviewed-By: Guinevere Larsen <guinevere@redhat.com>
Thanks Guinevere, I appreciate the feedback.
I've been wondering what to do about this patch. Usually I would have
self-approved it and applied it by now, but I'm very reluctant to do
that given Pedro's previous comments.
I've added Pedro to the 'To:' list, I should have done that with the
original v2 patch. I'll give this a little longer yet, my hope is to
land this for GDB 18.
Thanks,
Andrew
>
>>
>> While working on the commit:
>>
>> commit 9959019545d8d6d71d927f20f088efba944b1e9c
>> Date: Sun Sep 28 16:16:53 2025 +0100
>>
>> gdb: fix for 'set suppress-cli-notifications on' missed case
>>
>> I spotted this message in the gdb.mi/user-selected-context-sync.exp
>> test script:
>>
>> # Idea for the future: selecting a thread in a different inferior. For now,
>> # GDB doesn't show an inferior switch, but if it did, it would be a nice
>> # place to test it.
>>
>> What this message is talking about is this behaviour:
>>
>> (gdb) info threads
>> Id Target Id Frame
>> 1.1 Thread 0xf7dbc700 (LWP 818430) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
>> 1.2 Thread 0xf7dbbb40 (LWP 818433) "thr" 0xf7fd0579 in __kernel_vsyscall ()
>> 1.3 Thread 0xf73ffb40 (LWP 818434) "thr" breakpt () at thr.c:19
>> 2.1 Thread 0xf7dbc700 (LWP 818456) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
>> 2.2 Thread 0xf7dbbb40 (LWP 818457) "thr" breakpt () at thr.c:19
>> * 2.3 Thread 0xf73ffb40 (LWP 818458) "thr" breakpt () at thr.c:19
>> (gdb) inferior 1
>> [Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
>> [Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))]
>> #0 0xf7eb2888 in clone () from /lib/libc.so.6
>> (gdb) thread 2.2
>> [Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))]
>> #0 breakpt () at thr.c:19
>> 19 while (stop)
>> (gdb)
>>
>> Notice that when we switch from thread 2.3 to 1.1 using the 'inferior
>> 1' command, GDB tells us that the inferior has changed, and that the
>> thread has changed (and also that the frame has changed).
>>
>> But, when we switch from 1.1 to 2.2 using the 'thread 2.2' command, we
>> are only told about the thread change.
>>
>> The 'Switching to inferior ...' line includes some useful information,
>> the process PID and the executable name, and I think it is a shame
>> that these are not presented when using the 'thread' command to switch
>> inferior.
>>
>> So, this commit addresses this issue.
>>
>> A question that came up during review, and which I'm clarifying here:
>> this change only effects the output of GDB when the thread command is
>> also used to switch inferiors. I am (in effect) arguing that the
>> command 'thread 2.2' should be treated as a shorthand for 'inferior 2;
>> thread 2', and should display all of the associated output. If the
>> user is only switching threads within a single inferior then it is not
>> necessary to re-display the inferior information.
>>
>> I acknowledge that this does mean the output of the 'thread' command
>> will now be different depending on whether the user changes inferior
>> or not. However, I think this is better than the alternative, having
>> the 'thread' command always re-print the inferior information. I
>> think this would introduce excess noise that is not useful.
>>
>> There are changes in basically two areas. The easy part is in
>> thread_command (thread.c). Here we spot when the inferior has changed
>> as a result of the 'thread' command, and included
>> USER_SELECTED_INFERIOR in the set of state passed to the
>> notify_user_selected_context_changed function.
>>
>> The change in mi/mi-main.c is a little more involved. In the
>> mi_cmd_execute function we use an instance of user_selected_context to
>> spot if any inferior state (frame, thread, or inferior) changes after
>> an MI command, this is then used to decide if there should be a call
>> to notify_user_selected_context_changed.
>>
>> Currently, in mi_cmd_execute, notify_user_selected_context_changed is
>> always passed 'USER_SELECTED_THREAD | USER_SELECTED_FRAME'. This
>> makes sense, the MI doesn't allow "switching inferiors" as a command,
>> instead, an MI frontend must switch threads, and the inferior is
>> switched as a consequence. But this does mean that if a user has a
>> CLI and MI interpreter running, and the MI switches threads, the CLI
>> will only receive the thread switch style notifications, that is,
>> there will be no "Switching to inferior ..." line.
>>
>> What I've done is rename user_selected_context::has_changed to
>> user_selected_context::what_changed, this function is now responsible
>> for returning the set of USER_SELECTED_* flags that indicate what
>> changed.
>>
>> If anything has changed then we always return USER_SELECTED_THREAD |
>> USER_SELECTED_FRAME as a minimum. This retains the existing
>> behaviour, but is possibly more aggressive that we need to be; the
>> -stack-select-frame command can only change the frame, so maybe in
>> this case we should only return USER_SELECTED_FRAME? I've left that
>> for the future though.
>>
>> However, the important change is that in ::what_changed, I now spot
>> when the inferior has changed and include USER_SELECTED_INFERIOR in
>> the set of flags that are returned.
>>
>> In mi_cmd_execute we now call the new what_changed function, and use
>> the set of flags returned when calling
>> notify_user_selected_context_changed. This means that the CLI will
>> now receive inferior changed notifications when appropriate.
>>
>> The gdb.mi/user-selected-context-sync.exp script has been updated,
>> replacing the comment I quoted above with an actual test that the
>> inferior change is announced correctly.
>> ---
>> gdb/mi/mi-main.c | 44 ++++++++++++---
>> .../gdb.mi/user-selected-context-sync.exp | 56 ++++++++++++++++---
>> gdb/thread.c | 13 ++++-
>> 3 files changed, 93 insertions(+), 20 deletions(-)
>>
>> diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
>> index 77e56bc9fc8..a18209366ff 100644
>> --- a/gdb/mi/mi-main.c
>> +++ b/gdb/mi/mi-main.c
>> @@ -538,6 +538,11 @@ mi_cmd_thread_select (const char *command, const char *const *argv, int argc)
>>
>> thread_select (argv[0], thr);
>>
>> + /* We don't call print_selected_inferior here as this never prints
>> + anything when the output is MI like (as it is now). MI consumers are
>> + expected to derive the inferior change from the global thread-id
>> + included in the print_selected_thread_frame output. */
>> +
>> print_selected_thread_frame (current_uiout,
>> USER_SELECTED_THREAD | USER_SELECTED_FRAME);
>> }
>> @@ -1968,12 +1973,30 @@ struct user_selected_context
>>
>> /* Return true if the user selected context has changed since this object
>> was created. */
>> - bool has_changed () const
>> + user_selected_what what_changed () const
>> {
>> + /* If anything changed then we report both the thread and frame at a
>> + minimum. We optionally add the inferior if we know that it
>> + changed.
>> +
>> + This means that for pure frame changes, e.g. -stack-select-frame, we
>> + still report both a thread and a frame, which isn't ideal, but
>> + there's also the cases where -thread-select is used to re-select the
>> + current thread, in this case we'd still like to see the thread
>> + reported, at least, that's what we have historically done. */
>> + user_selected_what state
>> + = USER_SELECTED_THREAD | USER_SELECTED_FRAME;
>> +
>> /* Did the selected thread change? */
>> if (m_previous_ptid != null_ptid && inferior_ptid != null_ptid
>> && m_previous_ptid != inferior_ptid)
>> - return true;
>> + {
>> + /* Did the inferior change too? */
>> + if (m_previous_ptid.pid () != inferior_ptid.pid ())
>> + state |= USER_SELECTED_INFERIOR;
>> +
>> + return state;
>> + }
>>
>> /* Grab details of the currently selected frame, for comparison. */
>> frame_id current_frame_id;
>> @@ -1982,7 +2005,7 @@ struct user_selected_context
>>
>> /* Did the selected frame level change? */
>> if (current_frame_level != m_previous_frame_level)
>> - return true;
>> + return state;
>>
>> /* Did the selected frame id change? If the innermost frame is
>> selected then the level will be -1, and the frame-id will be
>> @@ -1991,10 +2014,10 @@ struct user_selected_context
>> other than the innermost frame selected. */
>> if (current_frame_level != -1
>> && current_frame_id != m_previous_frame_id)
>> - return true;
>> + return state;
>>
>> /* Nothing changed! */
>> - return false;
>> + return 0;
>> }
>> private:
>> /* The previously selected thread. This might be null_ptid if there was
>> @@ -2098,10 +2121,13 @@ mi_cmd_execute (struct mi_parse *parse)
>>
>> parse->cmd->invoke (parse);
>>
>> - if (!parse->cmd->preserve_user_selected_context ()
>> - && current_user_selected_context.has_changed ())
>> - interps_notify_user_selected_context_changed
>> - (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
>> + if (!parse->cmd->preserve_user_selected_context ())
>> + {
>> + user_selected_what what
>> + = current_user_selected_context.what_changed ();
>> + if (what != 0)
>> + notify_user_selected_context_changed (what);
>> + }
>> }
>>
>> /* See mi-main.h. */
>> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
>> index 3434ffa2a46..4f02b950f6e 100644
>> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
>> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
>> @@ -698,9 +698,21 @@ proc_with_prefix test_cli_thread { mode } {
>> }
>> }
>>
>> - # Idea for the future: selecting a thread in a different inferior. For now,
>> - # GDB doesn't show an inferior switch, but if it did, it would be a nice
>> - # place to test it.
>> + with_test_prefix "thread 2.2" {
>> + # Select a thread in a different inferior. This should trigger an
>> + # 'inferior changed' and 'thread changed' notification on the CLI,
>> + # and a single MI async notification.
>> + set mi_re [make_mi_re $mode 5 0 event]
>> + set cli_re [make_cli_re $mode 2 2.2 0]
>> +
>> + with_spawn_id $gdb_main_spawn_id {
>> + gdb_test "thread 2.2" $cli_re "select thread"
>> + }
>> +
>> + with_spawn_id $mi_spawn_id {
>> + match_re_or_ensure_no_output $mi_re "select thread, event on MI"
>> + }
>> + }
>> }
>>
>> # Test frame selection from CLI.
>> @@ -995,9 +1007,22 @@ proc_with_prefix test_mi_thread_select { mode } {
>> }
>> }
>>
>> - # Idea for the future: selecting a thread in a different inferior. For now,
>> - # GDB doesn't show an inferior switch, but if it did, it would be a nice
>> - # place to test it.
>> + with_test_prefix "thread 2.2" {
>> + # Select a thread in a different inferior. This should trigger an
>> + # 'inferior changed' and 'thread changed' notification on the CLI,
>> + # and a single MI async notification.
>> + set mi_re [make_mi_re $mode 5 0 response]
>> + set cli_re [make_cli_re $mode 2 2.2 0]
>> +
>> + with_spawn_id $mi_spawn_id {
>> + mi_gdb_test "-thread-select 5" $mi_re "-thread-select"
>> + }
>> +
>> + with_spawn_id $gdb_main_spawn_id {
>> + match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on CLI"
>> + }
>> +
>> + }
>> }
>>
>> proc_with_prefix test_mi_stack_select_frame { mode } {
>> @@ -1290,9 +1315,22 @@ proc_with_prefix test_cli_in_mi_thread { mode cli_in_mi_mode } {
>> }
>> }
>>
>> - # Idea for the future: selecting a thread in a different inferior. For now,
>> - # GDB doesn't show an inferior switch, but if it did, it would be a nice
>> - # place to test it.
>> + with_test_prefix "thread 2.2" {
>> + # Select a thread in a different inferior. This should trigger an
>> + # 'inferior changed' and 'thread changed' notification on the CLI,
>> + # and a single MI async notification.
>> + set command [make_cli_in_mi_command $cli_in_mi_mode "thread 2.2"]
>> + set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 2 2.2 5 0]
>> + set cli_re [make_cli_re $mode 2 2.2 0]
>> +
>> + with_spawn_id $mi_spawn_id {
>> + mi_gdb_test $command $mi_re "select thread"
>> + }
>> +
>> + with_spawn_id $gdb_main_spawn_id {
>> + match_re_or_ensure_no_output "$cli_re\r\n" "select thread, event on CLI"
>> + }
>> + }
>> }
>>
>> # Test selecting the frame using a CLI command in the MI channel.
>> diff --git a/gdb/thread.c b/gdb/thread.c
>> index 0788bea235a..9ca1a8d973a 100644
>> --- a/gdb/thread.c
>> +++ b/gdb/thread.c
>> @@ -1983,10 +1983,19 @@ thread_command (const char *tidstr, int from_tty)
>> }
>> else
>> {
>> + inferior *previous_inferior = current_inferior ();
>> +
>> thread_select (tidstr, parse_thread_id (tidstr, NULL));
>>
>> - notify_user_selected_context_changed
>> - (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
>> + user_selected_what selection = (USER_SELECTED_THREAD
>> + | USER_SELECTED_FRAME);
>> +
>> + /* If the inferior changed as a consequence of the thread change,
>> + then let the user know. */
>> + if (previous_inferior != current_inferior ())
>> + selection |= USER_SELECTED_INFERIOR;
>> +
>> + notify_user_selected_context_changed (selection);
>> }
>> }
>>
>>
>> base-commit: 449035c35f2169e0c690d83f28306275ab7f7463
>
>
> --
> Cheers,
> Guinevere Larsen
> It/she
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCHv3] gdb: notify of inferior switch when needed from 'thread' command
2026-01-26 13:58 ` [PATCHv2] " Andrew Burgess
2026-03-17 19:41 ` Guinevere Larsen
@ 2026-04-17 14:54 ` Andrew Burgess
1 sibling, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2026-04-17 14:54 UTC (permalink / raw)
To: gdb-patches; +Cc: Andrew Burgess, Guinevere Larsen
I looked into the issues that Baris raised in this email:
https://inbox.sourceware.org/gdb-patches/IA0PR11MB7307BB4B5B3CC3A354289261C4C7A@IA0PR11MB7307.namprd11.prod.outlook.com
About how in a multi-inferior debug session, if hitting a breakpoint
triggers a thread AND inferior switch, then we announce the new
thread, but not the new inferior. This is very similar to the fix
being proposed in this patch.
However, in this case we don't use
notify_user_selected_context_changed to announce the new
thread/inferior, instead this is done in normal_stop (infrunc.c).
I think we could and should change this code to announce the inferior
switch where appropriate. But given this change would be quite
different to the changes in this patch, then my current plan is to do
that in a follow up change once this is merged.
Speaking of which, my current plan is to push this next week. I don't
think Pedro, who had feedback on V1, is actively reviewing patches any
more, but if there's any feedback post-commit, I'm happy to discuss
things then.
In v3:
- Rebased and retested.
In v2:
- Rebased and retested.
- Reworked commit message to try and address Pedro's concerns.
Thanks,
Andrew
---
While working on the commit:
commit 9959019545d8d6d71d927f20f088efba944b1e9c
Date: Sun Sep 28 16:16:53 2025 +0100
gdb: fix for 'set suppress-cli-notifications on' missed case
I spotted this message in the gdb.mi/user-selected-context-sync.exp
test script:
# Idea for the future: selecting a thread in a different inferior. For now,
# GDB doesn't show an inferior switch, but if it did, it would be a nice
# place to test it.
What this message is talking about is this behaviour:
(gdb) info threads
Id Target Id Frame
1.1 Thread 0xf7dbc700 (LWP 818430) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
1.2 Thread 0xf7dbbb40 (LWP 818433) "thr" 0xf7fd0579 in __kernel_vsyscall ()
1.3 Thread 0xf73ffb40 (LWP 818434) "thr" breakpt () at thr.c:19
2.1 Thread 0xf7dbc700 (LWP 818456) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6
2.2 Thread 0xf7dbbb40 (LWP 818457) "thr" breakpt () at thr.c:19
* 2.3 Thread 0xf73ffb40 (LWP 818458) "thr" breakpt () at thr.c:19
(gdb) inferior 1
[Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)]
[Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))]
#0 0xf7eb2888 in clone () from /lib/libc.so.6
(gdb) thread 2.2
[Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))]
#0 breakpt () at thr.c:19
19 while (stop)
(gdb)
Notice that when we switch from thread 2.3 to 1.1 using the 'inferior
1' command, GDB tells us that the inferior has changed, and that the
thread has changed (and also that the frame has changed).
But, when we switch from 1.1 to 2.2 using the 'thread 2.2' command, we
are only told about the thread change.
The 'Switching to inferior ...' line includes some useful information,
the process PID and the executable name, and I think it is a shame
that these are not presented when using the 'thread' command to switch
inferior.
So, this commit addresses this issue.
A question that came up during review, and which I'm clarifying here:
this change only affects the output of GDB when the thread command is
also used to switch inferiors. I am (in effect) arguing that the
command 'thread 2.2' should be treated as a shorthand for 'inferior 2;
thread 2', and should display all of the associated output. If the
user is only switching threads within a single inferior then it is not
necessary to re-display the inferior information.
I acknowledge that this does mean the output of the 'thread' command
will now be different depending on whether the user changes inferior
or not. However, I think this is better than the alternative, having
the 'thread' command always re-print the inferior information. I
think this would introduce excess noise that is not useful.
There are changes in basically two areas. The easy part is in
thread_command (thread.c). Here we spot when the inferior has changed
as a result of the 'thread' command, and include
USER_SELECTED_INFERIOR in the set of state passed to the
notify_user_selected_context_changed function.
The change in mi/mi-main.c is a little more involved. In the
mi_cmd_execute function we use an instance of user_selected_context to
spot if any inferior state (frame, thread, or inferior) changes after
an MI command, this is then used to decide if there should be a call
to interps_notify_user_selected_context_changed.
First, by calling interps_notify_user_selected_context_changed
directly, instead of notify_user_selected_context_changed, we fail to
trigger the Python selected_context event, which feels like a
mistake. If the context is changed via an MI command, I think we
should still trigger the Python event. So the first thing I did was
change the interps_notify_user_selected_context_changed call into a
call to notify_user_selected_context_changed. I updated the
gdb.python/py-selected-context.exp test to cover this case.
After that, in mi_cmd_execute, notify_user_selected_context_changed is
always passed 'USER_SELECTED_THREAD | USER_SELECTED_FRAME'. This
makes sense, the MI doesn't allow "switching inferiors" as a command,
instead, an MI frontend must switch threads, and the inferior is
switched as a consequence. But this does mean that if a user has a
CLI and MI interpreter running, and the MI switches threads, the CLI
will only receive the thread switch style notifications, that is,
there will be no "Switching to inferior ..." line.
What I've done is rename user_selected_context::has_changed to
user_selected_context::what_changed, this function is now responsible
for returning the set of USER_SELECTED_* flags that indicate what
changed.
If anything has changed then we always return USER_SELECTED_THREAD |
USER_SELECTED_FRAME as a minimum. This retains the existing
behaviour, but is possibly more aggressive than we need to be; the
-stack-select-frame command can only change the frame, so maybe in
this case we should only return USER_SELECTED_FRAME? I've left that
for the future though.
However, the important change is that in ::what_changed, I now spot
when the inferior has changed and include USER_SELECTED_INFERIOR in
the set of flags that are returned.
In mi_cmd_execute we now call the new what_changed function, and use
the set of flags returned when calling
notify_user_selected_context_changed. This means that the CLI will
now receive inferior changed notifications when appropriate.
The gdb.mi/user-selected-context-sync.exp script has been updated,
replacing the comment I quoted above with an actual test that the
inferior change is announced correctly.
Reviewed-By: Guinevere Larsen <guinevere@redhat.com>
---
gdb/mi/mi-main.c | 49 ++++++++++++----
.../gdb.mi/user-selected-context-sync.exp | 56 ++++++++++++++++---
.../gdb.python/py-selected-context.exp | 19 +++++++
gdb/thread.c | 13 ++++-
4 files changed, 115 insertions(+), 22 deletions(-)
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index bf08fe822b3..47b9be3e54a 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -538,6 +538,11 @@ mi_cmd_thread_select (const char *command, const char *const *argv, int argc)
thread_select (argv[0], thr);
+ /* We don't call print_selected_inferior here as this never prints
+ anything when the output is MI like (as it is now). MI consumers are
+ expected to derive the inferior change from the global thread-id
+ included in the print_selected_thread_frame output. */
+
print_selected_thread_frame (current_uiout,
USER_SELECTED_THREAD | USER_SELECTED_FRAME);
}
@@ -1968,14 +1973,33 @@ struct user_selected_context
save_selected_frame (&m_previous_frame_id, &m_previous_frame_level);
}
- /* Return true if the user selected context has changed since this object
- was created. */
- bool has_changed () const
+ /* Return a set of flags indicating which parts of the user selected
+ context has changed since this object was created, or 0 (the empty
+ set of flags) if nothing has changed. */
+ user_selected_what what_changed () const
{
+ /* If anything changed then we report both the thread and frame at a
+ minimum. We optionally add the inferior if we know that it
+ changed.
+
+ This means that for pure frame changes, e.g. -stack-select-frame, we
+ still report both a thread and a frame, which isn't ideal, but
+ there's also the cases where -thread-select is used to re-select the
+ current thread, in this case we'd still like to see the thread
+ reported, at least, that's what we have historically done. */
+ user_selected_what state
+ = USER_SELECTED_THREAD | USER_SELECTED_FRAME;
+
/* Did the selected thread change? */
if (m_previous_ptid != null_ptid && inferior_ptid != null_ptid
&& m_previous_ptid != inferior_ptid)
- return true;
+ {
+ /* Did the inferior change too? */
+ if (m_previous_ptid.pid () != inferior_ptid.pid ())
+ state |= USER_SELECTED_INFERIOR;
+
+ return state;
+ }
/* Grab details of the currently selected frame, for comparison. */
frame_id current_frame_id;
@@ -1984,7 +2008,7 @@ struct user_selected_context
/* Did the selected frame level change? */
if (current_frame_level != m_previous_frame_level)
- return true;
+ return state;
/* Did the selected frame id change? If the innermost frame is
selected then the level will be -1, and the frame-id will be
@@ -1993,10 +2017,10 @@ struct user_selected_context
other than the innermost frame selected. */
if (current_frame_level != -1
&& current_frame_id != m_previous_frame_id)
- return true;
+ return state;
/* Nothing changed! */
- return false;
+ return 0;
}
private:
/* The previously selected thread. This might be null_ptid if there was
@@ -2100,10 +2124,13 @@ mi_cmd_execute (struct mi_parse *parse)
parse->cmd->invoke (parse);
- if (!parse->cmd->preserve_user_selected_context ()
- && current_user_selected_context.has_changed ())
- interps_notify_user_selected_context_changed
- (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
+ if (!parse->cmd->preserve_user_selected_context ())
+ {
+ user_selected_what what
+ = current_user_selected_context.what_changed ();
+ if (what != 0)
+ notify_user_selected_context_changed (what);
+ }
}
/* See mi-main.h. */
diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
index 844206f7511..fb781205a20 100644
--- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
+++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
@@ -698,9 +698,21 @@ proc_with_prefix test_cli_thread { mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set mi_re [make_mi_re $mode 5 0 event]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $gdb_main_spawn_id {
+ gdb_test "thread 2.2" $cli_re "select thread"
+ }
+
+ with_spawn_id $mi_spawn_id {
+ match_re_or_ensure_no_output $mi_re "select thread, event on MI"
+ }
+ }
}
# Test frame selection from CLI.
@@ -995,9 +1007,22 @@ proc_with_prefix test_mi_thread_select { mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set mi_re [make_mi_re $mode 5 0 response]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $mi_spawn_id {
+ mi_gdb_test "-thread-select 5" $mi_re "-thread-select"
+ }
+
+ with_spawn_id $gdb_main_spawn_id {
+ match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on CLI"
+ }
+
+ }
}
proc_with_prefix test_mi_stack_select_frame { mode } {
@@ -1290,9 +1315,22 @@ proc_with_prefix test_cli_in_mi_thread { mode cli_in_mi_mode } {
}
}
- # Idea for the future: selecting a thread in a different inferior. For now,
- # GDB doesn't show an inferior switch, but if it did, it would be a nice
- # place to test it.
+ with_test_prefix "thread 2.2" {
+ # Select a thread in a different inferior. This should trigger an
+ # 'inferior changed' and 'thread changed' notification on the CLI,
+ # and a single MI async notification.
+ set command [make_cli_in_mi_command $cli_in_mi_mode "thread 2.2"]
+ set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 2 2.2 5 0]
+ set cli_re [make_cli_re $mode 2 2.2 0]
+
+ with_spawn_id $mi_spawn_id {
+ mi_gdb_test $command $mi_re "select thread"
+ }
+
+ with_spawn_id $gdb_main_spawn_id {
+ match_re_or_ensure_no_output "$cli_re\r\n" "select thread, event on CLI"
+ }
+ }
}
# Test selecting the frame using a CLI command in the MI channel.
diff --git a/gdb/testsuite/gdb.python/py-selected-context.exp b/gdb/testsuite/gdb.python/py-selected-context.exp
index 030543466d2..28b9b456003 100644
--- a/gdb/testsuite/gdb.python/py-selected-context.exp
+++ b/gdb/testsuite/gdb.python/py-selected-context.exp
@@ -129,3 +129,22 @@ gdb_test "down" [event_regexp 1 1.2 #0] \
"move down a frame, event handler triggers"
gdb_test "frame 1" [event_regexp 1 1.2 #1] \
"select a frame, event handler triggers"
+
+# Check that switching threads via MI also triggers the Python
+# selected_context event. Grab the regexp we expect for the CLI, pull
+# it apart, and wrap each line with the usual ~"...\n" wrapper we see
+# with MI. Then add the MI '^done,....' line, and make this into
+# the expected output regexp.
+set cli_pattern [event_regexp 1 1.1 #0]
+set cli_pattern [string map {\r\n \n} $cli_pattern]
+set cli_pattern [split $cli_pattern \n]
+set mi_pattern {}
+foreach line $cli_pattern {
+ lappend mi_pattern "~\"$line\\\\n\""
+}
+lappend mi_pattern "\\^done,new-thread-id=\"1\",\[^\r\n\]+"
+set pattern [multi_line {*}$mi_pattern]
+
+# Switch threads using the MI. Python event should trigger.
+gdb_test "interpreter-exec mi \"-thread-select 1\"" $pattern \
+ "mi thread switch triggers Python event"
diff --git a/gdb/thread.c b/gdb/thread.c
index a6ae2a75139..46170537e28 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -2010,10 +2010,19 @@ thread_command (const char *tidstr, int from_tty)
}
else
{
+ inferior *previous_inferior = current_inferior ();
+
thread_select (tidstr, parse_thread_id (tidstr, NULL));
- notify_user_selected_context_changed
- (USER_SELECTED_THREAD | USER_SELECTED_FRAME);
+ user_selected_what selection = (USER_SELECTED_THREAD
+ | USER_SELECTED_FRAME);
+
+ /* If the inferior changed as a consequence of the thread change,
+ then let the user know. */
+ if (previous_inferior != current_inferior ())
+ selection |= USER_SELECTED_INFERIOR;
+
+ notify_user_selected_context_changed (selection);
}
}
base-commit: cc4600477f621c764011b8e2f5bf1a2ebcffb61a
--
2.25.4
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-04-17 15:05 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-08 8:48 [PATCH] gdb: notify of inferior switch when needed from 'thread' command Andrew Burgess
2025-10-09 18:59 ` Pedro Alves
2025-10-10 14:47 ` Andrew Burgess
2025-11-03 16:12 ` Aktemur, Tankut Baris
2025-11-03 17:57 ` Andrew Burgess
2026-01-06 13:37 ` Andrew Burgess
2026-01-26 13:58 ` [PATCHv2] " Andrew Burgess
2026-03-17 19:41 ` Guinevere Larsen
2026-03-18 14:34 ` Andrew Burgess
2026-04-17 14:54 ` [PATCHv3] " Andrew Burgess
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox