Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH v2] gdb: remember previously selected thread per inferior
@ 2026-03-25 12:23 Klaus Gerlicher
  2026-03-25 12:23 ` [PATCH v2 1/1] " Klaus Gerlicher
  2026-04-28  9:26 ` [PATCH v2] " Gerlicher, Klaus
  0 siblings, 2 replies; 4+ messages in thread
From: Klaus Gerlicher @ 2026-03-25 12:23 UTC (permalink / raw)
  To: gdb-patches

Hi,

This is V2 of my patch to add thread memory when switching inferiors.

Thanks for the feedback, @Andrew, @Pedro, addressing it here:

Changes since V1:
* made the feature switchable with 'set remember-threads-per-inferior [on|off]'
* added full documentation (gdb.texinfo)
* Added NEWS entry
* Added test for disabled behavior (test_disabled_behavior)
* default is ON (enabled by default)

1. Switchable Feature:
   I've made this controllable. The default is ON because I think most users
   would want this behavior but users who prefer the old "first available 
   thread" behavior can easily disable it. Pedro's concern in the V1 thread was
   that not everyone might find this natural, so now everyone can choose.

2. Documentation:
   Added full texinfo documentation with examples showing both enabled and
   disabled modes. Also added NEWS entry as requested.

3. Observer arch:
   You asked why we need the manual call in infrun.c and can't rely solely
   on the observer.

   The user_selected_context_changed observer only fires for explicit user
   commands (thread, inferior, frame), not for event switches.

   Example that breaks w/o infrun.c saving:

   (gdb) set schedule-multiple on
   (gdb) thread 1.1
   (gdb) continue
   # Breakpoint hits in inferior 2, thread 2.2 (automatic switch)
   # Observer does NOT fire (not a user command!)
   # Without infrun.c save: thread 2.2 never gets recorded
   (gdb) inferior 1
   (gdb) inferior 2
   # BUG: Would switch to thread 2.1 instead of 2.2

   My test_implicit scenario explicitly tests this and fails without the
   infrun.c call. 

   Alternative would be creating a new observer that fires for ALL context
   switches (user + automatic)?

I've kept the default as ON rather than OFF. If you prefer defaulting to OFF,
I can change it.

Tested on x86_64.

Thanks,
Klaus

Klaus Gerlicher (1):
  gdb: remember previously selected thread per inferior

 gdb/NEWS                                      |   7 +
 gdb/doc/gdb.texinfo                           |  19 ++
 gdb/gdbthread.h                               |   4 +
 gdb/inferior.c                                |  58 +++++-
 gdb/inferior.h                                |  14 ++
 gdb/infrun.c                                  |   6 +-
 gdb/testsuite/gdb.base/inferior-switch.c      |  42 +++++
 gdb/testsuite/gdb.base/inferior-switch.exp    | 172 ++++++++++++++++++
 .../gdb.mi/user-selected-context-sync.exp     |  14 ++
 gdb/thread.c                                  |   8 +
 10 files changed, 341 insertions(+), 3 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/inferior-switch.c
 create mode 100644 gdb/testsuite/gdb.base/inferior-switch.exp

-- 
2.34.1

Intel Deutschland GmbH
Registered Address: Dornacher Strasse 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 Muenchen HRB 186928


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

* [PATCH v2 1/1] gdb: remember previously selected thread per inferior
  2026-03-25 12:23 [PATCH v2] gdb: remember previously selected thread per inferior Klaus Gerlicher
@ 2026-03-25 12:23 ` Klaus Gerlicher
  2026-03-25 14:34   ` Eli Zaretskii
  2026-04-28  9:26 ` [PATCH v2] " Gerlicher, Klaus
  1 sibling, 1 reply; 4+ messages in thread
From: Klaus Gerlicher @ 2026-03-25 12:23 UTC (permalink / raw)
  To: gdb-patches

Add support for remembering which thread was selected when switching
between inferiors.  This feature can be controlled with a new setting
'set remember-threads-per-inferior' which is enabled by default.

Before this patch, GDB selected any non-exited thread when switching to
another inferior.  Note in the below example that the last inferior
command ends up in thread 2.1 even though we were previously in
thread 2.2:

  (gdb) info threads
    Id   Target Id
    1.1  Thread 0x7ffff7d7b740 (LWP 572047) "inferior-switch"
    1.2  Thread 0x7ffff7d7a640 (LWP 572050) "inferior-switch"
  * 2.1  Thread 0x7ffff7d7b740 (LWP 572618) "inferior-switch"
    2.2  Thread 0x7ffff7d7a640 (LWP 572619) "inferior-switch"

  (gdb) thread 2.2
  [Switching to thread 2.2 (Thread 0x7ffff7d7a640 (LWP 572619))]

  (gdb) inferior 1
  [Switching to inferior 1 [process 572047] (/bin/inferior-switch)]
  [Switching to thread 1.1 (Thread 0x7ffff7d7b740 (LWP 572047))]

  (gdb) thread 1.2
  [Switching to thread 1.2 (Thread 0x7ffff7d7a640 (LWP 572050))]

  (gdb) inferior 2
  [Switching to inferior 2 [process 572618] (/bin/inferior-switch)]
  [Switching to thread 2.1 (Thread 0x7ffff7d7b740 (LWP 572618))]
  ^^^ Expected 2.2, got 2.1 (context lost)

With this patch, GDB now records which thread was current when switching
away from an inferior, and automatically restores that thread when
switching back (if it still exists):

  (gdb) info threads
    Id   Target Id
    1.1  Thread 0x7ffff7d7b740 (LWP 559826) "inferior-switch"
    1.2  Thread 0x7ffff7d7a640 (LWP 559829) "inferior-switch"
  * 2.1  Thread 0x7ffff7d7b740 (LWP 560308) "inferior-switch"
    2.2  Thread 0x7ffff7d7a640 (LWP 560497) "inferior-switch"

  (gdb) thread 2.2
  [Switching to thread 2.2 (Thread 0x7ffff7d7a640 (LWP 560497))]

  (gdb) inferior 1
  [Switching to inferior 1 [process 559826] (/bin/inferior-switch)]
  [Switching to thread 1.1 (Thread 0x7ffff7d7b740 (LWP 559826))]

  (gdb) thread 1.2
  [Switching to thread 1.2 (Thread 0x7ffff7d7a640 (LWP 559829))]

  (gdb) inferior 2
  [Switching to inferior 2 [process 560308] (/bin/inferior-switch)]
  [Switching to thread 2.2 (Thread 0x7ffff7d7a640 (LWP 560497))]
  ^^^ Now correctly restores thread 2.2

  (gdb) inferior 1
  [Switching to inferior 1 [process 559826] (/bin/inferior-switch)]
  [Switching to thread 1.2 (Thread 0x7ffff7d7a640 (LWP 559829))]
  ^^^ And thread 1.2 is also remembered

The feature improves the debugging experience when working with multiple
inferiors by maintaining context.  Users who prefer the original behavior
can disable it with 'set remember-threads-per-inferior off'.

Implementation Details:

The implementation stores a thread reference in each inferior structure
and uses two mechanisms to keep it updated:

1. The user_selected_context_changed observer handles explicit user
   commands (thread, inferior) that switch the current thread.

2. A direct call in fetch_inferior_event handles event-driven thread
   switches that occur during execution (e.g., breakpoints, signals,
   schedule-multiple mode).

The dual mechanism is necessary because the user_selected_context_changed
observer only fires for explicit user commands, not for automatic
switches triggered by events.  Without the fetch_inferior_event save
point, automatic switches would not be recorded and the feature would
break in async scenarios.

When switching to an inferior, the stored thread is restored if it still
exists; otherwise, any available thread is selected as before.  The
feature respects the setting at both save and restore points to ensure
correct behavior when toggling the feature on/off.
---
 gdb/NEWS                                      |   7 +
 gdb/doc/gdb.texinfo                           |  19 ++
 gdb/gdbthread.h                               |   4 +
 gdb/inferior.c                                |  58 +++++-
 gdb/inferior.h                                |  14 ++
 gdb/infrun.c                                  |   6 +-
 gdb/testsuite/gdb.base/inferior-switch.c      |  42 +++++
 gdb/testsuite/gdb.base/inferior-switch.exp    | 172 ++++++++++++++++++
 .../gdb.mi/user-selected-context-sync.exp     |  14 ++
 gdb/thread.c                                  |   8 +
 10 files changed, 341 insertions(+), 3 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/inferior-switch.c
 create mode 100644 gdb/testsuite/gdb.base/inferior-switch.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 03f46df5400..44e6ed799a4 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,13 @@
 
 *** Changes since GDB 17
 
+*   By default, GDB now remembers which thread was selected when you were
+  last working in each inferior.  When you switch back to that inferior,
+  GDB automatically restores the previous thread selection (if the thread
+  still exists).  You can disable this behavior with
+  'set remember-threads-per-inferior off' to use the original behavior
+  of always selecting the first available thread.
+
 * Support for .gdb_index sections with version less than 7 has been
   removed.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ceb69669ea6..dcbbcb273c1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3516,6 +3516,25 @@ To switch focus between inferiors, use the @code{inferior} command:
 Make inferior number @var{infno} the current inferior.  The argument
 @var{infno} is the inferior number assigned by @value{GDBN}, as shown
 in the first field of the @samp{info inferiors} display.
+
+By default, when switching to an inferior, @value{GDBN} will restore the
+thread that was previously selected in that inferior (if it still exists).
+This behavior can be controlled with the @code{set remember-threads-per-inferior}
+command, described below.
+@end table
+
+@cindex remember threads per inferior
+@kindex set remember-threads-per-inferior
+@kindex show remember-threads-per-inferior
+@table @code
+@item set remember-threads-per-inferior on|off
+Control whether @value{GDBN} remembers the selected thread for each inferior.
+When enabled (the default), switching to a previously used inferior will
+restore the thread that was active when you switched away.  When disabled,
+@value{GDBN} always selects the first available thread.
+
+@item show remember-threads-per-inferior
+Show whether @value{GDBN} remembers the selected thread for each inferior.
 @end table
 
 @vindex $_inferior@r{, convenience variable}
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 68d7aebbbf7..cecbef8be20 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -906,6 +906,10 @@ class scoped_restore_current_thread
   scoped_restore_current_language m_lang;
 };
 
+/* Return true if there is a current thread.  */
+
+bool has_current_thread ();
+
 /* Returns a pointer into the thread_info corresponding to
    INFERIOR_PTID.  INFERIOR_PTID *must* be in the thread list.  */
 extern struct thread_info* inferior_thread (void);
diff --git a/gdb/inferior.c b/gdb/inferior.c
index e050dec402e..5ea00839692 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -46,6 +46,9 @@ static int highest_inferior_num;
 /* See inferior.h.  */
 bool print_inferior_events = true;
 
+/* Control whether to remember selected threads per inferior.  */
+bool remember_inferior_threads = true;
+
 /* The Current Inferior.  This is a strong reference.  I.e., whenever
    an inferior is the current inferior, its refcount is
    incremented.  */
@@ -508,6 +511,25 @@ inferior_pid_to_str (int pid)
 
 /* See inferior.h.  */
 
+void
+save_inferior_last_thread ()
+{
+  if (has_current_thread ())
+    current_inferior ()->last_user_thread
+      = thread_info_ref::new_reference (inferior_thread ());
+  else
+    current_inferior ()->last_user_thread = nullptr;
+}
+
+static void
+inferiors_on_user_selected_context_changed (user_selected_what selection)
+{
+  if (remember_inferior_threads && (selection & USER_SELECTED_THREAD))
+    save_inferior_last_thread ();
+}
+
+/* See inferior.h.  */
+
 void
 print_selected_inferior (struct ui_out *uiout)
 {
@@ -771,8 +793,23 @@ inferior_command (const char *args, int from_tty)
 	{
 	  if (inf != current_inferior ())
 	    {
-	      thread_info *tp = any_thread_of_inferior (inf);
-	      if (tp == NULL)
+	      thread_info *tp = nullptr;
+
+	      if (remember_inferior_threads)
+		{
+		  thread_info *stored_tp = inf->last_user_thread.get ();
+
+		  /* Fallback to selecting any non-exited thread of
+		     inferior.  */
+		  tp = (stored_tp == nullptr
+			|| stored_tp->state == THREAD_EXITED)
+		    ? any_thread_of_inferior (inf)
+		    : stored_tp;
+		}
+	      else
+		tp = any_thread_of_inferior (inf);
+
+	      if (tp == nullptr)
 		error (_("Inferior has no threads."));
 
 	      switch_to_thread (tp);
@@ -1255,5 +1292,22 @@ Show printing of inferior events (such as inferior start and exit)."), NULL,
 	 show_print_inferior_events,
 	 &setprintlist, &showprintlist);
 
+  add_setshow_boolean_cmd ("remember-threads-per-inferior", no_class,
+	 &remember_inferior_threads, _("\
+Set whether GDB will cache the current thread in each inferior."), _("\
+Show whether GDB will cache the current thread in each inferior."), _("\
+When on, GDB records which thread was current when switching away from\n\
+an inferior, and automatically restores that thread when switching back\n\
+to that inferior (if the thread still exists).  When off, GDB selects\n\
+the first available thread."),
+	 NULL,
+	 NULL,
+	 &setlist, &showlist);
+
   create_internalvar_type_lazy ("_inferior", &inferior_funcs, NULL);
+
+  /* Observe user_selected_context_changed to store the current user
+     thread.  */
+  gdb::observers::user_selected_context_changed.attach (
+      inferiors_on_user_selected_context_changed, "inferiors");
 }
diff --git a/gdb/inferior.h b/gdb/inferior.h
index fbf9765fb0e..49f0406710c 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -265,6 +265,10 @@ extern int stopped_by_random_signal;
    `set print inferior-events'.  */
 extern bool print_inferior_events;
 
+/* Control whether GDB remembers the selected thread per inferior, set with
+   `set remember-threads-per-inferior'.  */
+extern bool remember_inferior_threads;
+
 /* Anything but NO_STOP_QUIETLY means we expect a trap and the caller
    will handle it themselves.  STOP_QUIETLY is used when running in
    the shell before the child program has been exec'd and when running
@@ -685,6 +689,10 @@ class inferior : public refcounted_object,
   /* Per inferior data-pointers required by other GDB modules.  */
   registry<inferior> registry_fields;
 
+  /* The last thread that was current when inferior was switched away
+     from.  */
+  thread_info_ref last_user_thread;
+
 private:
 
   /* Unpush TARGET and assert that it worked.  */
@@ -891,6 +899,12 @@ extern void print_selected_inferior (struct ui_out *uiout);
 extern void switch_to_inferior_and_push_target
   (inferior *new_inf, bool no_connection, inferior *org_inf);
 
+/* Record the selected thread of the current inferior when the user
+   switches a context.  GDB will select the recorded thread, if alive,
+   instead of any thread from the current inferior.  */
+
+extern void save_inferior_last_thread ();
+
 /* Return true if ID is a valid global inferior number.  */
 
 inline bool
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9864b5bbdec..35292e13d95 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -4774,7 +4774,11 @@ fetch_inferior_event ()
 	    if (!non_stop
 		&& cmd_done
 		&& ecs.ws.kind () != TARGET_WAITKIND_NO_RESUMED)
-	      restore_thread.dont_restore ();
+	      {
+		restore_thread.dont_restore ();
+		if (remember_inferior_threads)
+		  save_inferior_last_thread ();
+	      }
 	  }
       }
 
diff --git a/gdb/testsuite/gdb.base/inferior-switch.c b/gdb/testsuite/gdb.base/inferior-switch.c
new file mode 100644
index 00000000000..107090d003c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/inferior-switch.c
@@ -0,0 +1,42 @@
+/* This testcase is part of GDB, the GNU debugger.
+   Copyright 2024 Free Software Foundation, Inc.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <unistd.h>
+#include <pthread.h>
+
+static void *
+task (void *arg)
+{
+  volatile unsigned int duration = 0;
+
+  int a = 1; /* worker thread break 1.  */
+
+  sleep (duration);
+  int b = 2; /* worker thread break 2.  */
+
+  sleep (duration);
+  return NULL;
+}
+
+int
+main (void)
+{
+  pthread_t th;
+
+  alarm (30);
+
+  pthread_create (&th, NULL, task, NULL);
+  pthread_join (th, NULL);
+
+  return 0; /* main thread break.  */
+}
diff --git a/gdb/testsuite/gdb.base/inferior-switch.exp b/gdb/testsuite/gdb.base/inferior-switch.exp
new file mode 100644
index 00000000000..4ac1aa707c2
--- /dev/null
+++ b/gdb/testsuite/gdb.base/inferior-switch.exp
@@ -0,0 +1,172 @@
+# Copyright 2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# This test covers retaining of current thread when switching between
+# inferiors.
+#
+# It starts two inferiors that have 2 threads each, a main thread and a
+# thread that will have strategically placed sleeps to control execution
+# behaviour.
+#
+# test_explicit: Switch threads and switch between inferiors during stops.
+# Check that GDB remembers the previously selected thread of an inferior when
+# we switch to that inferior.
+#
+# test_implicit: Check that GDB remembers the previously selected thread of
+# an inferior when we are implicitly switched to another thread due to an
+# event.
+
+standard_testfile
+
+# This testcase explicitly creates another inferior.
+if {[use_gdb_stub]} {
+    return
+}
+
+if {[build_executable "failed to prepare" $testfile $srcfile \
+    {debug pthreads}] == -1} {
+    return -1
+}
+
+proc switch_inferior { num msg } {
+    gdb_test "inferior ${num}" "\\\[Switching to inferior ${num}.*" "${msg}"
+}
+
+proc switch_inferior_expect_thread { inf tid msg } {
+    gdb_test "inferior ${inf}" "\\\[Switching to thread $tid.*" "${msg}"
+}
+
+proc switch_thread { tid msg } {
+    gdb_test "thread $tid" "\\\[Switching to thread $tid.*" "${msg}"
+}
+
+# Common test preparation: start two inferiors and let them run to BP
+# at "worker thread break 1" location.
+
+proc_with_prefix prepare_test { } {
+    global binfile testfile
+
+    clean_restart $testfile
+
+    gdb_breakpoint [gdb_get_line_number "worker thread break 1"]
+
+    # Add another inferior, switch to it, load the binary and run it to after
+    # additional threads have started.
+    gdb_test "add-inferior" "Added inferior 2.*" \
+	"add new inferior"
+    switch_inferior 2 "switch to the new inferior 2"
+
+    gdb_test "file $binfile" ".*" "load binary for inferior 2"
+    gdb_test_no_output "set remote exec-file $binfile" \
+	"set remote exec-file"
+
+
+    gdb_test "run" \
+	"Thread 2.2.*hit Breakpoint 1.2.*" \
+	"inferior 2 run to breakpoint break"
+
+    switch_inferior 1 "switch to inferior 1"
+
+    gdb_test "run" \
+	"Thread 1.2.*hit Breakpoint 1.1.*" \
+	"inferior 1 run to breakpoint break"
+}
+
+# Test scenario for verifying that during stops, explicit inferior and thread
+# switches store the correct last user thread.
+
+proc_with_prefix test_explicit {} {
+    prepare_test
+
+    switch_inferior_expect_thread 2 2.2 "switch to inferior 2 thread 2.2"
+    switch_inferior_expect_thread 1 1.2 "back to inferior 1 thread 1.2"
+
+    gdb_continue_to_end "inferior 1" continue 1
+
+    switch_inferior_expect_thread 2 2.2 "again back to inferior 2 thread 2.2"
+
+    gdb_continue_to_end "inferior 2" continue 1
+}
+
+# Test scenario for verifying that during stops, implicit inferior and thread
+# switches store the correct last user thread.
+
+proc_with_prefix test_implicit {} {
+    prepare_test
+
+    gdb_breakpoint [gdb_get_line_number "worker thread break 2"]
+
+    # Enable sleeps in inferior 1 worker thread to slow it down.  Consequently
+    # breakpoint in inferior 2 will be hit first.
+    gdb_test "print duration = 2" " = 2"
+
+    switch_thread 2.1 "switch inferior 2 to main thread"
+    switch_thread 1.1 "switch inferior 1 to main thread"
+
+    gdb_test_no_output "set schedule-multiple on"
+
+    gdb_test "continue" \
+	".*Thread 2.2.*Breakpoint 2.2.*" \
+	"continue next breakpoint expect T2.2"
+
+    # Enable sleeps in inferior 2 worker thread to slow it down.  Consequently
+    # next breakpoint in inferior 1 will be hit first.
+    gdb_test "print duration = 3" " = 3"
+
+    gdb_test "continue" \
+	".*Thread 1.2.*Breakpoint 2.1.*" \
+	"continue next breakpoint expect T1.2"
+
+    switch_inferior_expect_thread 2 2.2 "switch inferior 2 stopped at 2nd BP"
+    switch_inferior_expect_thread 1 1.2 "switch inferior 1 stopped at 2nd BP"
+}
+
+# Test scenario for verifying that the feature can be disabled.
+
+proc_with_prefix test_disabled_behavior {} {
+    prepare_test
+
+    # Disable the feature
+    gdb_test_no_output "set remember-threads-per-inferior off" \
+	"disable remember-threads-per-inferior feature"
+
+    # Switch to thread 2.2
+    switch_thread 2.2 "switch to thread 2.2"
+
+    # Switch to inferior 1 - with feature disabled, should NOT remember thread 1.2,
+    # should pick first available (1.1)
+    gdb_test "inferior 1" "\\\[Switching to thread 1.1.*" \
+	"with feature off, switches to first thread"
+
+    # Switch to thread 1.2
+    switch_thread 1.2 "switch to thread 1.2"
+
+    # Switch to inferior 2 - with feature disabled, should NOT remember thread 2.2,
+    # should pick first available (2.1)
+    gdb_test "inferior 2" "\\\[Switching to thread 2.1.*" \
+	"with feature off, selects first thread in inferior"
+
+    # Re-enable the feature and verify it works again
+    gdb_test_no_output "set remember-threads-per-inferior on" \
+	"re-enable remember-threads-per-inferior feature"
+
+    # Now switching back to inferior 1 should remember 1.2
+    switch_inferior_expect_thread 1 1.2 \
+	"feature on again, restores previously selected thread 1.2"
+}
+
+test_explicit
+test_implicit
+test_disabled_behavior
diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
index 844206f7511..3b6f174a1a1 100644
--- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
+++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
@@ -52,6 +52,14 @@ set main_break_line [gdb_get_line_number "main break line"]
 set thread_loop_line [gdb_get_line_number "thread loop line"]
 set thread_caller_line [gdb_get_line_number "thread caller line"]
 
+# Reset to thread 2.1.
+
+proc reset_to_known_thread { pfx } {
+    with_test_prefix "$pfx" {
+	reset_selection "2.1"
+    }
+}
+
 # Return whether we expect thread THREAD to be running in mode MODE.
 #
 # MODE can be either "all-stop" or "non-stop".
@@ -1398,6 +1406,9 @@ proc do_test { mode } {
     }
     pass $test
 
+    # Reset to known state.
+    reset_to_known_thread "before testing CLI"
+
     # Test selecting inferior, thread and frame from CLI
 
     test_cli_inferior $mode
@@ -1411,6 +1422,9 @@ proc do_test { mode } {
     test_mi_thread_select $mode
     test_mi_stack_select_frame $mode
 
+    # Reset to known state.
+    reset_to_known_thread "before testing MI"
+
     # Test some CLI commands sent through MI, both with a "direct" command,
     # such as "thread 1", and with -interpreter-exec, such as
     # '-interpreter-exec console "thread 1"'.
diff --git a/gdb/thread.c b/gdb/thread.c
index 96e3bb7b50f..72b44a95122 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -85,6 +85,14 @@ is_current_thread (const thread_info *thr)
   return thr == current_thread_;
 }
 
+/* See gdbthread.h.  */
+
+bool
+has_current_thread ()
+{
+  return current_thread_ != nullptr;
+}
+
 struct thread_info*
 inferior_thread (void)
 {
-- 
2.34.1

Intel Deutschland GmbH
Registered Address: Dornacher Strasse 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 Muenchen HRB 186928


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

* Re: [PATCH v2 1/1] gdb: remember previously selected thread per inferior
  2026-03-25 12:23 ` [PATCH v2 1/1] " Klaus Gerlicher
@ 2026-03-25 14:34   ` Eli Zaretskii
  0 siblings, 0 replies; 4+ messages in thread
From: Eli Zaretskii @ 2026-03-25 14:34 UTC (permalink / raw)
  To: Klaus Gerlicher; +Cc: gdb-patches

> From: Klaus Gerlicher <klaus.gerlicher@intel.com>
> Date: Wed, 25 Mar 2026 12:23:21 +0000
> 
>  gdb/NEWS                                      |   7 +
>  gdb/doc/gdb.texinfo                           |  19 ++
>  gdb/gdbthread.h                               |   4 +
>  gdb/inferior.c                                |  58 +++++-
>  gdb/inferior.h                                |  14 ++
>  gdb/infrun.c                                  |   6 +-
>  gdb/testsuite/gdb.base/inferior-switch.c      |  42 +++++
>  gdb/testsuite/gdb.base/inferior-switch.exp    | 172 ++++++++++++++++++
>  .../gdb.mi/user-selected-context-sync.exp     |  14 ++
>  gdb/thread.c                                  |   8 +
>  10 files changed, 341 insertions(+), 3 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.base/inferior-switch.c
>  create mode 100644 gdb/testsuite/gdb.base/inferior-switch.exp

Thanks.

> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,13 @@
>  
>  *** Changes since GDB 17
>  
> +*   By default, GDB now remembers which thread was selected when you were
> +  last working in each inferior.  When you switch back to that inferior,
> +  GDB automatically restores the previous thread selection (if the thread
> +  still exists).  You can disable this behavior with
> +  'set remember-threads-per-inferior off' to use the original behavior
> +  of always selecting the first available thread.
> +
>  * Support for .gdb_index sections with version less than 7 has been
>    removed.

This part is okay.

> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index ceb69669ea6..dcbbcb273c1 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo

This part is also okay, with one minor comment:

> +When enabled (the default), switching to a previously used inferior will
> +restore the thread that was active when you switched away.  When disabled,
                               ^^^^^^
I think we should say "selected" there, not "active".  The latter is
ambiguous in this context.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>

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

* RE: [PATCH v2] gdb: remember previously selected thread per inferior
  2026-03-25 12:23 [PATCH v2] gdb: remember previously selected thread per inferior Klaus Gerlicher
  2026-03-25 12:23 ` [PATCH v2 1/1] " Klaus Gerlicher
@ 2026-04-28  9:26 ` Gerlicher, Klaus
  1 sibling, 0 replies; 4+ messages in thread
From: Gerlicher, Klaus @ 2026-04-28  9:26 UTC (permalink / raw)
  To: gdb-patches

Kindly pinging.

Thanks
Klaus

> -----Original Message-----
> From: Klaus Gerlicher <klaus.gerlicher@intel.com>
> Sent: Wednesday, March 25, 2026 1:23 PM
> To: gdb-patches@sourceware.org
> Subject: [PATCH v2] gdb: remember previously selected thread per inferior
> 
> Hi,
> 
> This is V2 of my patch to add thread memory when switching inferiors.
> 
> Thanks for the feedback, @Andrew, @Pedro, addressing it here:
> 
> Changes since V1:
> * made the feature switchable with 'set remember-threads-per-inferior
> [on|off]'
> * added full documentation (gdb.texinfo)
> * Added NEWS entry
> * Added test for disabled behavior (test_disabled_behavior)
> * default is ON (enabled by default)
> 
> 1. Switchable Feature:
>    I've made this controllable. The default is ON because I think most users
>    would want this behavior but users who prefer the old "first available
>    thread" behavior can easily disable it. Pedro's concern in the V1 thread was
>    that not everyone might find this natural, so now everyone can choose.
> 
> 2. Documentation:
>    Added full texinfo documentation with examples showing both enabled and
>    disabled modes. Also added NEWS entry as requested.
> 
> 3. Observer arch:
>    You asked why we need the manual call in infrun.c and can't rely solely
>    on the observer.
> 
>    The user_selected_context_changed observer only fires for explicit user
>    commands (thread, inferior, frame), not for event switches.
> 
>    Example that breaks w/o infrun.c saving:
> 
>    (gdb) set schedule-multiple on
>    (gdb) thread 1.1
>    (gdb) continue
>    # Breakpoint hits in inferior 2, thread 2.2 (automatic switch)
>    # Observer does NOT fire (not a user command!)
>    # Without infrun.c save: thread 2.2 never gets recorded
>    (gdb) inferior 1
>    (gdb) inferior 2
>    # BUG: Would switch to thread 2.1 instead of 2.2
> 
>    My test_implicit scenario explicitly tests this and fails without the
>    infrun.c call.
> 
>    Alternative would be creating a new observer that fires for ALL context
>    switches (user + automatic)?
> 
> I've kept the default as ON rather than OFF. If you prefer defaulting to OFF,
> I can change it.
> 
> Tested on x86_64.
> 
> Thanks,
> Klaus
> 
> Klaus Gerlicher (1):
>   gdb: remember previously selected thread per inferior
> 
>  gdb/NEWS                                      |   7 +
>  gdb/doc/gdb.texinfo                           |  19 ++
>  gdb/gdbthread.h                               |   4 +
>  gdb/inferior.c                                |  58 +++++-
>  gdb/inferior.h                                |  14 ++
>  gdb/infrun.c                                  |   6 +-
>  gdb/testsuite/gdb.base/inferior-switch.c      |  42 +++++
>  gdb/testsuite/gdb.base/inferior-switch.exp    | 172 ++++++++++++++++++
>  .../gdb.mi/user-selected-context-sync.exp     |  14 ++
>  gdb/thread.c                                  |   8 +
>  10 files changed, 341 insertions(+), 3 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.base/inferior-switch.c
>  create mode 100644 gdb/testsuite/gdb.base/inferior-switch.exp
> 
> --
> 2.34.1
> 
> Intel Deutschland GmbH
> Registered Address: Dornacher Strasse 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 Muenchen HRB 186928
> 

Intel Deutschland GmbH
Registered Address: Dornacher Strasse 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 Muenchen HRB 186928


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

end of thread, other threads:[~2026-04-28  9:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-25 12:23 [PATCH v2] gdb: remember previously selected thread per inferior Klaus Gerlicher
2026-03-25 12:23 ` [PATCH v2 1/1] " Klaus Gerlicher
2026-03-25 14:34   ` Eli Zaretskii
2026-04-28  9:26 ` [PATCH v2] " Gerlicher, Klaus

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