[PATCH v2] Add "inferior id" and "id in inferior" info to -thread-info output

Simon Marchi simon.marchi@ericsson.com
Wed Apr 12 18:54:00 GMT 2017


This is a v2 of:

  https://sourceware.org/ml/gdb-patches/2017-01/msg00380.html
  [PATCH] Add "thread-group id" and "id in thread-group" info to -thread-info output

And it's meant to be applied on top of this series:

  https://sourceware.org/ml/gdb-patches/2017-04/msg00351.html
  [PATCH 1/2] Remove dead code and "current" field from MI thread output doc
  [PATCH 2/2] doc: Improve documentation about MI thread output

New in this version:

  - Doc and NEWS
  - Rename fields, use "inf" instead of "tg"
  - Test output with a single inferior before adding a second

The CLI has been showing inferior-qualified thread ids for a while, but
front-ends have no way to do the same, as only the global thread ids are
included in the MI output.  In front-ends in general, but mostly in
those that include a gdb console, it would be interesting to show the
same thread id in the GUI than what "info threads" displays.  The user
would then see consistent thread ids across the two UIs.

This patch adds two extra fields to the -thread-info MI command output.
In this snippet of prettified -thread-info output, the lines marked with
a + are new:

    {
+     inf-id = "2",
+     id-in-inf = "1",
      id = "3",
      target-id = "Thread 0x2aaaaab04640 (LWP 3228)",
      name = "mi-qualified-th",
      ...
    },

Here, the thread has the global id 3 (monotonously increasing across all
inferiors) and the inferior-qualified id 2.1.  The global thread id is
still the one used throughout the rest of MI.  The new fields are simply
intended to be presented to the user.

We chose adding the new information as two separate fields rather than a
single field with the value "2.1".  We think that it gives the front-end
more flexibility about how it want to present the info.

I updated the doc to mention the new fields.  I changed the example to
something that shows usefulness of the new fields.  It also shows a
better variety of thread states.  Note that the old example was
erroneous, it did show a thread as "running" with a frame.

gdb/ChangeLog:

	* thread.c (print_thread_info_1): Rename field id-in-tg to
	qualified-id.  Add new fields id-in-inf and inf-id when printing
	on MI.
	* NEWS: Mention new fields.

gdb/testsuite/ChangeLog:

	* mi-qualified-thread-id.exp: New file.
	* mi-qualified-thread-id.c: New file.

gdb/doc/ChangeLog:

	* gdb.texinfo (GDB/MI Thread Information): Document fields
	inf-id and id-in-inf.  Update example.
---
 gdb/NEWS                                        |  7 ++
 gdb/doc/gdb.texinfo                             | 86 +++++++++++++++++++---
 gdb/testsuite/gdb.mi/mi-qualified-thread-id.c   | 57 ++++++++++++++
 gdb/testsuite/gdb.mi/mi-qualified-thread-id.exp | 98 +++++++++++++++++++++++++
 gdb/thread.c                                    | 11 ++-
 5 files changed, 246 insertions(+), 13 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-qualified-thread-id.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-qualified-thread-id.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 5b7748631f..38dd671743 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -109,6 +109,13 @@ maint print arc arc-instruction address
 Alpha running FreeBSD         alpha*-*-freebsd*
 Alpha running GNU/kFreeBSD    alpha*-*-kfreebsd*-gnu
 
+* New fields in the MI thread output tuple
+
+  When MI prints information about threads (e.g. with -thread-info and
+  -list-thread-groups --recurse 1), it now includes the "inf-id" and
+  "id-in-inf" fields.  They respectively indicate the inferior this thread
+  belongs to and its per-inferior id.
+
 *** Changes in GDB 7.12
 
 * GDB and GDBserver now build with a C++ compiler by default.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c6da2573eb..2b9263edee 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -26859,6 +26859,12 @@ stated otherwise.
 @item id
 The global numeric id assigned to the thread by @value{GDBN}.
 
+@item inf-id
+The global numeric id of the inferior the thread belongs to.
+
+@item id-in-inf
+The per-inferior numeric id of the thread.
+
 @item target-id
 The target-specific string identifying the thread.
 
@@ -28114,16 +28120,76 @@ command.
 
 @smallexample
 -thread-info
-^done,threads=[
-@{id="2",target-id="Thread 0xb7e14b90 (LWP 21257)",
-   frame=@{level="0",addr="0xffffe410",func="__kernel_vsyscall",
-           args=[]@},state="running"@},
-@{id="1",target-id="Thread 0xb7e156b0 (LWP 21254)",
-   frame=@{level="0",addr="0x0804891f",func="foo",
-           args=[@{name="i",value="10"@}],
-           file="/tmp/a.c",fullname="/tmp/a.c",line="158"@},
-           state="running"@}],
-current-thread-id="1"
+^done,
+  threads = [
+    @{
+      inf-id = "1",
+      id-in-inf = "1",
+      id = "1",
+      target-id = "Thread 0x7ffff7fcb740 (LWP 28300)",
+      name = "a",
+      frame = @{
+        level = "0",
+        addr = "0x000000000040062a",
+        func = "main",
+        args = [],
+        file = "a.c",
+        fullname = "/tmp/a.c",
+        line = "13"
+      @},
+      state = "stopped",
+      core = "3"
+    @},
+    @{
+      inf-id = "1",
+      id-in-inf = "2",
+      id = "2",
+      target-id = "Thread 0x7ffff77f3700 (LWP 28304)",
+      name = "a",
+      frame = @{
+        level = "0",
+        addr = "0x0000000000400605",
+        func = "thread_func",
+        args = [
+          @{
+            name = "v",
+            value = "0x0"
+          @}
+        ],
+        file = "a.c",
+        fullname = "/tmp/a.c",
+        line = "5"
+      @},
+      state = "stopped",
+      core = "1"
+    @},
+    @{
+      inf-id = "2",
+      id-in-inf = "1",
+      id = "3",
+      target-id = "Thread 0x7ffff7fcb740 (LWP 28319)",
+      name = "b",
+      state = "running",
+      core = "0"
+    @},
+    @{
+      inf-id = "2",
+      id-in-inf = "2",
+      id = "4",
+      target-id = "Thread 0x7ffff77f3700 (LWP 28320)",
+      name = "b",
+      frame = @{
+        level = "0",
+        addr = "0x00007ffff78b893d",
+        func = "nanosleep",
+        args = [],
+        from = "/lib/x86_64-linux-gnu/libc.so.6"
+      @},
+      state = "stopped",
+      core = "3"
+    @}
+  ],
+  current-thread-id = "3"
 (gdb)
 @end smallexample
 
diff --git a/gdb/testsuite/gdb.mi/mi-qualified-thread-id.c b/gdb/testsuite/gdb.mi/mi-qualified-thread-id.c
new file mode 100644
index 0000000000..cb50e50c32
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-qualified-thread-id.c
@@ -0,0 +1,57 @@
+/* Copyright 2017 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 <pthread.h>
+
+static pthread_barrier_t barrier;
+
+static void *
+thread_func (void *arg)
+{
+  /* Notify the main thread that this thread has started.  */
+  pthread_barrier_wait (&barrier);
+
+  /* Wait until main gives us the signal that we can quit.  */
+  pthread_barrier_wait (&barrier);
+  return NULL;
+}
+
+static void
+thread_started ()
+{
+}
+
+int main ()
+{
+  pthread_t thread;
+
+  pthread_barrier_init (&barrier, NULL, 2);
+
+  pthread_create (&thread, NULL, thread_func, NULL);
+
+  /* Wait until the thread has started.  */
+  pthread_barrier_wait (&barrier);
+
+  thread_started ();
+
+  /* Tell the thread that it can quit.  */
+  pthread_barrier_wait (&barrier);
+
+  pthread_join (thread, NULL);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.mi/mi-qualified-thread-id.exp b/gdb/testsuite/gdb.mi/mi-qualified-thread-id.exp
new file mode 100644
index 0000000000..27f70c05ab
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-qualified-thread-id.exp
@@ -0,0 +1,98 @@
+# Copyright 2017 Free Software Foundation, Inc.
+
+# 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/>.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile
+
+if  { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+     untested "failed to compile"
+     return -1
+}
+
+# Start gdb and set up the first inferior.  Run it until the thread_started
+# function.
+
+proc start_gdb_and_first_inferior { } {
+    global binfile
+    global srcdir
+    global subdir
+    global srcfile
+
+    gdb_exit
+    mi_gdb_start
+    mi_gdb_reinitialize_dir $srcdir/$subdir
+    mi_gdb_load ${binfile}
+
+    mi_create_breakpoint "thread_started" "insert breakpoint at thread_started"
+
+    mi_run_cmd
+    mi_expect_stop "breakpoint-hit" "thread_started" ".*" "${srcfile}" ".*" {"" "disp=\"keep\""} "inferior 1 stops"
+
+}
+
+# Add and start a second inferior.  Run it until the thread_started function.
+
+proc start_second_inferior { } {
+    global srcfile
+    global binfile
+
+    mi_gdb_test "add-inferior" ".*=thread-group-added,id=\"i2\".*" "add second inferior"
+    mi_gdb_test "inferior 2" ".*" "switch to inferior 2"
+    mi_gdb_load ${binfile}
+    mi_run_cmd
+    mi_expect_stop "breakpoint-hit" "thread_started" ".*" "${srcfile}" ".*" {"" "disp=\"keep\""} "inferior 2 stops"
+}
+
+proc test_thread_info_qualified_thread_id { } {
+    start_gdb_and_first_inferior
+
+    # Test the output with a single inferior.
+    set expected [join \
+	{ "111\\^done,threads=.*" \
+	  "inf-id=\"1\",id-in-inf=\"1\",id=\"1\".*" \
+	  "inf-id=\"1\",id-in-inf=\"2\",id=\"2\".*" \
+	} ""]
+
+    mi_gdb_test \
+	"111-thread-info" \
+	 $expected \
+	"thread ids in -thread-info with 1 inferior"
+
+    if {[use_gdb_stub]} {
+	# We can't test with a second inferior if we can't have multiple
+	# inferiors.
+	return
+    }
+
+    start_second_inferior
+
+    # Test the output with two inferiors.
+    set expected [join \
+	{ "112\\^done,threads=.*" \
+	  "inf-id=\"1\",id-in-inf=\"1\",id=\"1\".*" \
+	  "inf-id=\"1\",id-in-inf=\"2\",id=\"2\".*" \
+	  "inf-id=\"2\",id-in-inf=\"1\",id=\"3\".*" \
+	  "inf-id=\"2\",id-in-inf=\"2\",id=\"4\".*" \
+	} ""]
+
+    mi_gdb_test \
+	"112-thread-info" \
+	 $expected \
+	"thread ids in -thread-info with 2 inferiors"
+}
+
+test_thread_info_qualified_thread_id
diff --git a/gdb/thread.c b/gdb/thread.c
index 74d0d65e02..bb1a638024 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1264,7 +1264,7 @@ print_thread_info_1 (struct ui_out *uiout, char *requested_threads,
       uiout->table_header (1, ui_left, "current", "");
 
       if (!uiout->is_mi_like_p ())
-	uiout->table_header (4, ui_left, "id-in-tg", "Id");
+	uiout->table_header (4, ui_left, "inf-qualified-id", "Id");
       if (show_global_ids || uiout->is_mi_like_p ())
 	uiout->table_header (4, ui_left, "id", "GId");
       uiout->table_header (17, ui_left, "target-id", "Target Id");
@@ -1291,8 +1291,13 @@ print_thread_info_1 (struct ui_out *uiout, char *requested_threads,
 	    uiout->field_skip ("current");
 	}
 
-      if (!uiout->is_mi_like_p ())
-	uiout->field_string ("id-in-tg", print_thread_id (tp));
+      if (uiout->is_mi_like_p ())
+	{
+	  uiout->field_int ("inf-id", tp->inf->num);
+	  uiout->field_int ("id-in-inf", tp->per_inf_num);
+	}
+      else
+	uiout->field_string ("inf-qualified-id", print_thread_id (tp));
 
       if (show_global_ids || uiout->is_mi_like_p ())
 	uiout->field_int ("id", tp->global_num);
-- 
2.11.0



More information about the Gdb-patches mailing list