From: Markus Metzger <markus.t.metzger@intel.com>
To: gdb-patches@sourceware.org
Subject: [PATCH v4 25/44] gdb: allow continuing an inferior without threads
Date: Wed, 12 Aug 2026 15:27:45 +0200 [thread overview]
Message-ID: <20260812132805.380163-26-markus.t.metzger@intel.com> (raw)
In-Reply-To: <20260812132805.380163-1-markus.t.metzger@intel.com>
When debugging an Intel GPU device, we may end up with a GPU inferior but
no threads, e.g. if we interrupted the device inferior and there was no
work dispatched onto that device.
We want to be able to continue the inferior in all-stop mode and go back
to waiting for events.
With schedule-multiple, we would not only continue the current inferior,
but other inferiors that we also stopped, as well.
When debugging the host process, one might argue that the user should
switch to a host thread before continuing. It's a matter of convenience
to not require this additional switch.
When debugging only GPU devices, however, there is no host thread to
switch to. To support that use-case, we have to allow continuing the
device inferior even though no thread is selected. There may not be any
threads at all at the moment.
---
gdb/infcmd.c | 21 +++++--
gdb/infrun.c | 159 +++++++++++++++++++++++++++++----------------------
2 files changed, 107 insertions(+), 73 deletions(-)
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 3da5a1366aa..43126c5ff35 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -722,6 +722,9 @@ error_is_running (void)
static void
ensure_not_running (void)
{
+ if (inferior_ptid == null_ptid)
+ return;
+
if (inferior_thread ()->state () == THREAD_RUNNING)
error_is_running ();
}
@@ -787,7 +790,9 @@ continue_1 (bool all_threads_p)
}
else
{
- ensure_valid_thread ();
+ /* Allow continuing inferiors without threads. */
+ if (inferior_ptid != null_ptid)
+ ensure_valid_thread ();
ensure_not_running ();
clear_proceed_status (0);
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
@@ -836,7 +841,7 @@ continue_command (const char *args, int from_tty)
struct thread_info *tp;
if (non_stop)
- tp = inferior_thread ();
+ tp = (inferior_ptid == null_ptid ? nullptr : inferior_thread ());
else
{
process_stratum_target *last_target;
@@ -870,13 +875,21 @@ continue_command (const char *args, int from_tty)
ensure_not_tfind_mode ();
+ /* Switch away from an exited thread if that is the last thread in the
+ inferior to allow resuming that inferior. */
+ inferior* inf = current_inferior ();
+ if (any_live_thread_of_inferior (inf) == nullptr)
+ switch_to_inferior_no_thread (inf);
+
if (!non_stop || !all_threads_p)
{
- ensure_valid_thread ();
+ /* Allow continuing inferiors without threads. */
+ if (inferior_ptid != null_ptid)
+ ensure_valid_thread ();
ensure_not_running ();
}
- prepare_execution_command (current_inferior ()->top_target (), async_exec);
+ prepare_execution_command (inf->top_target (), async_exec);
if (from_tty)
gdb_printf (_("Continuing.\n"));
diff --git a/gdb/infrun.c b/gdb/infrun.c
index ce7c376af14..d181d20ba83 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3249,6 +3249,9 @@ thread_still_needs_step_over (struct thread_info *tp)
static bool
schedlock_applies (struct thread_info *tp)
{
+ if (tp == nullptr)
+ return (scheduler_mode == schedlock_on);
+
return (scheduler_mode == schedlock_on
|| (scheduler_mode == schedlock_step
&& tp->control.stepping_command)
@@ -3645,15 +3648,12 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
{
INFRUN_SCOPED_DEBUG_ENTER_EXIT;
- struct gdbarch *gdbarch;
- CORE_ADDR pc;
-
/* If we're stopped at a fork/vfork, switch to either the parent or child
thread as defined by the "set follow-fork-mode" command, or, if both
the parent and child are controlled by GDB, and schedule-multiple is
on, follow the child. If none of the above apply then we just proceed
resuming the current thread. */
- if (!follow_fork ())
+ if ((inferior_ptid != null_ptid) && !follow_fork ())
{
/* The target for some reason decided not to resume. */
normal_stop ();
@@ -3665,56 +3665,69 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
/* We'll update this if & when we switch to a new thread. */
update_previous_thread ();
- thread_info *cur_thr = inferior_thread ();
- infrun_debug_printf ("cur_thr = %s", cur_thr->ptid.to_string ().c_str ());
+ thread_info *cur_thr = nullptr;
+ regcache *regcache = nullptr;
+ gdbarch *gdbarch = nullptr;
+ CORE_ADDR pc = 0;
+ int step = 0;
- regcache *regcache = get_thread_regcache (cur_thr);
- gdbarch = regcache->arch ();
- pc = regcache_read_pc_protected (regcache);
+ if (inferior_ptid != null_ptid)
+ {
+ cur_thr = inferior_thread ();
+ infrun_debug_printf ("cur_thr = %s",
+ cur_thr->ptid.to_string ().c_str ());
- /* Fill in with reasonable starting values. */
- init_thread_stepping_state (cur_thr);
+ regcache = get_thread_regcache (cur_thr);
+ gdbarch = regcache->arch ();
+ pc = regcache_read_pc_protected (regcache);
- gdb_assert (!thread_is_in_step_over_chain (cur_thr));
+ /* Fill in with reasonable starting values. */
+ init_thread_stepping_state (cur_thr);
+ step = cur_thr->control.stepping_command;
+
+ gdb_assert (!thread_is_in_step_over_chain (cur_thr));
+ }
- ptid_t resume_ptid
- = user_visible_resume_ptid (cur_thr->control.stepping_command);
+ ptid_t resume_ptid = user_visible_resume_ptid (step);
process_stratum_target *resume_target
= user_visible_resume_target (resume_ptid);
check_multi_target_resumption (resume_target);
- if (addr == (CORE_ADDR) -1)
- {
- const address_space *aspace = cur_thr->inf->aspace.get ();
-
- if (cur_thr->stop_pc_p ()
- && pc == cur_thr->stop_pc ()
- && breakpoint_here_p (aspace, pc) == ordinary_breakpoint_here
- && execution_direction != EXEC_REVERSE)
- /* There is a breakpoint at the address we will resume at,
- step one instruction before inserting breakpoints so that
- we do not stop right away (and report a second hit at this
- breakpoint).
-
- Note, we don't do this in reverse, because we won't
- actually be executing the breakpoint insn anyway.
- We'll be (un-)executing the previous instruction. */
- cur_thr->stepping_over_breakpoint = 1;
- else if (gdbarch_single_step_through_delay_p (gdbarch)
- && gdbarch_single_step_through_delay (gdbarch,
- get_current_frame ()))
- /* We stepped onto an instruction that needs to be stepped
- again before re-inserting the breakpoint, do so. */
- cur_thr->stepping_over_breakpoint = 1;
- }
- else
+ if (inferior_ptid != null_ptid)
{
- regcache_write_pc (regcache, addr);
- }
+ if (addr == (CORE_ADDR) -1)
+ {
+ const address_space *aspace = cur_thr->inf->aspace.get ();
+
+ if (cur_thr->stop_pc_p ()
+ && pc == cur_thr->stop_pc ()
+ && breakpoint_here_p (aspace, pc) == ordinary_breakpoint_here
+ && execution_direction != EXEC_REVERSE)
+ /* There is a breakpoint at the address we will resume at,
+ step one instruction before inserting breakpoints so that
+ we do not stop right away (and report a second hit at this
+ breakpoint).
+
+ Note, we don't do this in reverse, because we won't
+ actually be executing the breakpoint insn anyway.
+ We'll be (un-)executing the previous instruction. */
+ cur_thr->stepping_over_breakpoint = 1;
+ else if (gdbarch_single_step_through_delay_p (gdbarch)
+ && gdbarch_single_step_through_delay (gdbarch,
+ get_current_frame ()))
+ /* We stepped onto an instruction that needs to be stepped
+ again before re-inserting the breakpoint, do so. */
+ cur_thr->stepping_over_breakpoint = 1;
+ }
+ else
+ {
+ regcache_write_pc (regcache, addr);
+ }
- if (siggnal != GDB_SIGNAL_DEFAULT)
- cur_thr->set_stop_signal (siggnal);
+ if (siggnal != GDB_SIGNAL_DEFAULT)
+ cur_thr->set_stop_signal (siggnal);
+ }
/* If an exception is thrown from this point on, make sure to
propagate GDB's knowledge of the executing state to the
@@ -3724,11 +3737,15 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
/* Even if RESUME_PTID is a wildcard, and we end up resuming fewer
threads (e.g., we might need to set threads stepping over
breakpoints first), from the user/frontend's point of view, all
- threads in RESUME_PTID are now running. */
- set_state (resume_target, resume_ptid, THREAD_RUNNING);
+ threads in RESUME_PTID are now running.
+
+ Note that RESUME_PTID may be NULL_PTID when resuming an inferior that
+ (currently) has no threads. */
+ if (resume_ptid != null_ptid)
+ set_state (resume_target, resume_ptid, THREAD_RUNNING);
infrun_debug_printf ("addr=%s, signal=%s, resume_ptid=%s",
- paddress (gdbarch, addr),
+ hex_string (addr),
gdb_signal_to_symbol_string (siggnal),
resume_ptid.to_string ().c_str ());
@@ -3744,6 +3761,9 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
Ctrl-C from within target_pass_ctrlc). */
target_terminal::inferior ();
+ /* We don't want the user to see a different selected thread. */
+ scoped_restore_current_thread restore_thread;
+
/* In a multi-threaded task we may select another thread and
then continue or step.
@@ -3757,8 +3777,10 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
/* If scheduler locking applies, we can avoid iterating over all
threads. */
- if (!non_stop && !schedlock_applies (cur_thr))
+ if (resume_ptid != null_ptid && !non_stop && !schedlock_applies (cur_thr))
{
+ scoped_restore_current_thread restore;
+
for (thread_info &tp : all_non_exited_threads (resume_target,
resume_ptid))
{
@@ -3779,21 +3801,22 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
global_thread_step_over_chain_enqueue (&tp);
}
-
- switch_to_thread (cur_thr);
}
- /* Enqueue the current thread last, so that we move all other
- threads over their breakpoints first. */
- if (cur_thr->stepping_over_breakpoint)
- global_thread_step_over_chain_enqueue (cur_thr);
+ if (cur_thr != nullptr)
+ {
+ /* Enqueue the current thread last, so that we move all other
+ threads over their breakpoints first. */
+ if (cur_thr->stepping_over_breakpoint)
+ global_thread_step_over_chain_enqueue (cur_thr);
- /* If the thread isn't started, we'll still need to set its prev_pc,
- so that switch_back_to_stepped_thread knows the thread hasn't
- advanced. Must do this before resuming any thread, as in
- all-stop/remote, once we resume we can't send any other packet
- until the target stops again. */
- cur_thr->prev_pc = regcache_read_pc_protected (regcache);
+ /* If the thread isn't started, we'll still need to set its prev_pc,
+ so that switch_back_to_stepped_thread knows the thread hasn't
+ advanced. Must do this before resuming any thread, as in
+ all-stop/remote, once we resume we can't send any other packet
+ until the target stops again. */
+ cur_thr->prev_pc = regcache_read_pc_protected (regcache);
+ }
{
scoped_disable_commit_resumed disable_commit_resumed ("proceeding");
@@ -3817,14 +3840,17 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
/* In all-stop, but the target is always in non-stop mode.
Start all other threads that are implicitly resumed too. */
- for (thread_info &tp : all_non_exited_threads (resume_target,
- resume_ptid))
+ if (resume_ptid != null_ptid)
{
- switch_to_thread_no_regs (&tp);
- proceed_resume_thread_checked (&tp);
+ for (thread_info &tp : all_non_exited_threads (resume_target,
+ resume_ptid))
+ {
+ switch_to_thread_no_regs (&tp);
+ proceed_resume_thread_checked (&tp);
+ }
}
}
- else
+ else if (cur_thr != nullptr)
proceed_resume_thread_checked (cur_thr);
disable_commit_resumed.reset_and_commit ();
@@ -3832,11 +3858,6 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
finish_state.release ();
- /* If we've switched threads above, switch back to the previously
- current thread. We don't want the user to see a different
- selected thread. */
- switch_to_thread (cur_thr);
-
/* Tell the event loop to wait for it to stop. If the target
supports asynchronous execution, it'll do this from within
target_resume. */
--
2.43.0
________________________________________
Intel Deutschland GmbH
Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany
Tel: +49 (89) 99143-0
www.intel.de
Managing Directors: Candice Moore, Jeffrey Schneiderman, Ramachandran Sitaraman
Chairperson of the Supervisory Board: Sonja Pierer
Registered Seat: Munich Commercial Register B: Amtsgericht Munich HRB 186928
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
next prev parent reply other threads:[~2026-08-12 13:36 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-12 13:27 [PATCH v4 00/44] A new target to debug Intel GPUs Markus Metzger
2026-08-12 13:27 ` [PATCH v4 01/44] bfd: add intelgt target to BFD Markus Metzger
2026-08-12 13:27 ` [PATCH v4 02/44] opcodes: add intelgt as a configuration Markus Metzger
2026-08-12 13:27 ` [PATCH v4 03/44] gdbserver: allow configuring for a heterogeneous target Markus Metzger
2026-08-12 13:27 ` [PATCH v4 04/44] config.sub: recognize level-zero as "ze" Markus Metzger
2026-08-12 13:27 ` [PATCH v4 05/44] gdbserver: import AC_LIB_HAVE_LINKFLAGS macro into the autoconf script Markus Metzger
2026-08-12 13:27 ` [PATCH v4 06/44] gdb, gdbserver, gdbsupport: add 'device' tag to XML target description Markus Metzger
2026-08-12 13:27 ` [PATCH v4 07/44] gdb, arch, intelgt: add intelgt arch definitions Markus Metzger
2026-08-12 13:27 ` [PATCH v4 08/44] gdb: add a new extract_integer variant that takes two array_views Markus Metzger
2026-08-12 13:27 ` [PATCH v4 09/44] gdb, intelgt: add the target-dependent definitions for the Intel GT architecture Markus Metzger
2026-08-12 13:27 ` [PATCH v4 10/44] gdb, intelgt: add disassemble feature " Markus Metzger
2026-08-12 13:27 ` [PATCH v4 11/44] gdb: revise the pid_to_exec_file target op Markus Metzger
2026-08-12 13:27 ` [PATCH v4 12/44] gdb, remote: do 'remote_add_inferior' in 'remote_notice_new_inferior' earlier Markus Metzger
2026-08-12 13:27 ` [PATCH v4 13/44] gdbserver: move dlls_changed initialization on attach into targets Markus Metzger
2026-08-12 13:27 ` [PATCH v4 14/44] gdbserver: adjust pid after the target attaches Markus Metzger
2026-08-12 13:27 ` [PATCH v4 15/44] gdbserver: check process when we need a process Markus Metzger
2026-08-12 13:27 ` [PATCH v4 16/44] gdb: use process in xfer_partial if inferior_ptid is null_ptid Markus Metzger
2026-08-12 13:27 ` [PATCH v4 17/44] gdb: allow inferiors without threads in all_matching_threads_iterator Markus Metzger
2026-08-12 13:27 ` [PATCH v4 18/44] gdbserver: improve threads debug output for process general thread Markus Metzger
2026-08-12 13:27 ` [PATCH v4 19/44] gdb, gdbserver: allow setting null_ptid as " Markus Metzger
2026-08-12 13:27 ` [PATCH v4 20/44] gdbserver: allow inferiors without threads Markus Metzger
2026-08-12 13:27 ` [PATCH v4 21/44] gdb: allow creating and attaching to " Markus Metzger
2026-08-12 13:27 ` [PATCH v4 22/44] gdb, remote: don't create an inferior on attach Markus Metzger
2026-08-12 13:27 ` [PATCH v4 23/44] gdb: allow switching to an inferior without threads Markus Metzger
2026-08-12 13:27 ` [PATCH v4 24/44] gdb: allow resuming an inferior with no threads Markus Metzger
2026-08-12 13:27 ` Markus Metzger [this message]
2026-08-12 13:27 ` [PATCH v4 26/44] gdb: partially fix C-c not working Markus Metzger
2026-08-12 13:27 ` [PATCH v4 27/44] gdb, linux-nat: use current_inferior()->pid in mourn_inferior() Markus Metzger
2026-08-12 13:27 ` [PATCH v4 28/44] gdb: inferior events Markus Metzger
2026-08-12 13:27 ` [PATCH v4 29/44] gdb, remote: allow deleting the last thread in inferior in update_thread_list() Markus Metzger
2026-08-12 13:27 ` [PATCH v4 30/44] gdb: keep target registered in inferior_event_handler() Markus Metzger
2026-08-12 13:27 ` [PATCH v4 31/44] gdb, dwarf, ze: add DW_OP_INTEL_regval_bits Markus Metzger
2026-08-12 13:27 ` [PATCH v4 32/44] gdbserver: add a pointer to the owner thread in regcache Markus Metzger
2026-08-12 13:27 ` [PATCH v4 33/44] gdb, gdbserver, ze: in-memory libraries Markus Metzger
2026-08-12 13:27 ` [PATCH v4 34/44] gdb, gdbserver: library notifications Markus Metzger
2026-08-12 13:27 ` [PATCH v4 35/44] gdbserver, ze, intelgt: introduce ze-low and intelgt-ze-low targets Markus Metzger
2026-08-12 13:27 ` [PATCH v4 36/44] testsuite, sycl: add SYCL support Markus Metzger
2026-08-12 13:27 ` [PATCH v4 37/44] testsuite, sycl: add test for backtracing inside a kernel Markus Metzger
2026-08-12 13:27 ` [PATCH v4 38/44] testsuite, sycl: add test for 'info locals' and 'info args' Markus Metzger
2026-08-12 13:27 ` [PATCH v4 39/44] testsuite, sycl: add tests for stepping Markus Metzger
2026-08-12 13:28 ` [PATCH v4 40/44] testsuite, sycl: add test for 1-D and 2-D parallel_for kernels Markus Metzger
2026-08-12 13:28 ` [PATCH v4 41/44] testsuite, sycl: add test for scheduler-locking Markus Metzger
2026-08-12 13:28 ` [PATCH v4 42/44] testsuite, arch, intelgt: add a disassembly test Markus Metzger
2026-08-12 13:28 ` [PATCH v4 43/44] testsuite, arch, intelgt: add intelgt-program-bp.exp Markus Metzger
2026-08-12 13:28 ` [PATCH v4 44/44] testsuite, intelgt: add a test for interrupting an exited thread Markus Metzger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260812132805.380163-26-markus.t.metzger@intel.com \
--to=markus.t.metzger@intel.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox