Remove global continuations in favour of a per-thread
authorPedro Alves <palves@redhat.com>
Mon, 8 Sep 2008 21:57:42 +0000 (21:57 +0000)
committerPedro Alves <palves@redhat.com>
Mon, 8 Sep 2008 21:57:42 +0000 (21:57 +0000)
continuations.

* gdbthread.h (struct thread_info): Add comments around
continuations and intermediate_continuations.
(save_infrun_state, load_infrun_state): Delete continuations and
intermediate_continuations arguments.
* infrun.c (fetch_inferior_event): Only call normal_stop if
stop_soon is NO_STOP_QUIETLY.
(context_switch): Don't context-switch the continuations.
* thread.c (clear_thread_inferior_resources): Discard all
continuations of the thread we're clearing.
(save_infrun_state, load_infrun_state): Delete continuations and
intermediate_continuations arguments, and the code referencing
them.
* utils.c: Include "gdbthread.h".
(cmd_continuation, intermediate_continuation): Delete.
(add_continuation): Add thread_info* argument.  Install the
continuation on it.
(restore_thread_cleanup): New.
(do_all_continuations_ptid, do_all_continuations_thread_callback):
New.
(do_all_continuations): Reimplement.
(discard_all_continuations_thread_callback,
discard_all_continuations_thread): New.
(discard_all_continuations): Reimplement.
(add_intermediate_continuation): Add thread_info* argument.
Install the continuation on it.
(do_all_intermediate_continuations_thread_callback)
(do_all_intermediate_continuations_thread): New.
(do_all_intermediate_continuations): Reimplement.
(discard_all_intermediate_continuations_thread_callback): New.
(discard_all_intermediate_continuations_thread): New.
(discard_all_intermediate_continuations): Reimplement.

* breakpoint.c (until_break_command): Install the continuation on
the current thread.

* defs.h (cmd_continuation, intermediate_continuation): Delete.
(struct thread_info): Forward declare.
(add_continuation, add_intermediate_continuation): Add
thread_info* argument.
(do_all_continuations_thread, discard_all_continuations_thread)
(do_all_intermediate_continuations_thread)
(discard_all_intermediate_continuations_thread): Declare.
* inf-loop.c (inferior_event_handler): In non-stop only run
continuations on the thread that stopped.  In all-stop, run
continuations on all threads.
* infcmd.c (step_once, finish_command): Adjust.

gdb/ChangeLog
gdb/breakpoint.c
gdb/defs.h
gdb/gdbthread.h
gdb/inf-loop.c
gdb/infcmd.c
gdb/thread.c
gdb/utils.c

index 5d363ad4ebc737a28f56e603981cbb1860f73fbf..208157fc6fc2fe85f13b48b9201f46612a27c637 100644 (file)
@@ -1,3 +1,55 @@
+2008-09-08  Pedro Alves  <pedro@codesourcery.com>
+
+       Remove global continuations in favour of a per-thread
+       continuations.
+
+       * gdbthread.h (struct thread_info): Add comments around
+       continuations and intermediate_continuations.
+       (save_infrun_state, load_infrun_state): Delete continuations and
+       intermediate_continuations arguments.
+       * infrun.c (fetch_inferior_event): Only call normal_stop if
+       stop_soon is NO_STOP_QUIETLY.
+       (context_switch): Don't context-switch the continuations.
+       * thread.c (clear_thread_inferior_resources): Discard all
+       continuations of the thread we're clearing.
+       (save_infrun_state, load_infrun_state): Delete continuations and
+       intermediate_continuations arguments, and the code referencing
+       them.
+       * utils.c: Include "gdbthread.h".
+       (cmd_continuation, intermediate_continuation): Delete.
+       (add_continuation): Add thread_info* argument.  Install the
+       continuation on it.
+       (restore_thread_cleanup): New.
+       (do_all_continuations_ptid, do_all_continuations_thread_callback):
+       New.
+       (do_all_continuations): Reimplement.
+       (discard_all_continuations_thread_callback,
+       discard_all_continuations_thread): New.
+       (discard_all_continuations): Reimplement.
+       (add_intermediate_continuation): Add thread_info* argument.
+       Install the continuation on it.
+       (do_all_intermediate_continuations_thread_callback)
+       (do_all_intermediate_continuations_thread): New.
+       (do_all_intermediate_continuations): Reimplement.
+       (discard_all_intermediate_continuations_thread_callback): New.
+       (discard_all_intermediate_continuations_thread): New.
+       (discard_all_intermediate_continuations): Reimplement.
+
+       * breakpoint.c (until_break_command): Install the continuation on
+       the current thread.
+
+       * defs.h (cmd_continuation, intermediate_continuation): Delete.
+       (struct thread_info): Forward declare.
+       (add_continuation, add_intermediate_continuation): Add
+       thread_info* argument.
+       (do_all_continuations_thread, discard_all_continuations_thread)
+       (do_all_intermediate_continuations_thread)
+       (discard_all_intermediate_continuations_thread): Declare.
+       * inf-loop.c (inferior_event_handler): In non-stop only run
+       continuations on the thread that stopped.  In all-stop, run
+       continuations on all threads.
+       * infcmd.c (step_once, finish_command): Adjust.
+
 2008-09-08  Pedro Alves  <pedro@codesourcery.com>
 
        Remove the global stop_step in favour of a per-thread
index 8e6913125251965decc74d2b130f52b51684c164..fa7fb6947761bbef7ab2dd399ba55bef262062a3 100644 (file)
@@ -6320,7 +6320,8 @@ until_break_command (char *arg, int from_tty, int anywhere)
       args->breakpoint2 = breakpoint2;
 
       discard_cleanups (old_chain);
-      add_continuation (until_break_command_continuation, args,
+      add_continuation (inferior_thread (),
+                       until_break_command_continuation, args,
                        xfree);
     }
   else
index e5990c7c88072c23aa1a920f112733509274cabc..8d7e0e4bf0528952fe1535d46e2791cf035ed224 100644 (file)
@@ -681,22 +681,24 @@ extern void free_command_lines (struct command_line **);
    when opening an extended-remote connection. */
 
 struct continuation;
-
-/* In infrun.c. */
-extern struct continuation *cmd_continuation;
-/* Used only by the step_1 function. */
-extern struct continuation *intermediate_continuation;
+struct thread_info;
 
 /* From utils.c */
-extern void add_continuation (void (*)(void *), void *,
+extern void add_continuation (struct thread_info *,
+                             void (*)(void *), void *,
                              void (*)(void *));
 extern void do_all_continuations (void);
+extern void do_all_continuations_thread (struct thread_info *);
 extern void discard_all_continuations (void);
+extern void discard_all_continuations_thread (struct thread_info *);
 
-extern void add_intermediate_continuation (void (*)(void *), void *,
+extern void add_intermediate_continuation (struct thread_info *,
+                                          void (*)(void *), void *,
                                           void (*)(void *));
 extern void do_all_intermediate_continuations (void);
+extern void do_all_intermediate_continuations_thread (struct thread_info *);
 extern void discard_all_intermediate_continuations (void);
+extern void discard_all_intermediate_continuations_thread (struct thread_info *);
 
 /* String containing the current directory (what getwd would return).  */
 
index 398b713e7807a9598c17cfe32c27a8249af904b0..1510058c427519d981e260fef757a35932bd9aa5 100644 (file)
@@ -136,9 +136,16 @@ 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.  */
+
+  /* Pointer to what is left to do for an execution command after the
+     target stops.  Used only in asynchronous mode, by targets that
+     support async execution.  Several execution commands use it.  */
   struct continuation *continuations;
+
+  /* Similar to the above, but used when a single execution command
+     requires several resume/stop iterations.  Used by the step
+     command.  */
   struct continuation *intermediate_continuations;
 
   /* Nonzero if the thread is being proceeded for a "finish" command
@@ -226,15 +233,11 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
 extern int thread_count (void);
 
 /* infrun context switch: save the debugger state for the given thread.  */
-extern void save_infrun_state (ptid_t ptid,
-                              struct continuation *continuations,
-                              struct continuation *intermediate_continuations);
+extern void save_infrun_state (ptid_t ptid);
 
 /* infrun context switch: load the debugger state previously saved
    for the given thread.  */
-extern void load_infrun_state (ptid_t ptid,
-                              struct continuation **continuations,
-                              struct continuation **intermediate_continuations);
+extern void load_infrun_state (ptid_t ptid);
 
 /* Switch from one thread to another.  */
 extern void switch_to_thread (ptid_t ptid);
index 17fbd929999c05cd4dbff29fe4a9a337019309dc..8c2c282e18be3e5bb217b5ffe63dcf9f9623420b 100644 (file)
@@ -98,13 +98,23 @@ inferior_event_handler (enum inferior_event_type event_type,
         touch the inferior memory, e.g. to remove breakpoints, so run
         them before running breakpoint commands, which may resume the
         target.  */
-      do_all_intermediate_continuations ();
+      if (non_stop
+         && target_has_execution
+         && !ptid_equal (inferior_ptid, null_ptid))
+       do_all_intermediate_continuations_thread (inferior_thread ());
+      else
+       do_all_intermediate_continuations ();
 
       /* Always finish the previous command before running any
         breakpoint commands.  Any stop cancels the previous command.
         E.g. a "finish" or "step-n" command interrupted by an
         unrelated breakpoint is canceled.  */
-      do_all_continuations ();
+      if (non_stop
+         && target_has_execution
+         && !ptid_equal (inferior_ptid, null_ptid))
+       do_all_continuations_thread (inferior_thread ());
+      else
+       do_all_continuations ();
 
       if (current_language != expected_language
          && language_mode == language_mode_auto)
@@ -125,7 +135,11 @@ inferior_event_handler (enum inferior_event_type event_type,
     case INF_EXEC_CONTINUE:
       /* Is there anything left to do for the command issued to
          complete? */
-      do_all_intermediate_continuations ();
+
+      if (non_stop)
+       do_all_intermediate_continuations_thread (inferior_thread ());
+      else
+       do_all_intermediate_continuations ();
       break;
 
     case INF_QUIT_REQ: 
index a4c6c94a47cc1bcd24cb900b8406974f67786c2f..8bcfd63e1ad153d6ce6090bfc861f5665d6755bd 100644 (file)
@@ -947,7 +947,7 @@ which has no line number information.\n"), name);
       if (skip_subroutines)
        tp->step_over_calls = STEP_OVER_ALL;
 
-      inferior_thread ()->step_multi = (count > 1);
+      tp->step_multi = (count > 1);
       proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
 
       args = xmalloc (sizeof (*args));
@@ -955,7 +955,7 @@ which has no line number information.\n"), name);
       args->single_inst = single_inst;
       args->count = count;
       args->thread = thread;
-      add_intermediate_continuation (step_1_continuation, args, xfree);
+      add_intermediate_continuation (tp, step_1_continuation, args, xfree);
     }
 }
 
@@ -1440,7 +1440,7 @@ finish_command (char *arg, int from_tty)
 
   cargs->breakpoint = breakpoint;
   cargs->function = function;
-  add_continuation (finish_command_continuation, cargs,
+  add_continuation (tp, finish_command_continuation, cargs,
                    finish_command_continuation_free_arg);
 
   discard_cleanups (old_chain);
@@ -2103,7 +2103,8 @@ attach_command (char *args, int from_tty)
          a->args = xstrdup (args);
          a->from_tty = from_tty;
          a->async_exec = async_exec;
-         add_continuation (attach_command_continuation, a,
+         add_continuation (inferior_thread (),
+                           attach_command_continuation, a,
                            attach_command_continuation_free_args);
          return;
        }
index 39b353eb0370b39ab8f5ae29036e7b139d6dedae..8ebdff3abe7c1351fa53ffe215f886926450da55 100644 (file)
@@ -106,6 +106,9 @@ clear_thread_inferior_resources (struct thread_info *tp)
     }
 
   bpstat_clear (&tp->stop_bpstat);
+
+  discard_all_intermediate_continuations_thread (tp);
+  discard_all_continuations_thread (tp);
 }
 
 static void
@@ -442,9 +445,7 @@ gdb_list_thread_ids (struct ui_out *uiout, char **error_message)
 /* Load infrun state for the thread PID.  */
 
 void
-load_infrun_state (ptid_t ptid,
-                  struct continuation **continuations,
-                  struct continuation **intermediate_continuations)
+load_infrun_state (ptid_t ptid)
 {
   struct thread_info *tp;
 
@@ -453,24 +454,12 @@ load_infrun_state (ptid_t ptid,
   tp = find_thread_id (pid_to_thread_id (ptid));
   if (tp == NULL)
     return;
-
-  /* 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;
-    }
 }
 
 /* Save infrun state for the thread PID.  */
 
 void
-save_infrun_state (ptid_t ptid,
-                  struct continuation *continuations,
-                  struct continuation *intermediate_continuations)
+save_infrun_state (ptid_t ptid)
 {
   struct thread_info *tp;
 
@@ -479,14 +468,6 @@ save_infrun_state (ptid_t ptid,
   tp = find_thread_id (pid_to_thread_id (ptid));
   if (tp == NULL)
     return;
-
-  /* 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;
-    }
 }
 
 /* Return true if TP is an active thread. */
index 4aa336765047eb1eaf79a535e2819f247e24ed2e..ce05909fc7b3ae275111836c0fe9ece23ade01c4 100644 (file)
@@ -25,6 +25,7 @@
 #include "gdb_string.h"
 #include "event-top.h"
 #include "exceptions.h"
+#include "gdbthread.h"
 
 #ifdef TUI
 #include "tui/tui.h"           /* For tui_get_command_dimension.   */
@@ -105,13 +106,6 @@ static int debug_timestamp = 0;
 static struct cleanup *cleanup_chain;  /* cleaned up after a failed command */
 static struct cleanup *final_cleanup_chain;    /* cleaned up when gdb exits */
 
-/* Pointer to what is left to do for an execution command after the
-   target stops. Used only in asynchronous mode, by targets that
-   support async execution.  The finish and until commands use it. So
-   does the target extended-remote command. */
-struct continuation *cmd_continuation;
-struct continuation *intermediate_continuation;
-
 /* Nonzero if we have job control. */
 
 int job_control;
@@ -477,14 +471,14 @@ struct continuation
   struct cleanup base;
 };
 
-/* Add a continuation to the continuation list, the global list
-   cmd_continuation. The new continuation will be added at the
-   front.  */
+/* Add a continuation to the continuation list of THREAD.  The new
+   continuation will be added at the front.  */
 void
-add_continuation (void (*continuation_hook) (void *), void *args,
+add_continuation (struct thread_info *thread,
+                 void (*continuation_hook) (void *), void *args,
                  void (*continuation_free_args) (void *))
 {
-  struct cleanup *as_cleanup = &cmd_continuation->base;
+  struct cleanup *as_cleanup = &thread->continuations->base;
   make_cleanup_ftype *continuation_hook_fn = continuation_hook;
 
   make_my_cleanup2 (&as_cleanup,
@@ -492,53 +486,122 @@ add_continuation (void (*continuation_hook) (void *), void *args,
                    args,
                    continuation_free_args);
 
-  cmd_continuation = (struct continuation *) as_cleanup;
+  thread->continuations = (struct continuation *) as_cleanup;
 }
 
-/* Walk down the cmd_continuation list, and execute all the
-   continuations. There is a problem though. In some cases new
-   continuations may be added while we are in the middle of this
-   loop. If this happens they will be added in the front, and done
-   before we have a chance of exhausting those that were already
-   there. We need to then save the beginning of the list in a pointer
-   and do the continuations from there on, instead of using the
-   global beginning of list as our iteration pointer.  */
-void
-do_all_continuations (void)
+static void
+restore_thread_cleanup (void *arg)
 {
-  struct cleanup *continuation_ptr;
+  ptid_t *ptid_p = arg;
+  switch_to_thread (*ptid_p);
+}
+
+/* Walk down the continuation list of PTID, and execute all the
+   continuations.  There is a problem though.  In some cases new
+   continuations may be added while we are in the middle of this loop.
+   If this happens they will be added in the front, and done before we
+   have a chance of exhausting those that were already there.  We need
+   to then save the beginning of the list in a pointer and do the
+   continuations from there on, instead of using the global beginning
+   of list as our iteration pointer.  */
+static void
+do_all_continuations_ptid (ptid_t ptid,
+                          struct continuation **continuations_p)
+{
+  struct cleanup *old_chain;
+  ptid_t current_thread;
+  struct cleanup *as_cleanup;
+
+  if (*continuations_p == NULL)
+    return;
+
+  current_thread = inferior_ptid;
+
+  /* Restore selected thread on exit.  Don't try to restore the frame
+     as well, because:
+
+    - When running continuations, the selected frame is always #0.
+
+    - The continuations may trigger symbol file loads, which may
+      change the frame layout (frame ids change), which would trigger
+      a warning if we used make_cleanup_restore_current_thread.  */
+
+  old_chain = make_cleanup (restore_thread_cleanup, &current_thread);
+
+  /* Let the continuation see this thread as selected.  */
+  switch_to_thread (ptid);
 
   /* Copy the list header into another pointer, and set the global
      list header to null, so that the global list can change as a side
      effect of invoking the continuations and the processing of the
      preexisting continuations will not be affected.  */
 
-  continuation_ptr = &cmd_continuation->base;
-  cmd_continuation = NULL;
+  as_cleanup = &(*continuations_p)->base;
+  *continuations_p = NULL;
 
   /* Work now on the list we have set aside.  */
-  do_my_cleanups (&continuation_ptr, NULL);
+  do_my_cleanups (&as_cleanup, NULL);
+
+  do_cleanups (old_chain);
 }
 
-/* Walk down the cmd_continuation list, and get rid of all the
-   continuations. */
+/* Callback for iterate over threads.  */
+static int
+do_all_continuations_thread_callback (struct thread_info *thread, void *data)
+{
+  do_all_continuations_ptid (thread->ptid, &thread->continuations);
+  return 0;
+}
+
+/* Do all continuations of thread THREAD.  */
 void
-discard_all_continuations (void)
+do_all_continuations_thread (struct thread_info *thread)
+{
+  do_all_continuations_thread_callback (thread, NULL);
+}
+
+/* Do all continuations of all threads.  */
+void
+do_all_continuations (void)
+{
+  iterate_over_threads (do_all_continuations_thread_callback, NULL);
+}
+
+/* Callback for iterate over threads.  */
+static int
+discard_all_continuations_thread_callback (struct thread_info *thread,
+                                          void *data)
 {
-  struct cleanup *continuation_ptr = &cmd_continuation->base;
+  struct cleanup *continuation_ptr = &thread->continuations->base;
   discard_my_cleanups (&continuation_ptr, NULL);
-  cmd_continuation = NULL;
+  thread->continuations = NULL;
+  return 0;
+}
+
+/* Get rid of all the continuations of THREAD.  */
+void
+discard_all_continuations_thread (struct thread_info *thread)
+{
+  discard_all_continuations_thread_callback (thread, NULL);
+}
+
+/* Get rid of all the continuations of all threads.  */
+void
+discard_all_continuations (void)
+{
+  iterate_over_threads (discard_all_continuations_thread_callback, NULL);
 }
 
-/* Add a continuation to the continuation list, the global list
-   intermediate_continuation.  The new continuation will be added at
-   the front.  */
+
+/* Add a continuation to the intermediate continuation list of THREAD.
+   The new continuation will be added at the front.  */
 void
-add_intermediate_continuation (void (*continuation_hook)
+add_intermediate_continuation (struct thread_info *thread,
+                              void (*continuation_hook)
                               (void *), void *args,
                               void (*continuation_free_args) (void *))
 {
-  struct cleanup *as_cleanup = &intermediate_continuation->base;
+  struct cleanup *as_cleanup = &thread->intermediate_continuations->base;
   make_cleanup_ftype *continuation_hook_fn = continuation_hook;
 
   make_my_cleanup2 (&as_cleanup,
@@ -546,7 +609,7 @@ add_intermediate_continuation (void (*continuation_hook)
                    args,
                    continuation_free_args);
 
-  intermediate_continuation = (struct continuation *) as_cleanup;
+  thread->intermediate_continuations = (struct continuation *) as_cleanup;
 }
 
 /* Walk down the cmd_continuation list, and execute all the
@@ -557,31 +620,52 @@ add_intermediate_continuation (void (*continuation_hook)
    there. We need to then save the beginning of the list in a pointer
    and do the continuations from there on, instead of using the
    global beginning of list as our iteration pointer.*/
+static int
+do_all_intermediate_continuations_thread_callback (struct thread_info *thread,
+                                                  void *data)
+{
+  do_all_continuations_ptid (thread->ptid,
+                            &thread->intermediate_continuations);
+  return 0;
+}
+
+/* Do all intermediate continuations of thread THREAD.  */
 void
-do_all_intermediate_continuations (void)
+do_all_intermediate_continuations_thread (struct thread_info *thread)
 {
-  struct cleanup *continuation_ptr;
+  do_all_intermediate_continuations_thread_callback (thread, NULL);
+}
 
-  /* Copy the list header into another pointer, and set the global
-     list header to null, so that the global list can change as a side
-     effect of invoking the continuations and the processing of the
-     preexisting continuations will not be affected.  */
+/* Do all intermediate continuations of all threads.  */
+void
+do_all_intermediate_continuations (void)
+{
+  iterate_over_threads (do_all_intermediate_continuations_thread_callback, NULL);
+}
 
-  continuation_ptr = &intermediate_continuation->base;
-  intermediate_continuation = NULL;
+/* Callback for iterate over threads.  */
+static int
+discard_all_intermediate_continuations_thread_callback (struct thread_info *thread,
+                                                       void *data)
+{
+  struct cleanup *continuation_ptr = &thread->intermediate_continuations->base;
+  discard_my_cleanups (&continuation_ptr, NULL);
+  thread->intermediate_continuations = NULL;
+  return 0;
+}
 
-  /* Work now on the list we have set aside.  */
-  do_my_cleanups (&continuation_ptr, NULL);
+/* Get rid of all the intermediate continuations of THREAD.  */
+void
+discard_all_intermediate_continuations_thread (struct thread_info *thread)
+{
+  discard_all_intermediate_continuations_thread_callback (thread, NULL);
 }
 
-/* Walk down the cmd_continuation list, and get rid of all the
-   continuations. */
+/* Get rid of all the intermediate continuations of all threads.  */
 void
 discard_all_intermediate_continuations (void)
 {
-  struct cleanup *continuation_ptr = &intermediate_continuation->base;
-  discard_my_cleanups (&continuation_ptr, NULL);
-  continuation_ptr = NULL;
+  iterate_over_threads (discard_all_intermediate_continuations_thread_callback, NULL);
 }
 \f