[Ada] Re-implement `info tasks' command using ui-out
authorJoel Brobecker <brobecker@gnat.com>
Fri, 16 Sep 2011 19:09:57 +0000 (19:09 +0000)
committerJoel Brobecker <brobecker@gnat.com>
Fri, 16 Sep 2011 19:09:57 +0000 (19:09 +0000)
This is in preparation for providing a GDB/MI equivalent of
the `info tasks' command.  The previous implementation was using
various printf commands to generate the command output, which
does not work at all if we want to use that same code to generate
the result for that new GDB/MI command.

This patch thus re-implements the `info tasks' command (with no
arguments) in a way that makes it GDB/MI friendly.

There is an additional hicup, which is the fact that the `info tasks'
command displays a completely different type of output when a task
ID is given. For instance:

    (gdb) info task 2
    Ada Task: 0x644d20
    Name: my_callee
    Thread: 0
    LWP: 0x5809
    Parent: 1 (main_task)
    Base Priority: 48
    State: Blocked in accept or select with terminate

The above output is better when in CLI mode, but really not
what we want when in GDB/MI mode. In GDB/MI mode, we want to
follow what the `-thread-info' command does when a task-id
is given as an argument, which is to produce the same table,
but with only one element/task in it.

For compatibility as well as practical reasons, we do not want
to change the output of the `info task TASKNO' command when in
CLI mode.  But it's easy to preserve this behavior while providing
the desirable output when in GDB/MI mode.  For this, the function
used to generated the `info tasks' output has been enhanced to take
an argument interpreted as a string. The CLI command knows to never
provide that argument, while the GDB/MI command will pass one if
provided by the user.

gdb/ChangeLog:

        * ada-tasks.c (print_ada_task_info): New function, merging
        short_task_info and info_tasks together.  Reimplement using
        ui-out instead of printing to stdout directly.  Move the code
        building and checking the task list here, instead of leaving it
        in info_tasks_command.
        (info_task): Move the code building and checking the task
        list here, instead of leaving it in info_tasks_command.
        (info_tasks_command): Delete code building and checking
        the task list - moved elsewhere.  Update calls to info_tasks
        and info_task.

One of the minor changes the switch caused is the introduction
of a space between the "current" column, and the task "ID"
column, which wasn't there before.  This matches what we do
in the "info threads" command, so I kept that change.  This
required an adjustment in the testsuite, however...

gdb/testsuite/ChangeLog:

        * gdb.ada/tasks.exp: Make the expected output for
        the `info tasks' tests more resilient to spacing
        changes.

gdb/ChangeLog
gdb/ada-tasks.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.ada/tasks.exp

index 9b3702f68c7963a5615cc7ea8ec0d588b6cd0286..491e33d857a30d759d4f80554893bbcfae4dc529 100644 (file)
@@ -1,3 +1,16 @@
+2011-09-16  Joel Brobecker  <brobecker@adacore.com>
+
+       * ada-tasks.c (print_ada_task_info): New function, merging
+       short_task_info and info_tasks together.  Reimplement using
+       ui-out instead of printing to stdout directly.  Move the code
+       building and checking the task list here, instead of leaving it
+       in info_tasks_command.
+       (info_task): Move the code building and checking the task
+       list here, instead of leaving it in info_tasks_command.
+       (info_tasks_command): Delete code building and checking
+       the task list - moved elsewhere.  Update calls to info_tasks
+       and info_task.
+
 2011-09-16  Joel Brobecker  <brobecker@adacore.com>
 
        * ada-tasks.c (info_task): Delete parameter `from_tty'.
index e2020f717ceff29f47cdd0f87526c7f6abe517c7..6e2f2f590c6bb7a9eb6f99f257710f58fe57d19d 100644 (file)
@@ -924,87 +924,134 @@ ada_build_task_list (void)
   return VEC_length (ada_task_info_s, data->task_list);
 }
 
-/* Print a one-line description of the task running in inferior INF
-   whose number is TASKNO.
-
-   The formatting should fit the "info tasks" array.  */
+/* Print a table providing a short description of all Ada tasks
+   running inside inferior INF.  If ARG_STR is set, it will be
+   interpreted as a task number, and the table will be limited to
+   that task only.  */
 
 static void
-short_task_info (int taskno, struct inferior *inf)
+print_ada_task_info (struct ui_out *uiout,
+                    char *arg_str,
+                    struct inferior *inf)
 {
-  struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
-  const struct ada_task_info *const task_info =
-    VEC_index (ada_task_info_s, data->task_list, taskno - 1);
-  int active_task_p;
+  struct ada_tasks_inferior_data *data;
+  int taskno, nb_tasks;
+  int taskno_arg = 0;
+  struct cleanup *old_chain;
 
-  gdb_assert (task_info != NULL);
+  if (ada_build_task_list () == 0)
+    {
+      ui_out_message (uiout, 0,
+                     _("Your application does not use any Ada tasks.\n"));
+      return;
+    }
 
-  /* Print a star if this task is the current task (or the task currently
-     selected).  */
+  if (arg_str != NULL && arg_str[0] != '\0')
+    taskno_arg = value_as_long (parse_and_eval (arg_str));
 
-  active_task_p = ptid_equal (task_info->ptid, inferior_ptid);
-  if (active_task_p)
-    printf_filtered ("*");
-  else
-    printf_filtered (" ");
+  data = get_ada_tasks_inferior_data (inf);
+  nb_tasks = VEC_length (ada_task_info_s, data->task_list);
 
-  /* Print the task number.  */
-  printf_filtered ("%3d", taskno);
+  old_chain = make_cleanup_ui_out_table_begin_end (uiout, 7, nb_tasks,
+                                                   "tasks");
+  ui_out_table_header (uiout, 1, ui_left, "current", "");
+  ui_out_table_header (uiout, 3, ui_right, "id", "ID");
+  ui_out_table_header (uiout, 9, ui_right, "task-id", "TID");
+  ui_out_table_header (uiout, 4, ui_right, "parent-id", "P-ID");
+  ui_out_table_header (uiout, 3, ui_right, "priority", "Pri");
+  ui_out_table_header (uiout, 22, ui_left, "state", "State");
+  /* Use ui_noalign for the last column, to prevent the CLI uiout
+     from printing an extra space at the end of each row.  This
+     is a bit of a hack, but does get the job done.  */
+  ui_out_table_header (uiout, 1, ui_noalign, "name", "Name");
+  ui_out_table_body (uiout);
 
-  /* Print the Task ID.  */
-  printf_filtered (" %9lx", (long) task_info->task_id);
+  for (taskno = 1; taskno <= nb_tasks; taskno++)
+    {
+      const struct ada_task_info *const task_info =
+       VEC_index (ada_task_info_s, data->task_list, taskno - 1);
+      int parent_id;
+      struct cleanup *chain2;
 
-  /* Print the Task ID of the task parent.  */
-  printf_filtered (" %4d", get_task_number_from_id (task_info->parent, inf));
+      gdb_assert (task_info != NULL);
 
-  /* Print the base priority of the task.  */
-  printf_filtered (" %3d", task_info->priority);
+      /* If the user asked for the output to be restricted
+        to one task only, and this is not the task, skip
+        to the next one.  */
+      if (taskno_arg && taskno != taskno_arg)
+        continue;
 
-  /* Print the task current state.  */
-  if (task_info->caller_task)
-    printf_filtered (_(" Accepting RV with %-4d"),
-                     get_task_number_from_id (task_info->caller_task, inf));
-  else if (task_info->state == Entry_Caller_Sleep && task_info->called_task)
-    printf_filtered (_(" Waiting on RV with %-3d"),
-                     get_task_number_from_id (task_info->called_task, inf));
-  else
-    printf_filtered (" %-22s", _(task_states[task_info->state]));
+      chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
 
-  /* Finally, print the task name.  */
-  if (task_info->name[0] != '\0')
-    printf_filtered (" %s\n", task_info->name);
-  else
-    printf_filtered (_(" <no name>\n"));
-}
+      /* Print a star if this task is the current task (or the task
+         currently selected).  */
+      if (ptid_equal (task_info->ptid, inferior_ptid))
+       ui_out_field_string (uiout, "current", "*");
+      else
+       ui_out_field_skip (uiout, "current");
 
-/* Print a list containing a short description of all Ada tasks
-   running inside inferior INF.  */
-/* FIXME: Shouldn't we be using ui_out???  */
+      /* Print the task number.  */
+      ui_out_field_int (uiout, "id", taskno);
 
-static void
-info_tasks (struct inferior *inf)
-{
-  struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
-  int taskno;
-  const int nb_tasks = VEC_length (ada_task_info_s, data->task_list);
+      /* Print the Task ID.  */
+      ui_out_field_fmt (uiout, "task-id", "%9lx", (long) task_info->task_id);
 
-  printf_filtered (_("  ID       TID P-ID Pri State                  Name\n"));
-  
-  for (taskno = 1; taskno <= nb_tasks; taskno++)
-    short_task_info (taskno, inf);
+      /* Print the ID of the parent task.  */
+      parent_id = get_task_number_from_id (task_info->parent, inf);
+      if (parent_id)
+        ui_out_field_int (uiout, "parent-id", parent_id);
+      else
+        ui_out_field_skip (uiout, "parent-id");
+
+      /* Print the base priority of the task.  */
+      ui_out_field_int (uiout, "priority", task_info->priority);
+
+      /* Print the task current state.  */
+      if (task_info->caller_task)
+       ui_out_field_fmt (uiout, "state",
+                         _("Accepting RV with %-4d"),
+                         get_task_number_from_id (task_info->caller_task,
+                                                  inf));
+      else if (task_info->state == Entry_Caller_Sleep
+              && task_info->called_task)
+       ui_out_field_fmt (uiout, "state",
+                         _("Waiting on RV with %-3d"),
+                         get_task_number_from_id (task_info->called_task,
+                                                  inf));
+      else
+       ui_out_field_string (uiout, "state", task_states[task_info->state]);
+
+      /* Finally, print the task name.  */
+      ui_out_field_fmt (uiout, "name",
+                       "%s",
+                       task_info->name[0] != '\0' ? task_info->name
+                                                  : _("<no name>"));
+
+      ui_out_text (uiout, "\n");
+      do_cleanups (chain2);
+    }
+
+  do_cleanups (old_chain);
 }
 
 /* Print a detailed description of the Ada task whose ID is TASKNO_STR
    for the given inferior (INF).  */
 
 static void
-info_task (char *taskno_str, struct inferior *inf)
+info_task (struct ui_out *uiout, char *taskno_str, struct inferior *inf)
 {
   const int taskno = value_as_long (parse_and_eval (taskno_str));
   struct ada_task_info *task_info;
   int parent_taskno = 0;
   struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
 
+  if (ada_build_task_list () == 0)
+    {
+      ui_out_message (uiout, 0,
+                     _("Your application does not use any Ada tasks.\n"));
+      return;
+    }
+
   if (taskno <= 0 || taskno > VEC_length (ada_task_info_s, data->task_list))
     error (_("Task ID %d not known.  Use the \"info tasks\" command to\n"
              "see the IDs of currently known tasks"), taskno);
@@ -1086,17 +1133,10 @@ info_tasks_command (char *arg, int from_tty)
 {
   struct ui_out *uiout = current_uiout;
 
-  if (ada_build_task_list () == 0)
-    {
-      ui_out_message (uiout, 0,
-                     _("Your application does not use any Ada tasks.\n"));
-      return;
-    }
-
   if (arg == NULL || *arg == '\0')
-    info_tasks (current_inferior ());
+    print_ada_task_info (uiout, NULL, current_inferior ());
   else
-    info_task (arg, current_inferior ());
+    info_task (uiout, arg, current_inferior ());
 }
 
 /* Print a message telling the user id of the current task.
index 99e220c03023bb8e63ad83bbca193f91c9da931d..7222a2d812fe038eb795c2f83541468e861843f5 100644 (file)
@@ -1,3 +1,9 @@
+2011-09-16  Joel Brobecker  <brobecker@adacore.com>
+
+       * gdb.ada/tasks.exp: Make the expected output for
+       the `info tasks' tests more resilient to spacing
+       changes.
+
 2011-09-16  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * gdb.python/py-evthreads.exp (Run to breakpoint 1)
index 1ba1bb854bbec16866e9ba8b32089bec746fe2a6..17dd2b898a937eb56f0e1953499d46c6a9031146 100644 (file)
@@ -37,11 +37,11 @@ runto "foo.adb:$bp_location"
 # Make sure that all tasks appear in the "info tasks" listing, and
 # that the active task is the environment task.
 gdb_test "info tasks" \
-         [join {"  ID       TID P-ID Pri State                  Name" \
-                "\\*  1 .* main_task" \
-                "   2 .* task_list\\(1\\)" \
-                "   3 .* task_list\\(2\\)" \
-                "   4 .* task_list\\(3\\)"} \
+         [join {" +ID +TID P-ID Pri State +Name" \
+                "\\* +1 .* main_task" \
+                " +2 .* task_list\\(1\\)" \
+                " +3 .* task_list\\(2\\)" \
+                " +4 .* task_list\\(3\\)"} \
                "\r\n"] \
          "info tasks before inserting breakpoint"
 
@@ -59,11 +59,11 @@ gdb_test "continue" \
 # Check that it is indeed task 3 that hit the breakpoint by checking
 # which is the active task.
 gdb_test "info tasks" \
-         [join {"  ID       TID P-ID Pri State                  Name" \
-                "   1 .* main_task" \
-                "   2 .* task_list\\(1\\)" \
-                "\\*  3 .* task_list\\(2\\)" \
-                "   4 .* task_list\\(3\\)"} \
+         [join {" +ID +TID P-ID Pri State +Name" \
+                " +1 .* main_task" \
+                " +2 .* task_list\\(1\\)" \
+                "\\* +3 .* task_list\\(2\\)" \
+                " +4 .* task_list\\(3\\)"} \
                "\r\n"] \
          "info tasks after hitting breakpoint"