This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC: 8/9] Make continuations per-thread in all-stop, and don't context-switch them


This patch removes the last globals that are context-switched,
and makes them always per-thread in either non-stop and all-stop (they're
currently global in all-stop), effectivelly making context_switch just
a wrapper around switch_to_thread (I left it because it prints useful
info for `set debug infrun 1').

The changes I'm making to the continuations are:

 - Add a thread_info argument to add_*continuation, to register
   the continuation in that thread.

 - Add a way to run continuations on all threads, used in
   all-stop mode.  Each continuation is responsible to detect
   if it is being ran due to completion success, or if it is
   being canceled.  E.g., step_1_continuation detects if when
   doing a multi-step, it should proceed to the next iteration, or
   if the stepping was cancelled due to an unrelated event.
   Since in all-stop, the original step_1_continuation, may be
   installed in a thread other than the last that stopped, we
   still need to run the continuation of the original thread.
   For simplicitly, we just go through all threads and run all
   installed continuations.  All threads but one will have no
   continuations installed anyway.  In non-stop, we still only
   run the continuations on the thread that just stopped, as in
   non-stop, each thread can be stepping independently.
   
 - This change starts to make visible that since continuations
   are a per-thread command mechanism, perhaps should be moved
   either to infcmd.c, thread.c, or to its own file.  I volunteer
   to do that in a follow up patch, but as before, I prefer to
   split functional changes, from cleanups.

-- 
Pedro Alves
2008-08-16  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.

---
 gdb/breakpoint.c |    3 
 gdb/defs.h       |   16 ++---
 gdb/gdbthread.h  |   17 +++--
 gdb/inf-loop.c   |   20 +++++-
 gdb/infcmd.c     |    9 +-
 gdb/infrun.c     |    6 -
 gdb/thread.c     |   29 +--------
 gdb/utils.c      |  170 ++++++++++++++++++++++++++++++++++++++++---------------
 8 files changed, 175 insertions(+), 95 deletions(-)

Index: src/gdb/gdbthread.h
===================================================================
--- src.orig/gdb/gdbthread.h	2008-08-16 16:17:13.000000000 +0100
+++ src/gdb/gdbthread.h	2008-08-16 16:17:16.000000000 +0100
@@ -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_
 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: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c	2008-08-16 16:17:13.000000000 +0100
+++ src/gdb/infrun.c	2008-08-16 16:17:16.000000000 +0100
@@ -1728,12 +1728,10 @@ context_switch (ptid_t ptid)
   if (in_thread_list (inferior_ptid) && in_thread_list (ptid))
     {				/* Perform infrun state context switch: */
       /* Save infrun state for the old thread.  */
-      save_infrun_state (inferior_ptid,
-			 cmd_continuation, intermediate_continuation);
+      save_infrun_state (inferior_ptid);
 
       /* Load infrun state for the new thread.  */
-      load_infrun_state (ptid,
-			 &cmd_continuation, &intermediate_continuation);
+      load_infrun_state (ptid);
     }
 
   switch_to_thread (ptid);
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c	2008-08-16 16:17:13.000000000 +0100
+++ src/gdb/thread.c	2008-08-16 16:17:16.000000000 +0100
@@ -106,6 +106,9 @@ clear_thread_inferior_resources (struct 
     }
 
   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 *uiou
 /* 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: src/gdb/utils.c
===================================================================
--- src.orig/gdb/utils.c	2008-08-16 16:13:44.000000000 +0100
+++ src/gdb/utils.c	2008-08-16 16:17:16.000000000 +0100
@@ -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;
@@ -481,10 +475,11 @@ struct continuation
    cmd_continuation. 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 +487,120 @@ add_continuation (void (*continuation_ho
 		    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 THREAD, 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);
+}
+
+static int
+do_all_continuations_thread_callback (struct thread_info *thread, void *data)
+{
+  do_all_continuations_ptid (thread->ptid, &thread->continuations);
+  return 0;
+}
+
+void
+do_all_continuations_thread (struct thread_info *thread)
+{
+  do_all_continuations_thread_callback (thread, NULL);
+}
+
+void
+do_all_continuations (void)
+{
+  iterate_over_threads (do_all_continuations_thread_callback, NULL);
 }
 
 /* Walk down the cmd_continuation list, and get rid of all the
    continuations. */
+int
+discard_all_continuations_thread_callback (struct thread_info *thread,
+					   void *data)
+{
+  struct cleanup *continuation_ptr = &thread->continuations->base;
+  discard_my_cleanups (&continuation_ptr, NULL);
+  thread->continuations = NULL;
+  return 0;
+}
+
+void
+discard_all_continuations_thread (struct thread_info *thread)
+{
+  discard_all_continuations_thread_callback (thread, NULL);
+}
+
 void
 discard_all_continuations (void)
 {
-  struct cleanup *continuation_ptr = &cmd_continuation->base;
-  discard_my_cleanups (&continuation_ptr, NULL);
-  cmd_continuation = NULL;
+  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.  */
 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 +608,7 @@ add_intermediate_continuation (void (*co
 		    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 +619,49 @@ add_intermediate_continuation (void (*co
    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_intermediate_continuations (void)
+static int
+do_all_intermediate_continuations_thread_callback (struct thread_info *thread,
+						   void *data)
 {
-  struct cleanup *continuation_ptr;
-
-  /* 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_continuations_ptid (thread->ptid,
+			     &thread->intermediate_continuations);
+  return 0;
+}
 
-  continuation_ptr = &intermediate_continuation->base;
-  intermediate_continuation = NULL;
+void
+do_all_intermediate_continuations_thread (struct thread_info *thread)
+{
+  do_all_intermediate_continuations_thread_callback (thread, NULL);
+}
 
-  /* Work now on the list we have set aside.  */
-  do_my_cleanups (&continuation_ptr, NULL);
+void
+do_all_intermediate_continuations (void)
+{
+  iterate_over_threads (do_all_intermediate_continuations_thread_callback, NULL);
 }
 
 /* Walk down the cmd_continuation list, and get rid of all the
    continuations. */
+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;
+}
+
+void
+discard_all_intermediate_continuations_thread (struct thread_info *thread)
+{
+  discard_all_intermediate_continuations_thread_callback (thread, NULL);
+}
+
 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);
 }
 
 
Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c	2008-08-16 16:13:44.000000000 +0100
+++ src/gdb/breakpoint.c	2008-08-16 16:17:16.000000000 +0100
@@ -6270,7 +6270,8 @@ until_break_command (char *arg, int from
       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: src/gdb/defs.h
===================================================================
--- src.orig/gdb/defs.h	2008-08-16 16:13:44.000000000 +0100
+++ src/gdb/defs.h	2008-08-16 16:17:16.000000000 +0100
@@ -679,22 +679,24 @@ extern void free_command_lines (struct c
    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: src/gdb/inf-loop.c
===================================================================
--- src.orig/gdb/inf-loop.c	2008-08-16 16:13:44.000000000 +0100
+++ src/gdb/inf-loop.c	2008-08-16 16:17:16.000000000 +0100
@@ -98,13 +98,23 @@ inferior_event_handler (enum inferior_ev
 	 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_ev
     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: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c	2008-08-16 16:17:13.000000000 +0100
+++ src/gdb/infcmd.c	2008-08-16 16:17:16.000000000 +0100
@@ -970,7 +970,7 @@ which has no line number information.\n"
       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));
@@ -978,7 +978,7 @@ which has no line number information.\n"
       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);
     }
 }
 
@@ -1463,7 +1463,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);
@@ -2123,7 +2123,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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]