Non-stop inferior control.
* 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 manages adding threads to the thread list. Assert that there isn't a deferred_step_ptid set. 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:Include "cli/cli-decode.h". (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 executing. (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. (_initialize_thread): Mark "info threads" and "thread" and async_ok. * 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, interrupt only the selected thread. * inferior.h (error_is_running, ensure_not_running): Declare. * target.h (struct target_ops): Add ptid argument to the to_stop member. (target_stop): Add ptid_t argument. * target.c (update_current_target): Add ptid argument to to_stop's type. (debug_to_stop): Add ptid_t argument. (debug_to_rcmd): Set to_stop_ptid. * remote.c (remote_stop): Add ptid_t argument. (async_remote_interrupt): Add inferior_ptid to target_stop. * inf-ptrace.c (inf_ptrace_stop): Add ptid argument. * Makefile.in (thread.o): Depend on $(cli_decode_h).
This commit is contained in:
parent
59f0d5d953
commit
94cc34afe2
11 changed files with 258 additions and 72 deletions
|
@ -1,3 +1,61 @@
|
||||||
|
2008-07-09 Pedro Alves <pedro@codesourcery.com>
|
||||||
|
|
||||||
|
Non-stop inferior control.
|
||||||
|
|
||||||
|
* 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 manages adding
|
||||||
|
threads to the thread list. Assert that there isn't a
|
||||||
|
deferred_step_ptid set. 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:Include "cli/cli-decode.h".
|
||||||
|
(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 executing.
|
||||||
|
(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.
|
||||||
|
(_initialize_thread): Mark "info threads" and "thread" and
|
||||||
|
async_ok.
|
||||||
|
|
||||||
|
* 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, interrupt only the
|
||||||
|
selected thread.
|
||||||
|
|
||||||
|
* inferior.h (error_is_running, ensure_not_running): Declare.
|
||||||
|
|
||||||
|
* target.h (struct target_ops): Add ptid argument to the to_stop
|
||||||
|
member.
|
||||||
|
(target_stop): Add ptid_t argument.
|
||||||
|
|
||||||
|
* target.c (update_current_target): Add ptid argument to to_stop's
|
||||||
|
type.
|
||||||
|
(debug_to_stop): Add ptid_t argument.
|
||||||
|
(debug_to_rcmd): Set to_stop_ptid.
|
||||||
|
|
||||||
|
* remote.c (remote_stop): Add ptid_t argument.
|
||||||
|
(async_remote_interrupt): Add inferior_ptid to target_stop.
|
||||||
|
* inf-ptrace.c (inf_ptrace_stop): Add ptid argument.
|
||||||
|
|
||||||
|
* Makefile.in (thread.o): Depend on $(cli_decode_h).
|
||||||
|
|
||||||
2008-07-09 Pedro Alves <pedro@codesourcery.com>
|
2008-07-09 Pedro Alves <pedro@codesourcery.com>
|
||||||
|
|
||||||
Don't rely on ecs->wait_for_more.
|
Don't rely on ecs->wait_for_more.
|
||||||
|
|
|
@ -2921,7 +2921,7 @@ target-memory.o: target-memory.c $(defs_h) $(vec_h) $(target_h) \
|
||||||
thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \
|
thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \
|
||||||
$(environ_h) $(value_h) $(target_h) $(gdbthread_h) $(exceptions_h) \
|
$(environ_h) $(value_h) $(target_h) $(gdbthread_h) $(exceptions_h) \
|
||||||
$(command_h) $(gdbcmd_h) $(regcache_h) $(gdb_h) $(gdb_string_h) \
|
$(command_h) $(gdbcmd_h) $(regcache_h) $(gdb_h) $(gdb_string_h) \
|
||||||
$(ui_out_h) $(observer_h) $(annotate_h)
|
$(ui_out_h) $(observer_h) $(annotate_h) $(cli_decode_h)
|
||||||
top.o: top.c $(defs_h) $(gdbcmd_h) $(call_cmds_h) $(cli_cmds_h) \
|
top.o: top.c $(defs_h) $(gdbcmd_h) $(call_cmds_h) $(cli_cmds_h) \
|
||||||
$(cli_script_h) $(cli_setshow_h) $(cli_decode_h) $(symtab_h) \
|
$(cli_script_h) $(cli_setshow_h) $(cli_decode_h) $(symtab_h) \
|
||||||
$(inferior_h) $(exceptions_h) $(target_h) $(breakpoint_h) \
|
$(inferior_h) $(exceptions_h) $(target_h) $(breakpoint_h) \
|
||||||
|
|
|
@ -73,11 +73,15 @@ inferior_event_handler (enum inferior_event_type event_type,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INF_EXEC_COMPLETE:
|
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
|
if (!non_stop)
|
||||||
spurious inferior output. */
|
{
|
||||||
|
/* 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)
|
if (target_has_execution)
|
||||||
target_async (NULL, 0);
|
target_async (NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* The call to async_enable_stdin below resets 'sync_execution'.
|
/* The call to async_enable_stdin below resets 'sync_execution'.
|
||||||
However, if sync_execution is 1 now, we also need to show the
|
However, if sync_execution is 1 now, we also need to show the
|
||||||
|
|
|
@ -297,7 +297,7 @@ inf_ptrace_kill (void)
|
||||||
/* Stop the inferior. */
|
/* Stop the inferior. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
inf_ptrace_stop (void)
|
inf_ptrace_stop (ptid_t ptid)
|
||||||
{
|
{
|
||||||
/* Send a SIGINT to the process group. This acts just like the user
|
/* Send a SIGINT to the process group. This acts just like the user
|
||||||
typed a ^C on the controlling terminal. Note that using a
|
typed a ^C on the controlling terminal. Note that using a
|
||||||
|
|
|
@ -613,6 +613,7 @@ continue_command (char *proc_count_exp, int from_tty)
|
||||||
{
|
{
|
||||||
int async_exec = 0;
|
int async_exec = 0;
|
||||||
ERROR_NO_INFERIOR;
|
ERROR_NO_INFERIOR;
|
||||||
|
ensure_not_running ();
|
||||||
|
|
||||||
/* Find out whether we must run in the background. */
|
/* Find out whether we must run in the background. */
|
||||||
if (proc_count_exp != NULL)
|
if (proc_count_exp != NULL)
|
||||||
|
@ -714,6 +715,7 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
|
||||||
int thread = -1;
|
int thread = -1;
|
||||||
|
|
||||||
ERROR_NO_INFERIOR;
|
ERROR_NO_INFERIOR;
|
||||||
|
ensure_not_running ();
|
||||||
|
|
||||||
if (count_string)
|
if (count_string)
|
||||||
async_exec = strip_bg_char (&count_string);
|
async_exec = strip_bg_char (&count_string);
|
||||||
|
@ -936,6 +938,7 @@ jump_command (char *arg, int from_tty)
|
||||||
int async_exec = 0;
|
int async_exec = 0;
|
||||||
|
|
||||||
ERROR_NO_INFERIOR;
|
ERROR_NO_INFERIOR;
|
||||||
|
ensure_not_running ();
|
||||||
|
|
||||||
/* Find out whether we must run in the background. */
|
/* Find out whether we must run in the background. */
|
||||||
if (arg != NULL)
|
if (arg != NULL)
|
||||||
|
@ -1036,6 +1039,7 @@ signal_command (char *signum_exp, int from_tty)
|
||||||
|
|
||||||
dont_repeat (); /* Too dangerous. */
|
dont_repeat (); /* Too dangerous. */
|
||||||
ERROR_NO_INFERIOR;
|
ERROR_NO_INFERIOR;
|
||||||
|
ensure_not_running ();
|
||||||
|
|
||||||
/* Find out whether we must run in the background. */
|
/* Find out whether we must run in the background. */
|
||||||
if (signum_exp != NULL)
|
if (signum_exp != NULL)
|
||||||
|
@ -2102,7 +2106,8 @@ interrupt_target_command (char *args, int from_tty)
|
||||||
if (target_can_async_p ())
|
if (target_can_async_p ())
|
||||||
{
|
{
|
||||||
dont_repeat (); /* Not for the faint of heart */
|
dont_repeat (); /* Not for the faint of heart */
|
||||||
target_stop ();
|
|
||||||
|
target_stop (inferior_ptid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,6 +245,12 @@ extern void get_last_target_status(ptid_t *ptid,
|
||||||
|
|
||||||
extern void follow_inferior_reset_breakpoints (void);
|
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 */
|
/* From infcmd.c */
|
||||||
|
|
||||||
extern void tty_command (char *, int);
|
extern void tty_command (char *, int);
|
||||||
|
|
105
gdb/infrun.c
105
gdb/infrun.c
|
@ -1056,7 +1056,13 @@ a command like `return' or `jump' to continue execution."));
|
||||||
resume_ptid = inferior_ptid;
|
resume_ptid = inferior_ptid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((scheduler_mode == schedlock_on)
|
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
|
|| (scheduler_mode == schedlock_step
|
||||||
&& (step || singlestep_breakpoints_inserted_p)))
|
&& (step || singlestep_breakpoints_inserted_p)))
|
||||||
{
|
{
|
||||||
|
@ -1219,19 +1225,27 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
|
||||||
"infrun: proceed (addr=0x%s, signal=%d, step=%d)\n",
|
"infrun: proceed (addr=0x%s, signal=%d, step=%d)\n",
|
||||||
paddr_nz (addr), siggnal, step);
|
paddr_nz (addr), siggnal, step);
|
||||||
|
|
||||||
/* In a multi-threaded task we may select another thread
|
if (non_stop)
|
||||||
and then continue or step.
|
/* 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
|
But if the old thread was stopped at a breakpoint, it will
|
||||||
will immediately cause another breakpoint stop without
|
immediately cause another breakpoint stop without any
|
||||||
any execution (i.e. it will report a breakpoint hit
|
execution (i.e. it will report a breakpoint hit incorrectly).
|
||||||
incorrectly). So we must step over it first.
|
So we must step over it first.
|
||||||
|
|
||||||
prepare_to_proceed checks the current thread against the thread
|
prepare_to_proceed checks the current thread against the
|
||||||
that reported the most recent event. If a step-over is required
|
thread that reported the most recent event. If a step-over
|
||||||
it returns TRUE and sets the current thread to the old thread. */
|
is required it returns TRUE and sets the current thread to
|
||||||
|
the old thread. */
|
||||||
if (prepare_to_proceed (step))
|
if (prepare_to_proceed (step))
|
||||||
oneproc = 1;
|
oneproc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (oneproc)
|
if (oneproc)
|
||||||
{
|
{
|
||||||
|
@ -1535,6 +1549,15 @@ fetch_inferior_event (void *client_data)
|
||||||
else
|
else
|
||||||
ecs->ptid = target_wait (waiton_ptid, &ecs->ws);
|
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. */
|
/* Now figure out what to do with the result of the result. */
|
||||||
handle_inferior_event (ecs);
|
handle_inferior_event (ecs);
|
||||||
|
|
||||||
|
@ -1745,6 +1768,20 @@ init_infwait_state (void)
|
||||||
infwait_state = infwait_normal_state;
|
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
|
/* Given an execution control state that has been freshly filled in
|
||||||
by an event from the inferior, figure out what it means and take
|
by an event from the inferior, figure out what it means and take
|
||||||
appropriate action. */
|
appropriate action. */
|
||||||
|
@ -1818,10 +1855,16 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||||
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
|
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
|
||||||
add_thread (ecs->ptid);
|
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)
|
if (ecs->ws.kind != TARGET_WAITKIND_IGNORE)
|
||||||
|
{
|
||||||
|
/* Mark the non-executing threads accordingly. */
|
||||||
|
if (!non_stop
|
||||||
|
|| ecs->ws.kind == TARGET_WAITKIND_EXITED
|
||||||
|
|| ecs->ws.kind == TARGET_WAITKIND_SIGNALLED)
|
||||||
set_executing (pid_to_ptid (-1), 0);
|
set_executing (pid_to_ptid (-1), 0);
|
||||||
|
else
|
||||||
|
set_executing (ecs->ptid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
switch (ecs->ws.kind)
|
switch (ecs->ws.kind)
|
||||||
{
|
{
|
||||||
|
@ -2059,15 +2102,22 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||||
return;
|
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 (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__, "\
|
||||||
|
targets should add new threads to the thread list themselves 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);
|
target_resume (RESUME_ALL, 0, TARGET_SIGNAL_0);
|
||||||
prepare_to_wait (ecs);
|
prepare_to_wait (ecs);
|
||||||
return;
|
return;
|
||||||
|
@ -2134,6 +2184,9 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||||
|
|
||||||
if (!ptid_equal (deferred_step_ptid, null_ptid))
|
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
|
/* If we stopped for some other reason than single-stepping, ignore
|
||||||
the fact that we were supposed to switch back. */
|
the fact that we were supposed to switch back. */
|
||||||
if (stop_signal == TARGET_SIGNAL_TRAP)
|
if (stop_signal == TARGET_SIGNAL_TRAP)
|
||||||
|
@ -2282,8 +2335,13 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||||
if (!ptid_equal (inferior_ptid, ecs->ptid))
|
if (!ptid_equal (inferior_ptid, ecs->ptid))
|
||||||
context_switch (ecs->ptid);
|
context_switch (ecs->ptid);
|
||||||
|
|
||||||
|
if (!non_stop)
|
||||||
|
{
|
||||||
|
/* Only need to require the next event from this
|
||||||
|
thread in all-stop mode. */
|
||||||
waiton_ptid = ecs->ptid;
|
waiton_ptid = ecs->ptid;
|
||||||
infwait_state = infwait_thread_hop_state;
|
infwait_state = infwait_thread_hop_state;
|
||||||
|
}
|
||||||
|
|
||||||
tss->stepping_over_breakpoint = 1;
|
tss->stepping_over_breakpoint = 1;
|
||||||
keep_going (ecs);
|
keep_going (ecs);
|
||||||
|
@ -3838,7 +3896,16 @@ done:
|
||||||
/* Delete the breakpoint we stopped at, if it wants to be deleted.
|
/* Delete the breakpoint we stopped at, if it wants to be deleted.
|
||||||
Delete any breakpoint that is to be deleted at the next stop. */
|
Delete any breakpoint that is to be deleted at the next stop. */
|
||||||
breakpoint_auto_delete (stop_bpstat);
|
breakpoint_auto_delete (stop_bpstat);
|
||||||
|
|
||||||
|
if (target_has_execution
|
||||||
|
&& last.kind != TARGET_WAITKIND_SIGNALLED
|
||||||
|
&& last.kind != TARGET_WAITKIND_EXITED)
|
||||||
|
{
|
||||||
|
if (!non_stop)
|
||||||
set_running (pid_to_ptid (-1), 0);
|
set_running (pid_to_ptid (-1), 0);
|
||||||
|
else
|
||||||
|
set_running (inferior_ptid, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -155,7 +155,7 @@ static void init_remote_ops (void);
|
||||||
|
|
||||||
static void init_extended_remote_ops (void);
|
static void init_extended_remote_ops (void);
|
||||||
|
|
||||||
static void remote_stop (void);
|
static void remote_stop (ptid_t);
|
||||||
|
|
||||||
static int ishex (int ch, int *val);
|
static int ishex (int ch, int *val);
|
||||||
|
|
||||||
|
@ -3269,7 +3269,7 @@ async_remote_interrupt (gdb_client_data arg)
|
||||||
if (remote_debug)
|
if (remote_debug)
|
||||||
fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
|
fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
|
||||||
|
|
||||||
target_stop ();
|
target_stop (inferior_ptid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform interrupt, if the first attempt did not succeed. Just give
|
/* Perform interrupt, if the first attempt did not succeed. Just give
|
||||||
|
@ -3323,7 +3323,7 @@ remote_interrupt_twice (int signo)
|
||||||
interrupt is requested, either by the command line or the GUI, we
|
interrupt is requested, either by the command line or the GUI, we
|
||||||
will eventually end up here. */
|
will eventually end up here. */
|
||||||
static void
|
static void
|
||||||
remote_stop (void)
|
remote_stop (ptid_t ptid)
|
||||||
{
|
{
|
||||||
/* Send a break or a ^C, depending on user preference. */
|
/* Send a break or a ^C, depending on user preference. */
|
||||||
if (remote_debug)
|
if (remote_debug)
|
||||||
|
|
11
gdb/target.c
11
gdb/target.c
|
@ -165,7 +165,7 @@ static void debug_to_notice_signals (ptid_t);
|
||||||
|
|
||||||
static int debug_to_thread_alive (ptid_t);
|
static int debug_to_thread_alive (ptid_t);
|
||||||
|
|
||||||
static void debug_to_stop (void);
|
static void debug_to_stop (ptid_t);
|
||||||
|
|
||||||
/* NOTE: cagney/2004-09-29: Many targets reference this variable in
|
/* NOTE: cagney/2004-09-29: Many targets reference this variable in
|
||||||
wierd and mysterious ways. Putting the variable here lets those
|
wierd and mysterious ways. Putting the variable here lets those
|
||||||
|
@ -630,7 +630,7 @@ update_current_target (void)
|
||||||
(char *(*) (struct thread_info *))
|
(char *(*) (struct thread_info *))
|
||||||
return_zero);
|
return_zero);
|
||||||
de_fault (to_stop,
|
de_fault (to_stop,
|
||||||
(void (*) (void))
|
(void (*) (ptid_t))
|
||||||
target_ignore);
|
target_ignore);
|
||||||
current_target.to_xfer_partial = current_xfer_partial;
|
current_target.to_xfer_partial = current_xfer_partial;
|
||||||
de_fault (to_rcmd,
|
de_fault (to_rcmd,
|
||||||
|
@ -2997,11 +2997,12 @@ debug_to_find_new_threads (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
debug_to_stop (void)
|
debug_to_stop (ptid_t ptid)
|
||||||
{
|
{
|
||||||
debug_target.to_stop ();
|
debug_target.to_stop (ptid);
|
||||||
|
|
||||||
fprintf_unfiltered (gdb_stdlog, "target_stop ()\n");
|
fprintf_unfiltered (gdb_stdlog, "target_stop (%s)\n",
|
||||||
|
target_pid_to_str (ptid));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -401,7 +401,7 @@ struct target_ops
|
||||||
void (*to_find_new_threads) (void);
|
void (*to_find_new_threads) (void);
|
||||||
char *(*to_pid_to_str) (ptid_t);
|
char *(*to_pid_to_str) (ptid_t);
|
||||||
char *(*to_extra_thread_info) (struct thread_info *);
|
char *(*to_extra_thread_info) (struct thread_info *);
|
||||||
void (*to_stop) (void);
|
void (*to_stop) (ptid_t);
|
||||||
void (*to_rcmd) (char *command, struct ui_file *output);
|
void (*to_rcmd) (char *command, struct ui_file *output);
|
||||||
char *(*to_pid_to_exec_file) (int pid);
|
char *(*to_pid_to_exec_file) (int pid);
|
||||||
void (*to_log_command) (const char *);
|
void (*to_log_command) (const char *);
|
||||||
|
@ -906,7 +906,7 @@ int target_follow_fork (int follow_child);
|
||||||
Unix, this should act like SIGSTOP). This function is normally
|
Unix, this should act like SIGSTOP). This function is normally
|
||||||
used by GUIs to implement a stop button. */
|
used by GUIs to implement a stop button. */
|
||||||
|
|
||||||
#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
|
/* Send the specified COMMAND to the target's monitor
|
||||||
(shell,interpreter) for execution. The result of the query is
|
(shell,interpreter) for execution. The result of the query is
|
||||||
|
|
67
gdb/thread.c
67
gdb/thread.c
|
@ -42,6 +42,8 @@
|
||||||
#include "observer.h"
|
#include "observer.h"
|
||||||
#include "annotate.h"
|
#include "annotate.h"
|
||||||
|
|
||||||
|
#include "cli/cli-decode.h"
|
||||||
|
|
||||||
/* Definition of struct thread_info exported to gdbthread.h */
|
/* Definition of struct thread_info exported to gdbthread.h */
|
||||||
|
|
||||||
/* Prototypes for exported functions. */
|
/* Prototypes for exported functions. */
|
||||||
|
@ -640,9 +642,12 @@ print_thread_info (struct ui_out *uiout, int requested_thread)
|
||||||
int current_thread = -1;
|
int current_thread = -1;
|
||||||
|
|
||||||
/* Backup current thread and selected frame. */
|
/* Backup current thread and selected frame. */
|
||||||
|
if (!is_running (inferior_ptid))
|
||||||
saved_frame_id = get_frame_id (get_selected_frame (NULL));
|
saved_frame_id = get_frame_id (get_selected_frame (NULL));
|
||||||
old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
|
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");
|
make_cleanup_ui_out_list_begin_end (uiout, "threads");
|
||||||
|
|
||||||
prune_threads ();
|
prune_threads ();
|
||||||
|
@ -677,12 +682,18 @@ print_thread_info (struct ui_out *uiout, int requested_thread)
|
||||||
ui_out_text (uiout, ")");
|
ui_out_text (uiout, ")");
|
||||||
}
|
}
|
||||||
ui_out_text (uiout, " ");
|
ui_out_text (uiout, " ");
|
||||||
/* That switch put us at the top of the stack (leaf frame). */
|
if (tp->running_)
|
||||||
|
ui_out_text (uiout, "(running)\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The switch below puts us at the top of the stack (leaf
|
||||||
|
frame). */
|
||||||
switch_to_thread (tp->ptid);
|
switch_to_thread (tp->ptid);
|
||||||
print_stack_frame (get_selected_frame (NULL),
|
print_stack_frame (get_selected_frame (NULL),
|
||||||
/* For MI output, print frame level. */
|
/* For MI output, print frame level. */
|
||||||
ui_out_is_mi_like_p (uiout),
|
ui_out_is_mi_like_p (uiout),
|
||||||
LOCATION);
|
LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
do_cleanups (chain2);
|
do_cleanups (chain2);
|
||||||
}
|
}
|
||||||
|
@ -698,6 +709,9 @@ print_thread_info (struct ui_out *uiout, int requested_thread)
|
||||||
ui_out_field_int (uiout, "current-thread-id", current_thread);
|
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
|
/* If case we were not able to find the original frame, print the
|
||||||
new selected frame. */
|
new selected frame. */
|
||||||
if (frame_find_by_id (saved_frame_id) == NULL)
|
if (frame_find_by_id (saved_frame_id) == NULL)
|
||||||
|
@ -736,7 +750,11 @@ switch_to_thread (ptid_t ptid)
|
||||||
inferior_ptid = ptid;
|
inferior_ptid = ptid;
|
||||||
reinit_frame_cache ();
|
reinit_frame_cache ();
|
||||||
registers_changed ();
|
registers_changed ();
|
||||||
|
|
||||||
|
if (!is_executing (ptid))
|
||||||
stop_pc = read_pc ();
|
stop_pc = read_pc ();
|
||||||
|
else
|
||||||
|
stop_pc = ~(CORE_ADDR) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -773,6 +791,11 @@ do_restore_current_thread_cleanup (void *arg)
|
||||||
{
|
{
|
||||||
struct current_thread_cleanup *old = arg;
|
struct current_thread_cleanup *old = arg;
|
||||||
restore_current_thread (old->inferior_ptid);
|
restore_current_thread (old->inferior_ptid);
|
||||||
|
|
||||||
|
/* 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 (!is_running (old->inferior_ptid))
|
||||||
restore_selected_frame (old->selected_frame_id);
|
restore_selected_frame (old->selected_frame_id);
|
||||||
xfree (old);
|
xfree (old);
|
||||||
}
|
}
|
||||||
|
@ -801,8 +824,7 @@ static void
|
||||||
thread_apply_all_command (char *cmd, int from_tty)
|
thread_apply_all_command (char *cmd, int from_tty)
|
||||||
{
|
{
|
||||||
struct thread_info *tp;
|
struct thread_info *tp;
|
||||||
struct cleanup *old_chain;
|
struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
|
||||||
struct cleanup *saved_cmd_cleanup_chain;
|
|
||||||
char *saved_cmd;
|
char *saved_cmd;
|
||||||
struct frame_id saved_frame_id;
|
struct frame_id saved_frame_id;
|
||||||
ptid_t current_ptid;
|
ptid_t current_ptid;
|
||||||
|
@ -812,8 +834,12 @@ thread_apply_all_command (char *cmd, int from_tty)
|
||||||
error (_("Please specify a command following the thread ID list"));
|
error (_("Please specify a command following the thread ID list"));
|
||||||
|
|
||||||
current_ptid = inferior_ptid;
|
current_ptid = inferior_ptid;
|
||||||
|
|
||||||
|
if (!is_running (inferior_ptid))
|
||||||
saved_frame_id = get_frame_id (get_selected_frame (NULL));
|
saved_frame_id = get_frame_id (get_selected_frame (NULL));
|
||||||
old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
|
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
|
/* It is safe to update the thread list now, before
|
||||||
traversing it for "thread apply all". MVS */
|
traversing it for "thread apply all". MVS */
|
||||||
|
@ -822,11 +848,15 @@ thread_apply_all_command (char *cmd, int from_tty)
|
||||||
/* Save a copy of the command in case it is clobbered by
|
/* Save a copy of the command in case it is clobbered by
|
||||||
execute_command */
|
execute_command */
|
||||||
saved_cmd = xstrdup (cmd);
|
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)
|
for (tp = thread_list; tp; tp = tp->next)
|
||||||
if (thread_alive (tp))
|
if (thread_alive (tp))
|
||||||
{
|
{
|
||||||
|
if (non_stop)
|
||||||
|
context_switch_to (tp->ptid);
|
||||||
|
else
|
||||||
switch_to_thread (tp->ptid);
|
switch_to_thread (tp->ptid);
|
||||||
|
|
||||||
printf_filtered (_("\nThread %d (%s):\n"),
|
printf_filtered (_("\nThread %d (%s):\n"),
|
||||||
tp->num, target_tid_to_str (inferior_ptid));
|
tp->num, target_tid_to_str (inferior_ptid));
|
||||||
execute_command (cmd, from_tty);
|
execute_command (cmd, from_tty);
|
||||||
|
@ -836,12 +866,10 @@ thread_apply_all_command (char *cmd, int from_tty)
|
||||||
if (!ptid_equal (current_ptid, inferior_ptid))
|
if (!ptid_equal (current_ptid, inferior_ptid))
|
||||||
thread_has_changed = 1;
|
thread_has_changed = 1;
|
||||||
|
|
||||||
do_cleanups (saved_cmd_cleanup_chain);
|
|
||||||
do_cleanups (old_chain);
|
do_cleanups (old_chain);
|
||||||
/* Print stack frame only if we changed thread. */
|
/* 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);
|
print_stack_frame (get_current_frame (), 1, SRC_LINE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -865,7 +893,11 @@ thread_apply_command (char *tidlist, int from_tty)
|
||||||
error (_("Please specify a command following the thread ID list"));
|
error (_("Please specify a command following the thread ID list"));
|
||||||
|
|
||||||
current_ptid = inferior_ptid;
|
current_ptid = inferior_ptid;
|
||||||
|
|
||||||
|
if (!is_running (inferior_ptid))
|
||||||
saved_frame_id = get_frame_id (get_selected_frame (NULL));
|
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);
|
old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
|
||||||
|
|
||||||
/* Save a copy of the command in case it is clobbered by
|
/* Save a copy of the command in case it is clobbered by
|
||||||
|
@ -909,6 +941,9 @@ thread_apply_command (char *tidlist, int from_tty)
|
||||||
warning (_("Thread %d has terminated."), start);
|
warning (_("Thread %d has terminated."), start);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (non_stop)
|
||||||
|
context_switch_to (tp->ptid);
|
||||||
|
else
|
||||||
switch_to_thread (tp->ptid);
|
switch_to_thread (tp->ptid);
|
||||||
printf_filtered (_("\nThread %d (%s):\n"), tp->num,
|
printf_filtered (_("\nThread %d (%s):\n"), tp->num,
|
||||||
target_tid_to_str (inferior_ptid));
|
target_tid_to_str (inferior_ptid));
|
||||||
|
@ -977,6 +1012,9 @@ do_captured_thread_select (struct ui_out *uiout, void *tidstr)
|
||||||
if (!thread_alive (tp))
|
if (!thread_alive (tp))
|
||||||
error (_("Thread ID %d has terminated."), num);
|
error (_("Thread ID %d has terminated."), num);
|
||||||
|
|
||||||
|
if (non_stop)
|
||||||
|
context_switch_to (tp->ptid);
|
||||||
|
else
|
||||||
switch_to_thread (tp->ptid);
|
switch_to_thread (tp->ptid);
|
||||||
|
|
||||||
ui_out_text (uiout, "[Switching to thread ");
|
ui_out_text (uiout, "[Switching to thread ");
|
||||||
|
@ -985,7 +1023,11 @@ do_captured_thread_select (struct ui_out *uiout, void *tidstr)
|
||||||
ui_out_text (uiout, target_tid_to_str (inferior_ptid));
|
ui_out_text (uiout, target_tid_to_str (inferior_ptid));
|
||||||
ui_out_text (uiout, ")]");
|
ui_out_text (uiout, ")]");
|
||||||
|
|
||||||
|
if (!tp->running_)
|
||||||
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
|
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
|
||||||
|
else
|
||||||
|
ui_out_text (uiout, "(running)\n");
|
||||||
|
|
||||||
return GDB_RC_OK;
|
return GDB_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,14 +1047,17 @@ void
|
||||||
_initialize_thread (void)
|
_initialize_thread (void)
|
||||||
{
|
{
|
||||||
static struct cmd_list_element *thread_apply_list = NULL;
|
static struct cmd_list_element *thread_apply_list = NULL;
|
||||||
|
struct cmd_list_element *c;
|
||||||
|
|
||||||
add_info ("threads", info_threads_command,
|
c = add_info ("threads", info_threads_command,
|
||||||
_("IDs of currently known threads."));
|
_("IDs of currently known threads."));
|
||||||
|
set_cmd_async_ok (c);
|
||||||
|
|
||||||
add_prefix_cmd ("thread", class_run, thread_command, _("\
|
c = add_prefix_cmd ("thread", class_run, thread_command, _("\
|
||||||
Use this command to switch between threads.\n\
|
Use this command to switch between threads.\n\
|
||||||
The new thread ID must be currently known."),
|
The new thread ID must be currently known."),
|
||||||
&thread_cmd_list, "thread ", 1, &cmdlist);
|
&thread_cmd_list, "thread ", 1, &cmdlist);
|
||||||
|
set_cmd_async_ok (c);
|
||||||
|
|
||||||
add_prefix_cmd ("apply", class_run, thread_apply_command,
|
add_prefix_cmd ("apply", class_run, thread_apply_command,
|
||||||
_("Apply a command to a list of threads."),
|
_("Apply a command to a list of threads."),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue