Remote all-stop-on-top-of-non-stop
authorPedro Alves <palves@redhat.com>
Mon, 30 Nov 2015 16:05:13 +0000 (16:05 +0000)
committerPedro Alves <palves@redhat.com>
Mon, 30 Nov 2015 18:36:37 +0000 (18:36 +0000)
This is the first pass at implementing support for all-stop mode
running against the remote target using the non-stop variant of the
protocol.

The trickiest part here is the initial connection setup/synching.  We
need to fetch all inferiors' target descriptions etc. before stopping
threads, because stop_all_threads needs to read the threads' registers
(to record each thread's stop_pc).  But OTOH, the initial inferior
setup (target_post_attach, post_create_inferior, etc.), only works
correctly if the inferior is stopped...  So I've split that initial
setup part from attach_command_post_wait to a separate function, and
added a "still needs setup" flag to the inferior structure.  This is
similar to gdbserver/linux-low.c's handling of discovering the
process's target description).  Then if on connection all threads of
the remote inferior are running, when we go about stopping them, as
soon as they stop we call setup_inferior, from within
stop_all_threads.

Also, in all-stop, we need to process all the initial stop replies to
learn about all the pending signal the threads may already be stopped
for, and pick the one to report as current.  This is exposed by
gdb.threads/reconnect-signal.exp.

gdb/
2015-11-30  Pedro Alves  <palves@redhat.com>

* gdbthread.h (switch_to_thread_no_regs): Declare.
* infcmd.c (setup_inferior): New function, factored out from ...
(attach_command_post_wait): ... this.  Rename to ...
(attach_post_wait): ... this.  Replace parameter async_exec with
attach_post_wait_mode parameter.  Adjust.
(enum attach_post_wait_mode): New enum.
(struct attach_command_continuation_args): Replace 'async_exec'
field with 'mode' field.
(attach_command_continuation): Adjust.
(attach_command): Add comment.  Mark the inferior as needing
setup.  Adjust to use enum attach_post_wait_mode.
(notice_new_inferior): Use switch_to_thread_no_regs.  Adjust to
use enum attach_post_wait_mode.
* inferior.h (setup_inferior): Declare.
(struct inferior) <needs_setup>: New field.
* infrun.c (set_last_target_status): Make extern.
(stop_all_threads): Make extern.  Setup inferior, if necessary.
* infrun.h (set_last_target_status, stop_all_threads): Declare.
* remote-notif.c (remote_async_get_pending_events_handler)
(handle_notification): Replace non_stop checks with
target_is_non_stop_p() checks.
* remote.c (remote_notice_new_inferior): Remove non_stop check.
(remote_update_thread_list): Replace non_stop check with
target_is_non_stop_p() check.
(print_one_stopped_thread): New function.
(process_initial_stop_replies): New 'from_tty' parameter.
"Notice" all new live inferiors after storing initial stops as
pending status in each corresponding thread.  If all-stop, stop
all threads, try picking a signalled thread as current, and print
the status of that one thread.  Record the last target status.
(remote_start_remote): Replace non_stop checks with
target_is_non_stop_p() checks.  Don't query for the remote current
thread of use qOffsets here.  Pass from_tty to
process_initial_stop_replies.
(extended_remote_attach): Replace non_stop checks with
target_is_non_stop_p() checks.
(extended_remote_post_attach): Send qOffsets here.
(remote_vcont_resume, remote_resume, remote_stop)
(remote_interrupt, remote_parse_stop_reply, remote_wait): Replace
non_stop checks with target_is_non_stop_p() checks.
(remote_async): If target is non-stop, mark/clear the pending
events token.
* thread.c (switch_to_thread_no_regs): New function.

gdb/ChangeLog
gdb/gdbthread.h
gdb/infcmd.c
gdb/inferior.h
gdb/infrun.c
gdb/infrun.h
gdb/remote-notif.c
gdb/remote.c
gdb/thread.c

index c4b89e729fa413d34119098baeb561faf6ff6619..6833076ec32efa62d9aaa7b9745c67b89450b139 100644 (file)
@@ -1,3 +1,49 @@
+2015-11-30  Pedro Alves  <palves@redhat.com>
+
+       * gdbthread.h (switch_to_thread_no_regs): Declare.
+       * infcmd.c (setup_inferior): New function, factored out from ...
+       (attach_command_post_wait): ... this.  Rename to ...
+       (attach_post_wait): ... this.  Replace parameter async_exec with
+       attach_post_wait_mode parameter.  Adjust.
+       (enum attach_post_wait_mode): New enum.
+       (struct attach_command_continuation_args): Replace 'async_exec'
+       field with 'mode' field.
+       (attach_command_continuation): Adjust.
+       (attach_command): Add comment.  Mark the inferior as needing
+       setup.  Adjust to use enum attach_post_wait_mode.
+       (notice_new_inferior): Use switch_to_thread_no_regs.  Adjust to
+       use enum attach_post_wait_mode.
+       * inferior.h (setup_inferior): Declare.
+       (struct inferior) <needs_setup>: New field.
+       * infrun.c (set_last_target_status): Make extern.
+       (stop_all_threads): Make extern.  Setup inferior, if necessary.
+       * infrun.h (set_last_target_status, stop_all_threads): Declare.
+       * remote-notif.c (remote_async_get_pending_events_handler)
+       (handle_notification): Replace non_stop checks with
+       target_is_non_stop_p() checks.
+       * remote.c (remote_notice_new_inferior): Remove non_stop check.
+       (remote_update_thread_list): Replace non_stop check with
+       target_is_non_stop_p() check.
+       (print_one_stopped_thread): New function.
+       (process_initial_stop_replies): New 'from_tty' parameter.
+       "Notice" all new live inferiors after storing initial stops as
+       pending status in each corresponding thread.  If all-stop, stop
+       all threads, try picking a signalled thread as current, and print
+       the status of that one thread.  Record the last target status.
+       (remote_start_remote): Replace non_stop checks with
+       target_is_non_stop_p() checks.  Don't query for the remote current
+       thread of use qOffsets here.  Pass from_tty to
+       process_initial_stop_replies.
+       (extended_remote_attach): Replace non_stop checks with
+       target_is_non_stop_p() checks.
+       (extended_remote_post_attach): Send qOffsets here.
+       (remote_vcont_resume, remote_resume, remote_stop)
+       (remote_interrupt, remote_parse_stop_reply, remote_wait): Replace
+       non_stop checks with target_is_non_stop_p() checks.
+       (remote_async): If target is non-stop, mark/clear the pending
+       events token.
+       * thread.c (switch_to_thread_no_regs): New function.
+
 2015-11-30  Pedro Alves  <palves@redhat.com>
 
        * gdb.mi/mi-nonstop.exp: Append "set non-stop on" to GDBFLAGS
index 0f9734d0a06b93c969f636376084c79921758b16..eb7f8b84d054190c94af7f00b4d7c4e36c3b7bc4 100644 (file)
@@ -411,9 +411,14 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
 
 extern int thread_count (void);
 
-/* Switch from one thread to another.  */
+/* Switch from one thread to another.  Also sets the STOP_PC
+   global.  */
 extern void switch_to_thread (ptid_t ptid);
 
+/* Switch from one thread to another.  Does not read registers and
+   sets STOP_PC to -1.  */
+extern void switch_to_thread_no_regs (struct thread_info *thread);
+
 /* Marks or clears thread(s) PTID as resumed.  If PTID is
    MINUS_ONE_PTID, applies to all threads.  If ptid_is_pid(PTID) is
    true, applies to all threads of the process pointed at by PTID.  */
index 54aa1ef4cc49cfa01669972978bbc3ef33dca442..9aae86081e0cbafcfe15c1c836f399ca7513be59 100644 (file)
@@ -2609,18 +2609,15 @@ proceed_after_attach (int pid)
   do_cleanups (old_chain);
 }
 
-/* attach_command --
-   takes a program started up outside of gdb and ``attaches'' to it.
-   This stops it cold in its tracks and allows us to start debugging it.
-   and wait for the trace-trap that results from attaching.  */
+/* See inferior.h.  */
 
-static void
-attach_command_post_wait (char *args, int from_tty, int async_exec)
+void
+setup_inferior (int from_tty)
 {
   struct inferior *inferior;
 
   inferior = current_inferior ();
-  inferior->control.stop_soon = NO_STOP_QUIETLY;
+  inferior->needs_setup = 0;
 
   /* If no exec file is yet known, try to determine it from the
      process itself.  */
@@ -2636,8 +2633,37 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
   target_post_attach (ptid_get_pid (inferior_ptid));
 
   post_create_inferior (&current_target, from_tty);
+}
+
+/* What to do after the first program stops after attaching.  */
+enum attach_post_wait_mode
+{
+  /* Do nothing.  Leaves threads as they are.  */
+  ATTACH_POST_WAIT_NOTHING,
+
+  /* Re-resume threads that are marked running.  */
+  ATTACH_POST_WAIT_RESUME,
+
+  /* Stop all threads.  */
+  ATTACH_POST_WAIT_STOP,
+};
+
+/* Called after we've attached to a process and we've seen it stop for
+   the first time.  If ASYNC_EXEC is true, re-resume threads that
+   should be running.  Else if ATTACH, */
+
+static void
+attach_post_wait (char *args, int from_tty, enum attach_post_wait_mode mode)
+{
+  struct inferior *inferior;
 
-  if (async_exec)
+  inferior = current_inferior ();
+  inferior->control.stop_soon = NO_STOP_QUIETLY;
+
+  if (inferior->needs_setup)
+    setup_inferior (from_tty);
+
+  if (mode == ATTACH_POST_WAIT_RESUME)
     {
       /* The user requested an `attach&', so be sure to leave threads
         that didn't get a signal running.  */
@@ -2657,7 +2683,7 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
            }
        }
     }
-  else
+  else if (mode == ATTACH_POST_WAIT_STOP)
     {
       /* The user requested a plain `attach', so be sure to leave
         the inferior stopped.  */
@@ -2685,7 +2711,7 @@ struct attach_command_continuation_args
 {
   char *args;
   int from_tty;
-  int async_exec;
+  enum attach_post_wait_mode mode;
 };
 
 static void
@@ -2697,7 +2723,7 @@ attach_command_continuation (void *args, int err)
   if (err)
     return;
 
-  attach_command_post_wait (a->args, a->from_tty, a->async_exec);
+  attach_post_wait (a->args, a->from_tty, a->mode);
 }
 
 static void
@@ -2710,12 +2736,18 @@ attach_command_continuation_free_args (void *args)
   xfree (a);
 }
 
+/* "attach" command entry point.  Takes a program started up outside
+   of gdb and ``attaches'' to it.  This stops it cold in its tracks
+   and allows us to start debugging it.  */
+
 void
 attach_command (char *args, int from_tty)
 {
   int async_exec;
   struct cleanup *args_chain;
   struct target_ops *attach_target;
+  struct inferior *inferior = current_inferior ();
+  enum attach_post_wait_mode mode;
 
   dont_repeat ();              /* Not for the faint of heart */
 
@@ -2775,6 +2807,8 @@ attach_command (char *args, int from_tty)
   init_wait_for_inferior ();
   clear_proceed_status (0);
 
+  inferior->needs_setup = 1;
+
   if (target_is_non_stop_p ())
     {
       /* If we find that the current thread isn't stopped, explicitly
@@ -2790,12 +2824,13 @@ attach_command (char *args, int from_tty)
        target_stop (pid_to_ptid (ptid_get_pid (inferior_ptid)));
     }
 
+  mode = async_exec ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_STOP;
+
   /* Some system don't generate traps when attaching to inferior.
      E.g. Mach 3 or GNU hurd.  */
   if (!target_attach_no_wait)
     {
       struct attach_command_continuation_args *a;
-      struct inferior *inferior = current_inferior ();
 
       /* Careful here.  See comments in inferior.h.  Basically some
         OSes don't ignore SIGSTOPs on continue requests anymore.  We
@@ -2808,7 +2843,7 @@ attach_command (char *args, int from_tty)
       a = XNEW (struct attach_command_continuation_args);
       a->args = xstrdup (args);
       a->from_tty = from_tty;
-      a->async_exec = async_exec;
+      a->mode = mode;
       add_inferior_continuation (attach_command_continuation, a,
                                 attach_command_continuation_free_args);
       /* Done with ARGS.  */
@@ -2822,7 +2857,7 @@ attach_command (char *args, int from_tty)
   /* Done with ARGS.  */
   do_cleanups (args_chain);
 
-  attach_command_post_wait (args, from_tty, async_exec);
+  attach_post_wait (args, from_tty, mode);
 }
 
 /* We had just found out that the target was already attached to an
@@ -2837,7 +2872,7 @@ void
 notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
 {
   struct cleanup* old_chain;
-  int async_exec;
+  enum attach_post_wait_mode mode;
 
   old_chain = make_cleanup (null_cleanup, NULL);
 
@@ -2845,12 +2880,14 @@ notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
      they're stopped for some reason other than us telling it to, the
      target reports a signal != GDB_SIGNAL_0.  We don't try to
      resume threads with such a stop signal.  */
-  async_exec = non_stop;
+  mode = non_stop ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_NOTHING;
 
   if (!ptid_equal (inferior_ptid, null_ptid))
     make_cleanup_restore_current_thread ();
 
-  switch_to_thread (ptid);
+  /* Avoid reading registers -- we haven't fetched the target
+     description yet.  */
+  switch_to_thread_no_regs (find_thread_ptid (ptid));
 
   /* When we "notice" a new inferior we need to do all the things we
      would normally do if we had just attached to it.  */
@@ -2871,7 +2908,7 @@ notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
       a = XNEW (struct attach_command_continuation_args);
       a->args = xstrdup ("");
       a->from_tty = from_tty;
-      a->async_exec = async_exec;
+      a->mode = mode;
       add_inferior_continuation (attach_command_continuation, a,
                                 attach_command_continuation_free_args);
 
@@ -2879,8 +2916,8 @@ notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
       return;
     }
 
-  async_exec = leave_running;
-  attach_command_post_wait ("" /* args */, from_tty, async_exec);
+  mode = leave_running ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_NOTHING;
+  attach_post_wait ("" /* args */, from_tty, mode);
 
   do_cleanups (old_chain);
 }
index e09cb0021a91c39f573ace7ebb46facd5a30c35d..d3cf61578b775ffa74e181f65913337c22ddaf61 100644 (file)
@@ -143,6 +143,12 @@ extern char *construct_inferior_arguments (int, char **);
 
 /* From infcmd.c */
 
+/* Initial inferior setup.  Determines the exec file is not yet known,
+   takes any necessary post-attaching actions, fetches the target
+   description and syncs the shared library list.  */
+
+extern void setup_inferior (int from_tty);
+
 extern void post_create_inferior (struct target_ops *, int);
 
 extern void attach_command (char *, int);
@@ -364,6 +370,12 @@ struct inferior
      specific thread, see `struct thread_info'.  */
   struct continuation *continuations;
 
+  /* True if setup_inferior wasn't called for this inferior yet.
+     Until that is done, we must not access inferior memory or
+     registers, as we haven't determined the target
+     architecture/description.  */
+  int needs_setup;
+
   /* Private data used by the target vector implementation.  */
   struct private_inferior *priv;
 
index b14f34cbc0b9e12d2be644b78d2310c9c028e46b..266b89278c4a3814efd89cc7deb68e7044a12df0 100644 (file)
@@ -2052,7 +2052,6 @@ static void keep_going_pass_signal (struct execution_control_state *ecs);
 static void prepare_to_wait (struct execution_control_state *ecs);
 static int keep_going_stepped_thread (struct thread_info *tp);
 static step_over_what thread_still_needs_step_over (struct thread_info *tp);
-static void stop_all_threads (void);
 
 /* Are there any pending step-over requests?  If so, run all we can
    now and return true.  Otherwise, return false.  */
@@ -4015,7 +4014,7 @@ init_thread_stepping_state (struct thread_info *tss)
 
 /* Set the cached copy of the last ptid/waitstatus.  */
 
-static void
+void
 set_last_target_status (ptid_t ptid, struct target_waitstatus status)
 {
   target_last_wait_ptid = ptid;
@@ -4437,9 +4436,9 @@ save_waitstatus (struct thread_info *tp, struct target_waitstatus *ws)
     }
 }
 
-/* Stop all threads.  */
+/* See infrun.h.  */
 
-static void
+void
 stop_all_threads (void)
 {
   /* We may need multiple passes to discover all threads.  */
@@ -4548,6 +4547,8 @@ stop_all_threads (void)
            }
          else
            {
+             struct inferior *inf;
+
              t = find_thread_ptid (event_ptid);
              if (t == NULL)
                t = add_thread (event_ptid);
@@ -4557,6 +4558,15 @@ stop_all_threads (void)
              t->resumed = 0;
              t->control.may_range_step = 0;
 
+             /* This may be the first time we see the inferior report
+                a stop.  */
+             inf = find_inferior_ptid (event_ptid);
+             if (inf->needs_setup)
+               {
+                 switch_to_thread_no_regs (t);
+                 setup_inferior (0);
+               }
+
              if (ws.kind == TARGET_WAITKIND_STOPPED
                  && ws.value.sig == GDB_SIGNAL_0)
                {
index 736406553128dfe039fce5e108dcbd1f72edbbec..fe06a819c5c7057a654736297643a9613d36826c 100644 (file)
@@ -112,6 +112,12 @@ extern int normal_stop (void);
 extern void get_last_target_status (ptid_t *ptid,
                                    struct target_waitstatus *status);
 
+extern void set_last_target_status (ptid_t ptid,
+                                   struct target_waitstatus status);
+
+/* Stop all threads.  Only returns after everything is halted.  */
+extern void stop_all_threads (void);
+
 extern void prepare_for_detach (void);
 
 extern void fetch_inferior_event (void *);
index a8a628517b7fed780c4af9b7d5da7b9c26817da8..4377bda32e588da33c69eaa50a49ba07e9c684c8 100644 (file)
@@ -116,7 +116,7 @@ remote_notif_process (struct remote_notif_state *state,
 static void
 remote_async_get_pending_events_handler (gdb_client_data data)
 {
-  gdb_assert (non_stop);
+  gdb_assert (target_is_non_stop_p ());
   remote_notif_process ((struct remote_notif_state *) data, NULL);
 }
 
@@ -166,7 +166,7 @@ handle_notification (struct remote_notif_state *state, char *buf)
       /* Notify the event loop there's a stop reply to acknowledge
         and that there may be more events to fetch.  */
       QUEUE_enque (notif_client_p, state->notif_queue, nc);
-      if (non_stop)
+      if (target_is_non_stop_p ())
        {
          /* In non-stop, We mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN
             in order to go on what we were doing and postpone
index 90be8b6fa38e3a800eaaeedd03d9f778dc0f7deb..bbcdbe1f56c898f8d9e9db0c60b494b77d83a305 100644 (file)
@@ -1887,7 +1887,7 @@ remote_notice_new_inferior (ptid_t currthread, int running)
        {
          struct remote_state *rs = get_remote_state ();
 
-         if (non_stop || !rs->starting_up)
+         if (!rs->starting_up)
            notice_new_inferior (currthread, running, 0);
        }
     }
@@ -3165,7 +3165,7 @@ remote_update_thread_list (struct target_ops *ops)
                 running until proven otherwise with a stop reply.  In
                 all-stop, we can only get here if all threads are
                 stopped.  */
-             int running = non_stop ? 1 : 0;
+             int running = target_is_non_stop_p () ? 1 : 0;
 
              remote_notice_new_inferior (item->ptid, running);
 
@@ -3706,15 +3706,44 @@ add_current_inferior_and_thread (char *wait_status)
   add_thread_silent (inferior_ptid);
 }
 
+/* Print info about a thread that was found already stopped on
+   connection.  */
+
+static void
+print_one_stopped_thread (struct thread_info *thread)
+{
+  struct target_waitstatus *ws = &thread->suspend.waitstatus;
+
+  switch_to_thread (thread->ptid);
+  stop_pc = get_frame_pc (get_current_frame ());
+  set_current_sal_from_frame (get_current_frame ());
+
+  thread->suspend.waitstatus_pending_p = 0;
+
+  if (ws->kind == TARGET_WAITKIND_STOPPED)
+    {
+      enum gdb_signal sig = ws->value.sig;
+
+      if (signal_print_state (sig))
+       observer_notify_signal_received (sig);
+    }
+  observer_notify_normal_stop (NULL, 1);
+}
+
 /* Process all initial stop replies the remote side sent in response
    to the ? packet.  These indicate threads that were already stopped
    on initial connection.  We mark these threads as stopped and print
    their current frame before giving the user the prompt.  */
 
 static void
-process_initial_stop_replies (void)
+process_initial_stop_replies (int from_tty)
 {
   int pending_stop_replies = stop_reply_queue_length ();
+  struct inferior *inf;
+  struct thread_info *thread;
+  struct thread_info *selected = NULL;
+  struct thread_info *lowest_stopped = NULL;
+  struct thread_info *first = NULL;
 
   /* Consume the initial pending events.  */
   while (pending_stop_replies-- > 0)
@@ -3723,6 +3752,7 @@ process_initial_stop_replies (void)
       ptid_t event_ptid;
       struct target_waitstatus ws;
       int ignore_event = 0;
+      struct thread_info *thread;
 
       memset (&ws, 0, sizeof (ws));
       event_ptid = target_wait (waiton_ptid, &ws, TARGET_WNOHANG);
@@ -3751,12 +3781,7 @@ process_initial_stop_replies (void)
       if (ignore_event)
        continue;
 
-      switch_to_thread (event_ptid);
-      set_executing (event_ptid, 0);
-      set_running (event_ptid, 0);
-
-      stop_pc = get_frame_pc (get_current_frame ());
-      set_current_sal_from_frame (get_current_frame ());
+      thread = find_thread_ptid (event_ptid);
 
       if (ws.kind == TARGET_WAITKIND_STOPPED)
        {
@@ -3766,15 +3791,106 @@ process_initial_stop_replies (void)
             instead of signal 0.  Suppress it.  */
          if (sig == GDB_SIGNAL_TRAP)
            sig = GDB_SIGNAL_0;
-         inferior_thread ()->suspend.stop_signal = sig;
+         thread->suspend.stop_signal = sig;
+         ws.value.sig = sig;
+       }
 
-         if (signal_print_state (sig))
-           observer_notify_signal_received (sig);
-        }
+      thread->suspend.waitstatus = ws;
+
+      if (ws.kind != TARGET_WAITKIND_STOPPED
+         || ws.value.sig != GDB_SIGNAL_0)
+       thread->suspend.waitstatus_pending_p = 1;
+
+      set_executing (event_ptid, 0);
+      set_running (event_ptid, 0);
+    }
+
+  /* "Notice" the new inferiors before anything related to
+     registers/memory.  */
+  ALL_INFERIORS (inf)
+    {
+      if (inf->pid == 0)
+       continue;
+
+      inf->needs_setup = 1;
+
+      if (non_stop)
+       {
+         thread = any_live_thread_of_process (inf->pid);
+         notice_new_inferior (thread->ptid,
+                              thread->state == THREAD_RUNNING,
+                              from_tty);
+       }
+    }
+
+  /* If all-stop on top of non-stop, pause all threads.  Note this
+     records the threads' stop pc, so must be done after "noticing"
+     the inferiors.  */
+  if (!non_stop)
+    {
+      stop_all_threads ();
+
+      /* If all threads of an inferior were already stopped, we
+        haven't setup the inferior yet.  */
+      ALL_INFERIORS (inf)
+       {
+         if (inf->pid == 0)
+           continue;
 
-      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
-      observer_notify_normal_stop (NULL, 1);
+         if (inf->needs_setup)
+           {
+             thread = any_live_thread_of_process (inf->pid);
+             switch_to_thread_no_regs (thread);
+             setup_inferior (0);
+           }
+       }
     }
+
+  /* Now go over all threads that are stopped, and print their current
+     frame.  If all-stop, then if there's a signalled thread, pick
+     that as current.  */
+  ALL_NON_EXITED_THREADS (thread)
+    {
+      struct target_waitstatus *ws;
+
+      if (first == NULL)
+       first = thread;
+
+      if (!non_stop)
+       set_running (thread->ptid, 0);
+      else if (thread->state != THREAD_STOPPED)
+       continue;
+
+      ws = &thread->suspend.waitstatus;
+
+      if (selected == NULL
+         && thread->suspend.waitstatus_pending_p)
+       selected = thread;
+
+      if (lowest_stopped == NULL || thread->num < lowest_stopped->num)
+       lowest_stopped = thread;
+
+      if (non_stop)
+       print_one_stopped_thread (thread);
+    }
+
+  /* In all-stop, we only print the status of one thread, and leave
+     others with their status pending.  */
+  if (!non_stop)
+    {
+      thread = selected;
+      if (thread == NULL)
+       thread = lowest_stopped;
+      if (thread == NULL)
+       thread = first;
+
+      print_one_stopped_thread (thread);
+    }
+
+  /* For "info program".  */
+  thread = inferior_thread ();
+  if (thread->state == THREAD_STOPPED)
+    set_last_target_status (inferior_ptid, thread->suspend.waitstatus);
 }
 
 static void
@@ -3852,7 +3968,7 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
   if (gdbarch_has_global_solist (target_gdbarch ()))
     solib_add (NULL, from_tty, target, auto_solib_add);
 
-  if (non_stop)
+  if (target_is_non_stop_p ())
     {
       if (packet_support (PACKET_QNonStop) != PACKET_ENABLE)
        error (_("Non-stop mode requested, but remote "
@@ -3896,7 +4012,7 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
   putpkt ("?");
   getpkt (&rs->buf, &rs->buf_size, 0);
 
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     {
       ptid_t ptid;
       int fake_pid_p = 0;
@@ -3989,8 +4105,6 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
     }
   else
     {
-      ptid_t current_ptid;
-
       /* Clear WFI global state.  Do this before finding about new
         threads and inferiors, and setting the current inferior.
         Otherwise we would clear the proceed status of the current
@@ -4025,19 +4139,6 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
          return;
        }
 
-      /* Let the stub know that we want it to return the thread.  */
-
-      /* Force the stub to choose a thread.  */
-      set_general_thread (null_ptid);
-
-      /* Query it.  */
-      current_ptid = remote_current_thread (minus_one_ptid);
-      if (ptid_equal (inferior_ptid, minus_one_ptid))
-       error (_("remote didn't report the current thread in non-stop mode"));
-
-      inferior_ptid = current_ptid;
-      get_offsets ();          /* Get text, data & bss offsets.  */
-
       /* In non-stop mode, any cached wait status will be stored in
         the stop reply queue.  */
       gdb_assert (wait_status == NULL);
@@ -4047,9 +4148,7 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
 
       /* If there are already stopped threads, mark them stopped and
         report their stops before giving the prompt to the user.  */
-      process_initial_stop_replies ();
-
-      switch_to_thread (current_ptid);
+      process_initial_stop_replies (from_tty);
 
       if (target_can_async_p ())
        target_async (1);
@@ -5001,7 +5100,7 @@ extended_remote_attach (struct target_ops *target, const char *args,
                     &remote_protocol_packets[PACKET_vAttach]))
     {
     case PACKET_OK:
-      if (!non_stop)
+      if (!target_is_non_stop_p ())
        {
          /* Save the reply for later.  */
          wait_status = (char *) alloca (strlen (rs->buf) + 1);
@@ -5023,7 +5122,7 @@ extended_remote_attach (struct target_ops *target, const char *args,
 
   inferior_ptid = pid_to_ptid (pid);
 
-  if (non_stop)
+  if (target_is_non_stop_p ())
     {
       struct thread_info *thread;
 
@@ -5052,7 +5151,7 @@ extended_remote_attach (struct target_ops *target, const char *args,
      this before anything involving memory or registers.  */
   target_find_description ();
 
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     {
       /* Use the previously fetched status.  */
       gdb_assert (wait_status != NULL);
@@ -5082,6 +5181,9 @@ extended_remote_attach (struct target_ops *target, const char *args,
 static void
 extended_remote_post_attach (struct target_ops *ops, int pid)
 {
+  /* Get text, data & bss offsets.  */
+  get_offsets ();
+
   /* In certain cases GDB might not have had the chance to start
      symbol lookup up until now.  This could happen if the debugged
      binary is not using shared libraries, the vsyscall page is not
@@ -5314,7 +5416,7 @@ remote_vcont_resume (ptid_t ptid, int step, enum gdb_signal siggnal)
   gdb_assert (strlen (rs->buf) < get_remote_packet_size ());
   putpkt (rs->buf);
 
-  if (non_stop)
+  if (target_is_non_stop_p ())
     {
       /* In non-stop, the stub replies to vCont with "OK".  The stop
         reply will be reported asynchronously by means of a `%Stop'
@@ -5342,7 +5444,7 @@ remote_resume (struct target_ops *ops,
      it is safe to start a 'vNotif' sequence.  It is good to do it
      before resuming inferior, because inferior was stopped and no RSP
      traffic at that moment.  */
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     remote_notif_process (rs->notif_state, &notif_client_stop);
 
   rs->last_sent_signal = siggnal;
@@ -5406,7 +5508,7 @@ remote_resume (struct target_ops *ops,
      only to the base all-stop protocol, however.  In non-stop (which
      only supports vCont), the stub replies with an "OK", and is
      immediate able to process further serial input.  */
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     rs->waiting_for_stop_reply = 1;
 }
 \f
@@ -5593,7 +5695,7 @@ remote_stop (struct target_ops *self, ptid_t ptid)
   if (remote_debug)
     fprintf_unfiltered (gdb_stdlog, "remote_stop called\n");
 
-  if (non_stop)
+  if (target_is_non_stop_p ())
     remote_stop_ns (ptid);
   else
     {
@@ -5611,7 +5713,7 @@ remote_interrupt (struct target_ops *self, ptid_t ptid)
   if (remote_debug)
     fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
 
-  if (non_stop)
+  if (target_is_non_stop_p ())
     {
       /* We don't currently have a way to ^C the remote target in
         non-stop mode.  Stop it (with no signal) instead.  */
@@ -6405,7 +6507,7 @@ Packet: '%s'\n"),
       break;
     }
 
-  if (non_stop && ptid_equal (event->ptid, null_ptid))
+  if (target_is_non_stop_p () && ptid_equal (event->ptid, null_ptid))
     error (_("No process or thread specified in stop reply: %s"), buf);
 }
 
@@ -6755,7 +6857,7 @@ remote_wait (struct target_ops *ops,
 {
   ptid_t event_ptid;
 
-  if (non_stop)
+  if (target_is_non_stop_p ())
     event_ptid = remote_wait_ns (ptid, status, options);
   else
     event_ptid = remote_wait_as (ptid, status, options);
@@ -7984,7 +8086,9 @@ putpkt_binary (const char *buf, int cnt)
      case it's not possible to issue a command while the target is
      running.  This is not a problem in non-stop mode, because in that
      case, the stub is always ready to process serial input.  */
-  if (!non_stop && target_is_async_p () && rs->waiting_for_stop_reply)
+  if (!target_is_non_stop_p ()
+      && target_is_async_p ()
+      && rs->waiting_for_stop_reply)
     {
       error (_("Cannot execute this command while the target is running.\n"
               "Use the \"interrupt\" command to stop the target\n"
@@ -12959,11 +13063,23 @@ remote_async (struct target_ops *ops, int enable)
         event loop to process them.  */
       if (!QUEUE_is_empty (stop_reply_p, stop_reply_queue))
        mark_async_event_handler (remote_async_inferior_event_token);
+      /* For simplicity, below we clear the pending events token
+        without remembering whether it is marked, so here we always
+        mark it.  If there's actually no pending notification to
+        process, this ends up being a no-op (other than a spurious
+        event-loop wakeup).  */
+      if (target_is_non_stop_p ())
+       mark_async_event_handler (rs->notif_state->get_pending_events_token);
     }
   else
     {
       serial_async (rs->remote_desc, NULL, NULL);
+      /* If the core is disabling async, it doesn't want to be
+        disturbed with target events.  Clear all async event sources
+        too.  */
       clear_async_event_handler (remote_async_inferior_event_token);
+      if (target_is_non_stop_p ())
+       clear_async_event_handler (rs->notif_state->get_pending_events_token);
     }
 }
 
index f8103bd531818d14cd024a08bcdd687c142eca60..7d2232f731381937dc5e27b4f9bf62ceab175eca 100644 (file)
@@ -1321,6 +1321,22 @@ info_threads_command (char *arg, int from_tty)
   print_thread_info (current_uiout, arg, -1);
 }
 
+/* See gdbthread.h.  */
+
+void
+switch_to_thread_no_regs (struct thread_info *thread)
+{
+  struct inferior *inf;
+
+  inf = find_inferior_ptid (thread->ptid);
+  gdb_assert (inf != NULL);
+  set_current_program_space (inf->pspace);
+  set_current_inferior (inf);
+
+  inferior_ptid = thread->ptid;
+  stop_pc = ~(CORE_ADDR) 0;
+}
+
 /* Switch from one thread to another.  */
 
 void
This page took 0.043929 seconds and 4 git commands to generate.