This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 1/3] define and check itset
This patch is almost from Pedro's patch, with some minor fixes for the
new GDB code base and removal of command 'itfocus'.
[RFC/WIP PATCH v2 06/14] Add base itsets support
http://sourceware.org/ml/gdb-patches/2011-12/msg00566.html
command 'itfocus' will not only change 'current itset', but also associate
itset with other execution commands. I decide to postpone this bit
to next patch series.
gdb:
2011-12-16 Pedro Alves <pedro@codesourcery.com>
Tom Tromey <tromey@redhat.com>
* Makefile.in (SFILES): Add itset.c.
(COMMON_OBS): Add itset.o.
* gdbthread.h (get_thread_inferior): Declare.
(ALL_THREADS): New.
* thread.c (get_thread_inferior): New.
(thread_list): Make extern.
* itset.h, itset.c: New.
2012-05-31 Yao Qi <yao@codesourcery.com>
* itset.c (make_cleanup_itset_elt_free): Add static.
(parse_named_or_throw, iterate_over_itset_threads): Likewise.
Add DEF_VEC_I (int).
Declare _initialize_itset.
---
gdb/Makefile.in | 4 +-
gdb/gdbthread.h | 8 +
gdb/itset.c | 2380 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/itset.h | 122 +++
gdb/thread.c | 11 +-
5 files changed, 2522 insertions(+), 3 deletions(-)
create mode 100644 gdb/itset.c
create mode 100644 gdb/itset.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index bf6b0da..9b4140a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -738,7 +738,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
user-regs.c \
valarith.c valops.c valprint.c value.c varobj.c common/vec.c \
xml-tdesc.c xml-support.c \
- inferior.c gdb_usleep.c \
+ inferior.c itset.c gdb_usleep.c \
record.c gcore.c \
jit.c \
xml-syscall.c \
@@ -914,7 +914,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
prologue-value.o memory-map.o memrange.o \
xml-support.o xml-syscall.o xml-utils.o \
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
- inferior.o osdata.o gdb_usleep.o record.o gcore.o \
+ inferior.o itset.o osdata.o gdb_usleep.o record.o gcore.o \
jit.o progspace.o skip.o probe.o \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 2512357..a952315 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -38,6 +38,10 @@ enum thread_state
THREAD_EXITED,
};
+#define ALL_THREADS(T) \
+ for ((T) = thread_list; (T); (T) = (T)->next)
+
+extern struct thread_info *thread_list;
/* Inferior thread specific part of `struct infcall_control_state'.
Inferior process counterpart is `struct inferior_control_state'. */
@@ -389,4 +393,8 @@ extern struct thread_info* inferior_thread (void);
extern void update_thread_list (void);
+/* Return a pointer to the inferior of thread THR. */
+
+extern struct inferior *get_thread_inferior (struct thread_info *thr);
+
#endif /* GDBTHREAD_H */
diff --git a/gdb/itset.c b/gdb/itset.c
new file mode 100644
index 0000000..5b3098e
--- /dev/null
+++ b/gdb/itset.c
@@ -0,0 +1,2380 @@
+/* itset.c - Inferior/Thread sets.
+ Copyright (C) 2010 - 2012 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "itset.h"
+#include "vec.h"
+#include "bfd.h"
+#include "inferior.h"
+#include "progspace.h"
+#include "gdb_string.h"
+#include "cli/cli-utils.h"
+#include "gdbthread.h"
+#include "command.h"
+#include <ctype.h>
+#include "gdbcmd.h"
+
+/* Rather than creating/destroying these dynamic itsets when
+ necessary, keep global copies around (itsets are refcounted). */
+static struct itset *all_itset;
+static struct itset *empty_itset;
+static struct itset *running_itset;
+static struct itset *stopped_itset;
+static struct itset *curinf_itset;
+
+/* Forward declaration of the base class. */
+
+struct itset_elt;
+
+/* An element of an I/T set is a class with some virtual methods,
+ defined here. */
+
+struct itset_elt_vtable
+{
+ /* Destroy the contents of this element. If the element does not
+ require any special cleanup, this can be NULL. This should not
+ free the element itself; that is done by the caller. */
+
+ void (*destroy) (struct itset_elt *);
+
+ /* Return true if the element contains the inferior. The element
+ and the inferior are passed as arguments. */
+
+ int (*contains_inferior) (struct itset_elt *elt, struct inferior *inf);
+
+ /* Return true if the element contains the thread. The element and
+ the thread are passed as arguments. */
+
+ int (*contains_thread) (struct itset_elt *elt, struct thread_info *thr);
+
+ /* Return true if the element is empty. */
+
+ int (*is_empty) (struct itset_elt *elt);
+};
+
+/* The base class of all I/T set elements. */
+
+struct itset_elt
+{
+ const struct itset_elt_vtable *vtable;
+};
+
+static void
+itset_elt_free (struct itset_elt *elt)
+{
+ if (elt->vtable->destroy != NULL)
+ elt->vtable->destroy (elt);
+ xfree (elt);
+}
+
+static void
+itset_elt_free_cleanup (void *arg)
+{
+ struct itset_elt *elt = arg;
+
+ itset_elt_free (elt);
+}
+
+static struct cleanup *
+make_cleanup_itset_elt_free (struct itset_elt *elt)
+{
+ return make_cleanup (itset_elt_free_cleanup, elt);
+}
+
+typedef struct itset_elt *itset_elt_ptr;
+DEF_VEC_P (itset_elt_ptr);
+
+struct itset
+{
+ /* The itset's name. May be NULL. */
+ char *name;
+
+ /* The original specification of the set. */
+ char *spec;
+
+ /* The reference count. */
+ int refc;
+
+ /* The elements making up the set. */
+ VEC (itset_elt_ptr) *elements;
+};
+
+const char *
+itset_name (const struct itset *itset)
+{
+ return itset->name;
+}
+
+const char *
+itset_spec (const struct itset *itset)
+{
+ return itset->spec;
+}
+
+int
+itset_is_empty_set (struct itset *set)
+{
+ return VEC_empty (itset_elt_ptr, set->elements);
+}
+
+
+
+/* An element in the list of named itsets, which can be either
+ debugger built-in (all, stopped, running, etc.), or user
+ defined. */
+
+struct named_itset
+{
+ /* Pointer to next in linked list. */
+ struct named_itset *next;
+
+ /* Unique identifier. Positive if user defined, negative if
+ internal and built-in. */
+ int number;
+
+ /* The I/T set. */
+ struct itset *set;
+};
+
+/* The head of the list of named I/T sets. */
+
+static struct named_itset *named_itsets;
+
+/* Number of last named itset made. */
+
+static int named_itset_count;
+
+/* Number of last internal named itset made. */
+
+static int internal_named_itset_count;
+
+/* Traverse all named itsets. */
+
+#define ALL_NAMED_ITSETS(E) \
+ for ((E) = named_itsets; (E); (E) = (E)->next)
+
+/* Add IT at the end of the named itset chain. */
+
+static void
+add_to_named_itset_chain (struct named_itset *it)
+{
+ struct named_itset *it1;
+
+ /* Add this itset to the end of the chain so that a list of itsets
+ will come out in order of increasing numbers. */
+
+ it1 = named_itsets;
+ if (it1 == 0)
+ named_itsets = it;
+ else
+ {
+ while (it1->next)
+ it1 = it1->next;
+ it1->next = it;
+ }
+}
+
+static struct named_itset *
+get_named_itset (char *name)
+{
+ struct named_itset *it;
+
+ for (it = named_itsets; it != NULL; it = it->next)
+ if (strcmp (it->set->name, name) == 0)
+ return it;
+ return NULL;
+}
+
+
+
+/* A helper function that returns true if all elements in the ELEMENTS
+ set are empty. */
+
+static int
+set_is_empty (VEC (itset_elt_ptr) *elements)
+{
+ int ix;
+ struct itset_elt *elt;
+
+ for (ix = 0; VEC_iterate (itset_elt_ptr, elements, ix, elt); ++ix)
+ if (!elt->vtable->is_empty (elt))
+ return 0;
+
+ return 1;
+}
+
+/* A helper function that returns true if the inferior INF is
+ contained by the set ELEMENTS. */
+
+static int
+set_contains_inferior (VEC (itset_elt_ptr) *elements, struct inferior *inf)
+{
+ int ix;
+ struct itset_elt *elt;
+
+ for (ix = 0; VEC_iterate (itset_elt_ptr, elements, ix, elt); ++ix)
+ {
+ if (elt->vtable->contains_inferior (elt, inf))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* A helper function that returns true if the thread THR is contained
+ by the set ELEMENTS. */
+
+static int
+set_contains_thread (VEC (itset_elt_ptr) *elements, struct thread_info *thr)
+{
+ int ix;
+ struct itset_elt *elt;
+
+ for (ix = 0; VEC_iterate (itset_elt_ptr, elements, ix, elt); ++ix)
+ {
+ if (elt->vtable->contains_thread (elt, thr))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* A helper function to destroy all the elements in the set ELEMENTS.
+ This also destroys ELEMENTS itself. */
+
+static void
+set_free (VEC (itset_elt_ptr) *elements)
+{
+ int ix;
+ struct itset_elt *elt;
+
+ for (ix = 0; VEC_iterate (itset_elt_ptr, elements, ix, elt); ++ix)
+ itset_elt_free (elt);
+
+ VEC_free (itset_elt_ptr, elements);
+}
+
+
+
+/* An I/T set element representing all inferiors using a certain
+ executable. */
+
+struct itset_elt_exec
+{
+ struct itset_elt base;
+
+ /* The name of the executable. */
+ char *exec_name;
+};
+
+/* Implementation of `destroy' method. */
+
+static void
+exec_destroy (struct itset_elt *base)
+{
+ struct itset_elt_exec *exec = (struct itset_elt_exec *) base;
+
+ xfree (exec->exec_name);
+}
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+exec_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ struct itset_elt_exec *exec = (struct itset_elt_exec *) base;
+
+ /* FIXME: smarter compare. */
+ return (inf->pspace->ebfd != NULL
+ && strcmp (exec->exec_name,
+ bfd_get_filename (inf->pspace->ebfd)) == 0);
+}
+
+/* Implementation of `contains_thread' method. */
+
+static int
+exec_contains_thread (struct itset_elt *base, struct thread_info *thr)
+{
+ struct itset_elt_exec *exec = (struct itset_elt_exec *) base;
+ struct inferior *inf = get_thread_inferior (thr);
+
+ /* FIXME: smarter compare. */
+ return (inf->pspace->ebfd != NULL
+ && strcmp (exec->exec_name,
+ bfd_get_filename (inf->pspace->ebfd)) == 0);
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+exec_is_empty (struct itset_elt *base)
+{
+ struct itset_elt_exec *exec = (struct itset_elt_exec *) base;
+ struct inferior *inf;
+
+ ALL_INFERIORS (inf)
+ if (exec_contains_inferior (base, inf))
+ return 0;
+
+ return 1;
+}
+
+static const struct itset_elt_vtable exec_vtable =
+{
+ exec_destroy,
+ exec_contains_inferior,
+ exec_contains_thread,
+ exec_is_empty
+};
+
+/* Create a new `exec' I/T set element. */
+
+static struct itset_elt *
+create_exec_itset (char *arg)
+{
+ struct itset_elt_exec *elt;
+
+ elt = XNEW (struct itset_elt_exec);
+ elt->base.vtable = &exec_vtable;
+ elt->exec_name = arg;
+
+ return (struct itset_elt *) elt;
+}
+
+
+
+/* The value representing any inferior or thread. */
+
+#define WILDCARD -1
+
+/* An I/T set element representing a range of inferiors. */
+
+struct itset_elt_inferior_range
+{
+ struct itset_elt base;
+
+ /* The first and last inferiors in this range. If FIRST is
+ WILDCARD, then LAST is unused. */
+ int inf_first, inf_last;
+};
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+inferior_range_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ struct itset_elt_inferior_range *range
+ = (struct itset_elt_inferior_range *) base;
+
+ if (range->inf_first == WILDCARD
+ || (range->inf_first <= inf->num && inf->num <= range->inf_last))
+ return 1;
+
+ return 0;
+}
+
+/* Implementation of `contains_thread' method. */
+
+static int
+inferior_range_contains_thread (struct itset_elt *base, struct thread_info *thr)
+{
+ struct itset_elt_inferior_range *range
+ = (struct itset_elt_inferior_range *) base;
+ struct inferior *inf;
+
+ if (range->inf_first == WILDCARD)
+ return 1;
+
+ inf = get_thread_inferior (thr);
+ return range->inf_first <= inf->num && inf->num <= range->inf_last;
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+inferior_range_is_empty (struct itset_elt *base)
+{
+ struct itset_elt_inferior_range *range
+ = (struct itset_elt_inferior_range *) base;
+ struct inferior *inf;
+ struct thread_info *thr;
+
+ ALL_INFERIORS (inf)
+ {
+ if (inferior_range_contains_inferior (base, inf))
+ return 0;
+ }
+
+ ALL_THREADS (thr)
+ {
+ if (inferior_range_contains_thread (base, thr))
+ return 0;
+ }
+
+ return 1;
+}
+
+static const struct itset_elt_vtable inferior_range_vtable =
+{
+ NULL,
+ inferior_range_contains_inferior,
+ inferior_range_contains_thread,
+ inferior_range_is_empty
+};
+
+/* Create a new `range' I/T set element. */
+
+static struct itset_elt *
+create_inferior_range_itset (int inf_first, int inf_last)
+{
+ struct itset_elt_inferior_range *elt;
+
+ elt = XNEW (struct itset_elt_inferior_range);
+ elt->base.vtable = &inferior_range_vtable;
+ elt->inf_first = inf_first;
+ elt->inf_last = inf_last;
+
+ return (struct itset_elt *) elt;
+}
+
+
+
+/* An I/T set element representing a range of threads. */
+
+struct itset_elt_thread_range
+{
+ struct itset_elt base;
+
+ /* The first and last threads in this range. If FIRST is WILDCARD,
+ then LAST is unused. */
+ int thr_first, thr_last;
+};
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+thread_range_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ struct itset_elt_thread_range *range
+ = (struct itset_elt_thread_range *) base;
+ struct thread_info *thr;
+ int pid;
+
+ /* If there are no threads in the inferior, INF can't be part of any
+ thread range. */
+ if (inf->pid == 0)
+ return 0;
+
+ /* If range is a wildcard, this inferior is part of the range, given
+ that it must have at least one thread. */
+ if (range->thr_first == WILDCARD)
+ return 1;
+
+ /* Walk threads of INF, check if the range contains any of those.
+ If so, then the range contains the inferior. */
+ ALL_THREADS (thr)
+ if (ptid_get_pid (thr->ptid) == inf->pid)
+ {
+ if (range->thr_first <= thr->num && thr->num <= range->thr_last)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Implementation of `contains_thread' method. */
+
+static int
+thread_range_contains_thread (struct itset_elt *base, struct thread_info *thr)
+{
+ struct itset_elt_thread_range *range
+ = (struct itset_elt_thread_range *) base;
+
+ if (range->thr_first == WILDCARD
+ || (range->thr_first <= thr->num && thr->num <= range->thr_last))
+ return 1;
+
+ return 0;
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+thread_range_is_empty (struct itset_elt *base)
+{
+ struct itset_elt_inferior_range *range
+ = (struct itset_elt_inferior_range *) base;
+ struct inferior *inf;
+ struct thread_info *thr;
+
+ ALL_INFERIORS (inf)
+ {
+ if (thread_range_contains_inferior (base, inf))
+ return 0;
+ }
+
+ ALL_THREADS (thr)
+ {
+ if (thread_range_contains_thread (base, thr))
+ return 0;
+ }
+
+ return 1;
+}
+
+static const struct itset_elt_vtable thread_range_vtable =
+{
+ NULL,
+ thread_range_contains_inferior,
+ thread_range_contains_thread,
+ thread_range_is_empty
+};
+
+/* Create a new `range' I/T set element. */
+
+static struct itset_elt *
+create_thread_range_itset (int thr_first, int thr_last)
+{
+ struct itset_elt_thread_range *elt;
+
+ elt = XNEW (struct itset_elt_thread_range);
+ elt->base.vtable = &thread_range_vtable;
+ elt->thr_first = thr_first;
+ elt->thr_last = thr_last;
+
+ return (struct itset_elt *) elt;
+}
+
+
+
+/* An I/T set element representing a range of cores. */
+
+struct itset_elt_core_range
+{
+ struct itset_elt base;
+
+ /* The first and last cores in this range. If CORE_FIRST is
+ WILDCARD, then CORE_LAST is unused. */
+ int core_first, core_last;
+};
+
+/* Implementation of `contains_thread' method. */
+
+static int
+core_range_contains_thread (struct itset_elt *base, struct thread_info *thr)
+{
+ struct itset_elt_core_range *core_range
+ = (struct itset_elt_core_range *) base;
+ int core;
+
+ if (core_range->core_first == WILDCARD)
+ return 1;
+
+ core = target_core_of_thread (thr->ptid);
+ if (core_range->core_first <= core && core <= core_range->core_last)
+ return 1;
+
+ return 0;
+}
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+core_range_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ struct itset_elt_core_range *core_range
+ = (struct itset_elt_core_range *) base;
+ struct thread_info *thr;
+
+ /* True if we find a thread of this inferior that is running on our
+ core range. */
+ ALL_THREADS (thr)
+ {
+ /* It's cheaper to check the core range first, because looking
+ up the a thread's inferior is O(n). */
+ if (core_range_contains_thread (base, thr))
+ {
+ struct inferior *thr_inf;
+
+ thr_inf = get_thread_inferior (thr);
+ if (thr_inf == inf)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+core_range_is_empty (struct itset_elt *base)
+{
+ struct itset_elt_core_range *core_range
+ = (struct itset_elt_core_range *) base;
+ struct inferior *inf;
+ struct thread_info *thr;
+
+ ALL_THREADS (thr)
+ {
+ if (core_range_contains_thread (base, thr))
+ return 0;
+ }
+
+ return 1;
+}
+
+static const struct itset_elt_vtable core_range_vtable =
+{
+ NULL,
+ core_range_contains_inferior,
+ core_range_contains_thread,
+ core_range_is_empty
+};
+
+/* Create a new `core_range' I/T set element. */
+
+static struct itset_elt *
+create_core_range_itset (int core_first, int core_last)
+{
+ struct itset_elt_core_range *elt;
+
+ elt = XNEW (struct itset_elt_core_range);
+ elt->base.vtable = &core_range_vtable;
+ elt->core_first = core_first;
+ elt->core_last = core_last;
+
+ return (struct itset_elt *) elt;
+}
+
+
+
+/* An I/T set element representing an intersection of sets. */
+
+struct itset_elt_intersect
+{
+ struct itset_elt base;
+
+ /* The elements that will be intersected. */
+ VEC (itset_elt_ptr) *elements;
+};
+
+/* Implementation of `destroy' method. */
+
+static void
+intersect_destroy (struct itset_elt *base)
+{
+ struct itset_elt_intersect *set = (struct itset_elt_intersect *) base;
+
+ VEC_free (itset_elt_ptr, set->elements);
+}
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+intersect_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ struct itset_elt_intersect *intersect = (struct itset_elt_intersect *) base;
+ struct itset_elt *elt;
+ int ix;
+
+ gdb_assert (!VEC_empty (itset_elt_ptr, intersect->elements));
+
+ for (ix = 0; VEC_iterate (itset_elt_ptr, intersect->elements, ix, elt); ++ix)
+ {
+ if (!elt->vtable->contains_inferior (elt, inf))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Implementation of `contains_thread' method. */
+
+static int
+intersect_contains_thread (struct itset_elt *base, struct thread_info *thr)
+{
+ struct itset_elt_intersect *intersect = (struct itset_elt_intersect *) base;
+ struct itset_elt *elt;
+ int ix;
+
+ gdb_assert (!VEC_empty (itset_elt_ptr, intersect->elements));
+
+ for (ix = 0; VEC_iterate (itset_elt_ptr, intersect->elements, ix, elt); ++ix)
+ {
+ if (!elt->vtable->contains_thread (elt, thr))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+intersect_is_empty (struct itset_elt *base)
+{
+ struct itset_elt_intersect *intersect = (struct itset_elt_intersect *) base;
+ struct inferior *inf;
+ struct thread_info *thr;
+
+ ALL_INFERIORS (inf)
+ {
+ if (intersect_contains_inferior (base, inf))
+ return 0;
+ }
+
+ ALL_THREADS (thr)
+ {
+ if (intersect_contains_thread (base, thr))
+ return 0;
+ }
+
+ return 1;
+}
+
+static const struct itset_elt_vtable intersect_vtable =
+{
+ intersect_destroy,
+ intersect_contains_inferior,
+ intersect_contains_thread,
+ intersect_is_empty
+};
+
+/* Create a new `intersect' I/T set element. */
+
+static struct itset_elt_intersect *
+create_intersect_itset (void)
+{
+ struct itset_elt_intersect *elt;
+
+ elt = XNEW (struct itset_elt_intersect);
+ elt->base.vtable = &intersect_vtable;
+ elt->elements = NULL;
+
+ return elt;
+}
+
+
+
+/* An I/T set element representing all inferiors. */
+
+struct itset_elt_all
+{
+ struct itset_elt base;
+};
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+all_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ return 1;
+}
+
+/* Implementation of `contains_thread' method. */
+
+static int
+all_contains_thread (struct itset_elt *base, struct thread_info *thr)
+{
+ return 1;
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+all_is_empty (struct itset_elt *base)
+{
+ /* There's always at least one inferior. */
+ return 0;
+}
+
+static const struct itset_elt_vtable all_vtable =
+{
+ NULL,
+ all_contains_inferior,
+ all_contains_thread,
+ all_is_empty
+};
+
+static struct itset_elt *
+create_all_itset (void)
+{
+ struct itset_elt_all *elt;
+
+ elt = XNEW (struct itset_elt_all);
+ elt->base.vtable = &all_vtable;
+
+ return (struct itset_elt *) elt;
+}
+
+
+
+/* An I/T set element representing no inferiors. */
+
+struct itset_elt_empty
+{
+ struct itset_elt base;
+};
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+empty_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ return 0;
+}
+
+/* Implementation of `contains_thread' method. */
+
+static int
+empty_contains_thread (struct itset_elt *base, struct thread_info *thr)
+{
+ return 0;
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+empty_is_empty (struct itset_elt *base)
+{
+ /* Always empty. */
+ return 1;
+}
+
+static const struct itset_elt_vtable empty_vtable =
+{
+ NULL,
+ empty_contains_inferior,
+ empty_contains_thread,
+ empty_is_empty
+};
+
+static struct itset_elt *
+create_empty_itset (void)
+{
+ struct itset_elt_empty *elt;
+
+ elt = XNEW (struct itset_elt_empty);
+ elt->base.vtable = &empty_vtable;
+
+ return (struct itset_elt *) elt;
+}
+
+
+
+/* An I/T set element representing an itset. */
+
+struct itset_elt_itset
+{
+ struct itset_elt base;
+
+ /* The I/T set this element wraps. */
+ struct itset *set;
+};
+
+static void
+itset_elt_itset_destroy (struct itset_elt *base)
+{
+ struct itset_elt_itset *iiset = (struct itset_elt_itset *) base;
+
+ itset_free (iiset->set);
+}
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+itset_elt_itset_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ struct itset_elt_itset *iiset = (struct itset_elt_itset *) base;
+ return itset_contains_inferior (iiset->set, inf);
+}
+
+/* Implementation of `contains_thread' method. */
+
+static int
+itset_elt_itset_contains_thread (struct itset_elt *base,
+ struct thread_info *thr)
+{
+ struct itset_elt_itset *iiset = (struct itset_elt_itset *) base;
+ return itset_contains_thread (iiset->set, thr);
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+itset_elt_itset_is_empty (struct itset_elt *base)
+{
+ struct itset_elt_itset *iiset = (struct itset_elt_itset *) base;
+ return itset_is_empty (iiset->set);
+}
+
+static const struct itset_elt_vtable itset_elt_itset_vtable =
+{
+ itset_elt_itset_destroy,
+ itset_elt_itset_contains_inferior,
+ itset_elt_itset_contains_thread,
+ itset_elt_itset_is_empty
+};
+
+static struct itset_elt_itset *
+create_itset_elt_itset (struct itset *set)
+{
+ struct itset_elt_itset *elt;
+
+ elt = XNEW (struct itset_elt_itset);
+ elt->base.vtable = &itset_elt_itset_vtable;
+ elt->set = itset_reference (set);
+
+ return elt;
+}
+
+void
+itset_add_set (struct itset *to, struct itset *addme)
+{
+ struct itset_elt *elt;
+
+ elt = (struct itset_elt *) create_itset_elt_itset (addme);
+ VEC_safe_push (itset_elt_ptr, to->elements, elt);
+}
+
+
+
+/* An I/T set element representing a negated set. */
+
+struct itset_elt_negated
+{
+ struct itset_elt base;
+
+ /* The negated element. */
+ struct itset_elt *negated;
+};
+
+static void
+itset_elt_negated_destroy (struct itset_elt *base)
+{
+ struct itset_elt_negated *elt = (struct itset_elt_negated *) base;
+
+ if (elt->negated->vtable->destroy != NULL)
+ elt->negated->vtable->destroy (elt->negated);
+ xfree (elt->negated);
+}
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+itset_elt_negated_contains_inferior (struct itset_elt *base,
+ struct inferior *inf)
+{
+ struct itset_elt_negated *elt = (struct itset_elt_negated *) base;
+ return !elt->negated->vtable->contains_inferior (elt->negated, inf);
+}
+
+/* Implementation of `contains_thread' method. */
+
+static int
+itset_elt_negated_contains_thread (struct itset_elt *base,
+ struct thread_info *thr)
+{
+ struct itset_elt_negated *elt = (struct itset_elt_negated *) base;
+ return !elt->negated->vtable->contains_thread (elt->negated, thr);
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+itset_elt_negated_is_empty (struct itset_elt *base)
+{
+ struct itset_elt_negated *elt = (struct itset_elt_negated *) base;
+ struct inferior *inf;
+ struct thread_info *thr;
+
+ ALL_INFERIORS (inf)
+ {
+ if (itset_elt_negated_contains_inferior (base, inf))
+ return 0;
+ }
+
+ ALL_THREADS (thr)
+ {
+ if (itset_elt_negated_contains_thread (base, thr))
+ return 0;
+ }
+
+ return 1;
+}
+
+static const struct itset_elt_vtable itset_elt_negated_vtable =
+{
+ itset_elt_negated_destroy,
+ itset_elt_negated_contains_inferior,
+ itset_elt_negated_contains_thread,
+ itset_elt_negated_is_empty
+};
+
+static struct itset_elt_negated *
+create_itset_elt_negated (void)
+{
+ struct itset_elt_negated *elt;
+
+ elt = XNEW (struct itset_elt_negated);
+ elt->base.vtable = &itset_elt_negated_vtable;
+ elt->negated = NULL;
+
+ return elt;
+}
+
+
+
+/* An I/T set element representing all inferiors of a given state. */
+
+struct itset_elt_state
+{
+ struct itset_elt base;
+
+ int state;
+};
+
+/* Implementation of `contains_thread' method. */
+
+static int
+state_contains_thread (struct itset_elt *base, struct thread_info *thr)
+{
+ struct itset_elt_state *state = (struct itset_elt_state *) base;
+
+ return thr->state == state->state;
+}
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+state_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ struct itset_elt_state *state = (struct itset_elt_state *) base;
+ struct thread_info *thr;
+
+ /* True if we find a thread of this inferior that is in the state
+ we're interested in. */
+ ALL_THREADS (thr)
+ {
+ /* It's cheaper to check the state first, because looking up the
+ a thread's inferior is O(n). */
+ if (state_contains_thread (base, thr))
+ {
+ struct inferior *thr_inf;
+
+ thr_inf = get_thread_inferior (thr);
+ if (thr_inf == inf)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+state_is_empty (struct itset_elt *base)
+{
+ struct thread_info *thr;
+
+ ALL_THREADS (thr)
+ if (state_contains_thread (base, thr))
+ return 0;
+
+ return 1;
+}
+
+static const struct itset_elt_vtable state_vtable =
+{
+ NULL,
+ state_contains_inferior,
+ state_contains_thread,
+ state_is_empty
+};
+
+static struct itset_elt *
+create_state_itset (int thread_state)
+{
+ struct itset_elt_state *elt;
+
+ elt = XNEW (struct itset_elt_state);
+ elt->base.vtable = &state_vtable;
+ elt->state = thread_state;
+
+ return (struct itset_elt *) elt;
+}
+
+
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+current_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ return current_inferior () == inf;
+}
+
+/* Implementation of `contains_thread' method. */
+
+static int
+current_contains_thread (struct itset_elt *base, struct thread_info *thr)
+{
+ struct inferior *inf;
+
+ inf = get_thread_inferior (thr);
+ return current_inferior () == inf;
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+current_is_empty (struct itset_elt *base)
+{
+ /* There's always a current inferior. */
+ return 0;
+}
+
+static const struct itset_elt_vtable current_vtable =
+{
+ NULL,
+ current_contains_inferior,
+ current_contains_thread,
+ current_is_empty
+};
+
+/* Create a new I/T set element representing just the current
+ inferior. */
+
+static struct itset_elt *
+create_current_itset (void)
+{
+ struct itset_elt *elt;
+
+ elt = XNEW (struct itset_elt);
+ elt->vtable = ¤t_vtable;
+
+ return elt;
+}
+
+
+
+DEF_VEC_I (int);
+
+/* An I/T set element representing a static list of inferiors. */
+
+struct itset_elt_static
+{
+ struct itset_elt base;
+
+ /* The inferiors. */
+ VEC (int) *inferiors;
+
+ /* The threads. */
+ VEC (int) *threads;
+};
+
+/* Implementation of `destroy' method. */
+
+static void
+static_destroy (struct itset_elt *base)
+{
+ struct itset_elt_static *st = (struct itset_elt_static *) base;
+
+ VEC_free (int, st->inferiors);
+ VEC_free (int, st->threads);
+}
+
+/* Helper function to compare two ints. Returns true if the first
+ argument is strictly less than the second, useful for
+ VEC_lower_bound. */
+
+static int
+static_lessthan (const int a, const int b)
+{
+ return a < b;
+}
+
+/* Implementation of `contains_inferior' method. */
+
+static int
+static_contains_inferior (struct itset_elt *base, struct inferior *inf)
+{
+ struct itset_elt_static *st = (struct itset_elt_static *) base;
+ int idx;
+
+ idx = VEC_lower_bound (int, st->inferiors, inf->num, static_lessthan);
+ if (idx < VEC_length (int, st->inferiors)
+ && VEC_index (int, st->inferiors, idx) == inf->num)
+ return 1;
+ return 0;
+}
+
+/* Implementation of `contains_thread' method. */
+
+static int
+static_contains_thread (struct itset_elt *base, struct thread_info *thr)
+{
+ struct itset_elt_static *st = (struct itset_elt_static *) base;
+ int idx;
+
+ idx = VEC_lower_bound (int, st->threads, thr->num, static_lessthan);
+ if (idx < VEC_length (int, st->threads)
+ && VEC_index (int, st->threads, idx) == thr->num)
+ return 1;
+ return 0;
+}
+
+/* Implementation of `is_empty' method. */
+
+static int
+static_is_empty (struct itset_elt *base)
+{
+ struct itset_elt_static *st = (struct itset_elt_static *) base;
+ int idx;
+
+ return VEC_empty (int, st->inferiors);
+}
+
+static const struct itset_elt_vtable static_vtable =
+{
+ static_destroy,
+ static_contains_inferior,
+ static_contains_thread,
+ static_is_empty
+};
+
+
+
+/* Helper struct used to pass data through iterate_over_inferiors. */
+
+struct iter_data
+{
+ /* The I/T set we are constructing. */
+
+ struct itset_elt_static *st;
+
+ /* The elements of the original (dynamic) I/T set. */
+
+ VEC (itset_elt_ptr) *elements;
+};
+
+/* A callback for iterate_over_inferiors that adds an inferior to the
+ result set, if it is in the source set. */
+
+static int
+check_one_inferior (struct inferior *inf, void *datum)
+{
+ struct iter_data *id = datum;
+
+ if (set_contains_inferior (id->elements, inf))
+ VEC_safe_push (int, id->st->inferiors, inf->num);
+
+ /* Keep going. */
+ return 0;
+}
+
+/* A callback for iterate_over_threads that adds a thread to the
+ result set, if it is in the source set. */
+
+static int
+check_one_thread (struct thread_info *thr, void *datum)
+{
+ struct iter_data *id = datum;
+
+ if (set_contains_thread (id->elements, thr))
+ VEC_safe_push (int, id->st->threads, thr->num);
+
+ /* Keep going. */
+ return 0;
+}
+
+/* Create a new static I/T set from the list of elements. */
+
+static struct itset_elt *
+create_static_itset (VEC (itset_elt_ptr) *elements)
+{
+ struct itset_elt_static *elt;
+ struct iter_data datum;
+
+ elt = XNEW (struct itset_elt_static);
+ elt->base.vtable = &static_vtable;
+ elt->inferiors = NULL;
+ elt->threads = NULL;
+
+ datum.st = elt;
+ datum.elements = elements;
+
+ iterate_over_inferiors (check_one_inferior, &datum);
+ if (VEC_length (int, elt->inferiors) > 1)
+ qsort (VEC_address (int, elt->inferiors),
+ VEC_length (int, elt->inferiors),
+ sizeof (int), compare_positive_ints);
+
+ iterate_over_threads (check_one_thread, &datum);
+ if (VEC_length (int, elt->threads) > 1)
+ qsort (VEC_address (int, elt->threads),
+ VEC_length (int, elt->threads),
+ sizeof (int), compare_positive_ints);
+
+ return (struct itset_elt *) elt;
+}
+
+
+
+static int
+looks_like_range (char *spec)
+{
+ return isdigit (spec[0]) || spec[0] == '*';
+}
+
+/* Parse an I/T set range. A range has the form F[:L][.T], where F is
+ the starting inferior, L is the ending inferior, and T is the
+ thread. Updates RESULT with the new I/T set elements, and returns
+ an updated pointer into the spec. Throws an exception on
+ error. */
+
+static char *
+parse_range (char *spec, int *first, int *last)
+{
+ struct itset_elt *elt;
+
+ if (!looks_like_range (spec))
+ error (_("Invalid I/T syntax at `%s'. Expected '*' or digit."), spec);
+
+ if (*spec == '*')
+ {
+ *first = WILDCARD;
+ *last = WILDCARD;
+ ++spec;
+ }
+ else
+ {
+ *first = strtol (spec, &spec, 10);
+ if (*spec == '-')
+ {
+ ++spec;
+ if (!isdigit (*spec))
+ error (_("Expected digit in I/T set, at `%s'"), spec);
+ *last = strtol (spec, &spec, 10);
+ }
+ else
+ *last = *first;
+ }
+ return spec;
+}
+
+static struct itset_elt *
+parse_inferior_range (char **spec)
+{
+ int first, last;
+
+ if ((*spec)[0] != 'i' || !looks_like_range ((*spec) + 1))
+ return NULL;
+
+ (*spec)++;
+ *spec = parse_range (*spec, &first, &last);
+ return create_inferior_range_itset (first, last);
+}
+
+static struct itset_elt *
+parse_thread_range (char **spec)
+{
+ int first, last;
+
+ if ((*spec)[0] != 't' || !looks_like_range ((*spec) + 1))
+ return NULL;
+
+ (*spec)++;
+ *spec = parse_range (*spec, &first, &last);
+ return create_thread_range_itset (first, last);
+}
+
+static struct itset_elt *
+parse_core_range (char **spec)
+{
+ int first, last;
+
+ if ((*spec)[0] != 'c' || !looks_like_range ((*spec) + 1))
+ return NULL;
+
+ (*spec)++;
+ *spec = parse_range (*spec, &first, &last);
+ return create_core_range_itset (first, last);
+}
+
+
+
+/* Parse a named I/T set. Currently the only named sets which are
+ recognized are `exec (NAME)', and `current'. Updates RESULT with
+ the new I/T set elements, and returns an updated pointer into the
+ spec. Throws an exception on error. */
+
+static struct itset_elt *
+parse_named_or_throw (char **textp)
+{
+ struct itset_elt *elt;
+ char *text = *textp;
+ char *name = text;
+
+ for (text = name + 1; isalnum (*text) || *text == '_'; ++text)
+ ;
+
+ if (strncmp ("all", name, text - name) == 0)
+ elt = create_all_itset ();
+ else if (strncmp ("empty", name, text - name) == 0)
+ elt = create_empty_itset ();
+ else if (strncmp ("stopped", name, text - name) == 0)
+ elt = create_state_itset (THREAD_STOPPED);
+ else if (strncmp ("running", name, text - name) == 0)
+ elt = create_state_itset (THREAD_RUNNING);
+ else if (strncmp ("curinf", name, text - name) == 0)
+ elt = create_current_itset ();
+ else if (strncmp ("exec", name, text - name) == 0)
+ {
+ char *tem;
+ char *arg;
+
+ if (*text != '(')
+ error (_("'(' expected in I/T set after `exec'"));
+ text = skip_spaces (text + 1);
+ tem = strchr (text, ')');
+ if (!tem)
+ error (_("No closing ')' in I/T set for `exec'"));
+ if (tem - text == 0)
+ error (_("Empty argument to `exec' in I/T set"));
+ arg = xstrndup (text, tem - text);
+ text = tem + 1;
+ elt = create_exec_itset (arg);
+ }
+ else
+ {
+ struct named_itset *named_itset;
+ char *tem;
+
+ tem = alloca (text - name + 1);
+
+ memcpy (tem, name, text - name);
+ tem[text - name] = '\0';
+
+ named_itset = get_named_itset (tem);
+ if (named_itset == NULL)
+ error (_("Unknown named I/T set: `%s'"), tem);
+ elt = (struct itset_elt *) create_itset_elt_itset (named_itset->set);
+ }
+
+ *textp = text;
+ return elt;
+}
+
+/* A cleanup function that calls itset_free. */
+
+static void
+itset_free_cleanup (void *arg)
+{
+ struct itset *itset = arg;
+ itset_free (itset);
+}
+
+struct cleanup *
+make_cleanup_itset_free (struct itset *itset)
+{
+ return make_cleanup (itset_free_cleanup, itset);
+}
+
+/*
+
+ ',' (union) has precedence over '.' (intersect).
+
+ ELEM = RANGE | NEG | PARENS_SET | '$' | NAME
+ NEG = '~' ELEM
+ PARENS_SET = '(' ITSET_ONE ')'
+ INTERS = ELEM ('.' ELEM)*
+ ITSET_ONE = INTERS (',' INTERS)*
+ ITSET = | ('!' ITSET_ONE) | ITSET_ONE
+
+ E.g.,:
+
+ c1-3.~i1.(t1,other),foo is transformed to a tree like:
+
+ UNION
+ foo
+ INTERS
+ c1-3
+ NEG
+ i1-1
+ UNION
+ t1-1
+ other
+
+*/
+
+/* Forward declare. The parser is recursive. */
+static struct itset_elt *parse_neg (char **spec);
+static struct itset_elt *parse_parens_set (char **spec);
+static struct itset_elt *parse_itset_one (char **spec);
+static struct itset_elt *parse_current_focus (char **spec);
+
+static int
+valid_spec_end (char *spec)
+{
+ return *spec == '\0' || isspace (*spec);
+}
+
+static struct itset_elt *
+parse_elem (char **spec)
+{
+ struct itset_elt *elt;
+
+ elt = parse_inferior_range (spec);
+ if (elt != NULL)
+ return elt;
+
+ elt = parse_thread_range (spec);
+ if (elt != NULL)
+ return elt;
+
+ elt = parse_core_range (spec);
+ if (elt != NULL)
+ return elt;
+
+ elt = parse_neg (spec);
+ if (elt != NULL)
+ return elt;
+
+ elt = parse_parens_set (spec);
+ if (elt != NULL)
+ return elt;
+
+ elt = parse_current_focus (spec);
+ if (elt != NULL)
+ return elt;
+
+ return parse_named_or_throw (spec);
+}
+
+static struct itset_elt *
+parse_neg (char **spec)
+{
+ struct itset_elt_negated *neg_elt;
+ struct itset_elt *elt;
+
+ if (**spec != '~')
+ return NULL;
+
+ (*spec)++;
+
+ elt = parse_elem (spec);
+
+ neg_elt = create_itset_elt_negated ();
+ neg_elt->negated = elt;
+
+ return (struct itset_elt *) neg_elt;
+}
+
+static struct itset_elt *
+parse_current_focus (char **spec)
+{
+ struct itset_elt_itset *itset_elt;
+
+ if (**spec != '$')
+ return NULL;
+
+ (*spec)++;
+
+ itset_elt = create_itset_elt_itset (itset_reference (current_itset));
+ return (struct itset_elt *) itset_elt;
+}
+
+static struct itset_elt *
+parse_parens_set (char **spec)
+{
+ struct itset_elt_negated *neg_elt;
+ struct itset_elt *elt;
+ struct cleanup *old_chain;
+
+ if (**spec != '(')
+ return NULL;
+ (*spec)++;
+
+ elt = parse_itset_one (spec);
+ if (elt == NULL)
+ error (_("Invalid I/T syntax at `%s'"), *spec);
+
+ old_chain = make_cleanup_itset_elt_free (elt);
+ if (**spec != ')')
+ error (_("Invalid I/T syntax at `%s'"), *spec);
+
+ neg_elt = create_itset_elt_negated ();
+ neg_elt->negated = elt;
+
+ discard_cleanups (old_chain);
+
+ return (struct itset_elt *) neg_elt;
+}
+
+static struct itset_elt *
+parse_inters (char **spec)
+{
+ struct itset_elt *elt1, *elt2 = NULL;
+ struct itset_elt_intersect *intersect = NULL;
+ struct cleanup *old_chain;
+
+ elt1 = parse_elem (spec);
+ if (elt1 == NULL)
+ return NULL;
+
+ old_chain = make_cleanup_itset_elt_free (elt1);
+
+ if (**spec == '.')
+ {
+ intersect = create_intersect_itset ();
+ VEC_safe_push (itset_elt_ptr, intersect->elements, elt1);
+ elt1 = (struct itset_elt *) intersect;
+
+ discard_cleanups (old_chain);
+ old_chain = make_cleanup_itset_elt_free (elt1);
+ }
+
+ while (**spec == '.')
+ {
+ (*spec)++;
+
+ elt2 = parse_elem (spec);
+ if (elt2 == NULL)
+ {
+ do_cleanups (old_chain);
+ return NULL;
+ }
+ VEC_safe_push (itset_elt_ptr, intersect->elements, elt2);
+ }
+
+ discard_cleanups (old_chain);
+ return elt1;
+}
+
+static struct itset_elt *
+parse_itset_one (char **spec)
+{
+ struct itset_elt *inters1, *inters2 = NULL;
+ struct itset_elt_itset *un = NULL;
+ struct cleanup *old_chain;
+
+ inters1 = parse_inters (spec);
+ if (inters1 == NULL)
+ return NULL;
+ old_chain = make_cleanup_itset_elt_free (inters1);
+
+ if (**spec == ',')
+ {
+ struct itset *set;
+
+ set = XCNEW (struct itset);
+ set->refc = 1;
+
+ un = create_itset_elt_itset (set);
+
+ VEC_safe_push (itset_elt_ptr, set->elements, inters1);
+ inters1 = (struct itset_elt *) un;
+
+ discard_cleanups (old_chain);
+ old_chain = make_cleanup_itset_elt_free (inters1);
+ }
+
+ while (**spec == ',')
+ {
+ (*spec)++;
+
+ inters2 = parse_inters (spec);
+ if (inters2 == NULL)
+ {
+ do_cleanups (old_chain);
+ return NULL;
+ }
+ VEC_safe_push (itset_elt_ptr, un->set->elements, inters2);
+ }
+
+ discard_cleanups (old_chain);
+ return inters1;
+}
+
+/* Parse an I/T set specification and return a new I/T set. Throws an
+ exception on error. */
+
+struct itset *
+itset_create (char **specp)
+{
+ int is_static = 0;
+ struct itset *result;
+ struct itset_elt *elt;
+ struct cleanup *cleanups;
+ char *spec = *specp;
+ char *spec_start;
+
+ result = XCNEW (struct itset);
+ result->refc = 1;
+
+ cleanups = make_cleanup_itset_free (result);
+
+ spec = skip_spaces (spec);
+ spec_start = spec;
+
+ if (*spec == '!')
+ {
+ is_static = 1;
+ ++spec;
+ }
+
+ if (!valid_spec_end (spec))
+ {
+ elt = parse_itset_one (&spec);
+ VEC_safe_push (itset_elt_ptr, result->elements, elt);
+
+ if (!valid_spec_end (spec))
+ error (_("Invalid I/T syntax at `%s'"), spec);
+ }
+
+ result->spec = xstrndup (spec_start, spec - spec_start);
+ *specp = spec;
+
+ if (is_static)
+ {
+ struct itset_elt *st = create_static_itset (result->elements);
+
+ set_free (result->elements);
+ result->elements = NULL;
+ VEC_safe_push (itset_elt_ptr, result->elements, st);
+ }
+
+ discard_cleanups (cleanups);
+
+ return result;
+}
+
+struct itset *
+itset_create_empty (void)
+{
+ char *spec = "";
+
+ return itset_create (&spec);
+}
+
+/* Create a new I/T set which represents the current inferior and all
+ its threads. */
+
+static struct itset *
+itset_create_curinf (void)
+{
+ char *spec = "curinf";
+
+ return itset_create (&spec);
+}
+
+static struct itset *
+itset_create_all (void)
+{
+ char *spec = "all";
+
+ return itset_create (&spec);
+}
+
+static struct itset *
+itset_create_running (void)
+{
+ char *spec = "running";
+
+ return itset_create (&spec);
+}
+
+static struct itset *
+itset_create_stopped (void)
+{
+ char *spec = "stopped";
+
+ return itset_create (&spec);
+}
+
+/* Return 1 if SET contains INF, 0 otherwise. */
+
+int
+itset_is_empty (const struct itset *set)
+{
+ return set_is_empty (set->elements);
+}
+
+/* Return 1 if SET contains INF, 0 otherwise. */
+
+int
+itset_contains_inferior (struct itset *set, struct inferior *inf)
+{
+ return set_contains_inferior (set->elements, inf);
+}
+
+/* Return 1 if SET contains THR, 0 otherwise. */
+
+int
+itset_contains_thread (struct itset *set, struct thread_info *thr)
+{
+ return set_contains_thread (set->elements, thr);
+}
+
+/* Acquire a new reference to an I/T set. */
+
+struct itset *
+itset_reference (struct itset *itset)
+{
+ ++itset->refc;
+ return itset;
+}
+
+/* Destroy SET. */
+
+void
+itset_free (struct itset *set)
+{
+ /* Like xfree, allow NULL. */
+ if (set == NULL)
+ return;
+
+ if (--set->refc == 0)
+ {
+ set_free (set->elements);
+ xfree (set->name);
+ xfree (set->spec);
+ xfree (set);
+ }
+}
+
+/* Helper struct for iterate_over_itset. */
+
+struct iterate_data
+{
+ /* The I/T set we are using. */
+ struct itset *itset;
+
+ /* The original callback */
+ int (*callback) (struct inferior *, void *);
+
+ /* The data passed in to iterate_over_itset. */
+ void *client_data;
+};
+
+/* Callback function for iterate_over_inferiors, used by
+ iterate_over_itset. */
+
+static int
+iter_callback (struct inferior *inf, void *d)
+{
+ struct iterate_data *data = d;
+
+ if (itset_contains_inferior (data->itset, inf))
+ return data->callback (inf, data->client_data);
+
+ /* Keep going. */
+ return 0;
+}
+
+/* Like iterate_over_inferiors, but iterate over only those inferiors
+ in ITSET. */
+
+struct inferior *
+iterate_over_itset_inferiors (struct itset *itset,
+ itset_inf_callback_func *callback,
+ void *datum)
+{
+ struct iterate_data data;
+
+ data.itset = itset;
+ data.callback = callback;
+ data.client_data = datum;
+
+ return iterate_over_inferiors (iter_callback, &data);
+}
+
+/* Helper struct for iterate_over_itset. */
+
+struct iterate_thr_data
+{
+ /* The I/T set we are using. */
+ struct itset *itset;
+
+ /* The original callback */
+ int (*callback) (struct thread_info *, void *);
+
+ /* The data passed in to iterate_over_itset_threads. */
+ void *client_data;
+};
+
+/* Callback function for iterate_over_inferiors, used by
+ iterate_over_itset. */
+
+static int
+iter_thr_callback (struct thread_info *thr, void *d)
+{
+ struct iterate_thr_data *data = d;
+
+ if (itset_contains_thread (data->itset, thr))
+ return data->callback (thr, data->client_data);
+
+ /* Keep going. */
+ return 0;
+}
+
+/* Like iterate_over_inferiors, but iterate over only those inferiors
+ in ITSET. */
+
+static struct thread_info *
+iterate_over_itset_threads (struct itset *itset,
+ int (*callback) (struct thread_info *, void *),
+ void *datum)
+{
+ struct iterate_thr_data data;
+
+ data.itset = itset;
+ data.callback = callback;
+ data.client_data = datum;
+
+ return iterate_over_threads (iter_thr_callback, &data);
+}
+
+struct itset *current_itset = NULL;
+
+static struct named_itset *
+make_itset_named_itset (struct itset *set, char *name, int internal)
+{
+ struct named_itset *named_itset;
+
+ itset_reference (set);
+ set->name = name;
+
+ named_itset = XCNEW (struct named_itset);
+ named_itset->set = set;
+
+ if (internal)
+ named_itset->number = --internal_named_itset_count;
+ else
+ named_itset->number = ++named_itset_count;
+
+ return named_itset;
+}
+
+static int
+itset_elt_is_static (struct itset_elt *elt)
+{
+ return elt->vtable == &static_vtable;
+}
+
+static int
+itset_is_static (struct itset *itset)
+{
+ struct itset_elt *elt;
+ int ix;
+
+ /* True if all elements are static. */
+
+ if (VEC_empty (itset_elt_ptr, itset->elements))
+ return 0;
+
+ for (ix = 0; VEC_iterate (itset_elt_ptr, itset->elements, ix, elt); ++ix)
+ if (!itset_elt_is_static (elt))
+ return 0;
+
+ return 1;
+}
+
+static void
+defset_command (char *arg, int from_tty)
+{
+ char *endp;
+ char *name;
+ char *spec;
+ struct itset *itset;
+ struct named_itset *named_itset;
+ struct cleanup *old_chain;
+
+ if (arg == NULL || *arg == '\0')
+ error_no_arg (_("no args"));
+
+ arg = skip_spaces (arg);
+
+ endp = skip_to_space (arg);
+ spec = endp;
+
+ name = xstrndup (arg, endp - arg);
+ old_chain = make_cleanup (xfree, name);
+
+ named_itset = get_named_itset (name);
+ if (named_itset != NULL)
+ error (_("itset %s already exists"), name);
+
+ spec = skip_spaces (spec);
+
+ itset = itset_create (&spec);
+ make_cleanup_itset_free (itset);
+
+ if (itset_is_static (itset) && itset_is_empty (itset))
+ warning (_("static itset is empty"));
+
+ named_itset = make_itset_named_itset (itset, name, 0);
+ itset_free (itset);
+ discard_cleanups (old_chain);
+ add_to_named_itset_chain (named_itset);
+}
+
+static void
+free_named_itset (struct named_itset *it)
+{
+ itset_free (it->set);
+ xfree (it);
+}
+
+static void
+undefset_command (char *arg, int from_tty)
+{
+ char *name;
+ struct named_itset *it, **it_link;
+ int found;
+
+ if (arg == NULL || *arg == '\0')
+ error_no_arg (_("no args"));
+
+ name = skip_spaces (arg);
+
+ if (strcmp (name, "-all") == 0)
+ {
+ it = named_itsets;
+ it_link = &named_itsets;
+ while (it != NULL)
+ {
+ if (it->number > 0)
+ {
+ *it_link = it->next;
+ free_named_itset (it);
+ }
+ else
+ it_link = &it->next;
+ it = *it_link;
+ }
+ return;
+ }
+
+ found = 0;
+ it = named_itsets;
+ it_link = &named_itsets;
+ while (it != NULL)
+ {
+ if (strcmp (it->set->name, name) == 0)
+ {
+ if (it->number < 0)
+ error (_("cannot delete builtin I/T set"));
+
+ *it_link = it->next;
+ free_named_itset (it);
+ found = 1;
+ break;
+ }
+
+ it_link = &it->next;
+ it = *it_link;
+ }
+
+ if (!found)
+ warning (_("itset %s does not exist"), name);
+}
+
+static void
+itsets_info (char *arg, int allflag, int from_tty)
+{
+ struct named_itset *e;
+ int num_printable_entries;
+ struct cleanup *tbl_chain;
+
+ /* Compute the number of rows in the table. */
+ num_printable_entries = 0;
+ ALL_NAMED_ITSETS (e)
+ if (allflag
+ || (e->number > 0
+ && (arg == NULL || number_is_in_list (arg, e->number))))
+ num_printable_entries++;
+
+ if (num_printable_entries == 0)
+ {
+ if (arg == NULL)
+ ui_out_message (current_uiout, 0, _("No named itsets.\n"));
+ else
+ ui_out_message (current_uiout, 0,
+ _("No named itset found with number %s.\n"), arg);
+
+ return;
+ }
+
+ tbl_chain
+ = make_cleanup_ui_out_table_begin_end (current_uiout, 3,
+ num_printable_entries,
+ "NamedItsetListTable");
+
+ ui_out_table_header (current_uiout, 7, ui_left, "number", "Num"); /* 1 */
+ ui_out_table_header (current_uiout, 14, ui_left, "name", "Name"); /* 2 */
+ ui_out_table_header (current_uiout, 40, ui_noalign, "what", "What"); /* 3 */
+ ui_out_table_body (current_uiout);
+
+ ALL_NAMED_ITSETS (e)
+ if (allflag
+ || (e->number > 0
+ && (arg == NULL || number_is_in_list (arg, e->number))))
+ {
+ struct cleanup *entry_chain;
+
+ QUIT;
+
+ entry_chain
+ = make_cleanup_ui_out_tuple_begin_end (current_uiout, "named-itset");
+ ui_out_field_int (current_uiout, "number", e->number); /* 1 */
+ ui_out_field_string (current_uiout, "name", e->set->name); /* 2 */
+ ui_out_field_string (current_uiout, "what", e->set->spec); /* 3 */
+ ui_out_text (current_uiout, "\n");
+ do_cleanups (entry_chain);
+ }
+
+ do_cleanups (tbl_chain);
+}
+
+static void
+info_itsets_command (char *arg, int from_tty)
+{
+ itsets_info (arg, 0, from_tty);
+}
+
+static void
+maintenance_info_itsets_command (char *arg, int from_tty)
+{
+ itsets_info (arg, 1, from_tty);
+}
+
+static int
+whichsets_callback (struct thread_info *thr, void *data)
+{
+ struct named_itset *named_itset;
+ struct inferior *inf = get_thread_inferior (thr);
+ int printed = 0;
+
+ ALL_NAMED_ITSETS(named_itset)
+ {
+ QUIT;
+
+ if (itset_contains_thread (named_itset->set, thr))
+ {
+ if (!printed)
+ {
+ printf_filtered (_("i%d.t%d (%s) is in:"),
+ inf->num, thr->num,
+ target_pid_to_str (thr->ptid));
+ printf_filtered (" %s", itset_name (named_itset->set));
+ printed = 1;
+ }
+ else
+ printf_filtered (", %s", itset_name (named_itset->set));
+ }
+ }
+
+ if (printed)
+ printf_filtered ("\n");
+
+ return 0;
+}
+
+static void
+whichsets_command (char *arg, int from_tty)
+{
+ struct named_itset *named_itset;
+ struct itset *itset;
+ struct cleanup *old_chain;
+
+ if (arg == NULL)
+ {
+ /* No arg means all threads. */
+ itset = itset_reference (current_itset);
+ }
+ else
+ {
+ arg = skip_spaces (arg);
+ itset = itset_create (&arg);
+ }
+
+ old_chain = make_cleanup_itset_free (itset);
+ iterate_over_itset_threads (itset, whichsets_callback, NULL);
+ do_cleanups (old_chain);
+}
+
+static void
+viewset (struct itset *itset)
+{
+ struct inferior *inf;
+ struct thread_info *thr;
+ int printed;
+
+ printf_filtered ("%s contains:\n", itset_name (itset)
+ ? itset_name (itset) : itset_spec (itset));
+
+ printed = 0;
+ ALL_INFERIORS (inf)
+ {
+ if (itset_contains_inferior (itset, inf))
+ {
+ if (!printed)
+ {
+ printf_filtered (_(" inferiors: %d"), inf->num);
+ printed = 1;
+ }
+ else
+ printf_filtered (", %d", inf->num);
+
+ }
+ }
+ if (printed)
+ printf_filtered ("\n");
+
+ printed = 0;
+ ALL_THREADS (thr)
+ {
+ if (itset_contains_thread (itset, thr))
+ {
+ if (!printed)
+ {
+ printf_filtered (_(" threads: %d"), thr->num);
+ printed = 1;
+ }
+ else
+ printf_filtered (", %d", thr->num);
+ }
+ }
+ if (printed)
+ printf_filtered ("\n");
+
+ printed = 0;
+ ALL_THREADS (thr)
+ {
+ if (itset_contains_thread (itset, thr))
+ {
+ int core;
+
+ core = target_core_of_thread (thr->ptid);
+ if (core == -1)
+ break;
+
+ if (!printed)
+ {
+ printf_filtered (_(" cores: %d"), core);
+ printed = 1;
+ }
+ else
+ printf_filtered (", %d", core);
+ }
+ }
+ if (printed)
+ printf_filtered ("\n");
+}
+
+static void
+viewset_command (char *arg, int from_tty)
+{
+ struct named_itset *named_itset;
+
+ if (arg == NULL)
+ {
+ struct named_itset *e;
+ struct itset *itset;
+
+ /* No arg means all debugger- and user-defined sets. */
+ ALL_NAMED_ITSETS (named_itset)
+ viewset (named_itset->set);
+ }
+ else
+ {
+ struct itset *itset;
+ struct cleanup *old_chain;
+
+ arg = skip_spaces (arg);
+ itset = itset_create (&arg);
+ old_chain = make_cleanup_itset_free (itset);
+ viewset (itset);
+ do_cleanups (old_chain);
+ }
+}
+
+static void
+make_internal_itset (struct itset *itset, const char *name)
+{
+ struct named_itset *named_itset;
+
+ named_itset = make_itset_named_itset (itset, xstrdup (name), 1);
+ add_to_named_itset_chain (named_itset);
+}
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_itset;
+
+void
+_initialize_itset (void)
+{
+ struct cmd_list_element *c = NULL;
+
+ all_itset = itset_create_all ();
+ empty_itset = itset_create_empty ();
+ running_itset = itset_create_running ();
+ stopped_itset = itset_create_stopped ();
+ curinf_itset = itset_create_curinf ();
+
+ make_internal_itset (all_itset, "all");
+ make_internal_itset (empty_itset, "empty");
+ make_internal_itset (running_itset, "running");
+ make_internal_itset (stopped_itset, "stopped");
+ make_internal_itset (curinf_itset, "curinf");
+
+ current_itset = itset_reference (all_itset);
+
+ add_com ("defset", no_class, defset_command, _("\
+Define a new named set.\n\
+Usage: defset NAME SPEC"));
+
+ add_com ("undefset", no_class, undefset_command, _("\
+Undefine an existing named set.\n\
+Usage: undefset NAME | -all"));
+
+ add_com ("whichsets", no_class, whichsets_command, _("\
+List all sets to which threads in a given set belong to.\n\
+Usage: whichsets SET.\n\
+Defaults to the current set."));
+
+ add_com ("viewset", no_class, viewset_command, _("\
+List the members of a set.\n\
+Usage: viewset SET.\n\
+Defaults to all named sets."));
+
+ add_info ("itsets", info_itsets_command, _("\
+Display the list of defined named itsets.\n\
+You can specify numbers (e.g. \"info itsets 1 3\"),\n\
+ranges (e.g. \"info itsets 4-8\"), or both (e.g. \"info itsets 1 3 4-8\").\n\n\
+If you don't specify any numbers or ranges, we'll show all itsets.\n\n\
+Usage: info itsets [NUMBERS AND/OR RANGES]\n"));
+
+ add_cmd ("itsets", class_maintenance, maintenance_info_itsets_command, _("\
+Display the list of all defined named itsets, user-defined and built-in.\n"),
+ &maintenanceinfolist);
+}
diff --git a/gdb/itset.h b/gdb/itset.h
new file mode 100644
index 0000000..5712a3c
--- /dev/null
+++ b/gdb/itset.h
@@ -0,0 +1,122 @@
+/* itset.h - Inferior/Thread sets.
+ Copyright (C) 2010 - 2012 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef ITSET_H
+#define ITSET_H
+
+struct inferior;
+struct thread_info;
+struct cleanup;
+
+/* This is an opaque type representing an I/T set. An I/T set is
+ simply a set of inferiors and/or threads. A set may be dynamic
+ (the members are enumerated at the time of use) or static (the
+ members are enumerated at the time of construction); but this
+ distinction is hidden from the callers. An I/T set object is
+ reference counted. */
+
+struct itset;
+
+/* Create a new I/T set from a user specification. The valid forms of
+ a specification are documented in the manual. *SPEC is the input
+ specification, and it is updated to point to the first non-space
+ character after the end of the specification. */
+
+struct itset *itset_create (char **spec);
+
+/* Add ADDME to the I/T set TO. In other words, after the call, TO
+ will be the union set of TO at entry, and ADDME. */
+
+void itset_add_set (struct itset *to, struct itset *addme);
+
+/* Create an empty I/T set. Usually, an empty set is the set that
+ matches nothing. In some contexts, though, an empty set represents
+ some default. */
+
+struct itset *itset_create_empty (void);
+
+/* Returns true if SET is the empty set. That is a set whose spec is
+ either "" or "empty". */
+
+int itset_is_empty_set (struct itset *set);
+
+/* Returns true if ITSET is empty. That is, the set contains no
+ inferiors, threads, etc. */
+
+int itset_is_empty (const struct itset *itset);
+
+/* Create a new dynamic I/T set which represents the current inferior,
+ at the time the I/T set if consulted. */
+
+struct itset *itset_create_current (void);
+
+/* Like itset_create, but if *SPEC does not appear to be the start of
+ an I/T set, it will call itset_create_current and return the
+ result. */
+
+struct itset *itset_create_or_default (char **spec);
+
+/* Return true if the inferior is contained in the I/T set. */
+
+int itset_contains_inferior (struct itset *itset, struct inferior *inf);
+
+/* Return true if the thread is contained in the I/T set. */
+
+int itset_contains_thread (struct itset *itset, struct thread_info *inf);
+
+/* Return true if the inferior is contained in the I/T set. */
+
+int itset_member (struct itset *itset, int inf_id, int thread_id);
+
+/* Return a pointer to the I/T set's name. Unnamed I/T sets have a
+ NULL name. */
+
+const char *itset_name (const struct itset *itset);
+
+/* Return a pointer to the I/T set's spec. */
+
+const char *itset_spec (const struct itset *itset);
+
+/* Acquire a new reference to an I/T set. Returns the I/T set, for
+ convenience. */
+
+struct itset *itset_reference (struct itset *itset);
+
+/* Release a reference to an I/T set. */
+
+void itset_free (struct itset *itset);
+
+struct cleanup *make_cleanup_itset_free (struct itset *itset);
+
+/* A cleanup function that calls itset_free. */
+
+void itset_cleanup (void *itset);
+
+/* Like iterate_over_inferiors, but iterate over only those inferiors
+ in ITSET. */
+
+typedef int (itset_inf_callback_func) (struct inferior *, void *);
+struct inferior *iterate_over_itset_inferiors (struct itset *itset,
+ itset_inf_callback_func *callback,
+ void *data);
+
+/* The current I/T set. */
+
+extern struct itset *current_itset;
+
+#endif /* ITSET_H */
diff --git a/gdb/thread.c b/gdb/thread.c
index d361dd8..02fdc7d 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -54,7 +54,7 @@ void _initialize_thread (void);
/* Prototypes for local functions. */
-static struct thread_info *thread_list = NULL;
+struct thread_info *thread_list = NULL;
static int highest_thread_num;
static void thread_command (char *tidstr, int from_tty);
@@ -73,6 +73,15 @@ inferior_thread (void)
return tp;
}
+struct inferior *
+get_thread_inferior (struct thread_info *thr)
+{
+ int pid;
+
+ pid = ptid_get_pid (thr->ptid);
+ return find_inferior_pid (pid);
+}
+
void
delete_step_resume_breakpoint (struct thread_info *tp)
{
--
1.7.0.4