Per-thread commands.
authorPedro Alves <palves@redhat.com>
Wed, 9 Jul 2008 22:30:46 +0000 (22:30 +0000)
committerPedro Alves <palves@redhat.com>
Wed, 9 Jul 2008 22:30:46 +0000 (22:30 +0000)
* gdbthread.h: Remove unneeded forward declarations.
Include "inferior.h".
(struct thread_info): Add continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi and stop_signal members.
(save_infrun_state): Add continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi, stop_signal and stop_bpstat parameters.
(load_infrun_state): Add continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi, stop_signal and stop_bpstat parameters.

* thread.c (load_infrun_state): In non-stop mode, load
continuations, intermediate_continuations, proceed_to_finish,
step_over_calls, stop_step, step_multi and stop_signal.
(save_infrun_state): Store continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi, stop_signal and stop_bpstat.
(save_infrun_state): Store continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi, stop_signal and stop_bpstat.
(free_thread): Clear The thread's stop_bpstat.

* inferior.h (context_switch_to): Declare.

* infrun.c (ecss): New global.
(context_switch): Context switch continuations,
intermediate_continuations, proceed_to_finish, step_over_calls,
stop_step, step_multi, stop_signal and stop_bpstat.
(wait_for_inferior): Use global ecss.
(async_ecss, async_ecs): Delete.
(fetch_inferior_event): Use global ecss.
(context_switch_to): New.

* top.c (execute_command): In non-stop, only check if the current
thread is running, in all-stop, check if there's any thread
running.

* breakpoint.c (bpstat_remove_breakpoint): New.
(bpstat_remove_breakpoint_callback): New.
(delete_breakpoint): Clear the stop_bpstats of all threads.

* mi/mi-main.c (mi_cmd_execute): In non-stop, only check if the
current thread is running, in all-stop, check if there's any
thread running.

* Makefile.in (gdbthread_h): Depend on $(inferior_h).

gdb/ChangeLog
gdb/Makefile.in
gdb/breakpoint.c
gdb/gdbthread.h
gdb/inferior.h
gdb/infrun.c
gdb/mi/mi-main.c
gdb/thread.c
gdb/top.c

index 1b368739fd57d6e2a69fba368e2688e868235078..e4ead4c63bad2d2f0ecfa65c4f3525fed9b56a39 100644 (file)
@@ -1,3 +1,56 @@
+2008-07-09  Pedro Alves  <pedro@codesourcery.com>
+           Vladimir Prus  <vladimir@codesourcery.com>
+
+       Per-thread commands.
+
+       * gdbthread.h: Remove unneeded forward declarations.
+       Include "inferior.h".
+       (struct thread_info): Add continuations,
+       intermediate_continuations, proceed_to_finish, step_over_calls,
+       stop_step, step_multi and stop_signal members.
+       (save_infrun_state): Add continuations,
+       intermediate_continuations, proceed_to_finish, step_over_calls,
+       stop_step, step_multi, stop_signal and stop_bpstat parameters.
+       (load_infrun_state): Add continuations,
+       intermediate_continuations, proceed_to_finish, step_over_calls,
+       stop_step, step_multi, stop_signal and stop_bpstat parameters.
+
+       * thread.c (load_infrun_state): In non-stop mode, load
+       continuations, intermediate_continuations, proceed_to_finish,
+       step_over_calls, stop_step, step_multi and stop_signal.
+       (save_infrun_state): Store continuations,
+       intermediate_continuations, proceed_to_finish, step_over_calls,
+       stop_step, step_multi, stop_signal and stop_bpstat.
+       (save_infrun_state): Store continuations,
+       intermediate_continuations, proceed_to_finish, step_over_calls,
+       stop_step, step_multi, stop_signal and stop_bpstat.
+       (free_thread): Clear The thread's stop_bpstat.
+
+       * inferior.h (context_switch_to): Declare.
+
+       * infrun.c (ecss): New global.
+       (context_switch): Context switch continuations,
+       intermediate_continuations, proceed_to_finish, step_over_calls,
+       stop_step, step_multi, stop_signal and stop_bpstat.
+       (wait_for_inferior): Use global ecss.
+       (async_ecss, async_ecs): Delete.
+       (fetch_inferior_event): Use global ecss.
+       (context_switch_to): New.
+
+       * top.c (execute_command): In non-stop, only check if the current
+       thread is running, in all-stop, check if there's any thread
+       running.
+
+       * breakpoint.c (bpstat_remove_breakpoint): New.
+       (bpstat_remove_breakpoint_callback): New.
+       (delete_breakpoint): Clear the stop_bpstats of all threads.
+
+       * mi/mi-main.c (mi_cmd_execute): In non-stop, only check if the
+       current thread is running, in all-stop, check if there's any
+       thread running.
+
+       * Makefile.in (gdbthread_h): Depend on $(inferior_h).
+
 2008-07-09  Pedro Alves  <pedro@codesourcery.com>
 
        Add non_stop global.
index f12d38589673e7195b3041ed05fb6555b61359c3..d041e30fc7344766fed6df637573d0d86bfbcee9 100644 (file)
@@ -800,7 +800,7 @@ gdb_stabs_h = gdb-stabs.h
 gdb_stat_h = gdb_stat.h
 gdb_string_h = gdb_string.h
 gdb_thread_db_h = gdb_thread_db.h
-gdbthread_h = gdbthread.h $(breakpoint_h) $(frame_h) $(ui_out_h)
+gdbthread_h = gdbthread.h $(breakpoint_h) $(frame_h) $(ui_out_h) $(inferior_h)
 gdbtypes_h = gdbtypes.h $(hashtab_h)
 gdb_vfork_h = gdb_vfork.h
 gdb_wait_h = gdb_wait.h
index 3020de2114524110337a0eda1d9647c9591f0d50..ed99ca7778a515ef0fa5e265df72c14a7ebf95c0 100644 (file)
@@ -7168,6 +7168,29 @@ update_global_location_list_nothrow (int inserting)
     update_global_location_list (inserting);
 }
 
+/* Clear BPT from a BPS.  */
+static void
+bpstat_remove_breakpoint (bpstat bps, struct breakpoint *bpt)
+{
+  bpstat bs;
+  for (bs = bps; bs; bs = bs->next)
+    if (bs->breakpoint_at && bs->breakpoint_at->owner == bpt)
+      {
+       bs->breakpoint_at = NULL;
+       bs->old_val = NULL;
+       /* bs->commands will be freed later.  */
+      }
+}
+
+/* Callback for iterate_over_threads.  */
+static int
+bpstat_remove_breakpoint_callback (struct thread_info *th, void *data)
+{
+  struct breakpoint *bpt = data;
+  bpstat_remove_breakpoint (th->stop_bpstat, bpt);
+  return 0;
+}
+
 /* Delete a breakpoint and clean up all traces of it in the data
    structures. */
 
@@ -7175,7 +7198,6 @@ void
 delete_breakpoint (struct breakpoint *bpt)
 {
   struct breakpoint *b;
-  bpstat bs;
   struct bp_location *loc, *next;
 
   gdb_assert (bpt != NULL);
@@ -7239,13 +7261,11 @@ delete_breakpoint (struct breakpoint *bpt)
          bpstat_do_actions (&stop_bpstat);
      in event-top.c won't do anything, and temporary breakpoints
      with commands won't work.  */
-  for (bs = stop_bpstat; bs; bs = bs->next)
-    if (bs->breakpoint_at && bs->breakpoint_at->owner == bpt)
-      {
-       bs->breakpoint_at = NULL;
-       bs->old_val = NULL;
-       /* bs->commands will be freed later.  */
-      }
+
+  /* Clear the current context.  */
+  bpstat_remove_breakpoint (stop_bpstat, bpt);
+  /* And from all threads.  */
+  iterate_over_threads (bpstat_remove_breakpoint_callback, bpt);
 
   /* Now that breakpoint is removed from breakpoint
      list, update the global location list.  This
index 389b2fc24fcb6f886c0688320b62ea746d0a5774..76b8f6cb5399d5d3c085903df6cb50dd77c3054f 100644 (file)
 #ifndef GDBTHREAD_H
 #define GDBTHREAD_H
 
-struct breakpoint;
-struct frame_id;
 struct symtab;
 
-/* For bpstat */
 #include "breakpoint.h"
-
-/* For struct frame_id.  */
 #include "frame.h"
-
 #include "ui-out.h"
+#include "inferior.h"
 
 struct thread_info
 {
@@ -82,6 +77,20 @@ struct thread_info
      when we finally do stop stepping.  */
   bpstat stepping_through_solib_catchpoints;
 
+  /* The below are only per-thread in non-stop mode.  */
+  /* Per-thread command support.  */
+  struct continuation *continuations;
+  struct continuation *intermediate_continuations;
+  int proceed_to_finish;
+  enum step_over_calls_kind step_over_calls;
+  int stop_step;
+  int step_multi;
+
+  enum target_signal stop_signal;
+  /* Used in continue_command to set the proceed count of the
+     breakpoint the thread stopped at.  */
+  bpstat stop_bpstat;
+
   /* Private data used by the target vector implementation.  */
   struct private_thread_info *private;
 };
@@ -152,7 +161,15 @@ extern void save_infrun_state (ptid_t ptid,
                               int       stepping_through_solib_after_catch,
                               bpstat    stepping_through_solib_catchpoints,
                               int       current_line,
-                              struct symtab *current_symtab);
+                              struct symtab *current_symtab,
+                              struct continuation *continuations,
+                              struct continuation *intermediate_continuations,
+                              int proceed_to_finish,
+                              enum step_over_calls_kind step_over_calls,
+                              int stop_step,
+                              int step_multi,
+                              enum target_signal stop_signal,
+                              bpstat stop_bpstat);
 
 /* infrun context switch: load the debugger state previously saved
    for the given thread.  */
@@ -164,10 +181,18 @@ extern void load_infrun_state (ptid_t ptid,
                               CORE_ADDR *step_range_end,
                               struct frame_id *step_frame_id,
                               int       *another_trap,
-                              int       *stepping_through_solib_affter_catch,
+                              int       *stepping_through_solib_after_catch,
                               bpstat    *stepping_through_solib_catchpoints,
                               int       *current_line,
-                              struct symtab **current_symtab);
+                              struct symtab **current_symtab,
+                              struct continuation **continuations,
+                              struct continuation **intermediate_continuations,
+                              int *proceed_to_finish,
+                              enum step_over_calls_kind *step_over_calls,
+                              int *stop_step,
+                              int *step_multi,
+                              enum target_signal *stop_signal,
+                              bpstat *stop_bpstat);
 
 /* Switch from one thread to another.  */
 extern void switch_to_thread (ptid_t ptid);
index 9cbf4b4f188d44a4bf7fc78b6f09a330d5d80576..e89fb74b978bad14e369e1845c87017226d6a141 100644 (file)
@@ -132,6 +132,8 @@ extern void clear_proceed_status (void);
 
 extern void proceed (CORE_ADDR, enum target_signal, int);
 
+extern ptid_t context_switch_to (ptid_t ptid);
+
 /* When set, stop the 'step' command if we enter a function which has
    no line number information.  The normal behavior is that we step
    over such function.  */
index d9eca9fe1c75264e76a9294b32b7edc752ec6d94..457c0a0da0c52f42e31ea208891f6348244bdbe0 100644 (file)
@@ -288,6 +288,8 @@ static struct breakpoint *step_resume_breakpoint = NULL;
 static ptid_t target_last_wait_ptid;
 static struct target_waitstatus target_last_waitstatus;
 
+struct execution_control_state ecss;
+
 /* This is used to remember when a fork, vfork or exec event
    was caught by a catchpoint, and thus the event is to be
    followed at the next resume of the inferior, and not
@@ -1429,7 +1431,6 @@ void
 wait_for_inferior (int treat_exec_as_sigtrap)
 {
   struct cleanup *old_cleanups;
-  struct execution_control_state ecss;
   struct execution_control_state *ecs;
 
   if (debug_infrun)
@@ -1440,8 +1441,6 @@ wait_for_inferior (int treat_exec_as_sigtrap)
   old_cleanups = make_cleanup (delete_step_resume_breakpoint,
                               &step_resume_breakpoint);
 
-  /* wfi still stays in a loop, so it's OK just to take the address of
-     a local to get the ecs pointer.  */
   ecs = &ecss;
 
   /* Fill in with reasonable starting values.  */
@@ -1487,25 +1486,20 @@ wait_for_inferior (int treat_exec_as_sigtrap)
    event loop whenever a change of state is detected on the file
    descriptor corresponding to the target. It can be called more than
    once to complete a single execution command. In such cases we need
-   to keep the state in a global variable ASYNC_ECSS. If it is the
-   last time that this function is called for a single execution
-   command, then report to the user that the inferior has stopped, and
-   do the necessary cleanups. */
-
-struct execution_control_state async_ecss;
-struct execution_control_state *async_ecs;
+   to keep the state in a global variable ECSS. If it is the last time
+   that this function is called for a single execution command, then
+   report to the user that the inferior has stopped, and do the
+   necessary cleanups. */
 
 void
 fetch_inferior_event (void *client_data)
 {
-  static struct cleanup *old_cleanups;
-
-  async_ecs = &async_ecss;
+  struct execution_control_state *ecs = &ecss;
 
-  if (!async_ecs->wait_some_more)
+  if (!ecs->wait_some_more)
     {
       /* Fill in with reasonable starting values.  */
-      init_execution_control_state (async_ecs);
+      init_execution_control_state (ecs);
 
       /* We'll update this if & when we switch to a new thread. */
       previous_inferior_ptid = inferior_ptid;
@@ -1522,15 +1516,15 @@ fetch_inferior_event (void *client_data)
     }
 
   if (deprecated_target_wait_hook)
-    async_ecs->ptid =
-      deprecated_target_wait_hook (async_ecs->waiton_ptid, async_ecs->wp);
+    ecs->ptid =
+      deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
   else
-    async_ecs->ptid = target_wait (async_ecs->waiton_ptid, async_ecs->wp);
+    ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
 
   /* Now figure out what to do with the result of the result.  */
-  handle_inferior_event (async_ecs);
+  handle_inferior_event (ecs);
 
-  if (!async_ecs->wait_some_more)
+  if (!ecs->wait_some_more)
     {
       delete_step_resume_breakpoint (&step_resume_breakpoint);
 
@@ -1608,7 +1602,14 @@ context_switch (struct execution_control_state *ecs)
                         ecs->stepping_over_breakpoint,
                         ecs->stepping_through_solib_after_catch,
                         ecs->stepping_through_solib_catchpoints,
-                        ecs->current_line, ecs->current_symtab);
+                        ecs->current_line, ecs->current_symtab,
+                        cmd_continuation, intermediate_continuation,
+                        proceed_to_finish,
+                        step_over_calls,
+                        stop_step,
+                        step_multi,
+                        stop_signal,
+                        stop_bpstat);
 
       /* Load infrun state for the new thread.  */
       load_infrun_state (ecs->ptid, &prev_pc,
@@ -1618,12 +1619,34 @@ context_switch (struct execution_control_state *ecs)
                         &ecs->stepping_over_breakpoint,
                         &ecs->stepping_through_solib_after_catch,
                         &ecs->stepping_through_solib_catchpoints,
-                        &ecs->current_line, &ecs->current_symtab);
+                        &ecs->current_line, &ecs->current_symtab,
+                        &cmd_continuation, &intermediate_continuation,
+                        &proceed_to_finish,
+                        &step_over_calls,
+                        &stop_step,
+                        &step_multi,
+                        &stop_signal,
+                        &stop_bpstat);
     }
 
   switch_to_thread (ecs->ptid);
 }
 
+/* Context switch to thread PTID.  */
+ptid_t
+context_switch_to (ptid_t ptid)
+{
+  ptid_t current_ptid = inferior_ptid;
+
+  /* Context switch to the new thread. */
+  if (!ptid_equal (ptid, inferior_ptid))
+    {
+      ecss.ptid = ptid;
+      context_switch (&ecss);
+    }
+  return current_ptid;
+}
+
 static void
 adjust_pc_after_break (struct execution_control_state *ecs)
 {
index 5318a4a19b8a513ccaffa8767676826726a38e2c..06e9d63b0e4ebcbb4a52efc2208e0f699aefcd5b 100644 (file)
@@ -1059,7 +1059,8 @@ mi_cmd_execute (struct mi_parse *parse)
 
   if (parse->cmd->argv_func != NULL)
     {
-      if (is_running (inferior_ptid))
+      if ((!non_stop && any_running ())
+         || (non_stop && is_running (inferior_ptid)))
        {
          if (strcmp (parse->command, "exec-interrupt"))
            {
index 9bd5f04d23b751376af4948789f307433e22d8f9..e2f8cd7f3432aa754e458ee254680ae3167b852b 100644 (file)
@@ -93,6 +93,8 @@ free_thread (struct thread_info *tp)
   if (tp->step_resume_breakpoint)
     tp->step_resume_breakpoint->disposition = disp_del_at_next_stop;
 
+  bpstat_clear (&tp->stop_bpstat);
+
   /* FIXME: do I ever need to call the back-end to give it a
      chance at this private data before deleting the thread?  */
   if (tp->private)
@@ -358,7 +360,15 @@ load_infrun_state (ptid_t ptid,
                   int *stepping_through_solib_after_catch,
                   bpstat *stepping_through_solib_catchpoints,
                   int *current_line,
-                  struct symtab **current_symtab)
+                  struct symtab **current_symtab,
+                  struct continuation **continuations,
+                  struct continuation **intermediate_continuations,
+                  int *proceed_to_finish,
+                  enum step_over_calls_kind *step_over_calls,
+                  int *stop_step,
+                  int *step_multi,
+                  enum target_signal *stop_signal,
+                  bpstat *stop_bpstat)
 {
   struct thread_info *tp;
 
@@ -381,6 +391,26 @@ load_infrun_state (ptid_t ptid,
     tp->stepping_through_solib_catchpoints;
   *current_line = tp->current_line;
   *current_symtab = tp->current_symtab;
+
+  /* In all-stop mode, these are global state, while in non-stop mode,
+     they are per thread.  */
+  if (non_stop)
+    {
+      *continuations = tp->continuations;
+      tp->continuations = NULL;
+      *intermediate_continuations = tp->intermediate_continuations;
+      tp->intermediate_continuations = NULL;
+      *proceed_to_finish = tp->proceed_to_finish;
+      *step_over_calls = tp->step_over_calls;
+      *stop_step = tp->stop_step;
+      *step_multi = tp->step_multi;
+      *stop_signal = tp->stop_signal;
+
+      /* Swap instead of copy, so we only have to update one of
+        them.  */
+      *stop_bpstat = tp->stop_bpstat;
+      tp->stop_bpstat = 0;
+    }
 }
 
 /* Save infrun state for the thread PID.  */
@@ -397,7 +427,15 @@ save_infrun_state (ptid_t ptid,
                   int stepping_through_solib_after_catch,
                   bpstat stepping_through_solib_catchpoints,
                   int current_line,
-                  struct symtab *current_symtab)
+                  struct symtab *current_symtab,
+                  struct continuation *continuations,
+                  struct continuation *intermediate_continuations,
+                  int proceed_to_finish,
+                  enum step_over_calls_kind step_over_calls,
+                  int stop_step,
+                  int step_multi,
+                  enum target_signal stop_signal,
+                  bpstat stop_bpstat)
 {
   struct thread_info *tp;
 
@@ -418,6 +456,20 @@ save_infrun_state (ptid_t ptid,
   tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints;
   tp->current_line = current_line;
   tp->current_symtab = current_symtab;
+
+  /* In all-stop mode, these are global state, while in non-stop mode,
+     they are per thread.  */
+  if (non_stop)
+    {
+      tp->continuations = continuations;
+      tp->intermediate_continuations = intermediate_continuations;
+      tp->proceed_to_finish = proceed_to_finish;
+      tp->step_over_calls = step_over_calls;
+      tp->stop_step = stop_step;
+      tp->step_multi = step_multi;
+      tp->stop_signal = stop_signal;
+      tp->stop_bpstat = stop_bpstat;
+    }
 }
 
 /* Return true if TP is an active thread. */
index 84894346697c35b5a5c94105daca72f29f045e29..fe4b1d0aebdf27383f64807e9d81c7405fffb6d2 100644 (file)
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -418,7 +418,8 @@ execute_command (char *p, int from_tty)
       /* If the target is running, we allow only a limited set of
          commands. */
       if (target_can_async_p ()
-         && any_running ()
+         && ((!non_stop && any_running ())
+             || (non_stop && is_running (inferior_ptid)))
          && !get_cmd_async_ok (c))
        error (_("Cannot execute this command while the target is running."));