aboutsummaryrefslogtreecommitdiff
path: root/gdb/thread.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2016-01-13 10:56:07 +0000
committerPedro Alves <palves@redhat.com>2016-01-13 10:59:43 +0000
commit5d5658a1d3c3eb2a09c03f2f0662a1c01963c869 (patch)
treebe9eeeebd3d3e042d5f2865258ee41f731273f33 /gdb/thread.c
parent43792cf0de3a49fb871d432343672bdf16270e99 (diff)
downloadgdb-5d5658a1d3c3eb2a09c03f2f0662a1c01963c869.zip
gdb-5d5658a1d3c3eb2a09c03f2f0662a1c01963c869.tar.gz
gdb-5d5658a1d3c3eb2a09c03f2f0662a1c01963c869.tar.bz2
Per-inferior/Inferior-qualified thread IDs
This commit changes GDB to track thread numbers per-inferior. Then, if you're debugging multiple inferiors, GDB displays "inferior-num.thread-num" instead of just "thread-num" whenever it needs to display a thread: (gdb) info inferiors Num Description Executable 1 process 6022 /home/pedro/gdb/tests/threads * 2 process 6037 /home/pedro/gdb/tests/threads (gdb) info threads Id Target Id Frame 1.1 Thread 0x7ffff7fc2740 (LWP 6022) "threads" (running) 1.2 Thread 0x7ffff77c0700 (LWP 6028) "threads" (running) 1.3 Thread 0x7ffff7fc2740 (LWP 6032) "threads" (running) 2.1 Thread 0x7ffff7fc1700 (LWP 6037) "threads" (running) 2.2 Thread 0x7ffff77c0700 (LWP 6038) "threads" (running) * 2.3 Thread 0x7ffff7fc2740 (LWP 6039) "threads" (running) (gdb) ... (gdb) thread 1.1 [Switching to thread 1.1 (Thread 0x7ffff7fc2740 (LWP 8155))] (gdb) ... etc. You can still use "thread NUM", in which case GDB infers you're referring to thread NUM of the current inferior. The $_thread convenience var and Python's InferiorThread.num attribute are remapped to the new per-inferior thread number. It's a backward compatibility break, but since it only matters when debugging multiple inferiors, I think it's worth doing. Because MI thread IDs need to be a single integer, we keep giving threads a global identifier, _in addition_ to the per-inferior number, and make MI always refer to the global thread IDs. IOW, nothing changes from a MI frontend's perspective. Similarly, since Python's Breakpoint.thread and Guile's breakpoint-thread/set-breakpoint-thread breakpoint methods need to work with integers, those are adjusted to work with global thread IDs too. Follow up patches will provide convenient means to access threads' global IDs. To avoid potencially confusing users (which also avoids updating much of the testsuite), if there's only one inferior and its ID is "1", IOW, the user hasn't done anything multi-process/inferior related, then the "INF." part of thread IDs is not shown. E.g,.: (gdb) info inferiors Num Description Executable * 1 process 15275 /home/pedro/gdb/tests/threads (gdb) info threads Id Target Id Frame * 1 Thread 0x7ffff7fc1740 (LWP 15275) "threads" main () at threads.c:40 (gdb) add-inferior Added inferior 2 (gdb) info threads Id Target Id Frame * 1.1 Thread 0x7ffff7fc1740 (LWP 15275) "threads" main () at threads.c:40 (gdb) No regressions on x86_64 Fedora 20. gdb/ChangeLog: 2016-01-13 Pedro Alves <palves@redhat.com> * NEWS: Mention that thread IDs are now per inferior and global thread IDs. * Makefile.in (SFILES): Add tid-parse.c. (COMMON_OBS): Add tid-parse.o. (HFILES_NO_SRCDIR): Add tid-parse.h. * ada-tasks.c: Adjust to use ptid_to_global_thread_id. * breakpoint.c (insert_breakpoint_locations) (remove_threaded_breakpoints, bpstat_check_breakpoint_conditions) (print_one_breakpoint_location, set_longjmp_breakpoint) (check_longjmp_breakpoint_for_call_dummy) (set_momentary_breakpoint): Adjust to use global IDs. (find_condition_and_thread, watch_command_1): Use parse_thread_id. (until_break_command, longjmp_bkpt_dtor) (breakpoint_re_set_thread, insert_single_step_breakpoint): Adjust to use global IDs. * dummy-frame.c (pop_dummy_frame_bpt): Adjust to use ptid_to_global_thread_id. * elfread.c (elf_gnu_ifunc_resolver_stop): Likewise. * gdbthread.h (struct thread_info): Rename field 'num' to 'global_num. Add new fields 'per_inf_num' and 'inf'. (thread_id_to_pid): Rename thread_id_to_pid to global_thread_id_to_ptid. (pid_to_thread_id): Rename to ... (ptid_to_global_thread_id): ... this. (valid_thread_id): Rename to ... (valid_global_thread_id): ... this. (find_thread_id): Rename to ... (find_thread_global_id): ... this. (ALL_THREADS, ALL_THREADS_BY_INFERIOR): Declare. (print_thread_info): Add comment. * tid-parse.h: New file. * tid-parse.c: New file. * infcmd.c (step_command_fsm_prepare) (step_command_fsm_should_stop): Adjust to use the global thread ID. (until_next_command, until_next_command) (finish_command_fsm_should_stop): Adjust to use the global thread ID. (attach_post_wait): Adjust to check the inferior number too. * inferior.h (struct inferior) <highest_thread_num>: New field. * infrun.c (handle_signal_stop) (insert_exception_resume_breakpoint) (insert_exception_resume_from_probe): Adjust to use the global thread ID. * record-btrace.c (record_btrace_open): Use global thread IDs. * remote.c (process_initial_stop_replies): Also consider the inferior number. * target.c (target_pre_inferior): Clear the inferior's highest thread num. * thread.c (clear_thread_inferior_resources): Adjust to use the global thread ID. (new_thread): New inferior parameter. Adjust to use it. Set both the thread's global ID and the thread's per-inferior ID. (add_thread_silent): Adjust. (find_thread_global_id): New. (find_thread_id): Make static. Adjust to rename. (valid_thread_id): Rename to ... (valid_global_thread_id): ... this. (pid_to_thread_id): Rename to ... (ptid_to_global_thread_id): ... this. (thread_id_to_pid): Rename to ... (global_thread_id_to_ptid): ... this. Adjust. (first_thread_of_process): Adjust. (do_captured_list_thread_ids): Adjust to use global thread IDs. (should_print_thread): New function. (print_thread_info): Rename to ... (print_thread_info_1): ... this, and add new show_global_ids parameter. Handle it. Iterate over inferiors. (print_thread_info): Reimplement as wrapper around print_thread_info_1. (show_inferior_qualified_tids): New function. (print_thread_id): Use it. (tp_array_compar): Compare inferior numbers too. (thread_apply_command): Use tid_range_parser. (do_captured_thread_select): Use parse_thread_id. (thread_id_make_value): Adjust. (_initialize_thread): Adjust "info threads" help string. * varobj.c (struct varobj_root): Update comment. (varobj_create): Adjust to use global thread IDs. (value_of_root_1): Adjust to use global_thread_id_to_ptid. * windows-tdep.c (display_tib): No longer accept an argument. * cli/cli-utils.c (get_number_trailer): Make extern. * cli/cli-utils.h (get_number_trailer): Declare. (get_number_const): Adjust documentation. * mi/mi-cmd-var.c (mi_cmd_var_update_iter): Adjust to use global thread IDs. * mi/mi-interp.c (mi_new_thread, mi_thread_exit) (mi_on_normal_stop, mi_output_running_pid, mi_on_resume): * mi/mi-main.c (mi_execute_command, mi_cmd_execute): Likewise. * guile/scm-breakpoint.c (gdbscm_set_breakpoint_thread_x): Likewise. * python/py-breakpoint.c (bppy_set_thread): Likewise. * python/py-finishbreakpoint.c (bpfinishpy_init): Likewise. * python/py-infthread.c (thpy_get_num): Add comment and return the per-inferior thread ID. (thread_object_getset): Update comment of "num". gdb/testsuite/ChangeLog: 2016-01-07 Pedro Alves <palves@redhat.com> * gdb.base/break.exp: Adjust to output changes. * gdb.base/hbreak2.exp: Likewise. * gdb.base/sepdebug.exp: Likewise. * gdb.base/watch_thread_num.exp: Likewise. * gdb.linespec/keywords.exp: Likewise. * gdb.multi/info-threads.exp: Likewise. * gdb.threads/thread-find.exp: Likewise. * gdb.multi/tids.c: New file. * gdb.multi/tids.exp: New file. gdb/doc/ChangeLog: 2016-01-07 Pedro Alves <palves@redhat.com> * gdb.texinfo (Threads): Document per-inferior thread IDs, qualified thread IDs, global thread IDs and thread ID lists. (Set Watchpoints, Thread-Specific Breakpoints): Adjust to refer to thread IDs. (Convenience Vars): Document the $_thread convenience variable. (Ada Tasks): Adjust to refer to thread IDs. (GDB/MI Async Records, GDB/MI Thread Commands, GDB/MI Ada Tasking Commands, GDB/MI Variable Objects): Update to mention global thread IDs. * guile.texi (Breakpoints In Guile) <breakpoint-thread/set-breakpoint-thread breakpoint>: Mention global thread IDs instead of thread IDs. * python.texi (Threads In Python): Adjust documentation of InferiorThread.num. (Breakpoint.thread): Mention global thread IDs instead of thread IDs.
Diffstat (limited to 'gdb/thread.c')
-rw-r--r--gdb/thread.c340
1 files changed, 222 insertions, 118 deletions
diff --git a/gdb/thread.c b/gdb/thread.c
index 0ad26fc..dd8f7da 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -43,6 +43,7 @@
#include "gdb_regex.h"
#include "cli/cli-utils.h"
#include "thread-fsm.h"
+#include "tid-parse.h"
/* Definition of struct thread_info exported to gdbthread.h. */
@@ -182,7 +183,7 @@ clear_thread_inferior_resources (struct thread_info *tp)
delete_at_next_stop (&tp->control.exception_resume_breakpoint);
delete_at_next_stop (&tp->control.single_step_breakpoints);
- delete_longjmp_breakpoint_at_next_stop (tp->num);
+ delete_longjmp_breakpoint_at_next_stop (tp->global_num);
bpstat_clear (&tp->control.stop_bpstat);
@@ -226,16 +227,22 @@ init_thread_list (void)
threads_executing = 0;
}
-/* Allocate a new thread with target id PTID and add it to the thread
- list. */
+/* Allocate a new thread of inferior INF with target id PTID and add
+ it to the thread list. */
static struct thread_info *
-new_thread (ptid_t ptid)
+new_thread (struct inferior *inf, ptid_t ptid)
{
- struct thread_info *tp = XCNEW (struct thread_info);
+ struct thread_info *tp;
+
+ gdb_assert (inf != NULL);
+
+ tp = XCNEW (struct thread_info);
tp->ptid = ptid;
- tp->num = ++highest_thread_num;
+ tp->global_num = ++highest_thread_num;
+ tp->inf = inf;
+ tp->per_inf_num = ++inf->highest_thread_num;
if (thread_list == NULL)
thread_list = tp;
@@ -260,6 +267,8 @@ struct thread_info *
add_thread_silent (ptid_t ptid)
{
struct thread_info *tp;
+ struct inferior *inf = find_inferior_ptid (ptid);
+ gdb_assert (inf != NULL);
tp = find_thread_ptid (ptid);
if (tp)
@@ -277,7 +286,7 @@ add_thread_silent (ptid_t ptid)
if (ptid_equal (inferior_ptid, ptid))
{
- tp = new_thread (null_ptid);
+ tp = new_thread (inf, null_ptid);
/* Make switch_to_thread not read from the thread. */
tp->state = THREAD_EXITED;
@@ -301,7 +310,7 @@ add_thread_silent (ptid_t ptid)
delete_thread (ptid);
}
- tp = new_thread (ptid);
+ tp = new_thread (inf, ptid);
observer_notify_new_thread (tp);
return tp;
@@ -481,12 +490,24 @@ delete_thread_silent (ptid_t ptid)
}
struct thread_info *
-find_thread_id (int num)
+find_thread_global_id (int global_id)
{
struct thread_info *tp;
for (tp = thread_list; tp; tp = tp->next)
- if (tp->num == num)
+ if (tp->global_num == global_id)
+ return tp;
+
+ return NULL;
+}
+
+static struct thread_info *
+find_thread_id (struct inferior *inf, int thr_num)
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->inf == inf && tp->per_inf_num == thr_num)
return tp;
return NULL;
@@ -548,38 +569,38 @@ thread_count (void)
}
int
-valid_thread_id (int num)
+valid_global_thread_id (int global_id)
{
struct thread_info *tp;
for (tp = thread_list; tp; tp = tp->next)
- if (tp->num == num)
+ if (tp->global_num == global_id)
return 1;
return 0;
}
int
-pid_to_thread_id (ptid_t ptid)
+ptid_to_global_thread_id (ptid_t ptid)
{
struct thread_info *tp;
for (tp = thread_list; tp; tp = tp->next)
if (ptid_equal (tp->ptid, ptid))
- return tp->num;
+ return tp->global_num;
return 0;
}
ptid_t
-thread_id_to_pid (int num)
+global_thread_id_to_ptid (int global_id)
{
- struct thread_info *thread = find_thread_id (num);
+ struct thread_info *thread = find_thread_global_id (global_id);
if (thread)
return thread->ptid;
else
- return pid_to_ptid (-1);
+ return minus_one_ptid;
}
int
@@ -604,7 +625,7 @@ first_thread_of_process (int pid)
for (tp = thread_list; tp; tp = tp->next)
if (pid == -1 || ptid_get_pid (tp->ptid) == pid)
- if (ret == NULL || tp->num < ret->num)
+ if (ret == NULL || tp->global_num < ret->global_num)
ret = tp;
return ret;
@@ -688,10 +709,10 @@ do_captured_list_thread_ids (struct ui_out *uiout, void *arg)
continue;
if (ptid_equal (tp->ptid, inferior_ptid))
- current_thread = tp->num;
+ current_thread = tp->global_num;
num++;
- ui_out_field_int (uiout, "thread-id", tp->num);
+ ui_out_field_int (uiout, "thread-id", tp->global_num);
}
do_cleanups (cleanup_chain);
@@ -1127,25 +1148,62 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread)
&& pc < thread->control.step_range_end);
}
-/* Prints the list of threads and their details on UIOUT.
- This is a version of 'info_threads_command' suitable for
- use from MI.
- If REQUESTED_THREAD is not -1, it's the GDB id of the thread
- that should be printed. Otherwise, all threads are
- printed.
- If PID is not -1, only print threads from the process PID.
- Otherwise, threads from all attached PIDs are printed.
- If both REQUESTED_THREAD and PID are not -1, then the thread
- is printed if it belongs to the specified process. Otherwise,
- an error is raised. */
-void
-print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
+/* 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
+ is true if REQUESTED_THREADS is list of global IDs, false if a list
+ of per-inferior thread ids. If PID is not -1, only print THR if it
+ 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. */
+
+static int
+should_print_thread (const char *requested_threads, int default_inf_num,
+ int global_ids, int pid, struct thread_info *thr)
+{
+ if (requested_threads != NULL && *requested_threads != '\0')
+ {
+ int in_list;
+
+ if (global_ids)
+ in_list = number_is_in_list (requested_threads, thr->global_num);
+ else
+ in_list = tid_is_in_list (requested_threads, default_inf_num,
+ thr->inf->num, thr->per_inf_num);
+ if (!in_list)
+ return 0;
+ }
+
+ if (pid != -1 && ptid_get_pid (thr->ptid) != pid)
+ {
+ if (requested_threads != NULL && *requested_threads != '\0')
+ error (_("Requested thread not found in requested process"));
+ return 0;
+ }
+
+ if (thr->state == THREAD_EXITED)
+ return 0;
+
+ return 1;
+}
+
+/* Like print_thread_info, but in addition, GLOBAL_IDS indicates
+ whether REQUESTED_THREADS is a list of global or per-inferior
+ thread ids. */
+
+static void
+print_thread_info_1 (struct ui_out *uiout, char *requested_threads,
+ int global_ids, int pid,
+ int show_global_ids)
{
struct thread_info *tp;
ptid_t current_ptid;
struct cleanup *old_chain;
const char *extra_info, *name, *target_id;
int current_thread = -1;
+ struct inferior *inf;
+ int default_inf_num = current_inferior ()->num;
update_thread_list ();
current_ptid = inferior_ptid;
@@ -1164,13 +1222,8 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
for (tp = thread_list; tp; tp = tp->next)
{
- if (!number_is_in_list (requested_threads, tp->num))
- continue;
-
- if (pid != -1 && ptid_get_pid (tp->ptid) != pid)
- continue;
-
- if (tp->state == THREAD_EXITED)
+ if (!should_print_thread (requested_threads, default_inf_num,
+ global_ids, pid, tp))
continue;
++n_threads;
@@ -1187,34 +1240,32 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
return;
}
- make_cleanup_ui_out_table_begin_end (uiout, 4, n_threads, "threads");
+ if (show_global_ids || ui_out_is_mi_like_p (uiout))
+ make_cleanup_ui_out_table_begin_end (uiout, 5, n_threads, "threads");
+ else
+ make_cleanup_ui_out_table_begin_end (uiout, 4, n_threads, "threads");
ui_out_table_header (uiout, 1, ui_left, "current", "");
- ui_out_table_header (uiout, 4, ui_left, "id", "Id");
+
+ if (!ui_out_is_mi_like_p (uiout))
+ ui_out_table_header (uiout, 4, ui_left, "id-in-tg", "Id");
+ if (show_global_ids || ui_out_is_mi_like_p (uiout))
+ ui_out_table_header (uiout, 4, ui_left, "id", "GId");
ui_out_table_header (uiout, 17, ui_left, "target-id", "Target Id");
ui_out_table_header (uiout, 1, ui_left, "frame", "Frame");
ui_out_table_body (uiout);
}
- for (tp = thread_list; tp; tp = tp->next)
+ ALL_THREADS_BY_INFERIOR (inf, tp)
{
struct cleanup *chain2;
int core;
- if (!number_is_in_list (requested_threads, tp->num))
- continue;
-
- if (pid != -1 && ptid_get_pid (tp->ptid) != pid)
- {
- if (requested_threads != NULL && *requested_threads != '\0')
- error (_("Requested thread not found in requested process"));
- continue;
- }
-
if (ptid_equal (tp->ptid, current_ptid))
- current_thread = tp->num;
+ current_thread = tp->global_num;
- if (tp->state == THREAD_EXITED)
+ if (!should_print_thread (requested_threads, default_inf_num,
+ global_ids, pid, tp))
continue;
chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
@@ -1235,7 +1286,11 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
ui_out_field_skip (uiout, "current");
}
- ui_out_field_int (uiout, "id", tp->num);
+ if (!ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "id-in-tg", print_thread_id (tp));
+
+ if (show_global_ids || ui_out_is_mi_like_p (uiout))
+ ui_out_field_int (uiout, "id", tp->global_num);
/* For the CLI, we stuff everything into the target-id field.
This is a gross hack to make the output come out looking
@@ -1311,27 +1366,35 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
if (pid == -1 && requested_threads == NULL)
{
- gdb_assert (current_thread != -1
- || !thread_list
- || ptid_equal (inferior_ptid, null_ptid));
- if (current_thread != -1 && ui_out_is_mi_like_p (uiout))
- ui_out_field_int (uiout, "current-thread-id", current_thread);
+ if (ui_out_is_mi_like_p (uiout)
+ && !ptid_equal (inferior_ptid, null_ptid))
+ {
+ int num = ptid_to_global_thread_id (inferior_ptid);
+
+ gdb_assert (num != 0);
+ ui_out_field_int (uiout, "current-thread-id", num);
+ }
- if (current_thread != -1 && is_exited (current_ptid))
+ if (!ptid_equal (inferior_ptid, null_ptid) && is_exited (inferior_ptid))
ui_out_message (uiout, 0, "\n\
-The current thread <Thread ID %d> has terminated. See `help thread'.\n",
- current_thread);
- else if (thread_list
- && current_thread == -1
- && ptid_equal (current_ptid, null_ptid))
+The current thread <Thread ID %s> has terminated. See `help thread'.\n",
+ print_thread_id (inferior_thread ()));
+ else if (thread_list != NULL
+ && ptid_equal (inferior_ptid, null_ptid))
ui_out_message (uiout, 0, "\n\
No selected thread. See `help thread'.\n");
}
}
-/* Print information about currently known threads
+/* See gdbthread.h. */
- Optional ARG is a thread id, or list of thread ids.
+void
+print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
+{
+ print_thread_info_1 (uiout, requested_threads, 1, pid, 0);
+}
+
+/* Implementation of the "info threads" command.
Note: this has the drawback that it _really_ switches
threads, which frees the frame cache. A no-side
@@ -1340,7 +1403,7 @@ No selected thread. See `help thread'.\n");
static void
info_threads_command (char *arg, int from_tty)
{
- print_thread_info (current_uiout, arg, -1);
+ print_thread_info_1 (current_uiout, arg, 0, -1, 0);
}
/* See gdbthread.h. */
@@ -1612,12 +1675,23 @@ make_cleanup_restore_current_thread (void)
/* See gdbthread.h. */
+int
+show_inferior_qualified_tids (void)
+{
+ return (inferior_list->next != NULL || inferior_list->num != 1);
+}
+
+/* See gdbthread.h. */
+
const char *
print_thread_id (struct thread_info *thr)
{
char *s = get_print_cell ();
- xsnprintf (s, PRINT_CELL_SIZE, "%d", thr->num);
+ if (show_inferior_qualified_tids ())
+ xsnprintf (s, PRINT_CELL_SIZE, "%d.%d", thr->inf->num, thr->per_inf_num);
+ else
+ xsnprintf (s, PRINT_CELL_SIZE, "%d", thr->per_inf_num);
return s;
}
@@ -1626,18 +1700,24 @@ print_thread_id (struct thread_info *thr)
static int tp_array_compar_ascending;
-/* Sort an array for struct thread_info pointers by their NUM, order is
- determined by TP_ARRAY_COMPAR_ASCENDING. */
+/* Sort an array for struct thread_info pointers by thread ID (first
+ by inferior number, and then by per-inferior thread number). The
+ order is determined by TP_ARRAY_COMPAR_ASCENDING. */
static int
tp_array_compar (const void *ap_voidp, const void *bp_voidp)
{
- const struct thread_info *const *ap
- = (const struct thread_info * const*) ap_voidp;
- const struct thread_info *const *bp
- = (const struct thread_info * const*) bp_voidp;
+ const struct thread_info *a = *(const struct thread_info * const *) ap_voidp;
+ const struct thread_info *b = *(const struct thread_info * const *) bp_voidp;
+
+ if (a->inf->num != b->inf->num)
+ {
+ return ((a->inf->num > b->inf->num) - (a->inf->num < b->inf->num)
+ * (tp_array_compar_ascending ? +1 : -1));
+ }
- return ((((*ap)->num > (*bp)->num) - ((*ap)->num < (*bp)->num))
+ return (((a->per_inf_num > b->per_inf_num)
+ - (a->per_inf_num < b->per_inf_num))
* (tp_array_compar_ascending ? +1 : -1));
}
@@ -1732,7 +1812,7 @@ thread_apply_command (char *tidlist, int from_tty)
char *cmd;
struct cleanup *old_chain;
char *saved_cmd;
- struct get_number_or_range_state state;
+ struct tid_range_parser parser;
if (tidlist == NULL || *tidlist == '\000')
error (_("Please specify a thread ID list"));
@@ -1747,33 +1827,44 @@ thread_apply_command (char *tidlist, int from_tty)
saved_cmd = xstrdup (cmd);
old_chain = make_cleanup (xfree, saved_cmd);
- init_number_or_range (&state, tidlist);
- while (!state.finished && state.string < cmd)
- {
- struct thread_info *tp;
- int start;
-
- start = get_number_or_range (&state);
+ make_cleanup_restore_current_thread ();
- make_cleanup_restore_current_thread ();
+ tid_range_parser_init (&parser, tidlist, current_inferior ()->num);
+ while (!tid_range_parser_finished (&parser)
+ && tid_range_parser_string (&parser) < cmd)
+ {
+ struct thread_info *tp = NULL;
+ struct inferior *inf;
+ int inf_num, thr_num;
- tp = find_thread_id (start);
+ tid_range_parser_get_tid (&parser, &inf_num, &thr_num);
+ inf = find_inferior_id (inf_num);
+ if (inf != NULL)
+ tp = find_thread_id (inf, thr_num);
+ if (tp == NULL)
+ {
+ if (show_inferior_qualified_tids ()
+ || tid_range_parser_qualified (&parser))
+ warning (_("Unknown thread %d.%d"), inf_num, thr_num);
+ else
+ warning (_("Unknown thread %d"), thr_num);
+ continue;
+ }
- if (!tp)
- warning (_("Unknown thread %d."), start);
- else if (!thread_alive (tp))
- warning (_("Thread %d has terminated."), start);
- else
+ if (!thread_alive (tp))
{
- switch_to_thread (tp->ptid);
+ warning (_("Thread %s has terminated."), print_thread_id (tp));
+ continue;
+ }
- printf_filtered (_("\nThread %d (%s):\n"), tp->num,
- target_pid_to_str (inferior_ptid));
- execute_command (cmd, from_tty);
+ switch_to_thread (tp->ptid);
- /* Restore exact command used previously. */
- strcpy (cmd, saved_cmd);
- }
+ printf_filtered (_("\nThread %s (%s):\n"), print_thread_id (tp),
+ target_pid_to_str (inferior_ptid));
+ execute_command (cmd, from_tty);
+
+ /* Restore exact command used previously. */
+ strcpy (cmd, saved_cmd);
}
do_cleanups (old_chain);
@@ -1894,30 +1985,42 @@ show_print_thread_events (struct ui_file *file, int from_tty,
}
static int
-do_captured_thread_select (struct ui_out *uiout, void *tidstr)
+do_captured_thread_select (struct ui_out *uiout, void *tidstr_v)
{
- int num;
+ const char *tidstr = tidstr_v;
struct thread_info *tp;
- num = value_as_long (parse_and_eval ((const char *) tidstr));
-
- tp = find_thread_id (num);
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ int num = value_as_long (parse_and_eval (tidstr));
- if (!tp)
- error (_("Thread ID %d not known."), num);
+ tp = find_thread_global_id (num);
+ if (tp == NULL)
+ error (_("Thread ID %d not known."), num);
+ }
+ else
+ {
+ tp = parse_thread_id (tidstr, NULL);
+ gdb_assert (tp != NULL);
+ }
if (!thread_alive (tp))
- error (_("Thread ID %d has terminated."), num);
+ error (_("Thread ID %s has terminated."), tidstr);
switch_to_thread (tp->ptid);
annotate_thread_changed ();
- ui_out_text (uiout, "[Switching to thread ");
- ui_out_field_string (uiout, "new-thread-id", print_thread_id (tp));
- ui_out_text (uiout, " (");
- ui_out_text (uiout, target_pid_to_str (inferior_ptid));
- ui_out_text (uiout, ")]");
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_int (uiout, "new-thread-id", inferior_thread ()->global_num);
+ else
+ {
+ ui_out_text (uiout, "[Switching to thread ");
+ ui_out_field_string (uiout, "new-thread-id", print_thread_id (tp));
+ ui_out_text (uiout, " (");
+ ui_out_text (uiout, target_pid_to_str (inferior_ptid));
+ ui_out_text (uiout, ")]");
+ }
/* Note that we can't reach this with an exited thread, due to the
thread_alive check above. */
@@ -1971,8 +2074,9 @@ update_thread_list (void)
update_threads_executing ();
}
-/* Return a new value for the selected thread's id. Return a value of 0 if
- no thread is selected, or no threads exist. */
+/* Return a new value for the selected thread's per-inferior thread
+ number. Return a value of 0 if no thread is selected, or no
+ threads exist. */
static struct value *
thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
@@ -1981,7 +2085,7 @@ thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
struct thread_info *tp = find_thread_ptid (inferior_ptid);
return value_from_longest (builtin_type (gdbarch)->builtin_int,
- (tp ? tp->num : 0));
+ (tp ? tp->per_inf_num : 0));
}
/* Commands with a prefix of `thread'. */
@@ -2004,8 +2108,8 @@ _initialize_thread (void)
add_info ("threads", info_threads_command,
_("Display currently known threads.\n\
Usage: info threads [ID]...\n\
-Optional arguments are thread IDs with spaces between.\n\
-If no arguments, all threads are displayed."));
+If ID is given, it is a space-separated list of IDs of threads to display.\n\
+Otherwise, all threads are displayed."));
add_prefix_cmd ("thread", class_run, thread_command, _("\
Use this command to switch between threads.\n\