* [PATCH 0/3] Option to show stopped threads only
@ 2023-04-05 9:19 Tankut Baris Aktemur via Gdb-patches
2023-04-05 9:20 ` [PATCH 1/3] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur via Gdb-patches
` (4 more replies)
0 siblings, 5 replies; 32+ messages in thread
From: Tankut Baris Aktemur via Gdb-patches @ 2023-04-05 9:19 UTC (permalink / raw)
To: gdb-patches
Hi,
This is a short series that adds a "-stopped" option to the "info threads"
to show stopped threads only.
Regards
Baris
Tankut Baris Aktemur (3):
gdb: pass info_threads_opts to print_thread_info_1
gdb, doc: add the missing '-gid' option to 'info threads'
gdb: add a '-stopped' option to "info threads"
gdb/NEWS | 7 ++
gdb/doc/gdb.texinfo | 6 +-
gdb/testsuite/gdb.base/options.exp | 11 ++-
.../gdb.threads/info-threads-stopped.c | 78 +++++++++++++++++++
.../gdb.threads/info-threads-stopped.exp | 75 ++++++++++++++++++
gdb/thread.c | 76 +++++++++++-------
6 files changed, 221 insertions(+), 32 deletions(-)
create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c
create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp
--
2.25.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH 1/3] gdb: pass info_threads_opts to print_thread_info_1 2023-04-05 9:19 [PATCH 0/3] Option to show stopped threads only Tankut Baris Aktemur via Gdb-patches @ 2023-04-05 9:20 ` Tankut Baris Aktemur via Gdb-patches 2023-04-05 9:20 ` [PATCH 2/3] gdb, doc: add the missing '-gid' option to 'info threads' Tankut Baris Aktemur via Gdb-patches ` (3 subsequent siblings) 4 siblings, 0 replies; 32+ messages in thread From: Tankut Baris Aktemur via Gdb-patches @ 2023-04-05 9:20 UTC (permalink / raw) To: gdb-patches The "info threads" command tracks its options in a struct named 'info_threads_opts', which currently has only one option. Pass the whole options object to helper functions, instead of passing the option value individually. This is a refactoring to make adding more options easier. --- gdb/thread.c | 61 +++++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/gdb/thread.c b/gdb/thread.c index 4d97ed3f2d1..57b3f7611e2 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -951,6 +951,24 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread) && pc < thread->control.step_range_end); } +/* The options for the "info threads" command. */ + +struct info_threads_opts +{ + /* For "-gid". */ + bool show_global_ids = false; +}; + +static const gdb::option::option_def info_threads_option_defs[] = { + + gdb::option::flag_option_def<info_threads_opts> { + "gid", + [] (info_threads_opts *opts) { return &opts->show_global_ids; }, + N_("Show global thread IDs."), + }, + +}; + /* Helper for print_thread_info. Returns true if THR should be printed. If REQUESTED_THREADS, a list of GDB ids/ranges, is not NULL, only print THR if its ID is included in the list. GLOBAL_IDS @@ -959,11 +977,13 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread) is a thread from the process PID. Otherwise, threads from all attached PIDs are printed. If both REQUESTED_THREADS is not NULL and PID is not -1, then the thread is printed if it belongs to the - specified process. Otherwise, an error is raised. */ + specified process. Otherwise, an error is raised. OPTS is the + options of the "info threads" command. */ static bool should_print_thread (const char *requested_threads, int default_inf_num, - int global_ids, int pid, struct thread_info *thr) + int global_ids, int pid, thread_info *thr, + info_threads_opts opts) { if (requested_threads != NULL && *requested_threads != '\0') { @@ -1014,12 +1034,12 @@ thread_target_id_str (thread_info *tp) /* Like print_thread_info, but in addition, GLOBAL_IDS indicates whether REQUESTED_THREADS is a list of global or per-inferior - thread ids. */ + thread ids. OPTS is the options of the "info threads" command. */ static void print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, int global_ids, int pid, - int show_global_ids) + info_threads_opts opts) { int default_inf_num = current_inferior ()->num; @@ -1055,7 +1075,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, for (thread_info *tp : all_threads ()) { if (!should_print_thread (requested_threads, default_inf_num, - global_ids, pid, tp)) + global_ids, pid, tp, opts)) continue; /* Switch inferiors so we're looking at the right @@ -1079,12 +1099,12 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, return; } - table_emitter.emplace (uiout, show_global_ids ? 5 : 4, + table_emitter.emplace (uiout, opts.show_global_ids ? 5 : 4, n_threads, "threads"); uiout->table_header (1, ui_left, "current", ""); uiout->table_header (4, ui_left, "id-in-tg", "Id"); - if (show_global_ids) + if (opts.show_global_ids) uiout->table_header (4, ui_left, "id", "GId"); uiout->table_header (target_id_col_width, ui_left, "target-id", "Target Id"); @@ -1102,7 +1122,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, current_exited = true; if (!should_print_thread (requested_threads, default_inf_num, - global_ids, pid, tp)) + global_ids, pid, tp, opts)) continue; ui_out_emit_tuple tuple_emitter (uiout, NULL); @@ -1117,7 +1137,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, uiout->field_string ("id-in-tg", print_thread_id (tp)); } - if (show_global_ids || uiout->is_mi_like_p ()) + if (opts.show_global_ids || uiout->is_mi_like_p ()) uiout->field_signed ("id", tp->global_num); /* Switch to the thread (and inferior / target). */ @@ -1199,27 +1219,10 @@ void print_thread_info (struct ui_out *uiout, const char *requested_threads, int pid) { - print_thread_info_1 (uiout, requested_threads, 1, pid, 0); + info_threads_opts opts {false}; + print_thread_info_1 (uiout, requested_threads, 1, pid, opts); } -/* The options for the "info threads" command. */ - -struct info_threads_opts -{ - /* For "-gid". */ - bool show_global_ids = false; -}; - -static const gdb::option::option_def info_threads_option_defs[] = { - - gdb::option::flag_option_def<info_threads_opts> { - "gid", - [] (info_threads_opts *opts) { return &opts->show_global_ids; }, - N_("Show global thread IDs."), - }, - -}; - /* Create an option_def_group for the "info threads" options, with IT_OPTS as context. */ @@ -1244,7 +1247,7 @@ info_threads_command (const char *arg, int from_tty) gdb::option::process_options (&arg, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp); - print_thread_info_1 (current_uiout, arg, 0, -1, it_opts.show_global_ids); + print_thread_info_1 (current_uiout, arg, 0, -1, it_opts); } /* Completer for the "info threads" command. */ -- 2.25.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de> Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH 2/3] gdb, doc: add the missing '-gid' option to 'info threads' 2023-04-05 9:19 [PATCH 0/3] Option to show stopped threads only Tankut Baris Aktemur via Gdb-patches 2023-04-05 9:20 ` [PATCH 1/3] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur via Gdb-patches @ 2023-04-05 9:20 ` Tankut Baris Aktemur via Gdb-patches 2023-04-05 9:56 ` Eli Zaretskii via Gdb-patches 2023-04-05 9:20 ` [PATCH 3/3] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur via Gdb-patches ` (2 subsequent siblings) 4 siblings, 1 reply; 32+ messages in thread From: Tankut Baris Aktemur via Gdb-patches @ 2023-04-05 9:20 UTC (permalink / raw) To: gdb-patches The 'info threads' command does not show the '-gid' option in the syntax. Add the option. The flag is already explained in the command description and used in the examples. --- gdb/doc/gdb.texinfo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index fe76e5e0a0e..ed14888b77b 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -3678,7 +3678,7 @@ Thread 1 "main" received signal SIGINT, Interrupt. @table @code @anchor{info_threads} @kindex info threads -@item info threads @r{[}@var{thread-id-list}@r{]} +@item info threads @r{[}-gid@r{]} @r{[}@var{thread-id-list}@r{]} Display information about one or more threads. With no arguments displays information about all threads. You can specify the list of -- 2.25.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de> Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 2/3] gdb, doc: add the missing '-gid' option to 'info threads' 2023-04-05 9:20 ` [PATCH 2/3] gdb, doc: add the missing '-gid' option to 'info threads' Tankut Baris Aktemur via Gdb-patches @ 2023-04-05 9:56 ` Eli Zaretskii via Gdb-patches 2023-04-05 10:12 ` Aktemur, Tankut Baris via Gdb-patches 0 siblings, 1 reply; 32+ messages in thread From: Eli Zaretskii via Gdb-patches @ 2023-04-05 9:56 UTC (permalink / raw) To: Tankut Baris Aktemur; +Cc: gdb-patches > Date: Wed, 5 Apr 2023 11:20:01 +0200 > From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org> > > The 'info threads' command does not show the '-gid' option > in the syntax. Add the option. The flag is already explained > in the command description and used in the examples. > --- > gdb/doc/gdb.texinfo | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index fe76e5e0a0e..ed14888b77b 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -3678,7 +3678,7 @@ Thread 1 "main" received signal SIGINT, Interrupt. > @table @code > @anchor{info_threads} > @kindex info threads > -@item info threads @r{[}@var{thread-id-list}@r{]} > +@item info threads @r{[}-gid@r{]} @r{[}@var{thread-id-list}@r{]} > > Display information about one or more threads. With no arguments > displays information about all threads. You can specify the list of Thanks, this is OK. Approved-By: Eli Zaretskii <eliz@gnu.org> ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: [PATCH 2/3] gdb, doc: add the missing '-gid' option to 'info threads' 2023-04-05 9:56 ` Eli Zaretskii via Gdb-patches @ 2023-04-05 10:12 ` Aktemur, Tankut Baris via Gdb-patches 0 siblings, 0 replies; 32+ messages in thread From: Aktemur, Tankut Baris via Gdb-patches @ 2023-04-05 10:12 UTC (permalink / raw) To: Eli Zaretskii, gdb-patches On Wednesday, April 5, 2023 11:57 AM, Eli Zaretskii wrote: > > Date: Wed, 5 Apr 2023 11:20:01 +0200 > > From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org> > > > > The 'info threads' command does not show the '-gid' option > > in the syntax. Add the option. The flag is already explained > > in the command description and used in the examples. > > --- > > gdb/doc/gdb.texinfo | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > > index fe76e5e0a0e..ed14888b77b 100644 > > --- a/gdb/doc/gdb.texinfo > > +++ b/gdb/doc/gdb.texinfo > > @@ -3678,7 +3678,7 @@ Thread 1 "main" received signal SIGINT, Interrupt. > > @table @code > > @anchor{info_threads} > > @kindex info threads > > -@item info threads @r{[}@var{thread-id-list}@r{]} > > +@item info threads @r{[}-gid@r{]} @r{[}@var{thread-id-list}@r{]} > > > > Display information about one or more threads. With no arguments > > displays information about all threads. You can specify the list of > > Thanks, this is OK. > > Approved-By: Eli Zaretskii <eliz@gnu.org> Thank you. I pushed this single patch. -Baris Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de> Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH 3/3] gdb: add a '-stopped' option to "info threads" 2023-04-05 9:19 [PATCH 0/3] Option to show stopped threads only Tankut Baris Aktemur via Gdb-patches 2023-04-05 9:20 ` [PATCH 1/3] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur via Gdb-patches 2023-04-05 9:20 ` [PATCH 2/3] gdb, doc: add the missing '-gid' option to 'info threads' Tankut Baris Aktemur via Gdb-patches @ 2023-04-05 9:20 ` Tankut Baris Aktemur via Gdb-patches 2023-04-05 10:00 ` Eli Zaretskii via Gdb-patches 2025-03-18 18:04 ` [PATCH v2 0/2] Option to show stopped threads only Tankut Baris Aktemur 2025-04-04 13:36 ` [PATCH v3 " Tankut Baris Aktemur 4 siblings, 1 reply; 32+ messages in thread From: Tankut Baris Aktemur via Gdb-patches @ 2023-04-05 9:20 UTC (permalink / raw) To: gdb-patches Add a '-stopped' option to the "info threads" command to print stopped threads only and skip the running ones. This is a convenience flag to filter out the running threads in programs that have many threads. Suppose we have an application with 5 threads, 2 of which have hit a breakpoint. The "info threads" command in the non-stop mode gives: (gdb) info threads Id Target Id Frame * 1 Thread 0x7ffff7d99740 (running) 2 Thread 0x7ffff7d98700 something () at file.c:30 3 Thread 0x7ffff7597700 (running) 4 Thread 0x7ffff6d96700 something () at file.c:30 5 Thread 0x7ffff6595700 (running) (gdb) Using the "-stopped" flag, we get (gdb) info threads -stopped Id Target Id Frame 2 Thread 0x7ffff7d98700 something () at file.c:30 4 Thread 0x7ffff6d96700 something () at file.c:30 (gdb) When combined with a thread ID, the behavior is as follows: (gdb) info threads 3 Id Target Id Frame 3 Thread 0x7ffff7597700 (running) (gdb) info threads -stopped 3 No stopped threads match '3'. (gdb) Regression-tested on X86_64 Linux. --- gdb/NEWS | 7 ++ gdb/doc/gdb.texinfo | 6 +- gdb/testsuite/gdb.base/options.exp | 11 ++- .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++++++++ .../gdb.threads/info-threads-stopped.exp | 75 ++++++++++++++++++ gdb/thread.c | 17 +++- 6 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp diff --git a/gdb/NEWS b/gdb/NEWS index 10a1a70fa52..33b104fda72 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -96,6 +96,13 @@ info main $2 = 1 (gdb) break func if $_shell("some command") == 0 +* Changed commands + +info threads [-gid] [-stopped] [ID]... + This command now takes an optional flag, '-stopped', that causes only + the stopped threads to be printed. The flag can be useful to get a + reduced list when there is a large number of unstopped threads. + * MI changes ** mi now reports 'no-history' as a stop reason when hitting the end of the diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index ed14888b77b..02f6a9eb49a 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -3678,7 +3678,7 @@ Thread 1 "main" received signal SIGINT, Interrupt. @table @code @anchor{info_threads} @kindex info threads -@item info threads @r{[}-gid@r{]} @r{[}@var{thread-id-list}@r{]} +@item info threads @r{[}-gid@r{]} @r{[}-stopped@r{]} @r{[}@var{thread-id-list}@r{]} Display information about one or more threads. With no arguments displays information about all threads. You can specify the list of @@ -3728,6 +3728,10 @@ If you're debugging multiple inferiors, @value{GDBN} displays thread IDs using the qualified @var{inferior-num}.@var{thread-num} format. Otherwise, only @var{thread-num} is shown. +If you specify the @samp{-stopped} option, @value{GDBN} displays the +stopped threads only. This can be helpful to reduce the output list +if there is a large number of unstopped threads. + If you specify the @samp{-gid} option, @value{GDBN} displays a column indicating each thread's global thread ID: diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp index 6d90615710e..58c85567a4e 100644 --- a/gdb/testsuite/gdb.base/options.exp +++ b/gdb/testsuite/gdb.base/options.exp @@ -492,12 +492,21 @@ proc_with_prefix test-thread-apply {} { proc_with_prefix test-info-threads {} { test_gdb_complete_multiple "info threads " "" "" { "-gid" + "-stopped" "ID" } + test_gdb_complete_multiple "info threads " "-" "" { + "-gid" + "-stopped" + } + test_gdb_complete_unique \ - "info threads -" \ + "info threads -g" \ "info threads -gid" + test_gdb_complete_unique \ + "info threads -s" \ + "info threads -stopped" # "ID" isn't really something the user can type. test_gdb_complete_none "info threads I" diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.c b/gdb/testsuite/gdb.threads/info-threads-stopped.c new file mode 100644 index 00000000000..42ca8cf0b69 --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.c @@ -0,0 +1,78 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022-2023 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/>. */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <pthread.h> + +#define NUM 4 + +volatile int should_spin = 1; + +static void +something () +{ +} + +static void +spin () +{ + while (should_spin) + usleep (1); +} + +static void * +work (void *arg) +{ + int id = *((int *) arg); + + /* Sleep a bit to give the other threads a chance to run. */ + usleep (1); + + if (id % 2 == 0) + something (); /* break-here */ + else + spin (); + + pthread_exit (NULL); +} + +int +main () +{ + /* Ensure we stop if GDB crashes and DejaGNU fails to kill us. */ + alarm (10); + + pthread_t threads[NUM]; + void *thread_result; + int ids[NUM]; + + for (int i = 0; i < NUM; i++) + { + ids[i] = i + 2; + pthread_create (&threads[i], NULL, work, &(ids[i])); + } + + sleep (10); + should_spin = 0; + + for (int i = 0; i < NUM; i++) + pthread_join(threads[i], &thread_result); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.exp b/gdb/testsuite/gdb.threads/info-threads-stopped.exp new file mode 100644 index 00000000000..5643a513aff --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.exp @@ -0,0 +1,75 @@ +# Copyright (C) 2022-2023 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/>. + +# Test for the '-stopped' flag of the "info threads" command. + +standard_testfile + +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable debug] != "" } { + return -1 +} + +save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop on\"" + clean_restart $binfile +} + +gdb_breakpoint "something" +gdb_run_cmd + +# Two threads hit the bp. +set fill "\[^\r\n\]+" +set num_hits 0 +gdb_test_multiple "" "hit the breakpoint" -lbl { + -re "\r\nThread ${fill} hit Breakpoint 1${fill}" { + incr num_hits + if {$num_hits < 2} { + exp_continue + } + } + -re "\r\n$gdb_prompt " { + exp_continue + } +} +gdb_assert {$num_hits == 2} "two threads hit the bp" + +# Count the number of running/stopped threads reported +# by the "info threads" command. +foreach flag {"" "-stopped"} { + set num_running 0 + set num_stopped 0 + gdb_test_multiple "info threads $flag" "info threads $flag" { + -re "Id${fill}Target Id${fill}Frame${fill}" { + exp_continue + } + -re "^\r\n. ${decimal}${fill}Thread ${fill}.running." { + incr num_running + exp_continue + } + -re "^\r\n. ${decimal}${fill}Thread ${fill}something ${fill}" { + incr num_stopped + exp_continue + } + -re "^\r\n$gdb_prompt $" { + gdb_assert {$num_stopped == 2} "$gdb_test_name: num stopped" + if {$flag eq ""} { + gdb_assert {$num_running == 3} "$gdb_test_name: num running" + } else { + gdb_assert {$num_running == 0} "$gdb_test_name: num running" + } + } + } +} diff --git a/gdb/thread.c b/gdb/thread.c index 57b3f7611e2..8886bd45674 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -957,6 +957,8 @@ struct info_threads_opts { /* For "-gid". */ bool show_global_ids = false; + /* For "-stopped". */ + bool show_stopped_threads = false; }; static const gdb::option::option_def info_threads_option_defs[] = { @@ -966,6 +968,11 @@ static const gdb::option::option_def info_threads_option_defs[] = { [] (info_threads_opts *opts) { return &opts->show_global_ids; }, N_("Show global thread IDs."), }, + gdb::option::flag_option_def<info_threads_opts> { + "stopped", + [] (info_threads_opts *opts) { return &opts->show_stopped_threads; }, + N_("Show stopped threads only."), + }, }; @@ -1008,6 +1015,11 @@ should_print_thread (const char *requested_threads, int default_inf_num, if (thr->state == THREAD_EXITED) return false; + /* Skip a running thread if the user wants stopped threads only. */ + bool is_stopped = (thr->state == THREAD_STOPPED); + if (opts.show_stopped_threads && !is_stopped) + return false; + return true; } @@ -1094,7 +1106,8 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, if (requested_threads == NULL || *requested_threads == '\0') uiout->message (_("No threads.\n")); else - uiout->message (_("No threads match '%s'.\n"), + uiout->message (_("No %sthreads match '%s'.\n"), + (opts.show_stopped_threads ? "stopped " : ""), requested_threads); return; } @@ -1219,7 +1232,7 @@ void print_thread_info (struct ui_out *uiout, const char *requested_threads, int pid) { - info_threads_opts opts {false}; + info_threads_opts opts {false, false}; print_thread_info_1 (uiout, requested_threads, 1, pid, opts); } -- 2.25.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de> Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/3] gdb: add a '-stopped' option to "info threads" 2023-04-05 9:20 ` [PATCH 3/3] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur via Gdb-patches @ 2023-04-05 10:00 ` Eli Zaretskii via Gdb-patches 2023-04-05 10:19 ` Aktemur, Tankut Baris via Gdb-patches 0 siblings, 1 reply; 32+ messages in thread From: Eli Zaretskii via Gdb-patches @ 2023-04-05 10:00 UTC (permalink / raw) To: Tankut Baris Aktemur; +Cc: gdb-patches > Date: Wed, 5 Apr 2023 11:20:02 +0200 > From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org> > > gdb/NEWS | 7 ++ > gdb/doc/gdb.texinfo | 6 +- > gdb/testsuite/gdb.base/options.exp | 11 ++- > .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++++++++ > .../gdb.threads/info-threads-stopped.exp | 75 ++++++++++++++++++ > gdb/thread.c | 17 +++- > 6 files changed, 190 insertions(+), 4 deletions(-) > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp Thanks, the documentation parts are OK. But I have a question about the new behavior: > (gdb) info threads -stopped 3 > No stopped threads match '3'. Is it really useful to show nothing and emit an error message if explicit thread IDs were specified by the user? Wouldn't it be better to ignore the -stopped switch in that case? Reviewed-By: Eli Zaretskii <eliz@gnu.org> ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: [PATCH 3/3] gdb: add a '-stopped' option to "info threads" 2023-04-05 10:00 ` Eli Zaretskii via Gdb-patches @ 2023-04-05 10:19 ` Aktemur, Tankut Baris via Gdb-patches 2023-04-05 10:50 ` Eli Zaretskii via Gdb-patches 0 siblings, 1 reply; 32+ messages in thread From: Aktemur, Tankut Baris via Gdb-patches @ 2023-04-05 10:19 UTC (permalink / raw) To: Eli Zaretskii, gdb-patches On Wednesday, April 5, 2023 12:01 PM, Eli Zaretskii wrote: > > Date: Wed, 5 Apr 2023 11:20:02 +0200 > > From: Tankut Baris Aktemur via Gdb-patches <gdb-patches@sourceware.org> > > > > gdb/NEWS | 7 ++ > > gdb/doc/gdb.texinfo | 6 +- > > gdb/testsuite/gdb.base/options.exp | 11 ++- > > .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++++++++ > > .../gdb.threads/info-threads-stopped.exp | 75 ++++++++++++++++++ > > gdb/thread.c | 17 +++- > > 6 files changed, 190 insertions(+), 4 deletions(-) > > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c > > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp > > Thanks, the documentation parts are OK. > > But I have a question about the new behavior: > > > (gdb) info threads -stopped 3 > > No stopped threads match '3'. > > Is it really useful to show nothing and emit an error message if > explicit thread IDs were specified by the user? Wouldn't it be better > to ignore the -stopped switch in that case? > > Reviewed-By: Eli Zaretskii <eliz@gnu.org> The user may have given a thread id range or a wildcard, like "info threads -stopped 1-999" or "info threads -stopped 2.*". Ignoring the flag for these cases can output a very long list. I'm fine if we make the single thread id a special case. But then the question is, where do we draw the line? If the user gave just a few thread ids, do we still ignore the flag? What is the limit to the acceptable list length? Because of these questions, consistently applying the flag made more sense to me. Regards -Baris Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de> Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/3] gdb: add a '-stopped' option to "info threads" 2023-04-05 10:19 ` Aktemur, Tankut Baris via Gdb-patches @ 2023-04-05 10:50 ` Eli Zaretskii via Gdb-patches 2023-04-05 11:31 ` Aktemur, Tankut Baris via Gdb-patches 0 siblings, 1 reply; 32+ messages in thread From: Eli Zaretskii via Gdb-patches @ 2023-04-05 10:50 UTC (permalink / raw) To: Aktemur, Tankut Baris; +Cc: gdb-patches > From: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com> > Date: Wed, 5 Apr 2023 10:19:26 +0000 > > I'm fine if we make the single thread id a special case. Maybe that's all we should do. > But then the question is, where do we draw the line? If the user > gave just a few thread ids, do we still ignore the flag? What is > the limit to the acceptable list length? Because of these > questions, consistently applying the flag made more sense to me. We don't have to be 100% consistent, we just need to be useful. ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: [PATCH 3/3] gdb: add a '-stopped' option to "info threads" 2023-04-05 10:50 ` Eli Zaretskii via Gdb-patches @ 2023-04-05 11:31 ` Aktemur, Tankut Baris via Gdb-patches 2023-04-05 11:56 ` Eli Zaretskii via Gdb-patches 2025-04-24 14:50 ` Pedro Alves 0 siblings, 2 replies; 32+ messages in thread From: Aktemur, Tankut Baris via Gdb-patches @ 2023-04-05 11:31 UTC (permalink / raw) To: Eli Zaretskii, gdb-patches On Wednesday, April 5, 2023 12:51 PM, Eli Zaretskii wrote: > > From: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com> > > Date: Wed, 5 Apr 2023 10:19:26 +0000 > > > > I'm fine if we make the single thread id a special case. > > Maybe that's all we should do. > > > But then the question is, where do we draw the line? If the user > > gave just a few thread ids, do we still ignore the flag? What is > > the limit to the acceptable list length? Because of these > > questions, consistently applying the flag made more sense to me. > > We don't have to be 100% consistent, we just need to be useful. Let's please wait a bit in case other maintainers want to chime in. I don't have an objection to treating the single thread id case specially. -Baris Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de> Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/3] gdb: add a '-stopped' option to "info threads" 2023-04-05 11:31 ` Aktemur, Tankut Baris via Gdb-patches @ 2023-04-05 11:56 ` Eli Zaretskii via Gdb-patches 2025-04-24 14:50 ` Pedro Alves 1 sibling, 0 replies; 32+ messages in thread From: Eli Zaretskii via Gdb-patches @ 2023-04-05 11:56 UTC (permalink / raw) To: Aktemur, Tankut Baris; +Cc: gdb-patches > From: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com> > Date: Wed, 5 Apr 2023 11:31:16 +0000 > > On Wednesday, April 5, 2023 12:51 PM, Eli Zaretskii wrote: > > > From: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com> > > > Date: Wed, 5 Apr 2023 10:19:26 +0000 > > > > > > I'm fine if we make the single thread id a special case. > > > > Maybe that's all we should do. > > > > > But then the question is, where do we draw the line? If the user > > > gave just a few thread ids, do we still ignore the flag? What is > > > the limit to the acceptable list length? Because of these > > > questions, consistently applying the flag made more sense to me. > > > > We don't have to be 100% consistent, we just need to be useful. > > Let's please wait a bit in case other maintainers want to chime in. Sure. I just expressed my personal opinion, not a request to make changes in your patches right away. ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 3/3] gdb: add a '-stopped' option to "info threads" 2023-04-05 11:31 ` Aktemur, Tankut Baris via Gdb-patches 2023-04-05 11:56 ` Eli Zaretskii via Gdb-patches @ 2025-04-24 14:50 ` Pedro Alves 1 sibling, 0 replies; 32+ messages in thread From: Pedro Alves @ 2025-04-24 14:50 UTC (permalink / raw) To: Aktemur, Tankut Baris, Eli Zaretskii, gdb-patches Hi! On 2023-04-05 12:31, Aktemur, Tankut Baris via Gdb-patches wrote: > On Wednesday, April 5, 2023 12:51 PM, Eli Zaretskii wrote: >>> From: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com> >>> Date: Wed, 5 Apr 2023 10:19:26 +0000 >>> >>> I'm fine if we make the single thread id a special case. >> >> Maybe that's all we should do. >> >>> But then the question is, where do we draw the line? If the user >>> gave just a few thread ids, do we still ignore the flag? What is >>> the limit to the acceptable list length? Because of these >>> questions, consistently applying the flag made more sense to me. >> >> We don't have to be 100% consistent, we just need to be useful. > > Let's please wait a bit in case other maintainers want to chime in. > I don't have an objection to treating the single thread id case specially. I don't think we should give single ID any special treatment. It's as you say, what about "info thread 1 2 ", does that get an exception because it is two single IDs? Why would that be different from "info threads 1-2" ? What if I put the IDs in a convenience variable, and then do: (gdb) eval "info threads -stopped %s", $id Why should my script behave differently depending on what is saved in $id? Etc. BTW, the same rationale should apply to "thread apply". "info threads" and "thread apply" have basically the same logic and also share options. IMO, we should have a matching "thread apply -stopped" too. And with "thread apply", it is even clearer IMO that "thread apply $ID -stopped print foo" should not every try to run "print foo" on a not-stopped thread! From the fact that "info threads" and "thread apply" should walk the same threads given the same options, it follows that "info threads -stopped" should not walk any non-stopped thread. I'll look at later revisions of the series now. Thanks for doing this. We had talked about it a while ago but I hadn't realized you had sent it upstream. Thanks! Pedro Alves ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 0/2] Option to show stopped threads only 2023-04-05 9:19 [PATCH 0/3] Option to show stopped threads only Tankut Baris Aktemur via Gdb-patches ` (2 preceding siblings ...) 2023-04-05 9:20 ` [PATCH 3/3] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur via Gdb-patches @ 2025-03-18 18:04 ` Tankut Baris Aktemur 2025-03-18 18:05 ` [PATCH v2 1/2] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur ` (2 more replies) 2025-04-04 13:36 ` [PATCH v3 " Tankut Baris Aktemur 4 siblings, 3 replies; 32+ messages in thread From: Tankut Baris Aktemur @ 2025-03-18 18:04 UTC (permalink / raw) To: gdb-patches Hi, This is the rebased version of https://inbox.sourceware.org/gdb-patches/cover.1680686220.git.tankut.baris.aktemur@intel.com/ As a comment, Eli had expressed his view that when "info threads" is given a single thread ID, the "-stopped" flag could be ignored. I didn't implement this yet but can gladly do that if that's the general preference. Regards, Baris Tankut Baris Aktemur (2): gdb: pass info_threads_opts to print_thread_info_1 gdb: add a '-stopped' option to "info threads" gdb/NEWS | 7 ++ gdb/doc/gdb.texinfo | 6 +- gdb/testsuite/gdb.base/options.exp | 11 ++- .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++++++ .../gdb.threads/info-threads-stopped.exp | 75 ++++++++++++++++ gdb/thread.c | 86 +++++++++++-------- 6 files changed, 226 insertions(+), 37 deletions(-) create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 1/2] gdb: pass info_threads_opts to print_thread_info_1 2025-03-18 18:04 ` [PATCH v2 0/2] Option to show stopped threads only Tankut Baris Aktemur @ 2025-03-18 18:05 ` Tankut Baris Aktemur 2025-03-18 18:05 ` [PATCH v2 2/2] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur 2025-03-28 16:38 ` [PATCH v2 0/2] Option to show stopped threads only Guinevere Larsen 2 siblings, 0 replies; 32+ messages in thread From: Tankut Baris Aktemur @ 2025-03-18 18:05 UTC (permalink / raw) To: gdb-patches The "info threads" command tracks its options in a struct named 'info_threads_opts', which currently has only one option. Pass the whole options object to helper functions, instead of passing the option value individually. This is a refactoring to make adding more options easier. --- gdb/thread.c | 71 +++++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/gdb/thread.c b/gdb/thread.c index 8a34671bb6c..7dc8e7018c5 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1038,6 +1038,24 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread) && pc < thread->control.step_range_end); } +/* The options for the "info threads" command. */ + +struct info_threads_opts +{ + /* For "-gid". */ + bool show_global_ids = false; +}; + +static const gdb::option::option_def info_threads_option_defs[] = { + + gdb::option::flag_option_def<info_threads_opts> { + "gid", + [] (info_threads_opts *opts) { return &opts->show_global_ids; }, + N_("Show global thread IDs."), + }, + +}; + /* Helper for print_thread_info. Returns true if THR should be printed. If REQUESTED_THREADS, a list of GDB ids/ranges, is not NULL, only print THR if its ID is included in the list. GLOBAL_IDS @@ -1046,11 +1064,13 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread) is a thread from the process PID. Otherwise, threads from all attached PIDs are printed. If both REQUESTED_THREADS is not NULL and PID is not -1, then the thread is printed if it belongs to the - specified process. Otherwise, an error is raised. */ + specified process. Otherwise, an error is raised. OPTS is the + options of the "info threads" command. */ static bool should_print_thread (const char *requested_threads, int default_inf_num, - int global_ids, int pid, struct thread_info *thr) + int global_ids, int pid, thread_info *thr, + info_threads_opts opts) { if (requested_threads != NULL && *requested_threads != '\0') { @@ -1104,7 +1124,7 @@ thread_target_id_str (thread_info *tp) static void do_print_thread (ui_out *uiout, const char *requested_threads, - int global_ids, int pid, int show_global_ids, + int global_ids, int pid, info_threads_opts opts, int default_inf_num, thread_info *tp, thread_info *current_thread) { @@ -1115,7 +1135,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads, switch_to_thread (current_thread); if (!should_print_thread (requested_threads, default_inf_num, - global_ids, pid, tp)) + global_ids, pid, tp, opts)) return; ui_out_emit_tuple tuple_emitter (uiout, NULL); @@ -1130,7 +1150,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads, uiout->field_string ("id-in-tg", print_thread_id (tp)); } - if (show_global_ids || uiout->is_mi_like_p ()) + if (opts.show_global_ids || uiout->is_mi_like_p ()) uiout->field_signed ("id", tp->global_num); /* Switch to the thread (and inferior / target). */ @@ -1191,23 +1211,23 @@ do_print_thread (ui_out *uiout, const char *requested_threads, static void print_thread (ui_out *uiout, const char *requested_threads, - int global_ids, int pid, int show_global_ids, + int global_ids, int pid, info_threads_opts opts, int default_inf_num, thread_info *tp, thread_info *current_thread) { do_with_buffered_output (do_print_thread, uiout, requested_threads, - global_ids, pid, show_global_ids, - default_inf_num, tp, current_thread); + global_ids, pid, opts, default_inf_num, tp, + current_thread); } /* Like print_thread_info, but in addition, GLOBAL_IDS indicates whether REQUESTED_THREADS is a list of global or per-inferior - thread ids. */ + thread ids. OPTS is the options of the "info threads" command. */ static void print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, int global_ids, int pid, - int show_global_ids) + info_threads_opts opts) { int default_inf_num = current_inferior ()->num; @@ -1247,7 +1267,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, switch_to_thread (current_thread); if (!should_print_thread (requested_threads, default_inf_num, - global_ids, pid, tp)) + global_ids, pid, tp, opts)) continue; /* Switch inferiors so we're looking at the right @@ -1271,12 +1291,12 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, return; } - table_emitter.emplace (uiout, show_global_ids ? 5 : 4, + table_emitter.emplace (uiout, opts.show_global_ids ? 5 : 4, n_threads, "threads"); uiout->table_header (1, ui_left, "current", ""); uiout->table_header (4, ui_left, "id-in-tg", "Id"); - if (show_global_ids) + if (opts.show_global_ids) uiout->table_header (4, ui_left, "id", "GId"); uiout->table_header (target_id_col_width, ui_left, "target-id", "Target Id"); @@ -1293,7 +1313,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, current_exited = true; print_thread (uiout, requested_threads, global_ids, pid, - show_global_ids, default_inf_num, tp, current_thread); + opts, default_inf_num, tp, current_thread); } /* This end scope restores the current thread and the frame @@ -1322,27 +1342,10 @@ void print_thread_info (struct ui_out *uiout, const char *requested_threads, int pid) { - print_thread_info_1 (uiout, requested_threads, 1, pid, 0); + info_threads_opts opts {false}; + print_thread_info_1 (uiout, requested_threads, 1, pid, opts); } -/* The options for the "info threads" command. */ - -struct info_threads_opts -{ - /* For "-gid". */ - bool show_global_ids = false; -}; - -static const gdb::option::option_def info_threads_option_defs[] = { - - gdb::option::flag_option_def<info_threads_opts> { - "gid", - [] (info_threads_opts *opts) { return &opts->show_global_ids; }, - N_("Show global thread IDs."), - }, - -}; - /* Create an option_def_group for the "info threads" options, with IT_OPTS as context. */ @@ -1367,7 +1370,7 @@ info_threads_command (const char *arg, int from_tty) gdb::option::process_options (&arg, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp); - print_thread_info_1 (current_uiout, arg, 0, -1, it_opts.show_global_ids); + print_thread_info_1 (current_uiout, arg, 0, -1, it_opts); } /* Completer for the "info threads" command. */ -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 2/2] gdb: add a '-stopped' option to "info threads" 2025-03-18 18:04 ` [PATCH v2 0/2] Option to show stopped threads only Tankut Baris Aktemur 2025-03-18 18:05 ` [PATCH v2 1/2] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur @ 2025-03-18 18:05 ` Tankut Baris Aktemur 2025-03-28 16:38 ` [PATCH v2 0/2] Option to show stopped threads only Guinevere Larsen 2 siblings, 0 replies; 32+ messages in thread From: Tankut Baris Aktemur @ 2025-03-18 18:05 UTC (permalink / raw) To: gdb-patches Add a '-stopped' option to the "info threads" command to print stopped threads only and skip the running ones. This is a convenience flag to filter out the running threads in programs that have many threads. Suppose we have an application with 5 threads, 2 of which have hit a breakpoint. The "info threads" command in the non-stop mode gives: (gdb) info threads Id Target Id Frame * 1 Thread 0x7ffff7d99740 (running) 2 Thread 0x7ffff7d98700 something () at file.c:30 3 Thread 0x7ffff7597700 (running) 4 Thread 0x7ffff6d96700 something () at file.c:30 5 Thread 0x7ffff6595700 (running) (gdb) Using the "-stopped" flag, we get (gdb) info threads -stopped Id Target Id Frame 2 Thread 0x7ffff7d98700 something () at file.c:30 4 Thread 0x7ffff6d96700 something () at file.c:30 (gdb) When combined with a thread ID, the behavior is as follows: (gdb) info threads 3 Id Target Id Frame 3 Thread 0x7ffff7597700 (running) (gdb) info threads -stopped 3 No stopped threads match '3'. (gdb) Regression-tested on X86_64 Linux. Reviewed-By: Eli Zaretskii <eliz@gnu.org> --- gdb/NEWS | 7 ++ gdb/doc/gdb.texinfo | 6 +- gdb/testsuite/gdb.base/options.exp | 11 ++- .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++++++++ .../gdb.threads/info-threads-stopped.exp | 75 ++++++++++++++++++ gdb/thread.c | 17 +++- 6 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp diff --git a/gdb/NEWS b/gdb/NEWS index 0aac7a7b13a..be24ed0a251 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -45,6 +45,13 @@ show riscv numeric-register-names (e.g 'x1') or their abi names (e.g. 'ra'). Defaults to 'off', matching the old behaviour (abi names). +* Changed commands + +info threads [-gid] [-stopped] [ID]... + This command now takes an optional flag, '-stopped', that causes only + the stopped threads to be printed. The flag can be useful to get a + reduced list when there is a large number of unstopped threads. + * Python API ** New class gdb.Color for dealing with colors. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 473431011d1..537e2e2230b 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -3807,7 +3807,7 @@ Thread 1 "main" received signal SIGINT, Interrupt. @table @code @anchor{info_threads} @kindex info threads -@item info threads @r{[}-gid@r{]} @r{[}@var{thread-id-list}@r{]} +@item info threads @r{[}-gid@r{]} @r{[}-stopped@r{]} @r{[}@var{thread-id-list}@r{]} Display information about one or more threads. With no arguments displays information about all threads. You can specify the list of @@ -3857,6 +3857,10 @@ If you're debugging multiple inferiors, @value{GDBN} displays thread IDs using the qualified @var{inferior-num}.@var{thread-num} format. Otherwise, only @var{thread-num} is shown. +If you specify the @samp{-stopped} option, @value{GDBN} displays the +stopped threads only. This can be helpful to reduce the output list +if there is a large number of unstopped threads. + If you specify the @samp{-gid} option, @value{GDBN} displays a column indicating each thread's global thread ID: diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp index a1ca39eab11..a343867f189 100644 --- a/gdb/testsuite/gdb.base/options.exp +++ b/gdb/testsuite/gdb.base/options.exp @@ -508,12 +508,21 @@ proc_with_prefix test-thread-apply {} { proc_with_prefix test-info-threads {} { test_gdb_complete_multiple "info threads " "" "" { "-gid" + "-stopped" "ID" } + test_gdb_complete_multiple "info threads " "-" "" { + "-gid" + "-stopped" + } + test_gdb_complete_unique \ - "info threads -" \ + "info threads -g" \ "info threads -gid" + test_gdb_complete_unique \ + "info threads -s" \ + "info threads -stopped" # "ID" isn't really something the user can type. test_gdb_complete_none "info threads I" diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.c b/gdb/testsuite/gdb.threads/info-threads-stopped.c new file mode 100644 index 00000000000..2c38ecca074 --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.c @@ -0,0 +1,78 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022-2025 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/>. */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <pthread.h> + +#define NUM 4 + +volatile int should_spin = 1; + +static void +something () +{ +} + +static void +spin () +{ + while (should_spin) + usleep (1); +} + +static void * +work (void *arg) +{ + int id = *((int *) arg); + + /* Sleep a bit to give the other threads a chance to run. */ + usleep (1); + + if (id % 2 == 0) + something (); /* break-here */ + else + spin (); + + pthread_exit (NULL); +} + +int +main () +{ + /* Ensure we stop if GDB crashes and DejaGNU fails to kill us. */ + alarm (10); + + pthread_t threads[NUM]; + void *thread_result; + int ids[NUM]; + + for (int i = 0; i < NUM; i++) + { + ids[i] = i + 2; + pthread_create (&threads[i], NULL, work, &(ids[i])); + } + + sleep (10); + should_spin = 0; + + for (int i = 0; i < NUM; i++) + pthread_join(threads[i], &thread_result); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.exp b/gdb/testsuite/gdb.threads/info-threads-stopped.exp new file mode 100644 index 00000000000..3e6476c2f41 --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.exp @@ -0,0 +1,75 @@ +# Copyright (C) 2022-2025 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/>. + +# Test for the '-stopped' flag of the "info threads" command. + +standard_testfile + +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable debug] != "" } { + return -1 +} + +save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop on\"" + clean_restart $binfile +} + +gdb_breakpoint "something" +gdb_run_cmd + +# Two threads hit the bp. +set fill "\[^\r\n\]+" +set num_hits 0 +gdb_test_multiple "" "hit the breakpoint" -lbl { + -re "\r\nThread ${fill} hit Breakpoint 1${fill}" { + incr num_hits + if {$num_hits < 2} { + exp_continue + } + } + -re "\r\n$gdb_prompt " { + exp_continue + } +} +gdb_assert {$num_hits == 2} "two threads hit the bp" + +# Count the number of running/stopped threads reported +# by the "info threads" command. +foreach flag {"" "-stopped"} { + set num_running 0 + set num_stopped 0 + gdb_test_multiple "info threads $flag" "info threads $flag" { + -re "Id${fill}Target Id${fill}Frame${fill}" { + exp_continue + } + -re "^\r\n. ${decimal}${fill}Thread ${fill}.running." { + incr num_running + exp_continue + } + -re "^\r\n. ${decimal}${fill}Thread ${fill}something ${fill}" { + incr num_stopped + exp_continue + } + -re "^\r\n$gdb_prompt $" { + gdb_assert {$num_stopped == 2} "$gdb_test_name: num stopped" + if {$flag eq ""} { + gdb_assert {$num_running == 3} "$gdb_test_name: num running" + } else { + gdb_assert {$num_running == 0} "$gdb_test_name: num running" + } + } + } +} diff --git a/gdb/thread.c b/gdb/thread.c index 7dc8e7018c5..87ee9f66680 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1044,6 +1044,8 @@ struct info_threads_opts { /* For "-gid". */ bool show_global_ids = false; + /* For "-stopped". */ + bool show_stopped_threads = false; }; static const gdb::option::option_def info_threads_option_defs[] = { @@ -1053,6 +1055,11 @@ static const gdb::option::option_def info_threads_option_defs[] = { [] (info_threads_opts *opts) { return &opts->show_global_ids; }, N_("Show global thread IDs."), }, + gdb::option::flag_option_def<info_threads_opts> { + "stopped", + [] (info_threads_opts *opts) { return &opts->show_stopped_threads; }, + N_("Show stopped threads only."), + }, }; @@ -1095,6 +1102,11 @@ should_print_thread (const char *requested_threads, int default_inf_num, if (thr->state == THREAD_EXITED) return false; + /* Skip a running thread if the user wants stopped threads only. */ + bool is_stopped = (thr->state == THREAD_STOPPED); + if (opts.show_stopped_threads && !is_stopped) + return false; + return true; } @@ -1286,7 +1298,8 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, if (requested_threads == NULL || *requested_threads == '\0') uiout->message (_("No threads.\n")); else - uiout->message (_("No threads match '%s'.\n"), + uiout->message (_("No %sthreads match '%s'.\n"), + (opts.show_stopped_threads ? "stopped " : ""), requested_threads); return; } @@ -1342,7 +1355,7 @@ void print_thread_info (struct ui_out *uiout, const char *requested_threads, int pid) { - info_threads_opts opts {false}; + info_threads_opts opts {false, false}; print_thread_info_1 (uiout, requested_threads, 1, pid, opts); } -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 0/2] Option to show stopped threads only 2025-03-18 18:04 ` [PATCH v2 0/2] Option to show stopped threads only Tankut Baris Aktemur 2025-03-18 18:05 ` [PATCH v2 1/2] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur 2025-03-18 18:05 ` [PATCH v2 2/2] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur @ 2025-03-28 16:38 ` Guinevere Larsen 2025-04-04 13:39 ` Aktemur, Tankut Baris 2 siblings, 1 reply; 32+ messages in thread From: Guinevere Larsen @ 2025-03-28 16:38 UTC (permalink / raw) To: Tankut Baris Aktemur, gdb-patches On 3/18/25 3:04 PM, Tankut Baris Aktemur wrote: > Hi, > > This is the rebased version of > > https://inbox.sourceware.org/gdb-patches/cover.1680686220.git.tankut.baris.aktemur@intel.com/ > > As a comment, Eli had expressed his view that when "info threads" is > given a single thread ID, the "-stopped" flag could be ignored. I > didn't implement this yet but can gladly do that if that's the general > preference. Hi! Thanks for working on this! I took a look at your patch, and I think I like how it works at this point. Basically, I don't like the idea of ignoring part of the input from the user if a different part of the input happens to look a certain way (in this case non-empty). Either both options should interact, or they should be mutually exclusive, and allowing one to take precedence just inserts arbitrary rules that users need to either remember or double check the manual every time. However, this is personal preference, I'm not married to either idea. One thing that would be nice, though, would be also testing the behavior when a thread ID is given - whatever that behavior is. Adding a couple of tests calling one stopped ID, one running ID and multiple IDs, would essentially document to ourselves that "this is the behavior we want,it isn't an accident" so that if it is changed in the future, it is done so on purpose. As for the patches themselves, they look good to me. I hope this gets reviewed soon! Reviewed-By: Guinevere Larsen <guinevere@redhat.com> -- Cheers, Guinevere Larsen She/Her/Hers > > Regards, > Baris > > Tankut Baris Aktemur (2): > gdb: pass info_threads_opts to print_thread_info_1 > gdb: add a '-stopped' option to "info threads" > > gdb/NEWS | 7 ++ > gdb/doc/gdb.texinfo | 6 +- > gdb/testsuite/gdb.base/options.exp | 11 ++- > .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++++++ > .../gdb.threads/info-threads-stopped.exp | 75 ++++++++++++++++ > gdb/thread.c | 86 +++++++++++-------- > 6 files changed, 226 insertions(+), 37 deletions(-) > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp > ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: [PATCH v2 0/2] Option to show stopped threads only 2025-03-28 16:38 ` [PATCH v2 0/2] Option to show stopped threads only Guinevere Larsen @ 2025-04-04 13:39 ` Aktemur, Tankut Baris 0 siblings, 0 replies; 32+ messages in thread From: Aktemur, Tankut Baris @ 2025-04-04 13:39 UTC (permalink / raw) To: Guinevere Larsen, gdb-patches On Friday, March 28, 2025 5:38 PM, Guinevere Larsen wrote: > On 3/18/25 3:04 PM, Tankut Baris Aktemur wrote: > > Hi, > > > > This is the rebased version of > > > > https://inbox.sourceware.org/gdb- > patches/cover.1680686220.git.tankut.baris.aktemur@intel.com/ > > > > As a comment, Eli had expressed his view that when "info threads" is > > given a single thread ID, the "-stopped" flag could be ignored. I > > didn't implement this yet but can gladly do that if that's the general > > preference. > > Hi! Thanks for working on this! > > I took a look at your patch, and I think I like how it works at this > point. Basically, I don't like the idea of ignoring part of the input > from the user if a different part of the input happens to look a certain > way (in this case non-empty). Either both options should interact, or > they should be mutually exclusive, and allowing one to take precedence > just inserts arbitrary rules that users need to either remember or > double check the manual every time. However, this is personal > preference, I'm not married to either idea. > > One thing that would be nice, though, would be also testing the behavior > when a thread ID is given - whatever that behavior is. Adding a couple > of tests calling one stopped ID, one running ID and multiple IDs, would > essentially document to ourselves that "this is the behavior we want,it > isn't an accident" so that if it is changed in the future, it is done so > on purpose. > > As for the patches themselves, they look good to me. I hope this gets > reviewed soon! > > Reviewed-By: Guinevere Larsen <guinevere@redhat.com> Thank you for your review and comments. I added the new test cases and submitted v3. Regards -Baris Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v3 0/2] Option to show stopped threads only 2023-04-05 9:19 [PATCH 0/3] Option to show stopped threads only Tankut Baris Aktemur via Gdb-patches ` (3 preceding siblings ...) 2025-03-18 18:04 ` [PATCH v2 0/2] Option to show stopped threads only Tankut Baris Aktemur @ 2025-04-04 13:36 ` Tankut Baris Aktemur 2025-04-04 13:36 ` [PATCH v3 1/2] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur ` (4 more replies) 4 siblings, 5 replies; 32+ messages in thread From: Tankut Baris Aktemur @ 2025-04-04 13:36 UTC (permalink / raw) To: gdb-patches; +Cc: guinevere, eliz Hi, This is v3 of https://inbox.sourceware.org/gdb-patches/cover.1680686220.git.tankut.baris.aktemur@intel.com/ V2 is available at https://inbox.sourceware.org/gdb-patches/cover.1742320783.git.tankut.baris.aktemur@intel.com/ As a comment, Eli had expressed his view that when "info threads" is given a single thread ID, the "-stopped" flag could be ignored. I didn't implement this yet but can gladly do that if that's the general preference. As a review, Guinevere expressed her opinion that she prefers the submitted behavior. Revision 3 makes the following changes: * Address Guinevere's comment. That is, add new test cases that cover passing a single thread id, in one case a stopped thread, in another a running thread; and test passing two thread ids. * Add a trivial "print 42" to synchronize the GDB prompt. I received an email notification from the Linaro CI for v2 that there was a test failure. Although I could not reproduce locally, I believe it was caused because of the buffer contents in non-stop mode, which is hopefully fixed now. * Rebase to the current master branch. Regards, Baris Tankut Baris Aktemur (2): gdb: pass info_threads_opts to print_thread_info_1 gdb: add a '-stopped' option to "info threads" gdb/NEWS | 5 + gdb/doc/gdb.texinfo | 6 +- gdb/testsuite/gdb.base/options.exp | 11 +- .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++ .../gdb.threads/info-threads-stopped.exp | 107 ++++++++++++++++++ gdb/thread.c | 86 ++++++++------ 6 files changed, 256 insertions(+), 37 deletions(-) create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v3 1/2] gdb: pass info_threads_opts to print_thread_info_1 2025-04-04 13:36 ` [PATCH v3 " Tankut Baris Aktemur @ 2025-04-04 13:36 ` Tankut Baris Aktemur 2025-04-24 18:09 ` Pedro Alves 2025-04-04 13:36 ` [PATCH v3 2/2] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur ` (3 subsequent siblings) 4 siblings, 1 reply; 32+ messages in thread From: Tankut Baris Aktemur @ 2025-04-04 13:36 UTC (permalink / raw) To: gdb-patches; +Cc: guinevere, eliz The "info threads" command tracks its options in a struct named 'info_threads_opts', which currently has only one option. Pass the whole options object to helper functions, instead of passing the option value individually. This is a refactoring to make adding more options easier. Reviewed-By: Guinevere Larsen <guinevere@redhat.com> --- gdb/thread.c | 71 +++++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/gdb/thread.c b/gdb/thread.c index 8a34671bb6c..7dc8e7018c5 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1038,6 +1038,24 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread) && pc < thread->control.step_range_end); } +/* The options for the "info threads" command. */ + +struct info_threads_opts +{ + /* For "-gid". */ + bool show_global_ids = false; +}; + +static const gdb::option::option_def info_threads_option_defs[] = { + + gdb::option::flag_option_def<info_threads_opts> { + "gid", + [] (info_threads_opts *opts) { return &opts->show_global_ids; }, + N_("Show global thread IDs."), + }, + +}; + /* Helper for print_thread_info. Returns true if THR should be printed. If REQUESTED_THREADS, a list of GDB ids/ranges, is not NULL, only print THR if its ID is included in the list. GLOBAL_IDS @@ -1046,11 +1064,13 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread) is a thread from the process PID. Otherwise, threads from all attached PIDs are printed. If both REQUESTED_THREADS is not NULL and PID is not -1, then the thread is printed if it belongs to the - specified process. Otherwise, an error is raised. */ + specified process. Otherwise, an error is raised. OPTS is the + options of the "info threads" command. */ static bool should_print_thread (const char *requested_threads, int default_inf_num, - int global_ids, int pid, struct thread_info *thr) + int global_ids, int pid, thread_info *thr, + info_threads_opts opts) { if (requested_threads != NULL && *requested_threads != '\0') { @@ -1104,7 +1124,7 @@ thread_target_id_str (thread_info *tp) static void do_print_thread (ui_out *uiout, const char *requested_threads, - int global_ids, int pid, int show_global_ids, + int global_ids, int pid, info_threads_opts opts, int default_inf_num, thread_info *tp, thread_info *current_thread) { @@ -1115,7 +1135,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads, switch_to_thread (current_thread); if (!should_print_thread (requested_threads, default_inf_num, - global_ids, pid, tp)) + global_ids, pid, tp, opts)) return; ui_out_emit_tuple tuple_emitter (uiout, NULL); @@ -1130,7 +1150,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads, uiout->field_string ("id-in-tg", print_thread_id (tp)); } - if (show_global_ids || uiout->is_mi_like_p ()) + if (opts.show_global_ids || uiout->is_mi_like_p ()) uiout->field_signed ("id", tp->global_num); /* Switch to the thread (and inferior / target). */ @@ -1191,23 +1211,23 @@ do_print_thread (ui_out *uiout, const char *requested_threads, static void print_thread (ui_out *uiout, const char *requested_threads, - int global_ids, int pid, int show_global_ids, + int global_ids, int pid, info_threads_opts opts, int default_inf_num, thread_info *tp, thread_info *current_thread) { do_with_buffered_output (do_print_thread, uiout, requested_threads, - global_ids, pid, show_global_ids, - default_inf_num, tp, current_thread); + global_ids, pid, opts, default_inf_num, tp, + current_thread); } /* Like print_thread_info, but in addition, GLOBAL_IDS indicates whether REQUESTED_THREADS is a list of global or per-inferior - thread ids. */ + thread ids. OPTS is the options of the "info threads" command. */ static void print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, int global_ids, int pid, - int show_global_ids) + info_threads_opts opts) { int default_inf_num = current_inferior ()->num; @@ -1247,7 +1267,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, switch_to_thread (current_thread); if (!should_print_thread (requested_threads, default_inf_num, - global_ids, pid, tp)) + global_ids, pid, tp, opts)) continue; /* Switch inferiors so we're looking at the right @@ -1271,12 +1291,12 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, return; } - table_emitter.emplace (uiout, show_global_ids ? 5 : 4, + table_emitter.emplace (uiout, opts.show_global_ids ? 5 : 4, n_threads, "threads"); uiout->table_header (1, ui_left, "current", ""); uiout->table_header (4, ui_left, "id-in-tg", "Id"); - if (show_global_ids) + if (opts.show_global_ids) uiout->table_header (4, ui_left, "id", "GId"); uiout->table_header (target_id_col_width, ui_left, "target-id", "Target Id"); @@ -1293,7 +1313,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, current_exited = true; print_thread (uiout, requested_threads, global_ids, pid, - show_global_ids, default_inf_num, tp, current_thread); + opts, default_inf_num, tp, current_thread); } /* This end scope restores the current thread and the frame @@ -1322,27 +1342,10 @@ void print_thread_info (struct ui_out *uiout, const char *requested_threads, int pid) { - print_thread_info_1 (uiout, requested_threads, 1, pid, 0); + info_threads_opts opts {false}; + print_thread_info_1 (uiout, requested_threads, 1, pid, opts); } -/* The options for the "info threads" command. */ - -struct info_threads_opts -{ - /* For "-gid". */ - bool show_global_ids = false; -}; - -static const gdb::option::option_def info_threads_option_defs[] = { - - gdb::option::flag_option_def<info_threads_opts> { - "gid", - [] (info_threads_opts *opts) { return &opts->show_global_ids; }, - N_("Show global thread IDs."), - }, - -}; - /* Create an option_def_group for the "info threads" options, with IT_OPTS as context. */ @@ -1367,7 +1370,7 @@ info_threads_command (const char *arg, int from_tty) gdb::option::process_options (&arg, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp); - print_thread_info_1 (current_uiout, arg, 0, -1, it_opts.show_global_ids); + print_thread_info_1 (current_uiout, arg, 0, -1, it_opts); } /* Completer for the "info threads" command. */ -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 1/2] gdb: pass info_threads_opts to print_thread_info_1 2025-04-04 13:36 ` [PATCH v3 1/2] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur @ 2025-04-24 18:09 ` Pedro Alves 0 siblings, 0 replies; 32+ messages in thread From: Pedro Alves @ 2025-04-24 18:09 UTC (permalink / raw) To: Tankut Baris Aktemur, gdb-patches; +Cc: guinevere, eliz On 2025-04-04 14:36, Tankut Baris Aktemur wrote: > /* Helper for print_thread_info. Returns true if THR should be > printed. If REQUESTED_THREADS, a list of GDB ids/ranges, is not > NULL, only print THR if its ID is included in the list. GLOBAL_IDS > @@ -1046,11 +1064,13 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread) > is a thread from the process PID. Otherwise, threads from all > attached PIDs are printed. If both REQUESTED_THREADS is not NULL > and PID is not -1, then the thread is printed if it belongs to the > - specified process. Otherwise, an error is raised. */ > + specified process. Otherwise, an error is raised. OPTS is the > + options of the "info threads" command. */ > > static bool > should_print_thread (const char *requested_threads, int default_inf_num, > - int global_ids, int pid, struct thread_info *thr) > + int global_ids, int pid, thread_info *thr, > + info_threads_opts opts) Would you mind making that argument be the one after "requested_threads"? I.e., make it the second argument. That is so that both user-input arguments are next to one another. And make it a const ref, as this structure will grow other fields and become larger. I.e., write: static bool should_print_thread (const char *requested_threads, const info_threads_opts &opts, int default_inf_num, ... Same logic for the other functions. > /* This end scope restores the current thread and the frame > @@ -1322,27 +1342,10 @@ void > print_thread_info (struct ui_out *uiout, const char *requested_threads, > int pid) > { > - print_thread_info_1 (uiout, requested_threads, 1, pid, 0); > + info_threads_opts opts {false}; This can be just: info_threads_opts opts; as the boolean field has an in-class initializer. With that it LGTM. Pedro Alves ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v3 2/2] gdb: add a '-stopped' option to "info threads" 2025-04-04 13:36 ` [PATCH v3 " Tankut Baris Aktemur 2025-04-04 13:36 ` [PATCH v3 1/2] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur @ 2025-04-04 13:36 ` Tankut Baris Aktemur 2025-04-24 19:23 ` Pedro Alves 2025-04-23 8:00 ` [PATCH v3 0/2] Option to show stopped threads only Aktemur, Tankut Baris ` (2 subsequent siblings) 4 siblings, 1 reply; 32+ messages in thread From: Tankut Baris Aktemur @ 2025-04-04 13:36 UTC (permalink / raw) To: gdb-patches; +Cc: guinevere, eliz Add a '-stopped' option to the "info threads" command to print stopped threads only and skip the running ones. This is a convenience flag to filter out the running threads in programs that have many threads. Suppose we have an application with 5 threads, 2 of which have hit a breakpoint. The "info threads" command in the non-stop mode gives: (gdb) info threads Id Target Id Frame * 1 Thread 0x7ffff7d99740 (running) 2 Thread 0x7ffff7d98700 something () at file.c:30 3 Thread 0x7ffff7597700 (running) 4 Thread 0x7ffff6d96700 something () at file.c:30 5 Thread 0x7ffff6595700 (running) (gdb) Using the "-stopped" flag, we get (gdb) info threads -stopped Id Target Id Frame 2 Thread 0x7ffff7d98700 something () at file.c:30 4 Thread 0x7ffff6d96700 something () at file.c:30 (gdb) When combined with a thread ID, the behavior is as follows: (gdb) info threads 3 Id Target Id Frame 3 Thread 0x7ffff7597700 (running) (gdb) info threads -stopped 3 No stopped threads match '3'. (gdb) Regression-tested on X86_64 Linux. Reviewed-By: Eli Zaretskii <eliz@gnu.org> Reviewed-By: Guinevere Larsen <guinevere@redhat.com> --- gdb/NEWS | 5 + gdb/doc/gdb.texinfo | 6 +- gdb/testsuite/gdb.base/options.exp | 11 +- .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++ .../gdb.threads/info-threads-stopped.exp | 107 ++++++++++++++++++ gdb/thread.c | 17 ++- 6 files changed, 220 insertions(+), 4 deletions(-) create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp diff --git a/gdb/NEWS b/gdb/NEWS index 6a557bb4af9..d5c55c3c938 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -56,6 +56,11 @@ info sharedlibrary command are now for the full memory range allocated to the shared library. +info threads [-gid] [-stopped] [ID]... + This command now takes an optional flag, '-stopped', that causes only + the stopped threads to be printed. The flag can be useful to get a + reduced list when there is a large number of unstopped threads. + * Python API ** New class gdb.Color for dealing with colors. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index e034ac53295..3c03761dd00 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -3807,7 +3807,7 @@ Thread 1 "main" received signal SIGINT, Interrupt. @table @code @anchor{info_threads} @kindex info threads -@item info threads @r{[}-gid@r{]} @r{[}@var{thread-id-list}@r{]} +@item info threads @r{[}-gid@r{]} @r{[}-stopped@r{]} @r{[}@var{thread-id-list}@r{]} Display information about one or more threads. With no arguments displays information about all threads. You can specify the list of @@ -3857,6 +3857,10 @@ If you're debugging multiple inferiors, @value{GDBN} displays thread IDs using the qualified @var{inferior-num}.@var{thread-num} format. Otherwise, only @var{thread-num} is shown. +If you specify the @samp{-stopped} option, @value{GDBN} displays the +stopped threads only. This can be helpful to reduce the output list +if there is a large number of unstopped threads. + If you specify the @samp{-gid} option, @value{GDBN} displays a column indicating each thread's global thread ID: diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp index 8760a918082..90902e94086 100644 --- a/gdb/testsuite/gdb.base/options.exp +++ b/gdb/testsuite/gdb.base/options.exp @@ -509,12 +509,21 @@ proc_with_prefix test-thread-apply {} { proc_with_prefix test-info-threads {} { test_gdb_complete_multiple "info threads " "" "" { "-gid" + "-stopped" "ID" } + test_gdb_complete_multiple "info threads " "-" "" { + "-gid" + "-stopped" + } + test_gdb_complete_unique \ - "info threads -" \ + "info threads -g" \ "info threads -gid" + test_gdb_complete_unique \ + "info threads -s" \ + "info threads -stopped" # "ID" isn't really something the user can type. test_gdb_complete_none "info threads I" diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.c b/gdb/testsuite/gdb.threads/info-threads-stopped.c new file mode 100644 index 00000000000..2c38ecca074 --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.c @@ -0,0 +1,78 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022-2025 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/>. */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <pthread.h> + +#define NUM 4 + +volatile int should_spin = 1; + +static void +something () +{ +} + +static void +spin () +{ + while (should_spin) + usleep (1); +} + +static void * +work (void *arg) +{ + int id = *((int *) arg); + + /* Sleep a bit to give the other threads a chance to run. */ + usleep (1); + + if (id % 2 == 0) + something (); /* break-here */ + else + spin (); + + pthread_exit (NULL); +} + +int +main () +{ + /* Ensure we stop if GDB crashes and DejaGNU fails to kill us. */ + alarm (10); + + pthread_t threads[NUM]; + void *thread_result; + int ids[NUM]; + + for (int i = 0; i < NUM; i++) + { + ids[i] = i + 2; + pthread_create (&threads[i], NULL, work, &(ids[i])); + } + + sleep (10); + should_spin = 0; + + for (int i = 0; i < NUM; i++) + pthread_join(threads[i], &thread_result); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.exp b/gdb/testsuite/gdb.threads/info-threads-stopped.exp new file mode 100644 index 00000000000..37d6622697c --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.exp @@ -0,0 +1,107 @@ +# Copyright (C) 2022-2025 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/>. + +# Test for the '-stopped' flag of the "info threads" command. + +standard_testfile + +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable debug] != "" } { + return -1 +} + +save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop on\"" + clean_restart $binfile +} + +gdb_breakpoint "something" +gdb_run_cmd + +# Two threads hit the bp. +set fill "\[^\r\n\]+" +set num_hits 0 +gdb_test_multiple "" "hit the breakpoint" -lbl { + -re "\r\nThread ${fill} hit Breakpoint 1${fill}" { + incr num_hits + if {$num_hits < 2} { + exp_continue + } + } + -re "\r\n$gdb_prompt " { + exp_continue + } +} +gdb_assert {$num_hits == 2} "two threads hit the bp" + +# We are in non-stop mode. +# Send a simple command to resync the command prompt. +gdb_test "p 42" " = 42" + +# Count the number of running/stopped threads reported +# by the "info threads" command. We also capture thread ids +# for additional tests. +set running_tid "invalid" +set stopped_tid "invalid" + +foreach flag {"" "-stopped"} { + set num_running 0 + set num_stopped 0 + gdb_test_multiple "info threads $flag" "info threads $flag" { + -re "Id${fill}Target Id${fill}Frame${fill}" { + exp_continue + } + -re "^\r\n. (${decimal})${fill}Thread ${fill}.running." { + incr num_running + set running_tid $expect_out(1,string) + exp_continue + } + -re "^\r\n. (${decimal})${fill}Thread ${fill}something ${fill}${srcfile}:${decimal}" { + incr num_stopped + set stopped_tid $expect_out(1,string) + exp_continue + } + -re "^\r\n$gdb_prompt $" { + gdb_assert {$num_stopped == 2} "$gdb_test_name: num stopped" + if {$flag eq ""} { + gdb_assert {$num_running == 3} "$gdb_test_name: num running" + } else { + gdb_assert {$num_running == 0} "$gdb_test_name: num running" + } + } + } +} + +gdb_assert {$running_tid != "invalid"} "found a running thread" +gdb_assert {$stopped_tid != "invalid"} "found a stopped thread" + +# Test specifying thread ids. +gdb_test "info threads -stopped $running_tid" \ + "No stopped threads match '$running_tid'\." \ + "info thread -stopped for a running thread" + +set fill "\[^\r\n\]+" +set ws "\[ \t\]+" +gdb_test "info threads -stopped $stopped_tid" \ + [multi_line \ + "${ws}Id${ws}Target Id${ws}Frame${ws}" \ + "${ws}${stopped_tid}${ws}Thread ${fill} something ${fill}"] \ + "info thread -stopped for a stopped thread" + +gdb_test "info threads -stopped $running_tid $stopped_tid" \ + [multi_line \ + "${ws}Id${ws}Target Id${ws}Frame${ws}" \ + "${ws}${stopped_tid}${ws}Thread ${fill} something ${fill}"] \ + "info thread -stopped for a running and a stopped thread" diff --git a/gdb/thread.c b/gdb/thread.c index 7dc8e7018c5..87ee9f66680 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1044,6 +1044,8 @@ struct info_threads_opts { /* For "-gid". */ bool show_global_ids = false; + /* For "-stopped". */ + bool show_stopped_threads = false; }; static const gdb::option::option_def info_threads_option_defs[] = { @@ -1053,6 +1055,11 @@ static const gdb::option::option_def info_threads_option_defs[] = { [] (info_threads_opts *opts) { return &opts->show_global_ids; }, N_("Show global thread IDs."), }, + gdb::option::flag_option_def<info_threads_opts> { + "stopped", + [] (info_threads_opts *opts) { return &opts->show_stopped_threads; }, + N_("Show stopped threads only."), + }, }; @@ -1095,6 +1102,11 @@ should_print_thread (const char *requested_threads, int default_inf_num, if (thr->state == THREAD_EXITED) return false; + /* Skip a running thread if the user wants stopped threads only. */ + bool is_stopped = (thr->state == THREAD_STOPPED); + if (opts.show_stopped_threads && !is_stopped) + return false; + return true; } @@ -1286,7 +1298,8 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, if (requested_threads == NULL || *requested_threads == '\0') uiout->message (_("No threads.\n")); else - uiout->message (_("No threads match '%s'.\n"), + uiout->message (_("No %sthreads match '%s'.\n"), + (opts.show_stopped_threads ? "stopped " : ""), requested_threads); return; } @@ -1342,7 +1355,7 @@ void print_thread_info (struct ui_out *uiout, const char *requested_threads, int pid) { - info_threads_opts opts {false}; + info_threads_opts opts {false, false}; print_thread_info_1 (uiout, requested_threads, 1, pid, opts); } -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 2/2] gdb: add a '-stopped' option to "info threads" 2025-04-04 13:36 ` [PATCH v3 2/2] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur @ 2025-04-24 19:23 ` Pedro Alves 2025-05-05 16:17 ` Aktemur, Tankut Baris 0 siblings, 1 reply; 32+ messages in thread From: Pedro Alves @ 2025-04-24 19:23 UTC (permalink / raw) To: Tankut Baris Aktemur, gdb-patches; +Cc: guinevere, eliz [-- Attachment #1: Type: text/plain, Size: 15052 bytes --] Hi! On 2025-04-04 14:36, Tankut Baris Aktemur wrote: > Add a '-stopped' option to the "info threads" command to print stopped > threads only and skip the running ones. This is a convenience flag to > filter out the running threads in programs that have many threads. > > Suppose we have an application with 5 threads, 2 of which have hit a > breakpoint. The "info threads" command in the non-stop mode gives: > > (gdb) info threads > Id Target Id Frame > * 1 Thread 0x7ffff7d99740 (running) > 2 Thread 0x7ffff7d98700 something () at file.c:30 > 3 Thread 0x7ffff7597700 (running) > 4 Thread 0x7ffff6d96700 something () at file.c:30 > 5 Thread 0x7ffff6595700 (running) > (gdb) > > Using the "-stopped" flag, we get > > (gdb) info threads -stopped > Id Target Id Frame > 2 Thread 0x7ffff7d98700 something () at file.c:30 > 4 Thread 0x7ffff6d96700 something () at file.c:30 > (gdb) > > When combined with a thread ID, the behavior is as follows: > > (gdb) info threads 3 > Id Target Id Frame > 3 Thread 0x7ffff7597700 (running) > (gdb) info threads -stopped 3 > No stopped threads match '3'. > (gdb) > > Regression-tested on X86_64 Linux. > > Reviewed-By: Eli Zaretskii <eliz@gnu.org> > Reviewed-By: Guinevere Larsen <guinevere@redhat.com> > --- > gdb/NEWS | 5 + > gdb/doc/gdb.texinfo | 6 +- > gdb/testsuite/gdb.base/options.exp | 11 +- > .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++ > .../gdb.threads/info-threads-stopped.exp | 107 ++++++++++++++++++ > gdb/thread.c | 17 ++- > 6 files changed, 220 insertions(+), 4 deletions(-) > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp > > diff --git a/gdb/NEWS b/gdb/NEWS > index 6a557bb4af9..d5c55c3c938 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -56,6 +56,11 @@ info sharedlibrary > command are now for the full memory range allocated to the shared > library. > > +info threads [-gid] [-stopped] [ID]... > + This command now takes an optional flag, '-stopped', that causes only > + the stopped threads to be printed. The flag can be useful to get a > + reduced list when there is a large number of unstopped threads. Cool! (I would have added -running too while at it, and make "thread apply -stopped" work too. And then: "info threads -stopped -running" would print both stopped and running. Same logic as "info lanes -active -inactive" including both active and inactive in our offlist discussions.) > + > * Python API > > ** New class gdb.Color for dealing with colors. > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index e034ac53295..3c03761dd00 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -3807,7 +3807,7 @@ Thread 1 "main" received signal SIGINT, Interrupt. > @table @code > @anchor{info_threads} > @kindex info threads > -@item info threads @r{[}-gid@r{]} @r{[}@var{thread-id-list}@r{]} > +@item info threads @r{[}-gid@r{]} @r{[}-stopped@r{]} @r{[}@var{thread-id-list}@r{]} > > Display information about one or more threads. With no arguments > displays information about all threads. You can specify the list of > @@ -3857,6 +3857,10 @@ If you're debugging multiple inferiors, @value{GDBN} displays thread > IDs using the qualified @var{inferior-num}.@var{thread-num} format. > Otherwise, only @var{thread-num} is shown. > > +If you specify the @samp{-stopped} option, @value{GDBN} displays the > +stopped threads only. This can be helpful to reduce the output list > +if there is a large number of unstopped threads. > + > If you specify the @samp{-gid} option, @value{GDBN} displays a column > indicating each thread's global thread ID: > > diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp > index 8760a918082..90902e94086 100644 > --- a/gdb/testsuite/gdb.base/options.exp > +++ b/gdb/testsuite/gdb.base/options.exp > @@ -509,12 +509,21 @@ proc_with_prefix test-thread-apply {} { > proc_with_prefix test-info-threads {} { > test_gdb_complete_multiple "info threads " "" "" { > "-gid" > + "-stopped" > "ID" > } > > + test_gdb_complete_multiple "info threads " "-" "" { > + "-gid" > + "-stopped" > + } > + > test_gdb_complete_unique \ > - "info threads -" \ > + "info threads -g" \ > "info threads -gid" > + test_gdb_complete_unique \ > + "info threads -s" \ > + "info threads -stopped" > > # "ID" isn't really something the user can type. > test_gdb_complete_none "info threads I" > diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.c b/gdb/testsuite/gdb.threads/info-threads-stopped.c > new file mode 100644 > index 00000000000..2c38ecca074 > --- /dev/null > +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.c > @@ -0,0 +1,78 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2022-2025 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/>. */ > + > +#include <stdio.h> > +#include <unistd.h> > +#include <stdlib.h> > +#include <pthread.h> > + > +#define NUM 4 > + > +volatile int should_spin = 1; > + > +static void > +something () > +{ > +} > + > +static void > +spin () > +{ > + while (should_spin) > + usleep (1); > +} > + > +static void * > +work (void *arg) > +{ > + int id = *((int *) arg); > + > + /* Sleep a bit to give the other threads a chance to run. */ > + usleep (1); This usleep isn't in a loop, so why is it needed? > + > + if (id % 2 == 0) > + something (); /* break-here */ > + else > + spin (); > + > + pthread_exit (NULL); > +} > + > +int > +main () > +{ > + /* Ensure we stop if GDB crashes and DejaGNU fails to kill us. */ > + alarm (10); This is 10 seconds ... > + > + pthread_t threads[NUM]; > + void *thread_result; > + int ids[NUM]; > + > + for (int i = 0; i < NUM; i++) > + { > + ids[i] = i + 2; > + pthread_create (&threads[i], NULL, work, &(ids[i])); > + } > + > + sleep (10); ... and this is 10 seconds too. Shouldn't the alarm clock be larger to give it a chance of clean exit? Actually better is to not have a timer at all. We can do that with a barrier that guarantees that we reach a breakpoint only after all threads have been seen. That fixes an issue which is that the test is expecting to hit two breakpoints, but it isn't waiting until the threads that are not supposed to hit a breakpoint actually start! Due to scheduling, you could end up doing "info threads" before all those threads are seen by GDB. Using a barrier fixes that. > + should_spin = 0; > + > + for (int i = 0; i < NUM; i++) > + pthread_join(threads[i], &thread_result); Space missing: "pthread_join (". You are not using thread_result for anything, so that could be: pthread_join (threads[i], NULL); But really, with a barrier and given the alarm, this is dead code, basically. Since we need a breakpoint after the barrier, might as well make the main thread hit the something() breakpoint too and be considered a stopped thread. (See attached patch.) > + > + return 0; > +} > diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.exp b/gdb/testsuite/gdb.threads/info-threads-stopped.exp > new file mode 100644 > index 00000000000..37d6622697c > --- /dev/null > +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.exp > @@ -0,0 +1,107 @@ > +# Copyright (C) 2022-2025 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/>. > + > +# Test for the '-stopped' flag of the "info threads" command. > + > +standard_testfile > + > +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ > + executable debug] != "" } { > + return -1 > +} > + > +save_vars { GDBFLAGS } { > + append GDBFLAGS " -ex \"set non-stop on\"" > + clean_restart $binfile > +} > + > +gdb_breakpoint "something" > +gdb_run_cmd > + > +# Two threads hit the bp. > +set fill "\[^\r\n\]+" > +set num_hits 0 > +gdb_test_multiple "" "hit the breakpoint" -lbl { > + -re "\r\nThread ${fill} hit Breakpoint 1${fill}" { > + incr num_hits > + if {$num_hits < 2} { > + exp_continue > + } > + } > + -re "\r\n$gdb_prompt " { > + exp_continue > + } > +} It's better to write this in a way that explicitly always consumes the prompt. > +gdb_assert {$num_hits == 2} "two threads hit the bp" > + > +# We are in non-stop mode. > +# Send a simple command to resync the command prompt. > +gdb_test "p 42" " = 42" Then this shouldn't be needed. > + > +# Count the number of running/stopped threads reported > +# by the "info threads" command. We also capture thread ids > +# for additional tests. > +set running_tid "invalid" > +set stopped_tid "invalid" > + > +foreach flag {"" "-stopped"} { > + set num_running 0 > + set num_stopped 0 > + gdb_test_multiple "info threads $flag" "info threads $flag" { > + -re "Id${fill}Target Id${fill}Frame${fill}" { > + exp_continue > + } > + -re "^\r\n. (${decimal})${fill}Thread ${fill}.running." { > + incr num_running > + set running_tid $expect_out(1,string) > + exp_continue > + } > + -re "^\r\n. (${decimal})${fill}Thread ${fill}something ${fill}${srcfile}:${decimal}" { > + incr num_stopped > + set stopped_tid $expect_out(1,string) > + exp_continue > + } > + -re "^\r\n$gdb_prompt $" { > + gdb_assert {$num_stopped == 2} "$gdb_test_name: num stopped" > + if {$flag eq ""} { > + gdb_assert {$num_running == 3} "$gdb_test_name: num running" > + } else { > + gdb_assert {$num_running == 0} "$gdb_test_name: num running" It's better practice have the same number of PASSes and FAILs. They won't match if the prompt regexp doesn't match. > + } > + } > + } This needs some fixing around regexp matching. It is currently racy wrt to how much expect happens to manage to read into in the expect buffer at a time. If you run the test with "make check-read1" to force one byte at a time, it exposes the races reliably: $ make check-read1 TESTS="gdb.threads/info-threads-stopped.exp" ... FAIL: gdb.threads/info-threads-stopped.exp: info threads FAIL: gdb.threads/info-threads-stopped.exp: info threads -stopped === gdb Summary === # of expected passes 8 # of unexpected failures 2 I've attached a patch that fixes all the testcase issues that you can squash into yours. > +} > + > +gdb_assert {$running_tid != "invalid"} "found a running thread" > +gdb_assert {$stopped_tid != "invalid"} "found a stopped thread" > + > +# Test specifying thread ids. > +gdb_test "info threads -stopped $running_tid" \ > + "No stopped threads match '$running_tid'\." \ > + "info thread -stopped for a running thread" > + > +set fill "\[^\r\n\]+" > +set ws "\[ \t\]+" > +gdb_test "info threads -stopped $stopped_tid" \ > + [multi_line \ > + "${ws}Id${ws}Target Id${ws}Frame${ws}" \ > + "${ws}${stopped_tid}${ws}Thread ${fill} something ${fill}"] \ > + "info thread -stopped for a stopped thread" > + > +gdb_test "info threads -stopped $running_tid $stopped_tid" \ > + [multi_line \ > + "${ws}Id${ws}Target Id${ws}Frame${ws}" \ > + "${ws}${stopped_tid}${ws}Thread ${fill} something ${fill}"] \ > + "info thread -stopped for a running and a stopped thread" > diff --git a/gdb/thread.c b/gdb/thread.c > index 7dc8e7018c5..87ee9f66680 100644 > --- a/gdb/thread.c > +++ b/gdb/thread.c > @@ -1044,6 +1044,8 @@ struct info_threads_opts > { > /* For "-gid". */ > bool show_global_ids = false; > + /* For "-stopped". */ > + bool show_stopped_threads = false; > }; > > static const gdb::option::option_def info_threads_option_defs[] = { > @@ -1053,6 +1055,11 @@ static const gdb::option::option_def info_threads_option_defs[] = { > [] (info_threads_opts *opts) { return &opts->show_global_ids; }, > N_("Show global thread IDs."), > }, > + gdb::option::flag_option_def<info_threads_opts> { > + "stopped", > + [] (info_threads_opts *opts) { return &opts->show_stopped_threads; }, > + N_("Show stopped threads only."), > + }, > > }; > > @@ -1095,6 +1102,11 @@ should_print_thread (const char *requested_threads, int default_inf_num, > if (thr->state == THREAD_EXITED) > return false; > > + /* Skip a running thread if the user wants stopped threads only. */ > + bool is_stopped = (thr->state == THREAD_STOPPED); > + if (opts.show_stopped_threads && !is_stopped) > + return false; > + > return true; > } > > @@ -1286,7 +1298,8 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, > if (requested_threads == NULL || *requested_threads == '\0') > uiout->message (_("No threads.\n")); > else > - uiout->message (_("No threads match '%s'.\n"), > + uiout->message (_("No %sthreads match '%s'.\n"), > + (opts.show_stopped_threads ? "stopped " : ""), > requested_threads); I don't think we should do this. For one, it's not i18n friendly how that is written. Then, once we add a filter like "-running" too, then it'll get awkward with: (gdb) info threads -stopped -running *what would we say here?* I think the easiest is to just drop the %s part, and just say that no threads matched, like: if (!any_threads) uiout->message (_("No threads.\n")); else uiout->message (_("No threads matched.\n")); I've also attached a attached patch for this to make it easier to see what I mean. Note that "\." in your regexp does not match a period. It needs to be two back slashes "\\." as in my patch. Thanks, Pedro Alves [-- Attachment #2: 0001-Fix-test-races.patch --] [-- Type: text/x-patch, Size: 5764 bytes --] From f895c8244f61a24d7d8661a033324706940bfef5 Mon Sep 17 00:00:00 2001 From: Pedro Alves <pedro@palves.net> Date: Thu, 24 Apr 2025 20:09:16 +0100 Subject: [PATCH 1/2] Fix test races Change-Id: Ia98a3195282a82fc68104f61cba1216bf0a296a0 --- .../gdb.threads/info-threads-stopped.c | 27 +++++---- .../gdb.threads/info-threads-stopped.exp | 56 ++++++++++--------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.c b/gdb/testsuite/gdb.threads/info-threads-stopped.c index 2c38ecca074..2c4cd854bb7 100644 --- a/gdb/testsuite/gdb.threads/info-threads-stopped.c +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.c @@ -22,30 +22,29 @@ #define NUM 4 -volatile int should_spin = 1; +static pthread_barrier_t threads_started_barrier; static void -something () +stop_here () { } static void spin () { - while (should_spin) + while (1) usleep (1); } static void * work (void *arg) { - int id = *((int *) arg); + int id = *(int *) arg; - /* Sleep a bit to give the other threads a chance to run. */ - usleep (1); + pthread_barrier_wait (&threads_started_barrier); if (id % 2 == 0) - something (); /* break-here */ + stop_here (); else spin (); @@ -59,20 +58,20 @@ main () alarm (10); pthread_t threads[NUM]; - void *thread_result; int ids[NUM]; + pthread_barrier_init (&threads_started_barrier, NULL, NUM + 1); + for (int i = 0; i < NUM; i++) { - ids[i] = i + 2; - pthread_create (&threads[i], NULL, work, &(ids[i])); + ids[i] = i; + pthread_create (&threads[i], NULL, work, &ids[i]); } - sleep (10); - should_spin = 0; + /* Wait until all threads are seen running. */ + pthread_barrier_wait (&threads_started_barrier); - for (int i = 0; i < NUM; i++) - pthread_join(threads[i], &thread_result); + stop_here (); return 0; } diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.exp b/gdb/testsuite/gdb.threads/info-threads-stopped.exp index 37d6622697c..d554bd7ef2c 100644 --- a/gdb/testsuite/gdb.threads/info-threads-stopped.exp +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.exp @@ -27,28 +27,29 @@ save_vars { GDBFLAGS } { clean_restart $binfile } -gdb_breakpoint "something" -gdb_run_cmd +if ![runto_main] { + return -1 +} + +gdb_breakpoint "stop_here" +gdb_test_multiple "continue -a&" "" { + -re "Continuing.\r\n$gdb_prompt " { + pass $gdb_test_name + } +} -# Two threads hit the bp. +set expected_hits 3 set fill "\[^\r\n\]+" set num_hits 0 gdb_test_multiple "" "hit the breakpoint" -lbl { - -re "\r\nThread ${fill} hit Breakpoint 1${fill}" { + -re "\r\nThread ${fill} hit Breakpoint ${decimal}," { incr num_hits - if {$num_hits < 2} { + if {$num_hits < $expected_hits} { exp_continue } } - -re "\r\n$gdb_prompt " { - exp_continue - } } -gdb_assert {$num_hits == 2} "two threads hit the bp" - -# We are in non-stop mode. -# Send a simple command to resync the command prompt. -gdb_test "p 42" " = 42" +gdb_assert {$num_hits == $expected_hits} "expected threads hit the bp" # Count the number of running/stopped threads reported # by the "info threads" command. We also capture thread ids @@ -56,36 +57,37 @@ gdb_test "p 42" " = 42" set running_tid "invalid" set stopped_tid "invalid" +set eol "(?=\r\n)" + foreach flag {"" "-stopped"} { set num_running 0 set num_stopped 0 - gdb_test_multiple "info threads $flag" "info threads $flag" { - -re "Id${fill}Target Id${fill}Frame${fill}" { + gdb_test_multiple "info threads $flag" "info threads $flag" -lbl { + -re "Id${fill}Target Id${fill}Frame${fill}${eol}" { exp_continue } - -re "^\r\n. (${decimal})${fill}Thread ${fill}.running." { + -re "^\r\n. (${decimal})${fill}Thread ${fill}.running.${eol}" { incr num_running set running_tid $expect_out(1,string) exp_continue } - -re "^\r\n. (${decimal})${fill}Thread ${fill}something ${fill}${srcfile}:${decimal}" { + -re "^\r\n. (${decimal})${fill}Thread ${fill}stop_here ${fill}${srcfile}:${decimal}${fill}${eol}" { incr num_stopped set stopped_tid $expect_out(1,string) exp_continue } -re "^\r\n$gdb_prompt $" { - gdb_assert {$num_stopped == 2} "$gdb_test_name: num stopped" - if {$flag eq ""} { - gdb_assert {$num_running == 3} "$gdb_test_name: num running" - } else { - gdb_assert {$num_running == 0} "$gdb_test_name: num running" - } + pass $gdb_test_name } } } -gdb_assert {$running_tid != "invalid"} "found a running thread" -gdb_assert {$stopped_tid != "invalid"} "found a stopped thread" +gdb_assert {$num_stopped == 3} "num stopped" +if {$flag eq ""} { + gdb_assert {$num_running == 2} "num running" +} else { + gdb_assert {$num_running == 0} "num running" +} # Test specifying thread ids. gdb_test "info threads -stopped $running_tid" \ @@ -97,11 +99,11 @@ set ws "\[ \t\]+" gdb_test "info threads -stopped $stopped_tid" \ [multi_line \ "${ws}Id${ws}Target Id${ws}Frame${ws}" \ - "${ws}${stopped_tid}${ws}Thread ${fill} something ${fill}"] \ + "${ws}${stopped_tid}${ws}Thread ${fill} stop_here ${fill}"] \ "info thread -stopped for a stopped thread" gdb_test "info threads -stopped $running_tid $stopped_tid" \ [multi_line \ "${ws}Id${ws}Target Id${ws}Frame${ws}" \ - "${ws}${stopped_tid}${ws}Thread ${fill} something ${fill}"] \ + "${ws}${stopped_tid}${ws}Thread ${fill} stop_here ${fill}"] \ "info thread -stopped for a running and a stopped thread" base-commit: e32b976a152894c00a01e4e0a48cd1f1d82d1d39 prerequisite-patch-id: 38786aad181a17816a63708dcae88f8bffed5469 prerequisite-patch-id: f64471d0b4bbbb7cb787ae826e654baf8c1a5bf3 -- 2.49.0 [-- Attachment #3: 0002-No-threads-matched.patch --] [-- Type: text/x-patch, Size: 2875 bytes --] From a8e4beca721a9fb25fc3050bac2a44360f83f743 Mon Sep 17 00:00:00 2001 From: Pedro Alves <pedro@palves.net> Date: Thu, 24 Apr 2025 19:36:12 +0100 Subject: [PATCH 2/2] No threads matched Change-Id: I12ea3d283319c8249807e70de890b40ad3a00f7d --- .../gdb.threads/info-threads-stopped.exp | 2 +- gdb/thread.c | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/gdb/testsuite/gdb.threads/info-threads-stopped.exp b/gdb/testsuite/gdb.threads/info-threads-stopped.exp index d554bd7ef2c..660ed4aa197 100644 --- a/gdb/testsuite/gdb.threads/info-threads-stopped.exp +++ b/gdb/testsuite/gdb.threads/info-threads-stopped.exp @@ -91,7 +91,7 @@ if {$flag eq ""} { # Test specifying thread ids. gdb_test "info threads -stopped $running_tid" \ - "No stopped threads match '$running_tid'\." \ + "No threads matched\\." \ "info thread -stopped for a running thread" set fill "\[^\r\n\]+" diff --git a/gdb/thread.c b/gdb/thread.c index 7057fa1d641..7485dcce8d6 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1267,13 +1267,15 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, list_emitter.emplace (uiout, "threads"); else { - int n_threads = 0; + int n_matching_threads = 0; /* The width of the "Target Id" column. Grown below to accommodate the largest entry. */ size_t target_id_col_width = 17; for (thread_info *tp : all_threads ()) { + any_thread = true; + /* In case REQUESTED_THREADS contains $_thread. */ if (current_thread != nullptr) switch_to_thread (current_thread); @@ -1290,22 +1292,20 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, = std::max (target_id_col_width, thread_target_id_str (tp).size ()); - ++n_threads; + ++n_matching_threads; } - if (n_threads == 0) + if (n_matching_threads == 0) { - if (requested_threads == NULL || *requested_threads == '\0') + if (!any_thread) uiout->message (_("No threads.\n")); else - uiout->message (_("No %sthreads match '%s'.\n"), - (opts.show_stopped_threads ? "stopped " : ""), - requested_threads); + uiout->message (_("No threads matched.\n")); return; } table_emitter.emplace (uiout, opts.show_global_ids ? 5 : 4, - n_threads, "threads"); + n_matching_threads, "threads"); uiout->table_header (1, ui_left, "current", ""); uiout->table_header (4, ui_left, "id-in-tg", "Id"); @@ -1320,8 +1320,6 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, for (inferior *inf : all_inferiors ()) for (thread_info *tp : inf->threads ()) { - any_thread = true; - if (tp == current_thread && tp->state == THREAD_EXITED) current_exited = true; -- 2.49.0 ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: [PATCH v3 2/2] gdb: add a '-stopped' option to "info threads" 2025-04-24 19:23 ` Pedro Alves @ 2025-05-05 16:17 ` Aktemur, Tankut Baris 0 siblings, 0 replies; 32+ messages in thread From: Aktemur, Tankut Baris @ 2025-05-05 16:17 UTC (permalink / raw) To: Pedro Alves, gdb-patches; +Cc: guinevere, eliz On Thursday, April 24, 2025 9:23 PM, Pedro Alves wrote: > Hi! > > On 2025-04-04 14:36, Tankut Baris Aktemur wrote: > > Add a '-stopped' option to the "info threads" command to print stopped > > threads only and skip the running ones. This is a convenience flag to > > filter out the running threads in programs that have many threads. > > > > Suppose we have an application with 5 threads, 2 of which have hit a > > breakpoint. The "info threads" command in the non-stop mode gives: > > > > (gdb) info threads > > Id Target Id Frame > > * 1 Thread 0x7ffff7d99740 (running) > > 2 Thread 0x7ffff7d98700 something () at file.c:30 > > 3 Thread 0x7ffff7597700 (running) > > 4 Thread 0x7ffff6d96700 something () at file.c:30 > > 5 Thread 0x7ffff6595700 (running) > > (gdb) > > > > Using the "-stopped" flag, we get > > > > (gdb) info threads -stopped > > Id Target Id Frame > > 2 Thread 0x7ffff7d98700 something () at file.c:30 > > 4 Thread 0x7ffff6d96700 something () at file.c:30 > > (gdb) > > > > When combined with a thread ID, the behavior is as follows: > > > > (gdb) info threads 3 > > Id Target Id Frame > > 3 Thread 0x7ffff7597700 (running) > > (gdb) info threads -stopped 3 > > No stopped threads match '3'. > > (gdb) > > > > Regression-tested on X86_64 Linux. > > > > Reviewed-By: Eli Zaretskii <eliz@gnu.org> > > Reviewed-By: Guinevere Larsen <guinevere@redhat.com> > > --- > > gdb/NEWS | 5 + > > gdb/doc/gdb.texinfo | 6 +- > > gdb/testsuite/gdb.base/options.exp | 11 +- > > .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++ > > .../gdb.threads/info-threads-stopped.exp | 107 ++++++++++++++++++ > > gdb/thread.c | 17 ++- > > 6 files changed, 220 insertions(+), 4 deletions(-) > > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c > > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp > > > > diff --git a/gdb/NEWS b/gdb/NEWS > > index 6a557bb4af9..d5c55c3c938 100644 > > --- a/gdb/NEWS > > +++ b/gdb/NEWS > > @@ -56,6 +56,11 @@ info sharedlibrary > > command are now for the full memory range allocated to the shared > > library. > > > > +info threads [-gid] [-stopped] [ID]... > > + This command now takes an optional flag, '-stopped', that causes only > > + the stopped threads to be printed. The flag can be useful to get a > > + reduced list when there is a large number of unstopped threads. > > > Cool! > > (I would have added -running too while at it, and make "thread apply -stopped" work too. > > And then: > > "info threads -stopped -running" > > would print both stopped and running. > > Same logic as "info lanes -active -inactive" including both active and inactive in > our offlist discussions.) Hi Pedro, Thanks a lot for the thorough review. I'll soon send the next revision. I also added "-running" per your suggestion, but let's please complete this series first. I'd like to send "thread apply -stopped" separately. Thank you. -Baris Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* RE: [PATCH v3 0/2] Option to show stopped threads only 2025-04-04 13:36 ` [PATCH v3 " Tankut Baris Aktemur 2025-04-04 13:36 ` [PATCH v3 1/2] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur 2025-04-04 13:36 ` [PATCH v3 2/2] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur @ 2025-04-23 8:00 ` Aktemur, Tankut Baris 2025-04-24 17:53 ` Pedro Alves 2025-05-05 16:19 ` [PATCH v4 0/3] Option to show stopped/running " Tankut Baris Aktemur 4 siblings, 0 replies; 32+ messages in thread From: Aktemur, Tankut Baris @ 2025-04-23 8:00 UTC (permalink / raw) To: gdb-patches; +Cc: guinevere, eliz Kindly pinging. Thanks, -Baris On Friday, April 4, 2025 3:37 PM, Aktemur, Tankut Baris wrote: > Hi, > > This is v3 of > > https://inbox.sourceware.org/gdb- > patches/cover.1680686220.git.tankut.baris.aktemur@intel.com/ > > V2 is available at > > https://inbox.sourceware.org/gdb- > patches/cover.1742320783.git.tankut.baris.aktemur@intel.com/ > > As a comment, Eli had expressed his view that when "info threads" is > given a single thread ID, the "-stopped" flag could be ignored. I > didn't implement this yet but can gladly do that if that's the general > preference. As a review, Guinevere expressed her opinion that she > prefers the submitted behavior. > > Revision 3 makes the following changes: > > * Address Guinevere's comment. That is, add new test cases that > cover passing a single thread id, in one case a stopped thread, in > another a running thread; and test passing two thread ids. > > * Add a trivial "print 42" to synchronize the GDB prompt. I > received an email notification from the Linaro CI for v2 that > there was a test failure. Although I could not reproduce locally, > I believe it was caused because of the buffer contents in non-stop > mode, which is hopefully fixed now. > > * Rebase to the current master branch. > > Regards, > Baris > > Tankut Baris Aktemur (2): > gdb: pass info_threads_opts to print_thread_info_1 > gdb: add a '-stopped' option to "info threads" > > gdb/NEWS | 5 + > gdb/doc/gdb.texinfo | 6 +- > gdb/testsuite/gdb.base/options.exp | 11 +- > .../gdb.threads/info-threads-stopped.c | 78 +++++++++++++ > .../gdb.threads/info-threads-stopped.exp | 107 ++++++++++++++++++ > gdb/thread.c | 86 ++++++++------ > 6 files changed, 256 insertions(+), 37 deletions(-) > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.c > create mode 100644 gdb/testsuite/gdb.threads/info-threads-stopped.exp > > -- > 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 0/2] Option to show stopped threads only 2025-04-04 13:36 ` [PATCH v3 " Tankut Baris Aktemur ` (2 preceding siblings ...) 2025-04-23 8:00 ` [PATCH v3 0/2] Option to show stopped threads only Aktemur, Tankut Baris @ 2025-04-24 17:53 ` Pedro Alves 2025-05-05 16:19 ` [PATCH v4 0/3] Option to show stopped/running " Tankut Baris Aktemur 4 siblings, 0 replies; 32+ messages in thread From: Pedro Alves @ 2025-04-24 17:53 UTC (permalink / raw) To: Tankut Baris Aktemur, gdb-patches; +Cc: guinevere, eliz Hi Baris, On 2025-04-04 14:36, Tankut Baris Aktemur wrote: > Revision 3 makes the following changes: ... > > * Add a trivial "print 42" to synchronize the GDB prompt. I > received an email notification from the Linaro CI for v2 that > there was a test failure. Although I could not reproduce locally, > I believe it was caused because of the buffer contents in non-stop > mode, which is hopefully fixed now. This usually means something is off in the test, not matching expect output with gdb_test_multiple completely correctly, or some $gdb_prompt mishandling. I'll see if I can fix it for you. Stay tuned. Pedro Alves ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v4 0/3] Option to show stopped/running threads only 2025-04-04 13:36 ` [PATCH v3 " Tankut Baris Aktemur ` (3 preceding siblings ...) 2025-04-24 17:53 ` Pedro Alves @ 2025-05-05 16:19 ` Tankut Baris Aktemur 2025-05-05 16:19 ` [PATCH v4 1/3] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur ` (3 more replies) 4 siblings, 4 replies; 32+ messages in thread From: Tankut Baris Aktemur @ 2025-05-05 16:19 UTC (permalink / raw) To: gdb-patches; +Cc: guinevere, eliz, pedro Hi, This is v4 of a series that introduces options to filter the output of "info threads". V3 is available at https://inbox.sourceware.org/gdb-patches/cover.1743772891.git.tankut.baris.aktemur@intel.com/ In this revision I address Pedro's comments he gave on V3. Eli had previously approved the documentation changes, but I needed to update the docs in this revision. Hence, I removed his "Reviewed-By" and would like to request a doc review again. Best regards, Baris Tankut Baris Aktemur (3): gdb: pass info_threads_opts to print_thread_info_1 gdb: update "info threads" output when no threads match the arguments gdb: add '-stopped' and '-running' options to "info threads" gdb/NEWS | 12 ++ gdb/doc/gdb.texinfo | 10 +- gdb/testsuite/gdb.base/options.exp | 16 ++- gdb/testsuite/gdb.multi/tids.exp | 4 +- .../gdb.threads/current-lwp-dead.exp | 2 +- .../gdb.threads/info-threads-options.c | 77 ++++++++++ .../gdb.threads/info-threads-options.exp | 131 ++++++++++++++++++ .../gdb.threads/thread-bp-deleted.exp | 2 +- gdb/thread.c | 122 +++++++++------- 9 files changed, 321 insertions(+), 55 deletions(-) create mode 100644 gdb/testsuite/gdb.threads/info-threads-options.c create mode 100644 gdb/testsuite/gdb.threads/info-threads-options.exp -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v4 1/3] gdb: pass info_threads_opts to print_thread_info_1 2025-05-05 16:19 ` [PATCH v4 0/3] Option to show stopped/running " Tankut Baris Aktemur @ 2025-05-05 16:19 ` Tankut Baris Aktemur 2025-05-05 16:19 ` [PATCH v4 2/3] gdb: update "info threads" output when no threads match the arguments Tankut Baris Aktemur ` (2 subsequent siblings) 3 siblings, 0 replies; 32+ messages in thread From: Tankut Baris Aktemur @ 2025-05-05 16:19 UTC (permalink / raw) To: gdb-patches; +Cc: guinevere, eliz, pedro The "info threads" command tracks its options in a struct named 'info_threads_opts', which currently has only one option. Pass the whole options object to helper functions, instead of passing the option value individually. This is a refactoring to make adding more options easier. Reviewed-By: Guinevere Larsen <guinevere@redhat.com> --- gdb/thread.c | 80 +++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/gdb/thread.c b/gdb/thread.c index b659463ef02..3375cfcee24 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1038,6 +1038,24 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread) && pc < thread->control.step_range_end); } +/* The options for the "info threads" command. */ + +struct info_threads_opts +{ + /* For "-gid". */ + bool show_global_ids = false; +}; + +static const gdb::option::option_def info_threads_option_defs[] = { + + gdb::option::flag_option_def<info_threads_opts> { + "gid", + [] (info_threads_opts *opts) { return &opts->show_global_ids; }, + N_("Show global thread IDs."), + }, + +}; + /* Helper for print_thread_info. Returns true if THR should be printed. If REQUESTED_THREADS, a list of GDB ids/ranges, is not NULL, only print THR if its ID is included in the list. GLOBAL_IDS @@ -1046,11 +1064,13 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread) is a thread from the process PID. Otherwise, threads from all attached PIDs are printed. If both REQUESTED_THREADS is not NULL and PID is not -1, then the thread is printed if it belongs to the - specified process. Otherwise, an error is raised. */ + specified process. Otherwise, an error is raised. OPTS is the + options of the "info threads" command. */ static bool -should_print_thread (const char *requested_threads, int default_inf_num, - int global_ids, int pid, struct thread_info *thr) +should_print_thread (const char *requested_threads, + const info_threads_opts &opts, int default_inf_num, + int global_ids, int pid, thread_info *thr) { if (requested_threads != NULL && *requested_threads != '\0') { @@ -1104,8 +1124,8 @@ thread_target_id_str (thread_info *tp) static void do_print_thread (ui_out *uiout, const char *requested_threads, - int global_ids, int pid, int show_global_ids, - int default_inf_num, thread_info *tp, + const info_threads_opts &opts, int global_ids, + int pid, int default_inf_num, thread_info *tp, thread_info *current_thread) { int core; @@ -1114,7 +1134,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads, if (current_thread != nullptr) switch_to_thread (current_thread); - if (!should_print_thread (requested_threads, default_inf_num, + if (!should_print_thread (requested_threads, opts, default_inf_num, global_ids, pid, tp)) return; @@ -1130,7 +1150,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads, uiout->field_string ("id-in-tg", print_thread_id (tp)); } - if (show_global_ids || uiout->is_mi_like_p ()) + if (opts.show_global_ids || uiout->is_mi_like_p ()) uiout->field_signed ("id", tp->global_num); /* Switch to the thread (and inferior / target). */ @@ -1191,23 +1211,22 @@ do_print_thread (ui_out *uiout, const char *requested_threads, static void print_thread (ui_out *uiout, const char *requested_threads, - int global_ids, int pid, int show_global_ids, + const info_threads_opts &opts, int global_ids, int pid, int default_inf_num, thread_info *tp, thread_info *current_thread) { do_with_buffered_output (do_print_thread, uiout, requested_threads, - global_ids, pid, show_global_ids, - default_inf_num, tp, current_thread); + opts, global_ids, pid, default_inf_num, tp, + current_thread); } /* Like print_thread_info, but in addition, GLOBAL_IDS indicates whether REQUESTED_THREADS is a list of global or per-inferior - thread ids. */ + thread ids. OPTS is the options of the "info threads" command. */ static void print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, - int global_ids, int pid, - int show_global_ids) + const info_threads_opts &opts, int global_ids, int pid) { int default_inf_num = current_inferior ()->num; @@ -1246,8 +1265,8 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, if (current_thread != nullptr) switch_to_thread (current_thread); - if (!should_print_thread (requested_threads, default_inf_num, - global_ids, pid, tp)) + if (!should_print_thread (requested_threads, opts, + default_inf_num, global_ids, pid, tp)) continue; /* Switch inferiors so we're looking at the right @@ -1271,12 +1290,12 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, return; } - table_emitter.emplace (uiout, show_global_ids ? 5 : 4, + table_emitter.emplace (uiout, opts.show_global_ids ? 5 : 4, n_threads, "threads"); uiout->table_header (1, ui_left, "current", ""); uiout->table_header (4, ui_left, "id-in-tg", "Id"); - if (show_global_ids) + if (opts.show_global_ids) uiout->table_header (4, ui_left, "id", "GId"); uiout->table_header (target_id_col_width, ui_left, "target-id", "Target Id"); @@ -1292,8 +1311,8 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, if (tp == current_thread && tp->state == THREAD_EXITED) current_exited = true; - print_thread (uiout, requested_threads, global_ids, pid, - show_global_ids, default_inf_num, tp, current_thread); + print_thread (uiout, requested_threads, opts, global_ids, pid, + default_inf_num, tp, current_thread); } /* This end scope restores the current thread and the frame @@ -1322,27 +1341,10 @@ void print_thread_info (struct ui_out *uiout, const char *requested_threads, int pid) { - print_thread_info_1 (uiout, requested_threads, 1, pid, 0); + info_threads_opts opts; + print_thread_info_1 (uiout, requested_threads, opts, 1, pid); } -/* The options for the "info threads" command. */ - -struct info_threads_opts -{ - /* For "-gid". */ - bool show_global_ids = false; -}; - -static const gdb::option::option_def info_threads_option_defs[] = { - - gdb::option::flag_option_def<info_threads_opts> { - "gid", - [] (info_threads_opts *opts) { return &opts->show_global_ids; }, - N_("Show global thread IDs."), - }, - -}; - /* Create an option_def_group for the "info threads" options, with IT_OPTS as context. */ @@ -1367,7 +1369,7 @@ info_threads_command (const char *arg, int from_tty) gdb::option::process_options (&arg, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp); - print_thread_info_1 (current_uiout, arg, 0, -1, it_opts.show_global_ids); + print_thread_info_1 (current_uiout, arg, it_opts, 0, -1); } /* Completer for the "info threads" command. */ -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v4 2/3] gdb: update "info threads" output when no threads match the arguments 2025-05-05 16:19 ` [PATCH v4 0/3] Option to show stopped/running " Tankut Baris Aktemur 2025-05-05 16:19 ` [PATCH v4 1/3] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur @ 2025-05-05 16:19 ` Tankut Baris Aktemur 2025-05-05 17:19 ` Eli Zaretskii 2025-05-05 16:19 ` [PATCH v4 3/3] gdb: add '-stopped' and '-running' options to "info threads" Tankut Baris Aktemur 2025-05-09 20:54 ` [PATCH v4 0/3] Option to show stopped/running threads only Pedro Alves 3 siblings, 1 reply; 32+ messages in thread From: Tankut Baris Aktemur @ 2025-05-05 16:19 UTC (permalink / raw) To: gdb-patches; +Cc: guinevere, eliz, pedro If "info threads" is provided with the thread ID argument but no such threads matching the thread ID(s) are found, GDB prints No threads match '<ID...>'. Update this output to the more generalized No threads matched. The intention is that the next patch, and potentially future ones, will extend the command with more filter/match arguments. We cannot customize the output to each such argument. Hence, be more generic. --- gdb/NEWS | 7 +++++++ gdb/testsuite/gdb.multi/tids.exp | 4 ++-- gdb/testsuite/gdb.threads/current-lwp-dead.exp | 2 +- gdb/testsuite/gdb.threads/thread-bp-deleted.exp | 2 +- gdb/thread.c | 3 +-- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index a82b7e3342c..18a8b7475b4 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -90,6 +90,13 @@ info sharedlibrary command are now for the full memory range allocated to the shared library. +info threads [-gid] [ID]... + If no threads match the given ID(s), GDB now prints + + No threads matched. + + without printing the provided argument. + * GDB-internal Thread Local Storage (TLS) support ** Linux targets for the x86_64, aarch64, ppc64, s390x, and riscv diff --git a/gdb/testsuite/gdb.multi/tids.exp b/gdb/testsuite/gdb.multi/tids.exp index b84f9080cbd..dab6275dc03 100644 --- a/gdb/testsuite/gdb.multi/tids.exp +++ b/gdb/testsuite/gdb.multi/tids.exp @@ -290,7 +290,7 @@ with_test_prefix "two inferiors" { # Try both the convenience variable and the literal number. foreach thr {"\$thr" "20" "1.20" "\$inf.1" "30.1" } { set expected [string_to_regexp $thr] - gdb_test "info threads $thr" "No threads match '${expected}'." + gdb_test "info threads $thr" "No threads matched\\." # "info threads" works like a filter. If there's any other # valid thread in the list, there's no error. info_threads "$thr 1.1" "1.1" @@ -412,7 +412,7 @@ with_test_prefix "two inferiors" { # Check that we do parse the inferior number and don't confuse it. gdb_test "info threads 3.1" \ - "No threads match '3.1'\." + "No threads matched\\." } if { [allow_python_tests] } { diff --git a/gdb/testsuite/gdb.threads/current-lwp-dead.exp b/gdb/testsuite/gdb.threads/current-lwp-dead.exp index 7aa7ab951b5..c8364df0b84 100644 --- a/gdb/testsuite/gdb.threads/current-lwp-dead.exp +++ b/gdb/testsuite/gdb.threads/current-lwp-dead.exp @@ -47,6 +47,6 @@ gdb_breakpoint $line gdb_continue_to_breakpoint "fn_return" ".*at-fn_return.*" # Confirm thread 2 is really gone. -gdb_test "info threads 2" "No threads match '2'\\." +gdb_test "info threads 2" "No threads matched\\." gdb_continue_to_end "" continue 1 diff --git a/gdb/testsuite/gdb.threads/thread-bp-deleted.exp b/gdb/testsuite/gdb.threads/thread-bp-deleted.exp index 2eadd380370..8cabb709c0c 100644 --- a/gdb/testsuite/gdb.threads/thread-bp-deleted.exp +++ b/gdb/testsuite/gdb.threads/thread-bp-deleted.exp @@ -147,7 +147,7 @@ if {$is_remote} { exp_continue } - -re "No threads match '99'\\.\r\n$gdb_prompt $" { + -re "No threads matched\\.\r\n$gdb_prompt $" { if {!$saw_thread_exited && !$saw_bp_deleted && $attempt_count > 0} { sleep 1 incr attempt_count -1 diff --git a/gdb/thread.c b/gdb/thread.c index 3375cfcee24..d84d326a8c3 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1285,8 +1285,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, if (requested_threads == NULL || *requested_threads == '\0') uiout->message (_("No threads.\n")); else - uiout->message (_("No threads match '%s'.\n"), - requested_threads); + uiout->message (_("No threads matched.\n")); return; } -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v4 2/3] gdb: update "info threads" output when no threads match the arguments 2025-05-05 16:19 ` [PATCH v4 2/3] gdb: update "info threads" output when no threads match the arguments Tankut Baris Aktemur @ 2025-05-05 17:19 ` Eli Zaretskii 0 siblings, 0 replies; 32+ messages in thread From: Eli Zaretskii @ 2025-05-05 17:19 UTC (permalink / raw) To: Tankut Baris Aktemur; +Cc: gdb-patches, guinevere, pedro > From: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> > Cc: guinevere@redhat.com, > eliz@gnu.org, > pedro@palves.net > Date: Mon, 5 May 2025 18:19:30 +0200 > > If "info threads" is provided with the thread ID argument but no such > threads matching the thread ID(s) are found, GDB prints > > No threads match '<ID...>'. > > Update this output to the more generalized > > No threads matched. > > The intention is that the next patch, and potentially future ones, > will extend the command with more filter/match arguments. We cannot > customize the output to each such argument. Hence, be more generic. > --- > gdb/NEWS | 7 +++++++ > gdb/testsuite/gdb.multi/tids.exp | 4 ++-- > gdb/testsuite/gdb.threads/current-lwp-dead.exp | 2 +- > gdb/testsuite/gdb.threads/thread-bp-deleted.exp | 2 +- > gdb/thread.c | 3 +-- > 5 files changed, 12 insertions(+), 6 deletions(-) Thanks, the NEWS part is okay, ^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v4 3/3] gdb: add '-stopped' and '-running' options to "info threads" 2025-05-05 16:19 ` [PATCH v4 0/3] Option to show stopped/running " Tankut Baris Aktemur 2025-05-05 16:19 ` [PATCH v4 1/3] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur 2025-05-05 16:19 ` [PATCH v4 2/3] gdb: update "info threads" output when no threads match the arguments Tankut Baris Aktemur @ 2025-05-05 16:19 ` Tankut Baris Aktemur 2025-05-05 17:21 ` Eli Zaretskii 2025-05-09 20:54 ` [PATCH v4 0/3] Option to show stopped/running threads only Pedro Alves 3 siblings, 1 reply; 32+ messages in thread From: Tankut Baris Aktemur @ 2025-05-05 16:19 UTC (permalink / raw) To: gdb-patches; +Cc: guinevere, eliz, pedro Add two options to "info threads": `-stopped` and `-running`. The purpose of these options is to filter the output of the command. The `-stopped` option means "print stopped threads only" and, similarly, `-running` means "print the running threads only". When both options are provided by the user, the indication is that the user wants the union. That is, the output contains both stopped and running threads. Suppose we have an application with 5 threads, 2 of which have hit a breakpoint. The "info threads" command in the non-stop mode gives: (gdb) info threads Id Target Id Frame * 1 Thread 0x7ffff7d99740 (running) 2 Thread 0x7ffff7d98700 something () at file.c:30 3 Thread 0x7ffff7597700 (running) 4 Thread 0x7ffff6d96700 something () at file.c:30 5 Thread 0x7ffff6595700 (running) (gdb) Using the "-stopped" flag, we get (gdb) info threads -stopped Id Target Id Frame 2 Thread 0x7ffff7d98700 something () at file.c:30 4 Thread 0x7ffff6d96700 something () at file.c:30 (gdb) Using the "-running" flag, we get (gdb) info threads -running Id Target Id Frame * 1 Thread 0x7ffff7d99740 (running) 3 Thread 0x7ffff7597700 (running) 5 Thread 0x7ffff6595700 (running) (gdb) Using both flags prints all: (gdb) info threads -stopped -running Id Target Id Frame * 1 Thread 0x7ffff7d99740 (running) 2 Thread 0x7ffff7d98700 something () at file.c:30 3 Thread 0x7ffff7597700 (running) 4 Thread 0x7ffff6d96700 something () at file.c:30 5 Thread 0x7ffff6595700 (running) (gdb) When combined with a thread ID, filtering applies to those threads that are matched by the ID. (gdb) info threads 3 Id Target Id Frame 3 Thread 0x7ffff7597700 (running) (gdb) info threads -stopped 3 No threads matched. (gdb) Regression-tested on X86_64 Linux. Reviewed-By: Guinevere Larsen <guinevere@redhat.com> --- gdb/NEWS | 11 +- gdb/doc/gdb.texinfo | 10 +- gdb/testsuite/gdb.base/options.exp | 16 ++- .../gdb.threads/info-threads-options.c | 77 ++++++++++ .../gdb.threads/info-threads-options.exp | 131 ++++++++++++++++++ gdb/thread.c | 41 ++++-- 6 files changed, 272 insertions(+), 14 deletions(-) create mode 100644 gdb/testsuite/gdb.threads/info-threads-options.c create mode 100644 gdb/testsuite/gdb.threads/info-threads-options.exp diff --git a/gdb/NEWS b/gdb/NEWS index 18a8b7475b4..70729b501cc 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -90,12 +90,17 @@ info sharedlibrary command are now for the full memory range allocated to the shared library. -info threads [-gid] [ID]... - If no threads match the given ID(s), GDB now prints +info threads [-gid] [-stopped] [-running] [ID]... + If no threads match the given ID(s) or filter options, GDB now prints No threads matched. - without printing the provided argument. + without printing the provided arguments. The newly added '-stopped' + option makes GDB list the stopped threads only. Similarly, + '-running' makes GDB list the running threads only. If both options + are given together, GDB lists the union; that is, both stopped and + running threads are listed. These new flags can be useful to get a + reduced list when there is a large number of threads. * GDB-internal Thread Local Storage (TLS) support diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index b9fc160a171..989cc36fbee 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -3807,7 +3807,7 @@ Thread 1 "main" received signal SIGINT, Interrupt. @table @code @anchor{info_threads} @kindex info threads -@item info threads @r{[}-gid@r{]} @r{[}@var{thread-id-list}@r{]} +@item info threads @r{[}-gid@r{]} @r{[}-stopped@r{]} @r{[}-running@r{]} @r{[}@var{thread-id-list}@r{]} Display information about one or more threads. With no arguments displays information about all threads. You can specify the list of @@ -3857,6 +3857,14 @@ If you're debugging multiple inferiors, @value{GDBN} displays thread IDs using the qualified @var{inferior-num}.@var{thread-num} format. Otherwise, only @var{thread-num} is shown. +If you specify the @samp{-stopped} option, @value{GDBN} filters the +output of the command to print the stopped threads only. Similarly, +if you specify the @samp{-running} option, @value{GDBN} filters the +output to print the running threads only. These options can be +helpful to reduce the output list if there is a large number of +threads. If you specify both options, @value{GDBN} prints the union; +both stopped and running threads are printed. + If you specify the @samp{-gid} option, @value{GDBN} displays a column indicating each thread's global thread ID: diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp index 7822e4a0baa..a0947e2f6f4 100644 --- a/gdb/testsuite/gdb.base/options.exp +++ b/gdb/testsuite/gdb.base/options.exp @@ -508,12 +508,26 @@ proc_with_prefix test-thread-apply {} { proc_with_prefix test-info-threads {} { test_gdb_complete_multiple "info threads " "" "" { "-gid" + "-running" + "-stopped" "ID" } + test_gdb_complete_multiple "info threads " "-" "" { + "-gid" + "-running" + "-stopped" + } + test_gdb_complete_unique \ - "info threads -" \ + "info threads -g" \ "info threads -gid" + test_gdb_complete_unique \ + "info threads -r" \ + "info threads -running" + test_gdb_complete_unique \ + "info threads -s" \ + "info threads -stopped" # "ID" isn't really something the user can type. test_gdb_complete_none "info threads I" diff --git a/gdb/testsuite/gdb.threads/info-threads-options.c b/gdb/testsuite/gdb.threads/info-threads-options.c new file mode 100644 index 00000000000..2c4cd854bb7 --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-options.c @@ -0,0 +1,77 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022-2025 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/>. */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <pthread.h> + +#define NUM 4 + +static pthread_barrier_t threads_started_barrier; + +static void +stop_here () +{ +} + +static void +spin () +{ + while (1) + usleep (1); +} + +static void * +work (void *arg) +{ + int id = *(int *) arg; + + pthread_barrier_wait (&threads_started_barrier); + + if (id % 2 == 0) + stop_here (); + else + spin (); + + pthread_exit (NULL); +} + +int +main () +{ + /* Ensure we stop if GDB crashes and DejaGNU fails to kill us. */ + alarm (10); + + pthread_t threads[NUM]; + int ids[NUM]; + + pthread_barrier_init (&threads_started_barrier, NULL, NUM + 1); + + for (int i = 0; i < NUM; i++) + { + ids[i] = i; + pthread_create (&threads[i], NULL, work, &ids[i]); + } + + /* Wait until all threads are seen running. */ + pthread_barrier_wait (&threads_started_barrier); + + stop_here (); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/info-threads-options.exp b/gdb/testsuite/gdb.threads/info-threads-options.exp new file mode 100644 index 00000000000..38e4e67f08b --- /dev/null +++ b/gdb/testsuite/gdb.threads/info-threads-options.exp @@ -0,0 +1,131 @@ +# Copyright (C) 2022-2025 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/>. + +# Test the filter flags of the "info threads" command. + +standard_testfile + +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable debug] != "" } { + return -1 +} + +save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop on\"" + clean_restart $binfile +} + +if ![runto_main] { + return -1 +} + +gdb_breakpoint "stop_here" +gdb_test_multiple "continue -a&" "" { + -re "Continuing.\r\n$gdb_prompt " { + pass $gdb_test_name + } +} + +set expected_hits 3 +set fill "\[^\r\n\]+" +set num_hits 0 +gdb_test_multiple "" "hit the breakpoint" -lbl { + -re "\r\nThread ${fill} hit Breakpoint ${decimal}," { + incr num_hits + if {$num_hits < $expected_hits} { + exp_continue + } + } +} +gdb_assert {$num_hits == $expected_hits} "expected threads hit the bp" + +# Count the number of running/stopped threads reported +# by the "info threads" command. We also capture thread ids +# for additional tests. +set running_tid "invalid" +set stopped_tid "invalid" + +set eol "(?=\r\n)" + +foreach_with_prefix flag {"" "-running" "-stopped" "-running -stopped"} { + set num_running 0 + set num_stopped 0 + gdb_test_multiple "info threads $flag" "info threads $flag" -lbl { + -re "Id${fill}Target Id${fill}Frame${fill}${eol}" { + exp_continue + } + -re "^\r\n. (${decimal})${fill}Thread ${fill}.running.${eol}" { + incr num_running + set running_tid $expect_out(1,string) + exp_continue + } + -re "^\r\n. (${decimal})${fill}Thread ${fill}stop_here ${fill}${eol}" { + incr num_stopped + set stopped_tid $expect_out(1,string) + exp_continue + } + -re "^\r\n$gdb_prompt $" { + pass $gdb_test_name + } + } + + if {$flag eq "-running"} { + gdb_assert {$num_running == 2} "num running" + gdb_assert {$num_stopped == 0} "num stopped" + } elseif {$flag eq "-stopped"} { + gdb_assert {$num_running == 0} "num running" + gdb_assert {$num_stopped == 3} "num stopped" + } else { + gdb_assert {$num_running == 2} "num running" + gdb_assert {$num_stopped == 3} "num stopped" + } +} + +verbose -log "running_tid=$running_tid, stopped_tid=$stopped_tid" + +# Test specifying thread ids. +gdb_test "info threads -running $stopped_tid" \ + "No threads matched\\." \ + "info thread -running for a stopped thread" +gdb_test "info threads -stopped $running_tid" \ + "No threads matched\\." \ + "info thread -stopped for a running thread" + +set ws "\[ \t\]+" +foreach tid "\"$running_tid\" \"$running_tid $stopped_tid\"" { + gdb_test "info threads -running $tid" \ + [multi_line \ + "${ws}Id${ws}Target Id${ws}Frame${ws}" \ + "${ws}${running_tid}${ws}Thread ${fill}.running."] \ + "info thread -running with [llength $tid] thread ids" +} + +foreach tid "\"$stopped_tid\" \"$stopped_tid $running_tid\"" { + gdb_test "info threads -stopped $tid" \ + [multi_line \ + "${ws}Id${ws}Target Id${ws}Frame${ws}" \ + "${ws}${stopped_tid}${ws}Thread ${fill} stop_here ${fill}"] \ + "info thread -stopped with [llength $tid] thread ids" +} + +gdb_test_multiple "info threads -stopped -running $stopped_tid $running_tid" \ + "filter flags and tids combined" { + -re -wrap ".*stop_here.*running.*" { + pass $gdb_test_name + } + -re -wrap ".*running.*stop_here.*" { + pass $gdb_test_name + } +} diff --git a/gdb/thread.c b/gdb/thread.c index d84d326a8c3..0228027fb92 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1044,6 +1044,10 @@ struct info_threads_opts { /* For "-gid". */ bool show_global_ids = false; + /* For "-running". */ + bool show_running_threads = false; + /* For "-stopped". */ + bool show_stopped_threads = false; }; static const gdb::option::option_def info_threads_option_defs[] = { @@ -1053,7 +1057,16 @@ static const gdb::option::option_def info_threads_option_defs[] = { [] (info_threads_opts *opts) { return &opts->show_global_ids; }, N_("Show global thread IDs."), }, - + gdb::option::flag_option_def<info_threads_opts> { + "running", + [] (info_threads_opts *opts) { return &opts->show_running_threads; }, + N_("Show running threads only."), + }, + gdb::option::flag_option_def<info_threads_opts> { + "stopped", + [] (info_threads_opts *opts) { return &opts->show_stopped_threads; }, + N_("Show stopped threads only."), + }, }; /* Helper for print_thread_info. Returns true if THR should be @@ -1095,7 +1108,17 @@ should_print_thread (const char *requested_threads, if (thr->state == THREAD_EXITED) return false; - return true; + bool is_stopped = (thr->state == THREAD_STOPPED); + if (opts.show_stopped_threads && is_stopped) + return true; + + bool is_running = (thr->state == THREAD_RUNNING); + if (opts.show_running_threads && is_running) + return true; + + /* If the user did not pass a filter flag, show the thread. */ + return (!opts.show_stopped_threads + && !opts.show_running_threads); } /* Return the string to display in "info threads"'s "Target Id" @@ -1254,13 +1277,15 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, list_emitter.emplace (uiout, "threads"); else { - int n_threads = 0; + int n_matching_threads = 0; /* The width of the "Target Id" column. Grown below to accommodate the largest entry. */ size_t target_id_col_width = 17; for (thread_info *tp : all_threads ()) { + any_thread = true; + /* In case REQUESTED_THREADS contains $_thread. */ if (current_thread != nullptr) switch_to_thread (current_thread); @@ -1277,12 +1302,12 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, = std::max (target_id_col_width, thread_target_id_str (tp).size ()); - ++n_threads; + ++n_matching_threads; } - if (n_threads == 0) + if (n_matching_threads == 0) { - if (requested_threads == NULL || *requested_threads == '\0') + if (!any_thread) uiout->message (_("No threads.\n")); else uiout->message (_("No threads matched.\n")); @@ -1290,7 +1315,7 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, } table_emitter.emplace (uiout, opts.show_global_ids ? 5 : 4, - n_threads, "threads"); + n_matching_threads, "threads"); uiout->table_header (1, ui_left, "current", ""); uiout->table_header (4, ui_left, "id-in-tg", "Id"); @@ -1305,8 +1330,6 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads, for (inferior *inf : all_inferiors ()) for (thread_info *tp : inf->threads ()) { - any_thread = true; - if (tp == current_thread && tp->state == THREAD_EXITED) current_exited = true; -- 2.34.1 Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928 ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v4 3/3] gdb: add '-stopped' and '-running' options to "info threads" 2025-05-05 16:19 ` [PATCH v4 3/3] gdb: add '-stopped' and '-running' options to "info threads" Tankut Baris Aktemur @ 2025-05-05 17:21 ` Eli Zaretskii 0 siblings, 0 replies; 32+ messages in thread From: Eli Zaretskii @ 2025-05-05 17:21 UTC (permalink / raw) To: Tankut Baris Aktemur; +Cc: gdb-patches, guinevere, pedro > From: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> > Cc: guinevere@redhat.com, > eliz@gnu.org, > pedro@palves.net > Date: Mon, 5 May 2025 18:19:31 +0200 > > Add two options to "info threads": `-stopped` and `-running`. > > The purpose of these options is to filter the output of the command. > The `-stopped` option means "print stopped threads only" and, > similarly, `-running` means "print the running threads only". When > both options are provided by the user, the indication is that the user > wants the union. That is, the output contains both stopped and > running threads. > > Suppose we have an application with 5 threads, 2 of which have hit a > breakpoint. The "info threads" command in the non-stop mode gives: > > (gdb) info threads > Id Target Id Frame > * 1 Thread 0x7ffff7d99740 (running) > 2 Thread 0x7ffff7d98700 something () at file.c:30 > 3 Thread 0x7ffff7597700 (running) > 4 Thread 0x7ffff6d96700 something () at file.c:30 > 5 Thread 0x7ffff6595700 (running) > (gdb) > > Using the "-stopped" flag, we get > > (gdb) info threads -stopped > Id Target Id Frame > 2 Thread 0x7ffff7d98700 something () at file.c:30 > 4 Thread 0x7ffff6d96700 something () at file.c:30 > (gdb) > > Using the "-running" flag, we get > > (gdb) info threads -running > Id Target Id Frame > * 1 Thread 0x7ffff7d99740 (running) > 3 Thread 0x7ffff7597700 (running) > 5 Thread 0x7ffff6595700 (running) > (gdb) > > Using both flags prints all: > > (gdb) info threads -stopped -running > Id Target Id Frame > * 1 Thread 0x7ffff7d99740 (running) > 2 Thread 0x7ffff7d98700 something () at file.c:30 > 3 Thread 0x7ffff7597700 (running) > 4 Thread 0x7ffff6d96700 something () at file.c:30 > 5 Thread 0x7ffff6595700 (running) > (gdb) > > When combined with a thread ID, filtering applies to those threads that > are matched by the ID. > > (gdb) info threads 3 > Id Target Id Frame > 3 Thread 0x7ffff7597700 (running) > (gdb) info threads -stopped 3 > No threads matched. > (gdb) > > Regression-tested on X86_64 Linux. > > Reviewed-By: Guinevere Larsen <guinevere@redhat.com> > --- > gdb/NEWS | 11 +- > gdb/doc/gdb.texinfo | 10 +- > gdb/testsuite/gdb.base/options.exp | 16 ++- > .../gdb.threads/info-threads-options.c | 77 ++++++++++ > .../gdb.threads/info-threads-options.exp | 131 ++++++++++++++++++ > gdb/thread.c | 41 ++++-- > 6 files changed, 272 insertions(+), 14 deletions(-) > create mode 100644 gdb/testsuite/gdb.threads/info-threads-options.c > create mode 100644 gdb/testsuite/gdb.threads/info-threads-options.exp Thanks. The documentation parts are okay, but my suggestion is to drop the part that talks about "union": it adds nothing useful to the description. IOW, this: If you specify both options, @value{GDBN} prints both stopped and running threads. is enough and tells the whole story. Reviewed-By: Eli Zaretskii <eliz@gnu.org> ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v4 0/3] Option to show stopped/running threads only 2025-05-05 16:19 ` [PATCH v4 0/3] Option to show stopped/running " Tankut Baris Aktemur ` (2 preceding siblings ...) 2025-05-05 16:19 ` [PATCH v4 3/3] gdb: add '-stopped' and '-running' options to "info threads" Tankut Baris Aktemur @ 2025-05-09 20:54 ` Pedro Alves 3 siblings, 0 replies; 32+ messages in thread From: Pedro Alves @ 2025-05-09 20:54 UTC (permalink / raw) To: Tankut Baris Aktemur, gdb-patches; +Cc: guinevere, eliz On 2025-05-05 17:19, Tankut Baris Aktemur wrote: > Hi, > > This is v4 of a series that introduces options to filter the output of > "info threads". V3 is available at > > https://inbox.sourceware.org/gdb-patches/cover.1743772891.git.tankut.baris.aktemur@intel.com/ > > In this revision I address Pedro's comments he gave on V3. > > Eli had previously approved the documentation changes, but I needed to > update the docs in this revision. Hence, I removed his "Reviewed-By" > and would like to request a doc review again. Thank you! For the series: Approved-by: Pedro Alves <pedro@palves.net> Pedro Alves > > Best regards, > Baris > > Tankut Baris Aktemur (3): > gdb: pass info_threads_opts to print_thread_info_1 > gdb: update "info threads" output when no threads match the arguments > gdb: add '-stopped' and '-running' options to "info threads" > > gdb/NEWS | 12 ++ > gdb/doc/gdb.texinfo | 10 +- > gdb/testsuite/gdb.base/options.exp | 16 ++- > gdb/testsuite/gdb.multi/tids.exp | 4 +- > .../gdb.threads/current-lwp-dead.exp | 2 +- > .../gdb.threads/info-threads-options.c | 77 ++++++++++ > .../gdb.threads/info-threads-options.exp | 131 ++++++++++++++++++ > .../gdb.threads/thread-bp-deleted.exp | 2 +- > gdb/thread.c | 122 +++++++++------- > 9 files changed, 321 insertions(+), 55 deletions(-) > create mode 100644 gdb/testsuite/gdb.threads/info-threads-options.c > create mode 100644 gdb/testsuite/gdb.threads/info-threads-options.exp > ^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2025-05-09 20:55 UTC | newest] Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2023-04-05 9:19 [PATCH 0/3] Option to show stopped threads only Tankut Baris Aktemur via Gdb-patches 2023-04-05 9:20 ` [PATCH 1/3] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur via Gdb-patches 2023-04-05 9:20 ` [PATCH 2/3] gdb, doc: add the missing '-gid' option to 'info threads' Tankut Baris Aktemur via Gdb-patches 2023-04-05 9:56 ` Eli Zaretskii via Gdb-patches 2023-04-05 10:12 ` Aktemur, Tankut Baris via Gdb-patches 2023-04-05 9:20 ` [PATCH 3/3] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur via Gdb-patches 2023-04-05 10:00 ` Eli Zaretskii via Gdb-patches 2023-04-05 10:19 ` Aktemur, Tankut Baris via Gdb-patches 2023-04-05 10:50 ` Eli Zaretskii via Gdb-patches 2023-04-05 11:31 ` Aktemur, Tankut Baris via Gdb-patches 2023-04-05 11:56 ` Eli Zaretskii via Gdb-patches 2025-04-24 14:50 ` Pedro Alves 2025-03-18 18:04 ` [PATCH v2 0/2] Option to show stopped threads only Tankut Baris Aktemur 2025-03-18 18:05 ` [PATCH v2 1/2] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur 2025-03-18 18:05 ` [PATCH v2 2/2] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur 2025-03-28 16:38 ` [PATCH v2 0/2] Option to show stopped threads only Guinevere Larsen 2025-04-04 13:39 ` Aktemur, Tankut Baris 2025-04-04 13:36 ` [PATCH v3 " Tankut Baris Aktemur 2025-04-04 13:36 ` [PATCH v3 1/2] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur 2025-04-24 18:09 ` Pedro Alves 2025-04-04 13:36 ` [PATCH v3 2/2] gdb: add a '-stopped' option to "info threads" Tankut Baris Aktemur 2025-04-24 19:23 ` Pedro Alves 2025-05-05 16:17 ` Aktemur, Tankut Baris 2025-04-23 8:00 ` [PATCH v3 0/2] Option to show stopped threads only Aktemur, Tankut Baris 2025-04-24 17:53 ` Pedro Alves 2025-05-05 16:19 ` [PATCH v4 0/3] Option to show stopped/running " Tankut Baris Aktemur 2025-05-05 16:19 ` [PATCH v4 1/3] gdb: pass info_threads_opts to print_thread_info_1 Tankut Baris Aktemur 2025-05-05 16:19 ` [PATCH v4 2/3] gdb: update "info threads" output when no threads match the arguments Tankut Baris Aktemur 2025-05-05 17:19 ` Eli Zaretskii 2025-05-05 16:19 ` [PATCH v4 3/3] gdb: add '-stopped' and '-running' options to "info threads" Tankut Baris Aktemur 2025-05-05 17:21 ` Eli Zaretskii 2025-05-09 20:54 ` [PATCH v4 0/3] Option to show stopped/running threads only Pedro Alves
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox