* [RFC] 07/10 non-stop inferior control
@ 2008-05-06 17:43 Pedro Alves
2008-05-08 18:19 ` Eli Zaretskii
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Pedro Alves @ 2008-05-06 17:43 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1125 bytes --]
This patch adds the inferior control support for non-stop mode.
In non-stop mode, each thread is handled individually. It should
be like you have a separate debugger attached to each thread.
To accomplish that, as soon as we have an event, we context switch
to it, and go on handling it. The cases of hiting a breakpoint
in another thread while we're stepping don't need to be handled
specially, as the stepping thread will have its state, and the
other thread will have its own state.
Every exec command should apply only to the selected thread.
A new target_stop_ptid method was added to request the target
to interrupt a single thread.
Several checks have been added so GDB doesn't try to do
things with running threads, which don't make sense,
like asking for the current PC of a running thread.
Info threads now shows the running state of a thread. MI
support can be added on top.
(gdb) info threads
3 Thread 0xf7603b90 (LWP 23454) (running)
* 2 Thread 0xf7e04b90 (LWP 23453) 0xffffe410 in __kernel_vsyscall ()
1 Thread 0xf7e056b0 (LWP 23450) (running)
--
Pedro Alves
[-- Attachment #2: 007-non_stop_core.diff --]
[-- Type: text/x-diff, Size: 19025 bytes --]
2008-05-06 Pedro Alves <pedro@codesourcery.com>
* infrun.c (resume): In non-stop mode, always resume just one
thread.
(prepare_to_proceed): Do nothing in non-stop mode.
(fetch_inferior_event): In non-stop mode, switch context before
handling the event.
(error_is_running, ensure_not_running): New.
(handle_inferior_event): In non-stop mode: Mark only the event
thread as stopped. Require that the target module handles new
threads correctly. Don't switch to infwait_thread_hop_state.
(normal_stop): Only mark not-running if inferior hasn't exited.
In non-stop mode, only mark the event thread.
* thread.c (print_thread_info): Don't read from a running thread.
Output "(running)" if thread is running.
(switch_to_thread): Don't read stop_pc if thread is running.
(do_restore_current_thread_cleanup): Don't write to a running
thread.
(thread_apply_all_command): Don't read from a running thread. In
non-stop mode, do a full context-switch instead of just switching
threads.
(thread_apply_command): In non-stop mode, do a full context-switch
instead of just switching threads.
(do_captured_thread_select): Likewise. Inform user if selected
thread is running.
* inf-loop.c (inferior_event_handler): In non-stop mode, don't
unregister the target from the event loop.
* infcmd.c (continue_command, step_1, jump_command,
signal_command): Ensure the selected thread isn't running.
(interrupt_target_command): In non-stop mode, either interrupt
only the selected thread, or read the thread id to interrupt from
a parameter.
* inferior.h (error_is_running, ensure_not_running): Declare.
* target.h (struct target_ops): Add to_stop_ptid member.
(target_stop_ptid): Define.
* target.c (update_current_target): Inherit to_stop_ptid. Default
to_stop_ptid to target_ignore.
(debug_to_stop_ptid): New.
(debug_to_rcmd): Set to_stop_ptid.
---
gdb/inf-loop.c | 14 +++++---
gdb/infcmd.c | 25 ++++++++++++++-
gdb/inferior.h | 6 +++
gdb/infrun.c | 78 ++++++++++++++++++++++++++++++++++++++++++-----
gdb/target.c | 13 +++++++
gdb/target.h | 4 ++
gdb/thread.c | 93 ++++++++++++++++++++++++++++++++++++++++-----------------
7 files changed, 191 insertions(+), 42 deletions(-)
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c 2008-05-06 15:09:23.000000000 +0100
+++ src/gdb/infrun.c 2008-05-06 15:52:30.000000000 +0100
@@ -1052,9 +1052,15 @@ a command like `return' or `jump' to con
resume_ptid = inferior_ptid;
}
- if ((scheduler_mode == schedlock_on)
- || (scheduler_mode == schedlock_step
- && (step || singlestep_breakpoints_inserted_p)))
+ if (non_stop)
+ {
+ /* With non-stop mode on, threads are always handled
+ individually. */
+ resume_ptid = inferior_ptid;
+ }
+ else if ((scheduler_mode == schedlock_on)
+ || (scheduler_mode == schedlock_step
+ && (step || singlestep_breakpoints_inserted_p)))
{
/* User-settable 'scheduler' mode requires solo thread resume. */
resume_ptid = inferior_ptid;
@@ -1125,6 +1131,11 @@ prepare_to_proceed (int step)
ptid_t wait_ptid;
struct target_waitstatus wait_status;
+ if (non_stop)
+ /* In non-stop, each thread is handled individually. The context
+ must already be set to the right thread here. */
+ return 0;
+
/* Get the last target status returned by target_wait(). */
get_last_target_status (&wait_ptid, &wait_status);
@@ -1529,6 +1540,15 @@ fetch_inferior_event (void *client_data)
else
ecs->ptid = target_wait (waiton_ptid, &ecs->ws);
+ if (non_stop
+ && ecs->ws.kind != TARGET_WAITKIND_IGNORE
+ && ecs->ws.kind != TARGET_WAITKIND_EXITED
+ && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
+ /* In non-stop mode, each thread is handled individually. Switch
+ early, so the global state is set correctly for this
+ thread. */
+ context_switch (ecs->ptid);
+
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
@@ -1737,6 +1757,20 @@ init_infwait_state (void)
infwait_state = infwait_normal_state;
}
+void
+error_is_running (void)
+{
+ error (_("\
+Cannot execute this command while the selected thread is running."));
+}
+
+void
+ensure_not_running (void)
+{
+ if (is_running (inferior_ptid))
+ error_is_running ();
+}
+
/* Given an execution control state that has been freshly filled in
by an event from the inferior, figure out what it means and take
appropriate action. */
@@ -1808,11 +1842,15 @@ handle_inferior_event (struct execution_
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
add_thread (ecs->ptid);
- /* Mark all threads as not-executing. In non-stop, this should be
- adjusted to only mark ecs->ptid. */
if (ecs->ws.kind != TARGET_WAITKIND_IGNORE
&& stop_soon != STOP_QUIETLY)
- set_executing (pid_to_ptid (-1), 0);
+ {
+ /* Mark the stopped threads accordingly. */
+ if (!non_stop)
+ set_executing (pid_to_ptid (-1), 0);
+ else
+ set_executing (ecs->ptid, 0);
+ }
switch (ecs->ws.kind)
{
@@ -2058,6 +2096,11 @@ handle_inferior_event (struct execution_
all threads in order to make progress. */
if (ecs->new_thread_event)
{
+ if (non_stop)
+ /* Non-stop requires a behaving target. */
+ internal_error (__FILE__, __LINE__,
+ "target misreported a new thread in non-stop mode.");
+
target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
@@ -2124,6 +2167,9 @@ handle_inferior_event (struct execution_
if (!ptid_equal (deferred_step_ptid, null_ptid))
{
+ /* In non-stop mode, there's never a deferred_step_ptid set. */
+ gdb_assert (!non_stop);
+
/* If we stopped for some other reason than single-stepping, ignore
the fact that we were supposed to switch back. */
if (stop_signal == TARGET_SIGNAL_TRAP)
@@ -2272,8 +2318,13 @@ handle_inferior_event (struct execution_
if (!ptid_equal (inferior_ptid, ecs->ptid))
context_switch (ecs->ptid);
- waiton_ptid = ecs->ptid;
- infwait_state = infwait_thread_hop_state;
+ if (!non_stop)
+ {
+ /* Only need to require the next event from this
+ thread in all-stop mode. */
+ waiton_ptid = ecs->ptid;
+ infwait_state = infwait_thread_hop_state;
+ }
tss->stepping_over_breakpoint = 1;
keep_going (ecs);
@@ -3827,7 +3878,16 @@ done:
/* Delete the breakpoint we stopped at, if it wants to be deleted.
Delete any breakpoint that is to be deleted at the next stop. */
breakpoint_auto_delete (stop_bpstat);
- set_running (pid_to_ptid (-1), 0);
+
+ if (target_has_execution
+ && last.kind != TARGET_WAITKIND_SIGNALLED
+ && last.kind != TARGET_WAITKIND_EXITED)
+ {
+ if (!non_stop)
+ set_running (pid_to_ptid (-1), 0);
+ else
+ set_running (inferior_ptid, 0);
+ }
}
static int
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c 2008-05-06 15:08:43.000000000 +0100
+++ src/gdb/thread.c 2008-05-06 15:52:32.000000000 +0100
@@ -561,8 +561,12 @@ print_thread_info (struct ui_out *uiout,
char *extra_info;
int current_thread = -1;
+ tp = find_thread_pid (inferior_ptid);
+
/* Backup current thread and selected frame. */
- saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ if (tp && !tp->running_)
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+
old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
make_cleanup_ui_out_list_begin_end (uiout, "threads");
@@ -591,20 +595,26 @@ print_thread_info (struct ui_out *uiout,
ui_out_text (uiout, " ");
ui_out_field_string (uiout, "target-id", target_tid_to_str (tp->ptid));
- extra_info = target_extra_thread_info (tp);
- if (extra_info)
+ if (tp->running_)
+ ui_out_text (uiout, " (running)\n");
+ else
{
- ui_out_text (uiout, " (");
- ui_out_field_string (uiout, "details", extra_info);
- ui_out_text (uiout, ")");
+ extra_info = target_extra_thread_info (tp);
+ if (extra_info)
+ {
+ ui_out_text (uiout, " (");
+ ui_out_field_string (uiout, "details", extra_info);
+ ui_out_text (uiout, ")");
+ }
+ ui_out_text (uiout, " ");
+ /* The switch below puts us at the top of the stack (leaf
+ frame). */
+ switch_to_thread (tp->ptid);
+ print_stack_frame (get_selected_frame (NULL),
+ /* For MI output, print frame level. */
+ ui_out_is_mi_like_p (uiout),
+ LOCATION);
}
- ui_out_text (uiout, " ");
- /* That switch put us at the top of the stack (leaf frame). */
- switch_to_thread (tp->ptid);
- print_stack_frame (get_selected_frame (NULL),
- /* For MI output, print frame level. */
- ui_out_is_mi_like_p (uiout),
- LOCATION);
do_cleanups (chain2);
}
@@ -620,6 +630,10 @@ print_thread_info (struct ui_out *uiout,
ui_out_field_int (uiout, "current-thread-id", current_thread);
}
+ tp = find_thread_pid (inferior_ptid);
+ if (!tp || tp->running_)
+ return;
+
/* If case we were not able to find the original frame, print the
new selected frame. */
if (frame_find_by_id (saved_frame_id) == NULL)
@@ -658,7 +672,11 @@ switch_to_thread (ptid_t ptid)
inferior_ptid = ptid;
reinit_frame_cache ();
registers_changed ();
- stop_pc = read_pc ();
+
+ if (!is_executing (ptid))
+ stop_pc = read_pc ();
+ else
+ stop_pc = ~(CORE_ADDR) 0;
}
static void
@@ -695,7 +713,13 @@ do_restore_current_thread_cleanup (void
{
struct current_thread_cleanup *old = arg;
restore_current_thread (old->inferior_ptid);
- restore_selected_frame (old->selected_frame_id);
+
+ /* A command like 'thread apply all continue&' will change the
+ running state of the originally selected thread, so we have to
+ recheck it here. */
+ if (in_thread_list (old->inferior_ptid)
+ && !is_running (old->inferior_ptid))
+ restore_selected_frame (old->selected_frame_id);
xfree (old);
}
@@ -723,8 +747,7 @@ static void
thread_apply_all_command (char *cmd, int from_tty)
{
struct thread_info *tp;
- struct cleanup *old_chain;
- struct cleanup *saved_cmd_cleanup_chain;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
char *saved_cmd;
struct frame_id saved_frame_id;
ptid_t current_ptid;
@@ -734,8 +757,12 @@ thread_apply_all_command (char *cmd, int
error (_("Please specify a command following the thread ID list"));
current_ptid = inferior_ptid;
- saved_frame_id = get_frame_id (get_selected_frame (NULL));
- old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
+
+ if (!is_running (inferior_ptid))
+ {
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
+ }
/* It is safe to update the thread list now, before
traversing it for "thread apply all". MVS */
@@ -744,11 +771,15 @@ thread_apply_all_command (char *cmd, int
/* Save a copy of the command in case it is clobbered by
execute_command */
saved_cmd = xstrdup (cmd);
- saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd);
+ make_cleanup (xfree, saved_cmd);
for (tp = thread_list; tp; tp = tp->next)
if (thread_alive (tp))
{
- switch_to_thread (tp->ptid);
+ if (non_stop)
+ context_switch_to (tp->ptid);
+ else
+ switch_to_thread (tp->ptid);
+
printf_filtered (_("\nThread %d (%s):\n"),
tp->num, target_tid_to_str (inferior_ptid));
execute_command (cmd, from_tty);
@@ -758,12 +789,10 @@ thread_apply_all_command (char *cmd, int
if (!ptid_equal (current_ptid, inferior_ptid))
thread_has_changed = 1;
- do_cleanups (saved_cmd_cleanup_chain);
do_cleanups (old_chain);
/* Print stack frame only if we changed thread. */
- if (thread_has_changed)
+ if (thread_has_changed && !is_running (inferior_ptid))
print_stack_frame (get_current_frame (), 1, SRC_LINE);
-
}
static void
@@ -831,7 +860,10 @@ thread_apply_command (char *tidlist, int
warning (_("Thread %d has terminated."), start);
else
{
- switch_to_thread (tp->ptid);
+ if (non_stop)
+ context_switch_to (tp->ptid);
+ else
+ switch_to_thread (tp->ptid);
printf_filtered (_("\nThread %d (%s):\n"), tp->num,
target_tid_to_str (inferior_ptid));
execute_command (cmd, from_tty);
@@ -898,7 +930,10 @@ do_captured_thread_select (struct ui_out
if (!thread_alive (tp))
error (_("Thread ID %d has terminated."), num);
- switch_to_thread (tp->ptid);
+ if (non_stop)
+ context_switch_to (tp->ptid);
+ else
+ switch_to_thread (tp->ptid);
ui_out_text (uiout, "[Switching to thread ");
ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid));
@@ -906,7 +941,11 @@ do_captured_thread_select (struct ui_out
ui_out_text (uiout, target_tid_to_str (inferior_ptid));
ui_out_text (uiout, ")]");
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ if (!tp->running_)
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ else
+ ui_out_text (uiout, " (running)\n");
+
return GDB_RC_OK;
}
Index: src/gdb/inf-loop.c
===================================================================
--- src.orig/gdb/inf-loop.c 2008-05-06 15:07:58.000000000 +0100
+++ src/gdb/inf-loop.c 2008-05-06 15:10:02.000000000 +0100
@@ -73,11 +73,15 @@ inferior_event_handler (enum inferior_ev
break;
case INF_EXEC_COMPLETE:
- /* Unregister the inferior from the event loop. This is done so that
- when the inferior is not running we don't get distracted by
- spurious inferior output. */
- if (target_has_execution)
- target_async (NULL, 0);
+
+ if (!non_stop)
+ {
+ /* Unregister the inferior from the event loop. This is done
+ so that when the inferior is not running we don't get
+ distracted by spurious inferior output. */
+ if (target_has_execution)
+ target_async (NULL, 0);
+ }
/* The call to async_enable_stdin below resets 'sync_execution'.
However, if sync_execution is 1 now, we also need to show the
Index: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c 2008-05-06 15:07:24.000000000 +0100
+++ src/gdb/infcmd.c 2008-05-06 15:52:30.000000000 +0100
@@ -612,6 +612,7 @@ continue_command (char *proc_count_exp,
{
int async_exec = 0;
ERROR_NO_INFERIOR;
+ ensure_not_running ();
/* Find out whether we must run in the background. */
if (proc_count_exp != NULL)
@@ -713,6 +714,7 @@ step_1 (int skip_subroutines, int single
int thread = -1;
ERROR_NO_INFERIOR;
+ ensure_not_running ();
if (count_string)
async_exec = strip_bg_char (&count_string);
@@ -935,6 +937,7 @@ jump_command (char *arg, int from_tty)
int async_exec = 0;
ERROR_NO_INFERIOR;
+ ensure_not_running ();
/* Find out whether we must run in the background. */
if (arg != NULL)
@@ -1035,6 +1038,7 @@ signal_command (char *signum_exp, int fr
dont_repeat (); /* Too dangerous. */
ERROR_NO_INFERIOR;
+ ensure_not_running ();
/* Find out whether we must run in the background. */
if (signum_exp != NULL)
@@ -2103,7 +2107,26 @@ interrupt_target_command (char *args, in
if (target_can_async_p ())
{
dont_repeat (); /* Not for the faint of heart */
- target_stop ();
+
+ if (non_stop)
+ {
+ ptid_t ptid;
+ if (args && *args)
+ {
+ int num = value_as_long (parse_and_eval (args));
+
+ if (!valid_thread_id (num))
+ error (_("Thread ID %d not known."), num);
+
+ ptid = thread_id_to_pid (num);
+ }
+ else
+ ptid = inferior_ptid;
+
+ target_stop_ptid (ptid);
+ }
+ else
+ target_stop ();
}
}
Index: src/gdb/inferior.h
===================================================================
--- src.orig/gdb/inferior.h 2008-05-06 15:08:56.000000000 +0100
+++ src/gdb/inferior.h 2008-05-06 15:52:30.000000000 +0100
@@ -245,6 +245,12 @@ extern void get_last_target_status(ptid_
extern void follow_inferior_reset_breakpoints (void);
+/* Throw an error indicating the current thread is running. */
+extern void error_is_running (void);
+
+/* Calls error_is_running if the current thread is running. */
+extern void ensure_not_running (void);
+
/* From infcmd.c */
extern void tty_command (char *, int);
Index: src/gdb/target.h
===================================================================
--- src.orig/gdb/target.h 2008-05-06 15:08:23.000000000 +0100
+++ src/gdb/target.h 2008-05-06 15:10:02.000000000 +0100
@@ -397,6 +397,7 @@ struct target_ops
char *(*to_pid_to_str) (ptid_t);
char *(*to_extra_thread_info) (struct thread_info *);
void (*to_stop) (void);
+ void (*to_stop_ptid) (ptid_t ptid);
void (*to_rcmd) (char *command, struct ui_file *output);
char *(*to_pid_to_exec_file) (int pid);
void (*to_log_command) (const char *);
@@ -884,6 +885,9 @@ int target_follow_fork (int follow_child
#define target_stop current_target.to_stop
+#define target_stop_ptid current_target.to_stop_ptid
+
+
/* Send the specified COMMAND to the target's monitor
(shell,interpreter) for execution. The result of the query is
placed in OUTBUF. */
Index: src/gdb/target.c
===================================================================
--- src.orig/gdb/target.c 2008-05-06 15:07:58.000000000 +0100
+++ src/gdb/target.c 2008-05-06 15:10:02.000000000 +0100
@@ -456,6 +456,7 @@ update_current_target (void)
INHERIT (to_pid_to_str, t);
INHERIT (to_extra_thread_info, t);
INHERIT (to_stop, t);
+ INHERIT (to_stop_ptid, t);
/* Do not inherit to_xfer_partial. */
INHERIT (to_rcmd, t);
INHERIT (to_pid_to_exec_file, t);
@@ -631,6 +632,9 @@ update_current_target (void)
de_fault (to_stop,
(void (*) (void))
target_ignore);
+ de_fault (to_stop_ptid,
+ (void (*) (ptid_t))
+ target_ignore);
current_target.to_xfer_partial = current_xfer_partial;
de_fault (to_rcmd,
(void (*) (char *, struct ui_file *))
@@ -2787,6 +2791,14 @@ debug_to_stop (void)
}
static void
+debug_to_stop_ptid (ptid_t ptid)
+{
+ debug_target.to_stop_ptid (ptid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_stop_pid\n");
+}
+
+static void
debug_to_rcmd (char *command,
struct ui_file *outbuf)
{
@@ -2860,6 +2872,7 @@ setup_target_debug (void)
current_target.to_thread_alive = debug_to_thread_alive;
current_target.to_find_new_threads = debug_to_find_new_threads;
current_target.to_stop = debug_to_stop;
+ current_target.to_stop_ptid = debug_to_stop_ptid;
current_target.to_rcmd = debug_to_rcmd;
current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
}
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] 07/10 non-stop inferior control
2008-05-06 17:43 [RFC] 07/10 non-stop inferior control Pedro Alves
@ 2008-05-08 18:19 ` Eli Zaretskii
2008-05-09 2:08 ` Pedro Alves
2008-05-19 16:56 ` Pedro Alves
2008-06-04 11:49 ` Vladimir Prus
2 siblings, 1 reply; 9+ messages in thread
From: Eli Zaretskii @ 2008-05-08 18:19 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
> From: Pedro Alves <pedro@codesourcery.com>
> Date: Tue, 6 May 2008 16:49:23 +0100
>
> if (ecs->new_thread_event)
> {
> + if (non_stop)
> + /* Non-stop requires a behaving target. */
> + internal_error (__FILE__, __LINE__,
> + "target misreported a new thread in non-stop mode.");
> +
What does this internal_error mean? The wording of the error message
doesn't seem to justify an internal_error. What am I missing here?
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] 07/10 non-stop inferior control
2008-05-08 18:19 ` Eli Zaretskii
@ 2008-05-09 2:08 ` Pedro Alves
2008-05-09 2:52 ` Daniel Jacobowitz
0 siblings, 1 reply; 9+ messages in thread
From: Pedro Alves @ 2008-05-09 2:08 UTC (permalink / raw)
To: gdb-patches, Eli Zaretskii
A Thursday 08 May 2008 12:40:00, Eli Zaretskii wrote:
> > From: Pedro Alves <pedro@codesourcery.com>
> > Date: Tue, 6 May 2008 16:49:23 +0100
> >
> > if (ecs->new_thread_event)
> > {
> > + if (non_stop)
> > + /* Non-stop requires a behaving target. */
> > + internal_error (__FILE__, __LINE__,
> > + "target misreported a new thread in non-stop mode.");
> > +
>
> What does this internal_error mean? The wording of the error message
> doesn't seem to justify an internal_error. What am I missing here?
Isn't this new_thread_event handling a bandaid for some
misbehaving target? My understanding was that targets should handle
new thread events (and call add_thread*) themselves nowadays.
There are two issues with non-stop here.
First, is that I context switched before this code already, which
isn't that great when the new inferior ptid isn't listed yet
(the next context switch after the new thread is added to
the list will store the wrong context).
In non-stop, context switching should happen
before adjust_pc_after_break, because that relies on prev_pc, and
currently_stepping (ecs), which are per-thread, so to make the
new_thread_event handling correct in non-stop, would require
moving this bit:
/* If it's a new process, add it to the thread database */
ecs->new_thread_event = (!ptid_equal (ecs->ptid, inferior_ptid)
&& !ptid_equal (ecs->ptid, minus_one_ptid)
&& !in_thread_list (ecs->ptid));
if (ecs->ws.kind != TARGET_WAITKIND_EXITED
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
add_thread (ecs->ptid);
To the top of handle_inferior_event, and context switch right after it,
if non-stop, instead of context-switching in fetch_inferior_event.
Something like:
void
handle_inferior_event (struct execution_control_state *ecs)
{
int sw_single_step_trap_p = 0;
int stopped_by_watchpoint;
int stepped_after_stopped_by_watchpoint = 0;
/* If it's a new process, add it to the thread database */
ecs->new_thread_event = (!ptid_equal (ecs->ptid, inferior_ptid)
&& !ptid_equal (ecs->ptid, minus_one_ptid)
&& !in_thread_list (ecs->ptid));
if (ecs->ws.kind != TARGET_WAITKIND_EXITED
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
add_thread (ecs->ptid);
if (non_stop
&& ecs->ws.kind != TARGET_WAITKIND_IGNORE
&& ecs->ws.kind != TARGET_WAITKIND_EXITED
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
/* In non-stop mode, each thread is handled individually. Switch
early, so the global state is set correctly for this
thread. */
context_switch (ecs->ptid);
/* Cache the last pid/waitstatus. */
target_last_wait_ptid = ecs->ptid;
target_last_waitstatus = ecs->ws;
/* Always clear state belonging to the previous time we stopped. */
stop_stack_dummy = 0;
adjust_pc_after_break (ecs);
...
Since this is a new mode that will require adaptation
by each target, it sounded reasonable to require that the
the new_thread_event should never be hit, and that the
target handles adding threads to GDB's thread list.
Second is that what follows that code you pointed is
target_resume (RESUME_ALL), which should never happen
in non-stop mode:
/* At this point, all threads are stopped (happens automatically in
either the OS or the native code). Therefore we need to continue
all threads in order to make progress. */
if (ecs->new_thread_event)
{
target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
}
I can certainly change that to:
if (ecs->new_thread_event)
{
/* We may want to consider not doing a resume here in order to
give the user a chance to play with the new thread. It might
be good to make that a user-settable option. */
if (non_stop)
/* Only resume the event thread. */
target_resume (ecs->ptid, 0, TARGET_SIGNAL_0);
else
/* At this point, all threads are stopped (happens
automatically in either the OS or the native code).
Therefore we need to continue all threads in order to make
progress. */
target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
}
But should I ?
--
Pedro Alves
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] 07/10 non-stop inferior control
2008-05-09 2:08 ` Pedro Alves
@ 2008-05-09 2:52 ` Daniel Jacobowitz
2008-05-19 16:55 ` Pedro Alves
0 siblings, 1 reply; 9+ messages in thread
From: Daniel Jacobowitz @ 2008-05-09 2:52 UTC (permalink / raw)
To: gdb-patches
On Fri, May 09, 2008 at 02:22:51AM +0100, Pedro Alves wrote:
> Isn't this new_thread_event handling a bandaid for some
> misbehaving target? My understanding was that targets should handle
> new thread events (and call add_thread*) themselves nowadays.
That might be a little strong; but the Linux and remote targets do so,
because it was much more convenient.
> Since this is a new mode that will require adaptation
> by each target, it sounded reasonable to require that the
> the new_thread_event should never be hit, and that the
> target handles adding threads to GDB's thread list.
If documented in gdbint, I think this would be a reasonable new
restriction.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] 07/10 non-stop inferior control
2008-05-09 2:52 ` Daniel Jacobowitz
@ 2008-05-19 16:55 ` Pedro Alves
0 siblings, 0 replies; 9+ messages in thread
From: Pedro Alves @ 2008-05-19 16:55 UTC (permalink / raw)
To: gdb-patches; +Cc: Daniel Jacobowitz
A Friday 09 May 2008 02:44:54, Daniel Jacobowitz wrote:
> On Fri, May 09, 2008 at 02:22:51AM +0100, Pedro Alves wrote:
> > Isn't this new_thread_event handling a bandaid for some
> > misbehaving target? My understanding was that targets should handle
> > new thread events (and call add_thread*) themselves nowadays.
>
> That might be a little strong; but the Linux and remote targets do so,
> because it was much more convenient.
>
Ok. If you know off-hand of any target that relies on
new_thread_event, I'd like to get to know it. I think it's very bad
to rely on core GDB to do add threads. context_switch needed to be
bandaided for cases where threads are not managed by the target. We
can't distinguish a case of the target escaping a bad ptid_t due
to a bug from a valid event.
The comments around this aren't too optimistic.
static void
context_switch (ptid_t ptid)
{
/* Caution: it may happen that the new thread (or the old one!)
is not in the thread list. In this case we must not attempt
to "switch context", or we run the risk that our context may
be lost. This may happen as a result of the target module
mishandling thread creation. */
static void
record_currthread (int currthread)
{
general_thread = currthread;
/* If this is a new thread, add it to GDB's thread list.
If we leave it up to WFI to do this, bad things will happen. */
if (!in_thread_list (pid_to_ptid (currthread)))
add_thread (pid_to_ptid (currthread));
The only benefit of letting the core handle new threads, would
be to add support to stop on new thread events. But, this form
is of questinable value. I would argue for implementing that
with events/catchpoints, and/or a new target_waitstatus.
> > Since this is a new mode that will require adaptation
> > by each target, it sounded reasonable to require that the
> > the new_thread_event should never be hit, and that the
> > target handles adding threads to GDB's thread list.
>
> If documented in gdbint, I think this would be a reasonable new
> restriction.
Ok. I haven't managed to get to the docs yet, but I'll get
to it.
--
Pedro Alves
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] 07/10 non-stop inferior control
2008-05-06 17:43 [RFC] 07/10 non-stop inferior control Pedro Alves
2008-05-08 18:19 ` Eli Zaretskii
@ 2008-05-19 16:56 ` Pedro Alves
2008-06-04 11:49 ` Vladimir Prus
2 siblings, 0 replies; 9+ messages in thread
From: Pedro Alves @ 2008-05-19 16:56 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1389 bytes --]
A Tuesday 06 May 2008 16:49:23, Pedro Alves wrote:
> This patch adds the inferior control support for non-stop mode.
>
> In non-stop mode, each thread is handled individually. It should
> be like you have a separate debugger attached to each thread.
> To accomplish that, as soon as we have an event, we context switch
> to it, and go on handling it. The cases of hiting a breakpoint
> in another thread while we're stepping don't need to be handled
> specially, as the stepping thread will have its state, and the
> other thread will have its own state.
>
> Every exec command should apply only to the selected thread.
>
> A new target_stop_ptid method was added to request the target
> to interrupt a single thread.
>
> Several checks have been added so GDB doesn't try to do
> things with running threads, which don't make sense,
> like asking for the current PC of a running thread.
>
> Info threads now shows the running state of a thread. MI
> support can be added on top.
>
> (gdb) info threads
> 3 Thread 0xf7603b90 (LWP 23454) (running)
> * 2 Thread 0xf7e04b90 (LWP 23453) 0xffffe410 in __kernel_vsyscall ()
> 1 Thread 0xf7e056b0 (LWP 23450) (running)
Updated patch, mostly for convenience. The only thing that changed worth
of notice, was a check for non_stop in prepare_to_proceed
moved to its caller instead.
--
Pedro Alves
[-- Attachment #2: 007-non_stop_core.diff --]
[-- Type: text/x-diff, Size: 22180 bytes --]
2008-05-19 Pedro Alves <pedro@codesourcery.com>
* infrun.c (resume): In non-stop mode, always resume just one
thread.
(proceed): Don't call prepare_to_proceed in non-stop mode.
(fetch_inferior_event): In non-stop mode, switch context before
handling the event.
(error_is_running, ensure_not_running): New.
(handle_inferior_event): In non-stop mode: Mark only the event
thread as stopped. Require that the target module handles new
threads correctly. Don't switch to infwait_thread_hop_state.
(normal_stop): Only mark not-running if inferior hasn't exited.
In non-stop mode, only mark the event thread.
* thread.c (print_thread_info): Don't read from a running thread.
Output "(running)" if thread is running.
(switch_to_thread): Don't read stop_pc if thread is running.
(do_restore_current_thread_cleanup): Don't write to a running
thread.
(thread_apply_all_command): Don't read from a running thread. In
non-stop mode, do a full context-switch instead of just switching
threads.
(thread_apply_command): In non-stop mode, do a full context-switch
instead of just switching threads.
(do_captured_thread_select): Likewise. Inform user if selected
thread is running.
* inf-loop.c (inferior_event_handler): In non-stop mode, don't
unregister the target from the event loop.
* infcmd.c (continue_command, step_1, jump_command)
(signal_command): Ensure the selected thread isn't running.
(interrupt_target_command): In non-stop mode, either interrupt
only the selected thread, or read the thread id to interrupt from
a parameter.
* inferior.h (error_is_running, ensure_not_running): Declare.
* target.h (struct target_ops): Add to_stop_ptid member.
(target_stop_ptid): Define.
* target.c (update_current_target): Inherit to_stop_ptid. Default
to_stop_ptid to target_ignore.
(debug_to_stop_ptid): New.
(debug_to_rcmd): Set to_stop_ptid.
---
gdb/inf-loop.c | 14 ++++--
gdb/infcmd.c | 25 +++++++++++
gdb/inferior.h | 6 ++
gdb/infrun.c | 121 +++++++++++++++++++++++++++++++++++++++++++--------------
gdb/target.c | 13 ++++++
gdb/target.h | 7 +++
gdb/thread.c | 100 +++++++++++++++++++++++++++++++++--------------
7 files changed, 223 insertions(+), 63 deletions(-)
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c 2008-05-19 12:41:37.000000000 +0100
+++ src/gdb/infrun.c 2008-05-19 12:41:43.000000000 +0100
@@ -1052,9 +1052,15 @@ a command like `return' or `jump' to con
resume_ptid = inferior_ptid;
}
- if ((scheduler_mode == schedlock_on)
- || (scheduler_mode == schedlock_step
- && (step || singlestep_breakpoints_inserted_p)))
+ if (non_stop)
+ {
+ /* With non-stop mode on, threads are always handled
+ individually. */
+ resume_ptid = inferior_ptid;
+ }
+ else if ((scheduler_mode == schedlock_on)
+ || (scheduler_mode == schedlock_step
+ && (step || singlestep_breakpoints_inserted_p)))
{
/* User-settable 'scheduler' mode requires solo thread resume. */
resume_ptid = inferior_ptid;
@@ -1215,19 +1221,27 @@ proceed (CORE_ADDR addr, enum target_sig
"infrun: proceed (addr=0x%s, signal=%d, step=%d)\n",
paddr_nz (addr), siggnal, step);
- /* In a multi-threaded task we may select another thread
- and then continue or step.
+ if (non_stop)
+ /* In non-stop, each thread is handled individually. The context
+ must already be set to the right thread here. */
+ ;
+ else
+ {
+ /* In a multi-threaded task we may select another thread and
+ then continue or step.
- But if the old thread was stopped at a breakpoint, it
- will immediately cause another breakpoint stop without
- any execution (i.e. it will report a breakpoint hit
- incorrectly). So we must step over it first.
-
- prepare_to_proceed checks the current thread against the thread
- that reported the most recent event. If a step-over is required
- it returns TRUE and sets the current thread to the old thread. */
- if (prepare_to_proceed (step))
- oneproc = 1;
+ But if the old thread was stopped at a breakpoint, it will
+ immediately cause another breakpoint stop without any
+ execution (i.e. it will report a breakpoint hit incorrectly).
+ So we must step over it first.
+
+ prepare_to_proceed checks the current thread against the
+ thread that reported the most recent event. If a step-over
+ is required it returns TRUE and sets the current thread to
+ the old thread. */
+ if (prepare_to_proceed (step))
+ oneproc = 1;
+ }
if (oneproc)
{
@@ -1529,6 +1543,15 @@ fetch_inferior_event (void *client_data)
else
ecs->ptid = target_wait (waiton_ptid, &ecs->ws);
+ if (non_stop
+ && ecs->ws.kind != TARGET_WAITKIND_IGNORE
+ && ecs->ws.kind != TARGET_WAITKIND_EXITED
+ && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
+ /* In non-stop mode, each thread is handled individually. Switch
+ early, so the global state is set correctly for this
+ thread. */
+ context_switch (ecs->ptid);
+
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
@@ -1739,6 +1762,20 @@ init_infwait_state (void)
infwait_state = infwait_normal_state;
}
+void
+error_is_running (void)
+{
+ error (_("\
+Cannot execute this command while the selected thread is running."));
+}
+
+void
+ensure_not_running (void)
+{
+ if (is_running (inferior_ptid))
+ error_is_running ();
+}
+
/* Given an execution control state that has been freshly filled in
by an event from the inferior, figure out what it means and take
appropriate action. */
@@ -1810,11 +1847,15 @@ handle_inferior_event (struct execution_
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
add_thread (ecs->ptid);
- /* Mark all threads as not-executing. In non-stop, this should be
- adjusted to only mark ecs->ptid. */
if (ecs->ws.kind != TARGET_WAITKIND_IGNORE
&& stop_soon != STOP_QUIETLY)
- set_executing (pid_to_ptid (-1), 0);
+ {
+ /* Mark the stopped threads accordingly. */
+ if (!non_stop)
+ set_executing (pid_to_ptid (-1), 0);
+ else
+ set_executing (ecs->ptid, 0);
+ }
switch (ecs->ws.kind)
{
@@ -2052,15 +2093,22 @@ handle_inferior_event (struct execution_
return;
}
- /* We may want to consider not doing a resume here in order to give
- the user a chance to play with the new thread. It might be good
- to make that a user-settable option. */
-
- /* At this point, all threads are stopped (happens automatically in
- either the OS or the native code). Therefore we need to continue
- all threads in order to make progress. */
if (ecs->new_thread_event)
{
+ if (non_stop)
+ /* Non-stop assumes that the target handles adding new threads
+ to the thread list. */
+ internal_error (__FILE__, __LINE__,
+ "target misreported a new thread in non-stop mode.");
+
+ /* We may want to consider not doing a resume here in order to
+ give the user a chance to play with the new thread. It might
+ be good to make that a user-settable option. */
+
+ /* At this point, all threads are stopped (happens automatically
+ in either the OS or the native code). Therefore we need to
+ continue all threads in order to make progress. */
+
target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
@@ -2127,6 +2175,9 @@ handle_inferior_event (struct execution_
if (!ptid_equal (deferred_step_ptid, null_ptid))
{
+ /* In non-stop mode, there's never a deferred_step_ptid set. */
+ gdb_assert (!non_stop);
+
/* If we stopped for some other reason than single-stepping, ignore
the fact that we were supposed to switch back. */
if (stop_signal == TARGET_SIGNAL_TRAP)
@@ -2275,8 +2326,13 @@ handle_inferior_event (struct execution_
if (!ptid_equal (inferior_ptid, ecs->ptid))
context_switch (ecs->ptid);
- waiton_ptid = ecs->ptid;
- infwait_state = infwait_thread_hop_state;
+ if (!non_stop)
+ {
+ /* Only need to require the next event from this
+ thread in all-stop mode. */
+ waiton_ptid = ecs->ptid;
+ infwait_state = infwait_thread_hop_state;
+ }
tss->stepping_over_breakpoint = 1;
keep_going (ecs);
@@ -3830,7 +3886,16 @@ done:
/* Delete the breakpoint we stopped at, if it wants to be deleted.
Delete any breakpoint that is to be deleted at the next stop. */
breakpoint_auto_delete (stop_bpstat);
- set_running (pid_to_ptid (-1), 0);
+
+ if (target_has_execution
+ && last.kind != TARGET_WAITKIND_SIGNALLED
+ && last.kind != TARGET_WAITKIND_EXITED)
+ {
+ if (!non_stop)
+ set_running (pid_to_ptid (-1), 0);
+ else
+ set_running (inferior_ptid, 0);
+ }
}
static int
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c 2008-05-19 12:38:26.000000000 +0100
+++ src/gdb/thread.c 2008-05-19 13:32:12.000000000 +0100
@@ -597,9 +597,12 @@ print_thread_info (struct ui_out *uiout,
int current_thread = -1;
/* Backup current thread and selected frame. */
- saved_frame_id = get_frame_id (get_selected_frame (NULL));
- old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
+ if (!is_running (inferior_ptid))
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ else
+ saved_frame_id = null_frame_id;
+ old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
make_cleanup_ui_out_list_begin_end (uiout, "threads");
prune_threads ();
@@ -626,20 +629,26 @@ print_thread_info (struct ui_out *uiout,
ui_out_text (uiout, " ");
ui_out_field_string (uiout, "target-id", target_tid_to_str (tp->ptid));
- extra_info = target_extra_thread_info (tp);
- if (extra_info)
+ if (tp->running_)
+ ui_out_text (uiout, " (running)\n");
+ else
{
- ui_out_text (uiout, " (");
- ui_out_field_string (uiout, "details", extra_info);
- ui_out_text (uiout, ")");
+ extra_info = target_extra_thread_info (tp);
+ if (extra_info)
+ {
+ ui_out_text (uiout, " (");
+ ui_out_field_string (uiout, "details", extra_info);
+ ui_out_text (uiout, ")");
+ }
+ ui_out_text (uiout, " ");
+ /* The switch below puts us at the top of the stack (leaf
+ frame). */
+ switch_to_thread (tp->ptid);
+ print_stack_frame (get_selected_frame (NULL),
+ /* For MI output, print frame level. */
+ ui_out_is_mi_like_p (uiout),
+ LOCATION);
}
- ui_out_text (uiout, " ");
- /* That switch put us at the top of the stack (leaf frame). */
- switch_to_thread (tp->ptid);
- print_stack_frame (get_selected_frame (NULL),
- /* For MI output, print frame level. */
- ui_out_is_mi_like_p (uiout),
- LOCATION);
do_cleanups (chain2);
}
@@ -655,6 +664,9 @@ print_thread_info (struct ui_out *uiout,
ui_out_field_int (uiout, "current-thread-id", current_thread);
}
+ if (is_running (inferior_ptid))
+ return;
+
/* If case we were not able to find the original frame, print the
new selected frame. */
if (frame_find_by_id (saved_frame_id) == NULL)
@@ -693,7 +705,11 @@ switch_to_thread (ptid_t ptid)
inferior_ptid = ptid;
reinit_frame_cache ();
registers_changed ();
- stop_pc = read_pc ();
+
+ if (!is_executing (ptid))
+ stop_pc = read_pc ();
+ else
+ stop_pc = ~(CORE_ADDR) 0;
}
static void
@@ -723,6 +739,7 @@ struct current_thread_cleanup
{
ptid_t inferior_ptid;
struct frame_id selected_frame_id;
+ int was_running;
};
static void
@@ -730,7 +747,12 @@ do_restore_current_thread_cleanup (void
{
struct current_thread_cleanup *old = arg;
restore_current_thread (old->inferior_ptid);
- restore_selected_frame (old->selected_frame_id);
+
+ /* A command like 'thread apply all $exec_command&' may change the
+ running state of the originally selected thread, so we have to
+ recheck it here. */
+ if (!old->was_running && !is_running (old->inferior_ptid))
+ restore_selected_frame (old->selected_frame_id);
xfree (old);
}
@@ -742,6 +764,7 @@ make_cleanup_restore_current_thread (pti
= xmalloc (sizeof (struct current_thread_cleanup));
old->inferior_ptid = inferior_ptid;
old->selected_frame_id = a_frame_id;
+ old->was_running = is_running (inferior_ptid);
return make_cleanup (do_restore_current_thread_cleanup, old);
}
@@ -758,8 +781,7 @@ static void
thread_apply_all_command (char *cmd, int from_tty)
{
struct thread_info *tp;
- struct cleanup *old_chain;
- struct cleanup *saved_cmd_cleanup_chain;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
char *saved_cmd;
struct frame_id saved_frame_id;
ptid_t current_ptid;
@@ -769,8 +791,12 @@ thread_apply_all_command (char *cmd, int
error (_("Please specify a command following the thread ID list"));
current_ptid = inferior_ptid;
- saved_frame_id = get_frame_id (get_selected_frame (NULL));
- old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
+
+ if (!is_running (inferior_ptid))
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ else
+ saved_frame_id = null_frame_id;
+ make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
/* It is safe to update the thread list now, before
traversing it for "thread apply all". MVS */
@@ -779,11 +805,15 @@ thread_apply_all_command (char *cmd, int
/* Save a copy of the command in case it is clobbered by
execute_command */
saved_cmd = xstrdup (cmd);
- saved_cmd_cleanup_chain = make_cleanup (xfree, (void *) saved_cmd);
+ make_cleanup (xfree, saved_cmd);
for (tp = thread_list; tp; tp = tp->next)
if (thread_alive (tp))
{
- switch_to_thread (tp->ptid);
+ if (non_stop)
+ context_switch_to (tp->ptid);
+ else
+ switch_to_thread (tp->ptid);
+
printf_filtered (_("\nThread %d (%s):\n"),
tp->num, target_tid_to_str (inferior_ptid));
execute_command (cmd, from_tty);
@@ -793,12 +823,10 @@ thread_apply_all_command (char *cmd, int
if (!ptid_equal (current_ptid, inferior_ptid))
thread_has_changed = 1;
- do_cleanups (saved_cmd_cleanup_chain);
do_cleanups (old_chain);
/* Print stack frame only if we changed thread. */
- if (thread_has_changed)
+ if (thread_has_changed && !is_running (inferior_ptid))
print_stack_frame (get_current_frame (), 1, SRC_LINE);
-
}
static void
@@ -822,7 +850,11 @@ thread_apply_command (char *tidlist, int
error (_("Please specify a command following the thread ID list"));
current_ptid = inferior_ptid;
- saved_frame_id = get_frame_id (get_selected_frame (NULL));
+
+ if (!is_running (inferior_ptid))
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ else
+ saved_frame_id = null_frame_id;
old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
/* Save a copy of the command in case it is clobbered by
@@ -866,7 +898,10 @@ thread_apply_command (char *tidlist, int
warning (_("Thread %d has terminated."), start);
else
{
- switch_to_thread (tp->ptid);
+ if (non_stop)
+ context_switch_to (tp->ptid);
+ else
+ switch_to_thread (tp->ptid);
printf_filtered (_("\nThread %d (%s):\n"), tp->num,
target_tid_to_str (inferior_ptid));
execute_command (cmd, from_tty);
@@ -933,7 +968,10 @@ do_captured_thread_select (struct ui_out
if (!thread_alive (tp))
error (_("Thread ID %d has terminated."), num);
- switch_to_thread (tp->ptid);
+ if (non_stop)
+ context_switch_to (tp->ptid);
+ else
+ switch_to_thread (tp->ptid);
ui_out_text (uiout, "[Switching to thread ");
ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid));
@@ -941,7 +979,11 @@ do_captured_thread_select (struct ui_out
ui_out_text (uiout, target_tid_to_str (inferior_ptid));
ui_out_text (uiout, ")]");
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ if (!tp->running_)
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ else
+ ui_out_text (uiout, " (running)\n");
+
return GDB_RC_OK;
}
Index: src/gdb/inf-loop.c
===================================================================
--- src.orig/gdb/inf-loop.c 2008-05-19 12:38:09.000000000 +0100
+++ src/gdb/inf-loop.c 2008-05-19 12:41:43.000000000 +0100
@@ -73,11 +73,15 @@ inferior_event_handler (enum inferior_ev
break;
case INF_EXEC_COMPLETE:
- /* Unregister the inferior from the event loop. This is done so that
- when the inferior is not running we don't get distracted by
- spurious inferior output. */
- if (target_has_execution)
- target_async (NULL, 0);
+
+ if (!non_stop)
+ {
+ /* Unregister the inferior from the event loop. This is done
+ so that when the inferior is not running we don't get
+ distracted by spurious inferior output. */
+ if (target_has_execution)
+ target_async (NULL, 0);
+ }
/* The call to async_enable_stdin below resets 'sync_execution'.
However, if sync_execution is 1 now, we also need to show the
Index: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c 2008-05-19 12:38:08.000000000 +0100
+++ src/gdb/infcmd.c 2008-05-19 13:32:11.000000000 +0100
@@ -612,6 +612,7 @@ continue_command (char *proc_count_exp,
{
int async_exec = 0;
ERROR_NO_INFERIOR;
+ ensure_not_running ();
/* Find out whether we must run in the background. */
if (proc_count_exp != NULL)
@@ -713,6 +714,7 @@ step_1 (int skip_subroutines, int single
int thread = -1;
ERROR_NO_INFERIOR;
+ ensure_not_running ();
if (count_string)
async_exec = strip_bg_char (&count_string);
@@ -935,6 +937,7 @@ jump_command (char *arg, int from_tty)
int async_exec = 0;
ERROR_NO_INFERIOR;
+ ensure_not_running ();
/* Find out whether we must run in the background. */
if (arg != NULL)
@@ -1035,6 +1038,7 @@ signal_command (char *signum_exp, int fr
dont_repeat (); /* Too dangerous. */
ERROR_NO_INFERIOR;
+ ensure_not_running ();
/* Find out whether we must run in the background. */
if (signum_exp != NULL)
@@ -2103,7 +2107,26 @@ interrupt_target_command (char *args, in
if (target_can_async_p ())
{
dont_repeat (); /* Not for the faint of heart */
- target_stop ();
+
+ if (non_stop)
+ {
+ ptid_t ptid;
+ if (args && *args)
+ {
+ int num = value_as_long (parse_and_eval (args));
+
+ if (!valid_thread_id (num))
+ error (_("Thread ID %d not known."), num);
+
+ ptid = thread_id_to_pid (num);
+ }
+ else
+ ptid = inferior_ptid;
+
+ target_stop_ptid (ptid);
+ }
+ else
+ target_stop ();
}
}
Index: src/gdb/inferior.h
===================================================================
--- src.orig/gdb/inferior.h 2008-05-19 12:41:35.000000000 +0100
+++ src/gdb/inferior.h 2008-05-19 12:41:43.000000000 +0100
@@ -245,6 +245,12 @@ extern void get_last_target_status(ptid_
extern void follow_inferior_reset_breakpoints (void);
+/* Throw an error indicating the current thread is running. */
+extern void error_is_running (void);
+
+/* Calls error_is_running if the current thread is running. */
+extern void ensure_not_running (void);
+
/* From infcmd.c */
extern void tty_command (char *, int);
Index: src/gdb/target.h
===================================================================
--- src.orig/gdb/target.h 2008-05-19 12:38:19.000000000 +0100
+++ src/gdb/target.h 2008-05-19 13:31:41.000000000 +0100
@@ -397,6 +397,7 @@ struct target_ops
char *(*to_pid_to_str) (ptid_t);
char *(*to_extra_thread_info) (struct thread_info *);
void (*to_stop) (void);
+ void (*to_stop_ptid) (ptid_t ptid);
void (*to_rcmd) (char *command, struct ui_file *output);
char *(*to_pid_to_exec_file) (int pid);
void (*to_log_command) (const char *);
@@ -895,6 +896,12 @@ int target_follow_fork (int follow_child
#define target_stop current_target.to_stop
+/* Same as target_stop, but apply to PTID. Used in non-stop mode to
+ stop a single thread without affecting the running state of the
+ others. */
+#define target_stop_ptid(ptid) \
+ (*current_target.to_stop_ptid) (ptid)
+
/* Send the specified COMMAND to the target's monitor
(shell,interpreter) for execution. The result of the query is
placed in OUTBUF. */
Index: src/gdb/target.c
===================================================================
--- src.orig/gdb/target.c 2008-05-19 12:38:09.000000000 +0100
+++ src/gdb/target.c 2008-05-19 12:41:43.000000000 +0100
@@ -456,6 +456,7 @@ update_current_target (void)
INHERIT (to_pid_to_str, t);
INHERIT (to_extra_thread_info, t);
INHERIT (to_stop, t);
+ INHERIT (to_stop_ptid, t);
/* Do not inherit to_xfer_partial. */
INHERIT (to_rcmd, t);
INHERIT (to_pid_to_exec_file, t);
@@ -632,6 +633,9 @@ update_current_target (void)
de_fault (to_stop,
(void (*) (void))
target_ignore);
+ de_fault (to_stop_ptid,
+ (void (*) (ptid_t))
+ target_ignore);
current_target.to_xfer_partial = current_xfer_partial;
de_fault (to_rcmd,
(void (*) (char *, struct ui_file *))
@@ -2939,6 +2943,14 @@ debug_to_stop (void)
}
static void
+debug_to_stop_ptid (ptid_t ptid)
+{
+ debug_target.to_stop_ptid (ptid);
+
+ fprintf_unfiltered (gdb_stdlog, "target_stop_pid\n");
+}
+
+static void
debug_to_rcmd (char *command,
struct ui_file *outbuf)
{
@@ -3012,6 +3024,7 @@ setup_target_debug (void)
current_target.to_thread_alive = debug_to_thread_alive;
current_target.to_find_new_threads = debug_to_find_new_threads;
current_target.to_stop = debug_to_stop;
+ current_target.to_stop_ptid = debug_to_stop_ptid;
current_target.to_rcmd = debug_to_rcmd;
current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
}
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] 07/10 non-stop inferior control
2008-05-06 17:43 [RFC] 07/10 non-stop inferior control Pedro Alves
2008-05-08 18:19 ` Eli Zaretskii
2008-05-19 16:56 ` Pedro Alves
@ 2008-06-04 11:49 ` Vladimir Prus
2008-06-04 12:07 ` Pedro Alves
2 siblings, 1 reply; 9+ messages in thread
From: Vladimir Prus @ 2008-06-04 11:49 UTC (permalink / raw)
To: gdb-patches
Pedro Alves wrote:
> This patch adds the inferior control support for non-stop mode.
>
> In non-stop mode, each thread is handled individually. It should
> be like you have a separate debugger attached to each thread.
> To accomplish that, as soon as we have an event, we context switch
> to it, and go on handling it. The cases of hiting a breakpoint
> in another thread while we're stepping don't need to be handled
> specially, as the stepping thread will have its state, and the
> other thread will have its own state.
>
> Every exec command should apply only to the selected thread.
>
> A new target_stop_ptid method was added to request the target
> to interrupt a single thread.
>
> Several checks have been added so GDB doesn't try to do
> things with running threads, which don't make sense,
> like asking for the current PC of a running thread.
>
> Info threads now shows the running state of a thread. MI
> support can be added on top.
>
> (gdb) info threads
> 3 Thread 0xf7603b90 (LWP 23454) Â (running)
> * 2 Thread 0xf7e04b90 (LWP 23453) Â 0xffffe410 in __kernel_vsyscall ()
> 1 Thread 0xf7e056b0 (LWP 23450) Â (running)
Am I missing something, or there's no way to interrupt all threads?
Given that we have "continue -a"/"-exec-continue --all", I think a way
to interrupt all threads will be desirable. In fact, I'd claim that if
MI frontend has to issue several -exec-interrupt commands to stop the
program completely, it's a regression in functionality. Of course, I
can make MI do anything, but I need backend support for that :-)
Also, it seems inconsistent to me that "continue" has the -a option,
to resume all threads, while "interrupt" accepts an thread id. I'd
suggest that "interrupt" be modified to accept -a, and not accept
thread number. Or, alternatively, both continue and interrupt accept
both -a and thread number.
- Volodya
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] 07/10 non-stop inferior control
2008-06-04 11:49 ` Vladimir Prus
@ 2008-06-04 12:07 ` Pedro Alves
2008-06-04 12:18 ` Vladimir Prus
0 siblings, 1 reply; 9+ messages in thread
From: Pedro Alves @ 2008-06-04 12:07 UTC (permalink / raw)
To: gdb-patches; +Cc: Vladimir Prus
A Wednesday 04 June 2008 12:49:06, Vladimir Prus wrote:
> Pedro Alves wrote:
> Am I missing something, or there's no way to interrupt all threads?
> Given that we have "continue -a"/"-exec-continue --all", I think a way
> to interrupt all threads will be desirable. In fact, I'd claim that if
> MI frontend has to issue several -exec-interrupt commands to stop the
> program completely, it's a regression in functionality. Of course, I
> can make MI do anything, but I need backend support for that :-)
>
Yes, you're right. I had split the c -a into the other patch, because
I wanted to leave other interface extensions to be done incrementally,
and discurred `interrupt'.
> Also, it seems inconsistent to me that "continue" has the -a option,
> to resume all threads, while "interrupt" accepts an thread id. I'd
> suggest that "interrupt" be modified to accept -a, and not accept
> thread number.
I'll just do this, OK?
--
Pedro Alves
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC] 07/10 non-stop inferior control
2008-06-04 12:07 ` Pedro Alves
@ 2008-06-04 12:18 ` Vladimir Prus
0 siblings, 0 replies; 9+ messages in thread
From: Vladimir Prus @ 2008-06-04 12:18 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
On Wednesday 04 June 2008 16:06:55 Pedro Alves wrote:
> A Wednesday 04 June 2008 12:49:06, Vladimir Prus wrote:
> > Pedro Alves wrote:
>
> > Am I missing something, or there's no way to interrupt all threads?
> > Given that we have "continue -a"/"-exec-continue --all", I think a way
> > to interrupt all threads will be desirable. In fact, I'd claim that if
> > MI frontend has to issue several -exec-interrupt commands to stop the
> > program completely, it's a regression in functionality. Of course, I
> > can make MI do anything, but I need backend support for that :-)
> >
>
> Yes, you're right. I had split the c -a into the other patch, because
> I wanted to leave other interface extensions to be done incrementally,
> and discurred `interrupt'.
>
> > Also, it seems inconsistent to me that "continue" has the -a option,
> > to resume all threads, while "interrupt" accepts an thread id. I'd
> > suggest that "interrupt" be modified to accept -a, and not accept
> > thread number.
>
> I'll just do this, OK?
OK, sounds good.
Thanks,
Volodya
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-06-04 12:18 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-05-06 17:43 [RFC] 07/10 non-stop inferior control Pedro Alves
2008-05-08 18:19 ` Eli Zaretskii
2008-05-09 2:08 ` Pedro Alves
2008-05-09 2:52 ` Daniel Jacobowitz
2008-05-19 16:55 ` Pedro Alves
2008-05-19 16:56 ` Pedro Alves
2008-06-04 11:49 ` Vladimir Prus
2008-06-04 12:07 ` Pedro Alves
2008-06-04 12:18 ` Vladimir Prus
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox