2008-05-06 Pedro Alves * 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; }