aboutsummaryrefslogtreecommitdiff
path: root/gdb/mi/mi-main.c
diff options
context:
space:
mode:
authorVladimir Prus <vladimir@codesourcery.com>2010-01-12 21:40:25 +0000
committerVladimir Prus <vladimir@codesourcery.com>2010-01-12 21:40:25 +0000
commitdc146f7c09d1369f5621e4aac23d410d40d3a6f0 (patch)
tree801e78e7bbd124f1c503f26bf1173741e224cb33 /gdb/mi/mi-main.c
parent837504c42dbf7cb67ee328fb0bdf594b70c90209 (diff)
downloadgdb-dc146f7c09d1369f5621e4aac23d410d40d3a6f0.zip
gdb-dc146f7c09d1369f5621e4aac23d410d40d3a6f0.tar.gz
gdb-dc146f7c09d1369f5621e4aac23d410d40d3a6f0.tar.bz2
Implement core awareness.
* bcache.c (compare_ints): Remove (print_percentage): Use compare_positive_ints. * defs.h (compare_positive_ints): Declare. * linux-nat.h (struct lin_lwp): New field core. (linux_nat_core_of_thread_1): Declare. * linux-nat.c (add_lwp): Init the 'core' field. (linux_nat_wait_1): Record the core. (linux_nat_core_of_thread_1, linux_nat_core_of_thread): New. (linux_nat_add_target): Register the above. * linux-thread-db.c (update_thread_core): New. (thread_db_find_new_threads): Update core information for every thread. * remote.c (struct private_thread_info): New. (free_private_thread_info, demand_private_info): New. (PACKET_qXfer_threads, use_osdata_threads): New. (struct thread_item, threads_parsing_context (start_thread, end_thread, thread_attributes) (thread_children, threads_children, threads_elements): New. (remote_threads_info): Try qXfer:threads before anything else. (remote_protocol_packets): Register qXfer:threads. (remote_open_1): Init use_osdata_threads. (struct stop_reply): New field 'core'. (remote_parse_stop_reply): Parse core number. (process_stop_reply): Record core number. (remote_xfer_partial): Handle qXfer:threads. (remote_core_of_thread): New. (init_remote_ops): Register remote_core_of_thread. (_initialize_remote): Register qXfer:read. * target.c (target_core_of_thread): New * target.h (enum target_object): New value TARGET_OBJECT_THREADS. (struct target_ops): New field to_core_of_threads. (target_core_of_thread): Declare. * gdbthread.h (struct thread_info): New field private_dtor. * thread.c (print_thread_info): Report the core. * ui-out.c (MAX_UI_OUT_LEVELS): Increase. * utils.c (compare_positive_ints): New. * features/threads.dtd: New. * mi/mi-interp.c (mi_on_normal_stop): Report the core. * mi/mi-main.c (struct collect_cores_data, collect_cores) (do_nothing, free_vector_of_osdata_items) (splay_tree_int_comparator, free_splay_tree): New. (print_one_inferior_data): Implemented printing of selected inferiors. Collect and print cores. (output_cores): New. (mi_cmd_list_thread_groups): Support --recurse. Permit specifying thread groups together with --available.
Diffstat (limited to 'gdb/mi/mi-main.c')
-rw-r--r--gdb/mi/mi-main.c357
1 files changed, 310 insertions, 47 deletions
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 16f6102..aee246c 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -50,6 +50,7 @@
#include "valprint.h"
#include "inferior.h"
#include "osdata.h"
+#include "splay-tree.h"
#include <ctype.h>
#include <sys/time.h>
@@ -360,11 +361,55 @@ mi_cmd_thread_info (char *command, char **argv, int argc)
print_thread_info (uiout, thread, -1);
}
+struct collect_cores_data
+{
+ int pid;
+
+ VEC (int) *cores;
+};
+
+static int
+collect_cores (struct thread_info *ti, void *xdata)
+{
+ struct collect_cores_data *data = xdata;
+
+ if (ptid_get_pid (ti->ptid) == data->pid)
+ {
+ int core = target_core_of_thread (ti->ptid);
+ if (core != -1)
+ VEC_safe_push (int, data->cores, core);
+ }
+
+ return 0;
+}
+
+static int *
+unique (int *b, int *e)
+{
+ int *d = b;
+ while (++b != e)
+ if (*d != *b)
+ *++d = *b;
+ return ++d;
+}
+
+struct print_one_inferior_data
+{
+ int recurse;
+ VEC (int) *inferiors;
+};
+
static int
-print_one_inferior (struct inferior *inferior, void *arg)
+print_one_inferior (struct inferior *inferior, void *xdata)
{
- if (inferior->pid != 0)
+ struct print_one_inferior_data *top_data = xdata;
+
+ if (VEC_empty (int, top_data->inferiors)
+ || bsearch (&(inferior->pid), VEC_address (int, top_data->inferiors),
+ VEC_length (int, top_data->inferiors), sizeof (int),
+ compare_positive_ints))
{
+ struct collect_cores_data data;
struct cleanup *back_to
= make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
@@ -372,81 +417,299 @@ print_one_inferior (struct inferior *inferior, void *arg)
ui_out_field_string (uiout, "type", "process");
ui_out_field_int (uiout, "pid", inferior->pid);
+ data.pid = inferior->pid;
+ data.cores = 0;
+ iterate_over_threads (collect_cores, &data);
+
+ if (!VEC_empty (int, data.cores))
+ {
+ int elt;
+ int i;
+ int *b, *e;
+ struct cleanup *back_to_2 =
+ make_cleanup_ui_out_list_begin_end (uiout, "cores");
+
+ qsort (VEC_address (int, data.cores),
+ VEC_length (int, data.cores), sizeof (int),
+ compare_positive_ints);
+
+ b = VEC_address (int, data.cores);
+ e = b + VEC_length (int, data.cores);
+ e = unique (b, e);
+
+ for (; b != e; ++b)
+ ui_out_field_int (uiout, NULL, *b);
+
+ do_cleanups (back_to_2);
+ }
+
+ if (top_data->recurse)
+ print_thread_info (uiout, -1, inferior->pid);
+
do_cleanups (back_to);
}
return 0;
}
-void
-mi_cmd_list_thread_groups (char *command, char **argv, int argc)
+/* Output a field named 'cores' with a list as the value. The elements of
+ the list are obtained by splitting 'cores' on comma. */
+
+static void
+output_cores (struct ui_out *uiout, const char *field_name, const char *xcores)
{
- struct cleanup *back_to;
- int available = 0;
- char *id = NULL;
+ struct cleanup *back_to = make_cleanup_ui_out_list_begin_end (uiout,
+ field_name);
+ char *cores = xstrdup (xcores);
+ char *p = cores;
- if (argc > 0 && strcmp (argv[0], "--available") == 0)
- {
- ++argv;
- --argc;
- available = 1;
- }
+ make_cleanup (xfree, cores);
- if (argc > 0)
- id = argv[0];
+ for (p = strtok (p, ","); p; p = strtok (NULL, ","))
+ ui_out_field_string (uiout, NULL, p);
- back_to = make_cleanup (null_cleanup, NULL);
+ do_cleanups (back_to);
+}
- if (available && id)
- {
- error (_("Can only report top-level available thread groups"));
- }
- else if (available)
- {
- struct osdata *data;
- struct osdata_item *item;
- int ix_items;
+static void
+free_vector_of_ints (void *xvector)
+{
+ VEC (int) **vector = xvector;
+ VEC_free (int, *vector);
+}
- data = get_osdata ("processes");
- make_cleanup_osdata_free (data);
+static void
+do_nothing (splay_tree_key k)
+{
+}
- make_cleanup_ui_out_list_begin_end (uiout, "groups");
+static void
+free_vector_of_osdata_items (splay_tree_value xvalue)
+{
+ VEC (osdata_item_s) *value = (VEC (osdata_item_s) *) xvalue;
+ /* We don't free the items itself, it will be done separately. */
+ VEC_free (osdata_item_s, value);
+}
+
+static int
+splay_tree_int_comparator (splay_tree_key xa, splay_tree_key xb)
+{
+ int a = xa;
+ int b = xb;
+ return a - b;
+}
+
+static void
+free_splay_tree (void *xt)
+{
+ splay_tree t = xt;
+ splay_tree_delete (t);
+}
+
+static void
+list_available_thread_groups (VEC (int) *ids, int recurse)
+{
+ struct osdata *data;
+ struct osdata_item *item;
+ int ix_items;
+ /* This keeps a map from integer (pid) to VEC (struct osdata_item *)*
+ The vector contains information about all threads for the given
+ pid. */
+ splay_tree tree;
+
+ /* get_osdata will throw if it cannot return data. */
+ data = get_osdata ("processes");
+ make_cleanup_osdata_free (data);
+
+ if (recurse)
+ {
+ struct osdata *threads = get_osdata ("threads");
+ make_cleanup_osdata_free (threads);
+
+ tree = splay_tree_new (splay_tree_int_comparator,
+ do_nothing,
+ free_vector_of_osdata_items);
+ make_cleanup (free_splay_tree, tree);
for (ix_items = 0;
- VEC_iterate (osdata_item_s, data->items,
+ VEC_iterate (osdata_item_s, threads->items,
ix_items, item);
ix_items++)
{
- struct cleanup *back_to =
- make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
-
const char *pid = get_osdata_column (item, "pid");
- const char *cmd = get_osdata_column (item, "command");
- const char *user = get_osdata_column (item, "user");
+ int pid_i = strtoul (pid, NULL, 0);
+ VEC (osdata_item_s) *vec = 0;
+
+ splay_tree_node n = splay_tree_lookup (tree, pid_i);
+ if (!n)
+ {
+ VEC_safe_push (osdata_item_s, vec, item);
+ splay_tree_insert (tree, pid_i, (splay_tree_value)vec);
+ }
+ else
+ {
+ vec = (VEC (osdata_item_s) *) n->value;
+ VEC_safe_push (osdata_item_s, vec, item);
+ n->value = (splay_tree_value) vec;
+ }
+ }
+ }
+
+ make_cleanup_ui_out_list_begin_end (uiout, "groups");
+
+ for (ix_items = 0;
+ VEC_iterate (osdata_item_s, data->items,
+ ix_items, item);
+ ix_items++)
+ {
+ struct cleanup *back_to;
+
+ const char *pid = get_osdata_column (item, "pid");
+ const char *cmd = get_osdata_column (item, "command");
+ const char *user = get_osdata_column (item, "user");
+ const char *cores = get_osdata_column (item, "cores");
+
+ int pid_i = strtoul (pid, NULL, 0);
+
+ /* At present, the target will return all available processes
+ and if information about specific ones was required, we filter
+ undesired processes here. */
+ if (ids && bsearch (&pid_i, VEC_address (int, ids),
+ VEC_length (int, ids),
+ sizeof (int), compare_positive_ints) == NULL)
+ continue;
+
- ui_out_field_fmt (uiout, "id", "%s", pid);
- ui_out_field_string (uiout, "type", "process");
- if (cmd)
- ui_out_field_string (uiout, "description", cmd);
- if (user)
- ui_out_field_string (uiout, "user", user);
+ back_to = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
- do_cleanups (back_to);
+ ui_out_field_fmt (uiout, "id", "%s", pid);
+ ui_out_field_string (uiout, "type", "process");
+ if (cmd)
+ ui_out_field_string (uiout, "description", cmd);
+ if (user)
+ ui_out_field_string (uiout, "user", user);
+ if (cores)
+ output_cores (uiout, "cores", cores);
+
+ if (recurse)
+ {
+ splay_tree_node n = splay_tree_lookup (tree, pid_i);
+ if (n)
+ {
+ VEC (osdata_item_s) *children = (VEC (osdata_item_s) *) n->value;
+ struct osdata_item *child;
+ int ix_child;
+
+ make_cleanup_ui_out_list_begin_end (uiout, "threads");
+
+ for (ix_child = 0;
+ VEC_iterate (osdata_item_s, children, ix_child, child);
+ ++ix_child)
+ {
+ struct cleanup *back_to_2 =
+ make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+
+ const char *tid = get_osdata_column (child, "tid");
+ const char *tcore = get_osdata_column (child, "core");
+ ui_out_field_string (uiout, "id", tid);
+ if (tcore)
+ ui_out_field_string (uiout, "core", tcore);
+
+ do_cleanups (back_to_2);
+ }
+ }
}
+
+ do_cleanups (back_to);
}
- else if (id)
+}
+
+void
+mi_cmd_list_thread_groups (char *command, char **argv, int argc)
+{
+ struct cleanup *back_to;
+ int available = 0;
+ int recurse = 0;
+ VEC (int) *ids = 0;
+
+ enum opt
{
- int pid = atoi (id);
+ AVAILABLE_OPT, RECURSE_OPT
+ };
+ static struct mi_opt opts[] =
+ {
+ {"-available", AVAILABLE_OPT, 0},
+ {"-recurse", RECURSE_OPT, 1},
+ { 0, 0, 0 }
+ };
+
+ int optind = 0;
+ char *optarg;
+
+ while (1)
+ {
+ int opt = mi_getopt ("-list-thread-groups", argc, argv, opts,
+ &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case AVAILABLE_OPT:
+ available = 1;
+ break;
+ case RECURSE_OPT:
+ if (strcmp (optarg, "0") == 0)
+ ;
+ else if (strcmp (optarg, "1") == 0)
+ recurse = 1;
+ else
+ error ("only '0' and '1' are valid values for the '--recurse' option");
+ break;
+ }
+ }
+
+ for (; optind < argc; ++optind)
+ {
+ char *end;
+ int inf = strtoul (argv[optind], &end, 0);
+ if (*end != '\0')
+ error ("invalid group id '%s'", argv[optind]);
+ VEC_safe_push (int, ids, inf);
+ }
+ if (VEC_length (int, ids) > 1)
+ qsort (VEC_address (int, ids),
+ VEC_length (int, ids),
+ sizeof (int), compare_positive_ints);
+
+ back_to = make_cleanup (free_vector_of_ints, &ids);
+
+ if (available)
+ {
+ list_available_thread_groups (ids, recurse);
+ }
+ else if (VEC_length (int, ids) == 1)
+ {
+ /* Local thread groups, single id. */
+ int pid = *VEC_address (int, ids);
if (!in_inferior_list (pid))
- error ("Invalid thread group id '%s'", id);
- print_thread_info (uiout, -1, pid);
+ error ("Invalid thread group id '%d'", pid);
+ print_thread_info (uiout, -1, pid);
}
else
{
+ struct print_one_inferior_data data;
+ data.recurse = recurse;
+ data.inferiors = ids;
+
+ /* Local thread groups. Either no explicit ids -- and we
+ print everything, or several explicit ids. In both cases,
+ we print more than one group, and have to use 'groups'
+ as the top-level element. */
make_cleanup_ui_out_list_begin_end (uiout, "groups");
- iterate_over_inferiors (print_one_inferior, NULL);
+ update_thread_list ();
+ iterate_over_inferiors (print_one_inferior, &data);
}
-
+
do_cleanups (back_to);
}