From: Pedro Alves Date: Wed, 9 Jul 2008 22:42:43 +0000 (+0000) Subject: Non-stop inferior control. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=94cc34afe2c3d9377f1b9cfd481b5822a03c283f;p=binutils-gdb.git 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). --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 42a147a04d4..6231f89aa7d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,61 @@ +2008-07-09 Pedro Alves + + 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 Don't rely on ecs->wait_for_more. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index d041e30fc73..efa18ea1622 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -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) \ $(environ_h) $(value_h) $(target_h) $(gdbthread_h) $(exceptions_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) \ $(cli_script_h) $(cli_setshow_h) $(cli_decode_h) $(symtab_h) \ $(inferior_h) $(exceptions_h) $(target_h) $(breakpoint_h) \ diff --git a/gdb/inf-loop.c b/gdb/inf-loop.c index 3f98bfcaa15..94ced19ad98 100644 --- a/gdb/inf-loop.c +++ b/gdb/inf-loop.c @@ -73,11 +73,15 @@ inferior_event_handler (enum inferior_event_type event_type, 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 diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c index e4f0d1ded40..ee2c8fa397d 100644 --- a/gdb/inf-ptrace.c +++ b/gdb/inf-ptrace.c @@ -297,7 +297,7 @@ inf_ptrace_kill (void) /* Stop the inferior. */ 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 typed a ^C on the controlling terminal. Note that using a diff --git a/gdb/infcmd.c b/gdb/infcmd.c index fead6d16a7a..db03cf27938 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -613,6 +613,7 @@ continue_command (char *proc_count_exp, int from_tty) { int async_exec = 0; ERROR_NO_INFERIOR; + ensure_not_running (); /* Find out whether we must run in the background. */ if (proc_count_exp != NULL) @@ -714,6 +715,7 @@ step_1 (int skip_subroutines, int single_inst, char *count_string) int thread = -1; ERROR_NO_INFERIOR; + ensure_not_running (); if (count_string) async_exec = strip_bg_char (&count_string); @@ -936,6 +938,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) @@ -1036,6 +1039,7 @@ signal_command (char *signum_exp, int from_tty) dont_repeat (); /* Too dangerous. */ ERROR_NO_INFERIOR; + ensure_not_running (); /* Find out whether we must run in the background. */ if (signum_exp != NULL) @@ -2102,7 +2106,8 @@ interrupt_target_command (char *args, int from_tty) if (target_can_async_p ()) { dont_repeat (); /* Not for the faint of heart */ - target_stop (); + + target_stop (inferior_ptid); } } diff --git a/gdb/inferior.h b/gdb/inferior.h index e89fb74b978..60d0352f9ad 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -245,6 +245,12 @@ extern void get_last_target_status(ptid_t *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); diff --git a/gdb/infrun.c b/gdb/infrun.c index fdf17a35222..f74b945eb42 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1056,9 +1056,15 @@ a command like `return' or `jump' to continue execution.")); 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; @@ -1219,19 +1225,27 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) "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. - - 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 (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; + } if (oneproc) { @@ -1535,6 +1549,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); @@ -1745,6 +1768,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. */ @@ -1818,10 +1855,16 @@ handle_inferior_event (struct execution_control_state *ecs) && 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) - set_executing (pid_to_ptid (-1), 0); + { + /* 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); + else + set_executing (ecs->ptid, 0); + } switch (ecs->ws.kind) { @@ -2059,15 +2102,22 @@ handle_inferior_event (struct execution_control_state *ecs) 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__, "\ +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); prepare_to_wait (ecs); return; @@ -2134,6 +2184,9 @@ handle_inferior_event (struct execution_control_state *ecs) 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) @@ -2282,8 +2335,13 @@ handle_inferior_event (struct execution_control_state *ecs) 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); @@ -3838,7 +3896,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 diff --git a/gdb/remote.c b/gdb/remote.c index 4792cada24a..14e04da7ba9 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -155,7 +155,7 @@ static void init_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); @@ -3269,7 +3269,7 @@ async_remote_interrupt (gdb_client_data arg) if (remote_debug) 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 @@ -3323,7 +3323,7 @@ remote_interrupt_twice (int signo) interrupt is requested, either by the command line or the GUI, we will eventually end up here. */ static void -remote_stop (void) +remote_stop (ptid_t ptid) { /* Send a break or a ^C, depending on user preference. */ if (remote_debug) diff --git a/gdb/target.c b/gdb/target.c index 6e7108035b9..461cfe390c2 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -165,7 +165,7 @@ static void debug_to_notice_signals (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 wierd and mysterious ways. Putting the variable here lets those @@ -630,7 +630,7 @@ update_current_target (void) (char *(*) (struct thread_info *)) return_zero); de_fault (to_stop, - (void (*) (void)) + (void (*) (ptid_t)) target_ignore); current_target.to_xfer_partial = current_xfer_partial; de_fault (to_rcmd, @@ -2997,11 +2997,12 @@ debug_to_find_new_threads (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 diff --git a/gdb/target.h b/gdb/target.h index db2d58e44c2..e2425667ea8 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -401,7 +401,7 @@ struct target_ops void (*to_find_new_threads) (void); char *(*to_pid_to_str) (ptid_t); 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); char *(*to_pid_to_exec_file) (int pid); 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 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 (shell,interpreter) for execution. The result of the query is diff --git a/gdb/thread.c b/gdb/thread.c index e2f8cd7f343..1ae9adfebef 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -42,6 +42,8 @@ #include "observer.h" #include "annotate.h" +#include "cli/cli-decode.h" + /* Definition of struct thread_info exported to gdbthread.h */ /* Prototypes for exported functions. */ @@ -640,9 +642,12 @@ print_thread_info (struct ui_out *uiout, int requested_thread) 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 (); @@ -677,12 +682,18 @@ print_thread_info (struct ui_out *uiout, int requested_thread) ui_out_text (uiout, ")"); } 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); + 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); + print_stack_frame (get_selected_frame (NULL), + /* For MI output, print frame level. */ + ui_out_is_mi_like_p (uiout), + LOCATION); + } 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); } + 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) @@ -736,7 +750,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 @@ -773,7 +791,12 @@ do_restore_current_thread_cleanup (void *arg) { 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 (!is_running (old->inferior_ptid)) + restore_selected_frame (old->selected_frame_id); xfree (old); } @@ -801,8 +824,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; @@ -812,8 +834,12 @@ thread_apply_all_command (char *cmd, int from_tty) 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 */ @@ -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 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); @@ -836,12 +866,10 @@ thread_apply_all_command (char *cmd, int from_tty) 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 @@ -865,7 +893,11 @@ thread_apply_command (char *tidlist, int from_tty) 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 @@ -909,7 +941,10 @@ thread_apply_command (char *tidlist, int from_tty) 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); @@ -977,7 +1012,10 @@ do_captured_thread_select (struct ui_out *uiout, void *tidstr) 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)); @@ -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, ")]"); - 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; } @@ -1005,14 +1047,17 @@ void _initialize_thread (void) { static struct cmd_list_element *thread_apply_list = NULL; + struct cmd_list_element *c; - add_info ("threads", info_threads_command, - _("IDs of currently known threads.")); + c = add_info ("threads", info_threads_command, + _("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\ 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, _("Apply a command to a list of threads."),