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:
Pedro Alves 2008-07-09 22:42:43 +00:00
parent 59f0d5d953
commit 94cc34afe2
11 changed files with 258 additions and 72 deletions

View file

@ -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.

View file

@ -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) \

View file

@ -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

View file

@ -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

View file

@ -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);
} }
} }

View file

@ -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);

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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."),