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]

[PATCH 2/5] New command: scope


This patch adds a new command "scope", which can set the current
itset, and invoke other commands, which assign "target set" of these
commands.  For example,

  scope ITSET COMMAND

The "target set" of COMMAND is ITSET.  The "scope" command is renamed
from "itfocus", because this command specifies the "scope" of the
COMMAND will apply to, so "scope" is better than "itfocus".

gdb:

2013-04-02  Pedro Alves  <pedro@codesourcery.com>
	    Yao Qi  <yao@codesourcery.com>

	* itset.c (restore_itset, save_current_itset): New.
	(first_inferior, count_inferiors): New.
	(first_thread_of, struct count_threads_arg): New.
	(count_threads_of, switch_to_itset): New.
	(scope_command): New.
	(itset_get_target_set_reference): New.
	(_initialize_itset): Register command "scope".
	itset.h (itset_get_target_set_reference): Declare.
---
 gdb/itset.c |  200 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/itset.h |    2 +
 2 files changed, 202 insertions(+), 0 deletions(-)

diff --git a/gdb/itset.c b/gdb/itset.c
index 08060b3..da79be1 100644
--- a/gdb/itset.c
+++ b/gdb/itset.c
@@ -1156,6 +1156,203 @@ iterate_over_itset_threads (struct itset *itset,
 }
 
 static struct itset *current_itset = NULL;
+/* A cleanups callback, helper for save_current_itset
+   below.  */
+
+static void
+restore_itset (void *arg)
+{
+  struct itset *saved_itset = arg;
+
+  current_itset = saved_itset;
+  itset_free (current_itset);
+}
+
+/* Save the current itset so that it may be restored by a later call
+   to do_cleanups.  Returns the struct cleanup pointer needed for
+   later doing the cleanup.  */
+
+static struct cleanup *
+save_current_itset (void)
+{
+  struct cleanup *old_chain
+    = make_cleanup (restore_itset,
+		    itset_reference (current_itset));
+
+  return old_chain;
+}
+
+static int
+first_inferior (struct inferior *inf, void *data)
+{
+  return 1;
+}
+
+static int
+count_inferiors (struct inferior *inf, void *data)
+{
+  int *count_p = (int *) data;
+  (*count_p)++;
+  return 0;
+}
+
+static int
+first_thread_of (struct thread_info *thr, void *data)
+{
+  int inf_pid = * (int *) data;
+
+  if (ptid_get_pid (thr->ptid) != inf_pid)
+    return 0;
+
+  if (thr->state != THREAD_EXITED)
+    return 1;
+  return 0;
+}
+
+struct count_threads_arg
+{
+  int pid;
+  int count;
+};
+
+static int
+count_threads_of (struct thread_info *thr, void *data)
+{
+  struct count_threads_arg *c = data;
+
+  if (ptid_get_pid (thr->ptid) != c->pid)
+    return 0;
+
+  c->count++;
+  return 0;
+}
+
+/* Switch current inferior and thread to one of ITSET.  */
+
+static void
+switch_to_itset (struct itset *itset)
+{
+  struct inferior *inf;
+  struct cleanup *old_chain;
+  int inf_count;
+
+  /* For now, set a current inferior from the first element of the
+     focus set.  */
+  inf = iterate_over_itset_inferiors (itset, first_inferior, NULL);
+  if (inf == NULL)
+    {
+      /* Empty set.  Switch to no thread selected.  There's no concept
+	 of no inferior selected, so just leave the current
+	 selected.  */
+      switch_to_thread (null_ptid);
+      set_current_program_space (current_inferior ()->pspace);
+      return;
+    }
+
+  inf_count = 0;
+  iterate_over_itset_inferiors (itset, count_inferiors, &inf_count);
+  /* If there are multiple inferiors, switch inferior to INF.  */
+  if (inf_count > 1)
+    warning ("\
+%d inferiors in the current i/t set, switching to inf %d",
+	     inf_count, inf->num);
+
+  if (inf->pid != 0)
+    {
+      struct count_threads_arg count_threads_arg;
+
+      count_threads_arg.pid = inf->pid;
+      count_threads_arg.count = 0;
+      iterate_over_itset_threads (itset, count_threads_of,
+				  &count_threads_arg);
+      if (count_threads_arg.count != 0)
+	{
+	  struct thread_info *thr;
+
+	  if (count_threads_arg.count > 1)
+	    warning (_("\
+%d threads for inferior %d in the current i/t set, switching to the first"),
+		     count_threads_arg.count, inf->num);
+	  thr = iterate_over_itset_threads (itset, first_thread_of,
+					    &inf->pid);
+	  switch_to_thread (thr->ptid);
+	}
+    }
+  else
+    {
+      set_current_inferior (inf);
+      switch_to_thread (null_ptid);
+      set_current_program_space (inf->pspace);
+    }
+}
+
+/* When command 'scope ITSET COMMAND' is called, this variable is
+   set to true, and it is restored to false when the execution of
+   commands is done.  */
+
+static int scope_being_called_p = 0;
+
+static void
+scope_command (char *spec, int from_tty)
+{
+  struct itset *itset;
+  struct cleanup *old_chain;
+
+  if (spec == NULL)
+    {
+      if (current_itset)
+	printf_filtered (_("Focus is `%s' (current inferior is %d)"),
+			 current_itset->spec,
+			 current_inferior ()->num);
+      else
+	printf_filtered (_("No focus has been set. (current inferior is %d)"),
+			 current_inferior ()->num);
+      printf_filtered ("\n");
+      return;
+    }
+
+  itset = itset_create (&spec);
+  old_chain = make_cleanup_itset_free (itset);
+
+  spec = skip_spaces (spec);
+  if (*spec != '\0')
+    {
+      save_current_itset ();
+      current_itset = itset;
+
+      old_chain = make_cleanup_restore_current_thread ();
+      make_cleanup_restore_integer (&scope_being_called_p);
+      scope_being_called_p = 1;
+
+      execute_command (spec, from_tty);
+
+      do_cleanups (old_chain);
+      return;
+    }
+
+  if (itset_is_empty (itset))
+    warning (_("focus set is empty"));
+
+  discard_cleanups (old_chain);
+
+  itset_free (current_itset);
+  current_itset = itset;
+
+  switch_to_itset (itset);
+
+  /* Confirm the choice of focus.  */
+  printf_filtered (_("Current inferior is %d.\n"),
+		   current_inferior ()->num);
+}
+
+struct itset *
+itset_get_target_set_reference (void)
+{
+  if (scope_being_called_p)
+    return itset_reference (current_itset);
+  else
+    return NULL;
+}
 
 /* Create a named itset which references to SET.  Its name is NAME.
    The named itset is an internal named itset if INTERNAL is true.  */
@@ -1530,6 +1727,9 @@ _initialize_itset (void)
 
   current_itset = itset_reference (all_itset);
 
+  add_com ("scope", no_class, scope_command, _("\
+Change the set of current inferiors/threads."));
+
   add_com ("defset", no_class, defset_command, _("\
 Define a new named set.\n\
 Usage: defset NAME SPEC"));
diff --git a/gdb/itset.h b/gdb/itset.h
index 1faa4e8..c240199 100644
--- a/gdb/itset.h
+++ b/gdb/itset.h
@@ -42,6 +42,8 @@ int itset_contains_thread (struct itset *itset, struct thread_info *inf);
 
 /* Return a new reference to 'target_set' of commands.  */
 
+struct itset *itset_get_target_set_reference (void);
+
 /* Release a reference to an I/T set.  */
 
 void itset_free (struct itset *itset);
-- 
1.7.7.6


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]