@@ -3,6 +3,45 @@
*** Changes since GDB 7.10
+* Per-inferior thread IDs
+
+ Thread numbers are now per inferior instead of global. If you're
+ debugging multiple inferiors, GDB displays thread IDs using an
+ expanded INF_NUM.THR_NUM form. For example:
+
+ (gdb) info threads
+ Id Target Id Frame
+ 1.1 Thread 0x7ffff7fc2740 (LWP 8155) (running)
+ 1.2 Thread 0x7ffff7fc1700 (LWP 8168) (running)
+ * 2.1 Thread 0x7ffff7fc2740 (LWP 8157) (running)
+ 2.2 Thread 0x7ffff7fc1700 (LWP 8190) (running)
+
+ Commands that accept thread IDs now accept the expanded form as
+ well:
+
+ (gdb) thread 2.1
+ [Switching to thread 2.1 (Thread 0x7ffff7fc2740 (LWP 8157))] (running)
+ (gdb)
+
+ As consequence, thread IDs as visible in the $_thread convenience
+ variable are no longer unique between inferiors.
+
+ GDB now maintains a second thread ID per thread, referred to as the
+ global thread ID, which is the new equivalent of thread IDs in
+ previous releases.
+
+ For backwards compatibility, MI's thread IDs always refer to the
+ global ID.
+
+* You can use "info threads -gid" to display the global thread ID of
+ all threads.
+
+* The new convenience variable $_gthread holds the global number of
+ the current thread.
+
+* The new convenience variable $_inferior holds the number of the
+ current inferior.
+
* Record btrace now supports non-stop mode.
* Support for tracepoints on aarch64-linux was added in GDBserver.
@@ -141,6 +180,14 @@ show remote exec-event-feature-packet
format. It outputs data in hexadecimal format with zero-padding on the
left.
+* Python Scripting
+
+ ** gdb.InferiorThread objects have a new attribute "global_num",
+ which refers to the thread's global thread ID. The existing
+ "num" attribute now refers to the thread's per-inferior ID.
+ ** gdb.InferiorThread objects have a new attribute "inferior", which
+ is the Inferior object the thread belongs to.
+
*** Changes in GDB 7.10
* Support for process record-replay and reverse debugging on aarch64*-linux*
@@ -1102,7 +1102,7 @@ print_ada_task_info (struct ui_out *uiout,
/* Print the associated Thread ID. */
if (ui_out_is_mi_like_p (uiout))
{
- const int thread_id = pid_to_thread_id (task_info->ptid);
+ const int thread_id = ptid_to_global_thread_id (task_info->ptid);
if (thread_id != 0)
ui_out_field_int (uiout, "thread-id", thread_id);
@@ -3144,7 +3144,7 @@ insert_breakpoint_locations (void)
the thread no longer exists. ALL_BP_LOCATIONS bp_location
has BL->OWNER always non-NULL. */
if (bl->owner->thread != -1
- && !valid_thread_id (bl->owner->thread))
+ && !valid_global_thread_id (bl->owner->thread))
continue;
switch_to_program_space_and_thread (bl->pspace);
@@ -3244,13 +3244,13 @@ remove_threaded_breakpoints (struct thread_info *tp, int silent)
ALL_BREAKPOINTS_SAFE (b, b_tmp)
{
- if (b->thread == tp->num && user_breakpoint_p (b))
+ if (b->thread == tp->global_id && user_breakpoint_p (b))
{
b->disposition = disp_del_at_next_stop;
printf_filtered (_("\
-Thread-specific breakpoint %d deleted - thread %d no longer in the thread list.\n"),
- b->number, tp->num);
+Thread-specific breakpoint %d deleted - thread %s no longer in the thread list.\n"),
+ b->number, print_thread_id (tp));
/* Hide it from the user. */
b->number = 0;
@@ -5447,7 +5447,7 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
/* If this is a thread/task-specific breakpoint, don't waste cpu
evaluating the condition if this isn't the specified
thread/task. */
- if ((b->thread != -1 && b->thread != pid_to_thread_id (ptid))
+ if ((b->thread != -1 && b->thread != ptid_to_global_thread_id (ptid))
|| (b->task != 0 && b->task != ada_get_task_number (ptid)))
{
@@ -6516,7 +6516,14 @@ print_one_breakpoint_location (struct breakpoint *b,
{
/* FIXME should make an annotation for this. */
ui_out_text (uiout, "\tstop only in thread ");
- ui_out_field_int (uiout, "thread", b->thread);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_int (uiout, "thread", b->thread);
+ else
+ {
+ struct thread_info *thr = find_thread_global_id (b->thread);
+
+ ui_out_field_string (uiout, "thread", print_thread_id (thr));
+ }
ui_out_text (uiout, "\n");
}
@@ -7572,7 +7579,7 @@ void
set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame)
{
struct breakpoint *b, *b_tmp;
- int thread = tp->num;
+ int thread = tp->global_id;
/* To avoid having to rescan all objfile symbols at every step,
we maintain a list of continually-inserted but always disabled
@@ -7641,7 +7648,7 @@ set_longjmp_breakpoint_for_call_dummy (void)
new_b = momentary_breakpoint_from_master (b, bp_longjmp_call_dummy,
&momentary_breakpoint_ops,
1);
- new_b->thread = pid_to_thread_id (inferior_ptid);
+ new_b->thread = ptid_to_global_thread_id (inferior_ptid);
/* Link NEW_B into the chain of RETVAL breakpoints. */
@@ -7671,7 +7678,7 @@ check_longjmp_breakpoint_for_call_dummy (struct thread_info *tp)
struct breakpoint *b, *b_tmp;
ALL_BREAKPOINTS_SAFE (b, b_tmp)
- if (b->type == bp_longjmp_call_dummy && b->thread == tp->num)
+ if (b->type == bp_longjmp_call_dummy && b->thread == tp->global_id)
{
struct breakpoint *dummy_b = b->related_breakpoint;
@@ -8891,7 +8898,7 @@ set_momentary_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line sal,
momentary breakpoints to be active in only a single thread of
control. */
if (in_thread_list (inferior_ptid))
- b->thread = pid_to_thread_id (inferior_ptid);
+ b->thread = ptid_to_global_thread_id (inferior_ptid);
update_global_location_list_nothrow (UGLL_MAY_INSERT);
@@ -9565,14 +9572,6 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch,
}
}
-/* Issue an invalid thread ID error. */
-
-static void ATTRIBUTE_NORETURN
-invalid_thread_id_error (int id)
-{
- error (_("Unknown thread %d."), id);
-}
-
/* Given TOK, a string specification of condition and thread, as
accepted by the 'break' command, extract the condition
string and thread number and set *COND_STRING and *THREAD.
@@ -9621,14 +9620,14 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
}
else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
{
- char *tmptok;
+ const char *tmptok;
+ struct thread_info *thr;
tok = end_tok + 1;
- *thread = strtol (tok, &tmptok, 0);
+ thr = parse_thread_id (tok, &tmptok);
if (tok == tmptok)
error (_("Junk after thread keyword."));
- if (!valid_thread_id (*thread))
- invalid_thread_id_error (*thread);
+ *thread = thr->global_id;
tok = tmptok;
}
else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0)
@@ -11133,25 +11132,23 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
if (toklen == 6 && startswith (tok, "thread"))
{
+ struct thread_info *thr;
/* At this point we've found a "thread" token, which means
the user is trying to set a watchpoint that triggers
only in a specific thread. */
- char *endp;
+ const char *endp;
if (thread != -1)
error(_("You can specify only one thread."));
/* Extract the thread ID from the next token. */
- thread = strtol (value_start, &endp, 0);
+ thr = parse_thread_id (value_start, &endp);
- /* Check if the user provided a valid numeric value for the
- thread ID. */
+ /* Check if the user provided a valid thread ID. */
if (*endp != ' ' && *endp != '\t' && *endp != '\0')
error (_("Invalid thread ID specification %s."), value_start);
- /* Check if the thread actually exists. */
- if (!valid_thread_id (thread))
- invalid_thread_id_error (thread);
+ thread = thr->global_id;
}
else if (toklen == 4 && startswith (tok, "mask"))
{
@@ -11692,7 +11689,7 @@ until_break_command (char *arg, int from_tty, int anywhere)
resolve_sal_pc (&sal);
tp = inferior_thread ();
- thread = tp->num;
+ thread = tp->global_id;
old_chain = make_cleanup (null_cleanup, NULL);
@@ -11742,7 +11739,8 @@ until_break_command (char *arg, int from_tty, int anywhere)
stack_frame_id, bp_until);
make_cleanup_delete_breakpoint (location_breakpoint);
- sm = new_until_break_fsm (tp->num, location_breakpoint, caller_breakpoint);
+ sm = new_until_break_fsm (tp->global_id,
+ location_breakpoint, caller_breakpoint);
tp->thread_fsm = &sm->thread_fsm;
discard_cleanups (old_chain);
@@ -13364,7 +13362,7 @@ momentary_bkpt_print_mention (struct breakpoint *b)
static void
longjmp_bkpt_dtor (struct breakpoint *self)
{
- struct thread_info *tp = find_thread_id (self->thread);
+ struct thread_info *tp = find_thread_global_id (self->thread);
if (tp)
tp->initiating_frame = null_frame_id;
@@ -14545,7 +14543,7 @@ breakpoint_re_set_thread (struct breakpoint *b)
if (b->thread != -1)
{
if (in_thread_list (inferior_ptid))
- b->thread = pid_to_thread_id (inferior_ptid);
+ b->thread = ptid_to_global_thread_id (inferior_ptid);
/* We're being called after following a fork. The new fork is
selected as current, and unless this was a vfork will have a
@@ -15056,7 +15054,7 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch,
if (tp->control.single_step_breakpoints == NULL)
{
tp->control.single_step_breakpoints
- = new_single_step_breakpoint (tp->num, gdbarch);
+ = new_single_step_breakpoint (tp->global_id, gdbarch);
}
sal = find_pc_line (pc, 0);
@@ -1043,7 +1043,8 @@ btrace_enable (struct thread_info *tp, const struct btrace_config *conf)
if (!target_supports_btrace (conf->format))
error (_("Target does not support branch tracing."));
- DEBUG ("enable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+ DEBUG ("enable thread %s (%s)", print_thread_id (tp),
+ target_pid_to_str (tp->ptid));
tp->btrace.target = target_enable_btrace (tp->ptid, conf);
@@ -1075,7 +1076,8 @@ btrace_disable (struct thread_info *tp)
if (btp->target == NULL)
return;
- DEBUG ("disable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+ DEBUG ("disable thread %s (%s)", print_thread_id (tp),
+ target_pid_to_str (tp->ptid));
target_disable_btrace (btp->target);
btp->target = NULL;
@@ -1094,7 +1096,8 @@ btrace_teardown (struct thread_info *tp)
if (btp->target == NULL)
return;
- DEBUG ("teardown thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+ DEBUG ("teardown thread %s (%s)", print_thread_id (tp),
+ target_pid_to_str (tp->ptid));
target_teardown_btrace (btp->target);
btp->target = NULL;
@@ -1268,7 +1271,8 @@ btrace_fetch (struct thread_info *tp)
struct cleanup *cleanup;
int errcode;
- DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+ DEBUG ("fetch thread %s (%s)", print_thread_id (tp),
+ target_pid_to_str (tp->ptid));
btinfo = &tp->btrace;
tinfo = btinfo->target;
@@ -1340,7 +1344,8 @@ btrace_clear (struct thread_info *tp)
struct btrace_thread_info *btinfo;
struct btrace_function *it, *trash;
- DEBUG ("clear thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+ DEBUG ("clear thread %s (%s)", print_thread_id (tp),
+ target_pid_to_str (tp->ptid));
/* Make sure btrace frames that may hold a pointer into the branch
trace data are destroyed. */
@@ -23,16 +23,9 @@
#include <ctype.h>
-/* *PP is a string denoting a number. Get the number of the. Advance
- *PP after the string and any trailing whitespace.
-
- Currently the string can either be a number, or "$" followed by the
- name of a convenience variable, or ("$" or "$$") followed by digits.
-
- TRAILER is a character which can be found after the number; most
- commonly this is `-'. If you don't want a trailer, use \0. */
+/* See documentation in cli-utils.h. */
-static int
+int
get_number_trailer (const char **pp, int trailer)
{
int retval = 0; /* default */
@@ -20,11 +20,18 @@
#ifndef CLI_UTILS_H
#define CLI_UTILS_H
-/* *PP is a string denoting a number. Get the number of the. Advance
- *PP after the string and any trailing whitespace.
+/* *PP is a string denoting a number. Get the number. Advance PP
+ *after the string and any trailing whitespace.
- Currently the string can either be a number, or "$" followed by the
- name of a convenience variable, or ("$" or "$$") followed by digits. */
+ The string can either be a number, or "$" followed by the name of a
+ convenience variable, or ("$" or "$$") followed by digits.
+
+ TRAILER is a character which can be found after the number; most
+ commonly this is `-'. If you don't want a trailer, use \0. */
+
+extern int get_number_trailer (const char **pp, int trailer);
+
+/* Convenience. Like get_number_trailer, but with no TRAILER. */
extern int get_number_const (const char **);
@@ -22,14 +22,13 @@
/* Temporary storage using circular buffer. */
#define NUMCELLS 16
-#define CELLSIZE 50
/* Return the next entry in the circular buffer. */
-static char *
-get_cell (void)
+char *
+get_print_cell (void)
{
- static char buf[NUMCELLS][CELLSIZE];
+ static char buf[NUMCELLS][PRINT_CELL_SIZE];
static int cell = 0;
if (++cell >= NUMCELLS)
@@ -43,7 +42,7 @@ decimal2str (char *sign, ULONGEST addr, int width)
/* Steal code from valprint.c:print_decimal(). Should this worry
about the real size of addr as the above does? */
unsigned long temp[3];
- char *str = get_cell ();
+ char *str = get_print_cell ();
int i = 0;
do
@@ -62,14 +61,14 @@ decimal2str (char *sign, ULONGEST addr, int width)
switch (i)
{
case 1:
- xsnprintf (str, CELLSIZE, "%s%0*lu", sign, width, temp[0]);
+ xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu", sign, width, temp[0]);
break;
case 2:
- xsnprintf (str, CELLSIZE, "%s%0*lu%09lu", sign, width,
+ xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu%09lu", sign, width,
temp[1], temp[0]);
break;
case 3:
- xsnprintf (str, CELLSIZE, "%s%0*lu%09lu%09lu", sign, width,
+ xsnprintf (str, PRINT_CELL_SIZE, "%s%0*lu%09lu%09lu", sign, width,
temp[2], temp[1], temp[0]);
break;
default:
@@ -84,7 +83,7 @@ static char *
octal2str (ULONGEST addr, int width)
{
unsigned long temp[3];
- char *str = get_cell ();
+ char *str = get_print_cell ();
int i = 0;
do
@@ -104,15 +103,15 @@ octal2str (ULONGEST addr, int width)
{
case 1:
if (temp[0] == 0)
- xsnprintf (str, CELLSIZE, "%*o", width, 0);
+ xsnprintf (str, PRINT_CELL_SIZE, "%*o", width, 0);
else
- xsnprintf (str, CELLSIZE, "0%0*lo", width, temp[0]);
+ xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo", width, temp[0]);
break;
case 2:
- xsnprintf (str, CELLSIZE, "0%0*lo%010lo", width, temp[1], temp[0]);
+ xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo%010lo", width, temp[1], temp[0]);
break;
case 3:
- xsnprintf (str, CELLSIZE, "0%0*lo%010lo%010lo", width,
+ xsnprintf (str, PRINT_CELL_SIZE, "0%0*lo%010lo%010lo", width,
temp[2], temp[1], temp[0]);
break;
default:
@@ -155,18 +154,18 @@ phex (ULONGEST l, int sizeof_l)
switch (sizeof_l)
{
case 8:
- str = get_cell ();
- xsnprintf (str, CELLSIZE, "%08lx%08lx",
+ str = get_print_cell ();
+ xsnprintf (str, PRINT_CELL_SIZE, "%08lx%08lx",
(unsigned long) (l >> thirty_two),
(unsigned long) (l & 0xffffffff));
break;
case 4:
- str = get_cell ();
- xsnprintf (str, CELLSIZE, "%08lx", (unsigned long) l);
+ str = get_print_cell ();
+ xsnprintf (str, PRINT_CELL_SIZE, "%08lx", (unsigned long) l);
break;
case 2:
- str = get_cell ();
- xsnprintf (str, CELLSIZE, "%04x", (unsigned short) (l & 0xffff));
+ str = get_print_cell ();
+ xsnprintf (str, PRINT_CELL_SIZE, "%04x", (unsigned short) (l & 0xffff));
break;
default:
str = phex (l, sizeof (l));
@@ -189,22 +188,22 @@ phex_nz (ULONGEST l, int sizeof_l)
{
unsigned long high = (unsigned long) (l >> thirty_two);
- str = get_cell ();
+ str = get_print_cell ();
if (high == 0)
- xsnprintf (str, CELLSIZE, "%lx",
+ xsnprintf (str, PRINT_CELL_SIZE, "%lx",
(unsigned long) (l & 0xffffffff));
else
- xsnprintf (str, CELLSIZE, "%lx%08lx", high,
+ xsnprintf (str, PRINT_CELL_SIZE, "%lx%08lx", high,
(unsigned long) (l & 0xffffffff));
break;
}
case 4:
- str = get_cell ();
- xsnprintf (str, CELLSIZE, "%lx", (unsigned long) l);
+ str = get_print_cell ();
+ xsnprintf (str, PRINT_CELL_SIZE, "%lx", (unsigned long) l);
break;
case 2:
- str = get_cell ();
- xsnprintf (str, CELLSIZE, "%x", (unsigned short) (l & 0xffff));
+ str = get_print_cell ();
+ xsnprintf (str, PRINT_CELL_SIZE, "%x", (unsigned short) (l & 0xffff));
break;
default:
str = phex_nz (l, sizeof (l));
@@ -219,9 +218,9 @@ phex_nz (ULONGEST l, int sizeof_l)
char *
hex_string (LONGEST num)
{
- char *result = get_cell ();
+ char *result = get_print_cell ();
- xsnprintf (result, CELLSIZE, "0x%s", phex_nz (num, sizeof (num)));
+ xsnprintf (result, PRINT_CELL_SIZE, "0x%s", phex_nz (num, sizeof (num)));
return result;
}
@@ -230,14 +229,14 @@ hex_string (LONGEST num)
char *
hex_string_custom (LONGEST num, int width)
{
- char *result = get_cell ();
- char *result_end = result + CELLSIZE - 1;
+ char *result = get_print_cell ();
+ char *result_end = result + PRINT_CELL_SIZE - 1;
const char *hex = phex_nz (num, sizeof (num));
int hex_len = strlen (hex);
if (hex_len > width)
width = hex_len;
- if (width + 2 >= CELLSIZE)
+ if (width + 2 >= PRINT_CELL_SIZE)
internal_error (__FILE__, __LINE__, _("\
hex_string_custom: insufficient space to store result"));
@@ -294,7 +293,7 @@ int_string (LONGEST val, int radix, int is_signed, int width,
const char *
core_addr_to_string (const CORE_ADDR addr)
{
- char *str = get_cell ();
+ char *str = get_print_cell ();
strcpy (str, "0x");
strcat (str, phex (addr, sizeof (addr)));
@@ -306,7 +305,7 @@ core_addr_to_string (const CORE_ADDR addr)
const char *
core_addr_to_string_nz (const CORE_ADDR addr)
{
- char *str = get_cell ();
+ char *str = get_print_cell ();
strcpy (str, "0x");
strcat (str, phex_nz (addr, sizeof (addr)));
@@ -318,8 +317,9 @@ core_addr_to_string_nz (const CORE_ADDR addr)
const char *
host_address_to_string_1 (const void *addr)
{
- char *str = get_cell ();
+ char *str = get_print_cell ();
- xsnprintf (str, CELLSIZE, "0x%s", phex_nz ((uintptr_t) addr, sizeof (addr)));
+ xsnprintf (str, PRINT_CELL_SIZE, "0x%s",
+ phex_nz ((uintptr_t) addr, sizeof (addr)));
return str;
}
@@ -71,4 +71,8 @@ extern const char *host_address_to_string_1 (const void *addr);
#define host_address_to_string(ADDR) \
host_address_to_string_1 ((const void *) (ADDR))
+extern char *get_print_cell (void);
+
+#define PRINT_CELL_SIZE 50
+
#endif /* COMMON_CELLS_H */
@@ -2658,6 +2658,12 @@ Make inferior number @var{infno} the current inferior. The argument
in the first field of the @samp{info inferiors} display.
@end table
+@vindex $_inferior@r{, convenience variable}
+The debugger convenience variable @samp{$_inferior} contains the
+number of the current inferior. You may find this useful in writing
+breakpoint conditional expressions, command scripts, and so forth.
+See @xref{Convenience Vars,, Convenience Variables}, for general
+information on convenience variables.
You can get multiple executables into a debugging session via the
@code{add-inferior} and @w{@code{clone-inferior}} commands. On some
@@ -2880,10 +2886,31 @@ further qualifier.
@c multithread systems permit starting a program with multiple
@c threads ab initio?
-@cindex thread number
+@cindex thread number, per inferior
@cindex thread identifier (GDB)
-For debugging purposes, @value{GDBN} associates its own thread
-number---always a single integer---with each thread in your program.
+For debugging purposes, @value{GDBN} associates its own thread number
+---always a single integer---with each thread of an inferior. This ID
+is unique between all threads of an inferior, but not unique between
+threads of different inferiors.
+
+You can refer to a given thread in an inferior using the
+@var{inferior-num}.@var{thread-num} syntax, with @var{inferior-num}
+being the inferior number and @var{thread-num} being the thread number
+of the given inferior. For example, thread @code{2.3} refers to
+thread number 3 of inferior 2. If you omit @var{inferior-num}, then
+@value{GDBN} infers you're referring to a thread of the current
+inferior.
+
+Until you create a second inferior, @value{GDBN} does not show the
+@var{inferior-num} part of thread IDs, even though you can always use
+the full @var{inferior-num}.@var{thread-num} form to refer to threads
+of inferior 1, the initial inferior.
+
+@cindex global thread number
+@cindex global thread identifier (GDB)
+In addition to a @emph{per-inferior} ID, each thread is also assigned
+a unique @emph{global} ID. Unlike the former, no two threads have the
+same global ID, even when you're debugging multiple inferiors.
From @value{GDBN}'s perspective, a process always has at least one
thread. In other words, @value{GDBN} assigns a thread number to the
@@ -2899,7 +2926,11 @@ means to print information only about the specified thread or threads.
@enumerate
@item
-the thread number assigned by @value{GDBN}
+the per-inferior thread number assigned by @value{GDBN}
+
+@item
+the global thread number assigned by @value{GDBN}, if the @samp{-gid}
+option was specified.
@item
the target system's thread identifier (@var{systag})
@@ -2930,6 +2961,21 @@ For example,
at threadtest.c:68
@end smallexample
+If you're debugging multiple inferiors, @value{GDBN} displays thread
+IDs using an expanded @var{inferior-num}.@var{thread-num} format.
+
+If you specify the @samp{-gid} option, @value{GDBN} displays a column
+indicating each thread's global thread ID:
+
+@smallexample
+(@value{GDBP}) info threads
+ Id GId Target Id Frame
+ 1.1 1 process 35 thread 13 main (argc=1, argv=0x7ffffff8)
+ 1.2 3 process 35 thread 23 0x34e5 in sigpause ()
+ 1.3 4 process 35 thread 27 0x34e5 in sigpause ()
+* 2.1 2 process 65 thread 1 main (argc=1, argv=0x7ffffff8)
+@end smallexample
+
On Solaris, you can display more information about user threads with a
Solaris-specific command:
@@ -2944,10 +2990,10 @@ Display info on Solaris user threads.
@kindex thread @var{threadno}
@item thread @var{threadno}
Make thread number @var{threadno} the current thread. The command
-argument @var{threadno} is the internal @value{GDBN} thread number, as
-shown in the first field of the @samp{info threads} display.
-@value{GDBN} responds by displaying the system identifier of the thread
-you selected, and its current stack frame summary:
+argument @var{threadno} is the internal per-inferior @value{GDBN}
+thread number, as shown in the first field of the @samp{info threads}
+display. @value{GDBN} responds by displaying the system identifier of
+the thread you selected, and its current stack frame summary:
@smallexample
(@value{GDBP}) thread 2
@@ -2962,11 +3008,19 @@ As with the @samp{[New @dots{}]} message, the form of the text after
threads.
@vindex $_thread@r{, convenience variable}
-The debugger convenience variable @samp{$_thread} contains the number
-of the current thread. You may find this useful in writing breakpoint
-conditional expressions, command scripts, and so forth. See
-@xref{Convenience Vars,, Convenience Variables}, for general
-information on convenience variables.
+The debugger convenience variable @samp{$_thread} contains the
+per-inferior thread number of the current thread. You may find this
+useful in writing breakpoint conditional expressions, command scripts,
+and so forth. See @xref{Convenience Vars,, Convenience Variables},
+for general information on convenience variables.
+
+@vindex $_gthread@r{, convenience variable}
+The debugger convenience variable @samp{$_gthread} contains the global
+number of the current thread, independent of the thread's containing
+inferior. You may find this useful in writing breakpoint conditional
+expressions, command scripts, and so forth. See @xref{Convenience
+Vars,, Convenience Variables}, for general information on convenience
+variables.
@kindex thread apply
@cindex apply command to several threads
@@ -2975,9 +3029,10 @@ The @code{thread apply} command allows you to apply the named
@var{command} to one or more threads. Specify the numbers of the
threads that you want affected with the command argument
@var{threadno}. It can be a single thread number, one of the numbers
-shown in the first field of the @samp{info threads} display; or it
-could be a range of thread numbers, as in @code{2-4}. To apply
-a command to all threads in descending order, type @kbd{thread apply all
+shown in the first field of the @samp{info threads} display, with or
+without a inferior qualifier (e.g., @samp{2.1} or @samp{1}); or it
+could be a range of thread numbers, as in @code{2-4}. To apply a
+command to all threads in descending order, type @kbd{thread apply all
@var{command}}. To apply a command to all threads in ascending order,
type @kbd{thread apply all -ascending @var{command}}.
@@ -25357,8 +25412,8 @@ increases the risk that by relying on implicitly selected thread, the
frontend may be operating on a wrong one. Therefore, each MI command
should explicitly specify which thread and frame to operate on. To
make it possible, each MI command accepts the @samp{--thread} and
-@samp{--frame} options, the value to each is @value{GDBN} identifier
-for thread and frame to operate on.
+@samp{--frame} options, the value to each is @value{GDBN} global
+identifier for thread and frame to operate on.
Usually, each top-level window in a frontend allows the user to select
a thread and a frame, and remembers the user selection for further
@@ -25911,15 +25966,16 @@ The following is the list of possible async records:
@table @code
@item *running,thread-id="@var{thread}"
-The target is now running. The @var{thread} field tells which
-specific thread is now running, and can be @samp{all} if all threads
-are running. The frontend should assume that no interaction with a
-running thread is possible after this notification is produced.
-The frontend should not assume that this notification is output
-only once for any command. @value{GDBN} may emit this notification
-several times, either for different threads, because it cannot resume
-all threads together, or even for a single thread, if the thread must
-be stepped though some code before letting it run freely.
+The target is now running. The @var{thread} field can be the global
+thread ID of the the thread that is now running, and it can be
+@samp{all} if all threads are running. The frontend should assume
+that no interaction with a running thread is possible after this
+notification is produced. The frontend should not assume that this
+notification is output only once for any command. @value{GDBN} may
+emit this notification several times, either for different threads,
+because it cannot resume all threads together, or even for a single
+thread, if the thread must be stepped though some code before letting
+it run freely.
@item *stopped,reason="@var{reason}",thread-id="@var{id}",stopped-threads="@var{stopped}",core="@var{core}"
The target has stopped. The @var{reason} field can have one of the
@@ -25973,8 +26029,9 @@ The inferior called @code{exec}. This is reported when @code{catch exec}
(@pxref{Set Catchpoints}) has been used.
@end table
-The @var{id} field identifies the thread that directly caused the stop
+The @var{id} field identifies the global thread ID of the thread
+that directly caused the stop -- for example by hitting a breakpoint.
+Depending on whether all-stop
mode is in effect (@pxref{All-Stop Mode}), @value{GDBN} may either
stop all threads, or only the thread that directly triggered the stop.
If all threads are stopped, the @var{stopped} field will have the
@@ -26010,7 +26067,7 @@ only when the inferior exited with some code.
@item =thread-created,id="@var{id}",group-id="@var{gid}"
@itemx =thread-exited,id="@var{id}",group-id="@var{gid}"
A thread either was created, or has exited. The @var{id} field
-contains the @value{GDBN} identifier of the thread. The @var{gid}
+contains the global @value{GDBN} identifier of the thread. The @var{gid}
field identifies the thread group this thread belongs to.
@item =thread-selected,id="@var{id}"
@@ -26271,7 +26328,7 @@ uses a tuple with the following fields:
@table @code
@item id
-The numeric id assigned to the thread by @value{GDBN}. This field is
+The global numeric id assigned to the thread by @value{GDBN}. This field is
always present.
@item target-id
@@ -26744,7 +26801,8 @@ Make the breakpoint conditional on @var{condition}.
@item -i @var{ignore-count}
Initialize the @var{ignore-count}.
@item -p @var{thread-id}
-Restrict the breakpoint to the specified @var{thread-id}.
+Restrict the breakpoint to the thread with the specified global
+@var{thread-id}.
@end table
@subsubheading Result
@@ -26834,7 +26892,8 @@ Make the breakpoint conditional on @var{condition}.
Set the ignore count of the breakpoint (@pxref{Conditions, ignore count})
to @var{ignore-count}.
@item -p @var{thread-id}
-Restrict the breakpoint to the specified @var{thread-id}.
+Restrict the breakpoint to the thread with the specified global
+@var{thread-id}.
@end table
@subsubheading Result
@@ -27484,10 +27543,11 @@ The corresponding @value{GDBN} command is @samp{pwd}.
-thread-info [ @var{thread-id} ]
@end smallexample
-Reports information about either a specific thread, if
-the @var{thread-id} parameter is present, or about all
-threads. When printing information about all threads,
-also reports the current thread.
+Reports information about either a specific thread, if the
+@var{thread-id} parameter is present, or about all threads.
+@var{thread-id} is the thread's @emph{global} thread ID. When
+printing information about all threads, also reports the global ID of
+the current thread.
@subsubheading @value{GDBN} Command
@@ -27504,7 +27564,7 @@ defined for a given thread:
This field exists only for the current thread. It has the value @samp{*}.
@item id
-The identifier that @value{GDBN} uses to refer to the thread.
+The global identifier that @value{GDBN} uses to refer to the thread.
@item target-id
The identifier that the target uses to refer to the thread.
@@ -27570,8 +27630,9 @@ current-thread-id="1"
-thread-list-ids
@end smallexample
-Produces a list of the currently known @value{GDBN} thread ids. At the
-end of the list it also prints the total number of such threads.
+Produces a list of the currently known global @value{GDBN} thread ids.
+At the end of the list it also prints the total number of such
+threads.
This command is retained for historical reasons, the
@code{-thread-info} command should be used instead.
@@ -27600,8 +27661,9 @@ current-thread-id="1",number-of-threads="3"
-thread-select @var{threadnum}
@end smallexample
-Make @var{threadnum} the current thread. It prints the number of the new
-current thread, and the topmost frame for that thread.
+Make thread with global thread num @var{threadnum} the current thread.
+It prints the number of the new current thread, and the topmost frame
+for that thread.
This command is deprecated in favor of explicitly using the
@samp{--thread} option to each command.
@@ -27670,7 +27732,8 @@ The identifier that @value{GDBN} uses to refer to the Ada task.
The identifier that the target uses to refer to the Ada task.
@item thread-id
-The identifier of the thread corresponding to the Ada task.
+The global thread identifier of the thread corresponding to the Ada
+task.
This field should always exist, as Ada tasks are always implemented
on top of a thread. But if @value{GDBN} cannot find this corresponding
@@ -28886,7 +28949,7 @@ would be printed by the @value{GDBN} CLI. If @samp{print object}
@item thread-id
If a variable object is bound to a specific thread, then this is the
-thread's identifier.
+thread's global identifier.
@item has_more
For a dynamic varobj, this indicates whether there appear to be any
@@ -29067,8 +29130,8 @@ The type of the child. If @samp{print object}
If values were requested, this is the value.
@item thread-id
-If this variable object is associated with a thread, this is the thread id.
-Otherwise this result is not present.
+If this variable object is associated with a thread, this is the
+thread's global thread id. Otherwise this result is not present.
@item frozen
If the variable object is frozen, this variable will be present with a value of 1.
@@ -3127,13 +3127,14 @@ At present, @var{count} must be zero.
@end deffn
@deffn {Scheme Procedure} breakpoint-thread breakpoint
-Return the thread-id for thread-specific breakpoint @var{breakpoint}.
-Return #f if @var{breakpoint} is not thread-specific.
+Return the global-thread-id for thread-specific breakpoint
+@var{breakpoint}. Return #f if @var{breakpoint} is not
+thread-specific.
@end deffn
-@deffn {Scheme Procedure} set-breakpoint-thread! breakpoint thread-id|#f
-Set the thread-id for @var{breakpoint} to @var{thread-id}.
-If set to @code{#f}, the breakpoint is no longer thread-specific.
+@deffn {Scheme Procedure} set-breakpoint-thread! breakpoint global-thread-id|#f
+Set the thread-id for @var{breakpoint} to @var{global-thread-id} If
+set to @code{#f}, the breakpoint is no longer thread-specific.
@end deffn
@deffn {Scheme Procedure} breakpoint-task breakpoint
@@ -2995,7 +2995,11 @@ user-specified thread name.
@end defvar
@defvar InferiorThread.num
-ID of the thread, as assigned by GDB.
+The per-inferior ID of the thread, as assigned by GDB.
+@end defvar
+
+@defvar InferiorThread.global_num
+The global ID of the thread, as assigned by GDB.
@end defvar
@defvar InferiorThread.ptid
@@ -4638,9 +4642,9 @@ first command is @code{silent}. This is not reported by the
@end defvar
@defvar Breakpoint.thread
-If the breakpoint is thread-specific, this attribute holds the thread
-id. If the breakpoint is not thread-specific, this attribute is
-@code{None}. This attribute is writable.
+If the breakpoint is thread-specific, this attribute holds the
+thread's global id. If the breakpoint is not thread-specific, this
+attribute is @code{None}. This attribute is writable.
@end defvar
@defvar Breakpoint.task
@@ -130,7 +130,7 @@ pop_dummy_frame_bpt (struct breakpoint *b, void *dummy_voidp)
{
struct dummy_frame *dummy = (struct dummy_frame *) dummy_voidp;
- if (b->thread == pid_to_thread_id (dummy->id.ptid)
+ if (b->thread == ptid_to_global_thread_id (dummy->id.ptid)
&& b->disposition == disp_del && frame_id_eq (b->frame_id, dummy->id.id))
{
while (b->related_breakpoint != b)
@@ -902,7 +902,7 @@ elf_gnu_ifunc_resolver_stop (struct breakpoint *b)
struct frame_info *prev_frame = get_prev_frame (get_current_frame ());
struct frame_id prev_frame_id = get_stack_frame_id (prev_frame);
CORE_ADDR prev_pc = get_frame_pc (prev_frame);
- int thread_id = pid_to_thread_id (inferior_ptid);
+ int thread_id = ptid_to_global_thread_id (inferior_ptid);
gdb_assert (b->type == bp_gnu_ifunc_resolver);
@@ -187,7 +187,33 @@ struct thread_info
ptid_t ptid; /* "Actual process id";
In fact, this may be overloaded with
kernel thread id, etc. */
- int num; /* Convenient handle (GDB thread id) */
+
+ /* Each thread has two GDB ID's -- one global (GId), and one
+ per-inferior (Id):
+
+ (gdb) info threads -gid
+ Id GId Target Id Frame
+ * 1.1 1 Thread A 0x16a09237 in foo () at foo.c:10
+ 1.2 3 Thread B 0x15ebc6ed in bar () at foo.c:20
+ 1.3 5 Thread C 0x15ebc6ed in bar () at foo.c:20
+ 2.1 2 Thread A 0x16a09237 in foo () at foo.c:10
+ 2.2 4 Thread B 0x15ebc6ed in bar () at foo.c:20
+ 2.3 6 Thread C 0x15ebc6ed in bar () at foo.c:20
+
+ Above, both inferiors 1 and 2 have threads numbered 1-3, but each
+ thread has its own unique global ID. */
+
+ /* The thread's global GDB thread id. It's exposed to MI,
+ Python/Scheme, visible with "info threads -gid", and is also what
+ the $_thread convenience variable is bound to. */
+ int global_id;
+
+ /* The GDB thread Id unique in the inferior the thread belongs to.
+ Each inferior has its own number space for this ID. */
+ int per_inf_id;
+
+ /* The inferior this thread belongs to. */
+ struct inferior *inf;
/* The name of the thread, as specified by the user. This is NULL
if the thread does not have a user-given name. */
@@ -353,27 +379,38 @@ extern int thread_has_single_step_breakpoint_here (struct thread_info *tp,
struct address_space *aspace,
CORE_ADDR addr);
-/* Translate the integer thread id (GDB's homegrown id, not the system's)
- into a "pid" (which may be overloaded with extra thread information). */
-extern ptid_t thread_id_to_pid (int);
+/* Translate the integer thread id (GDB's homegrown global id, not the
+ system's) into a "pid" (which may be overloaded with extra thread
+ information). */
+extern ptid_t global_thread_id_to_ptid (int num);
/* Translate a 'pid' (which may be overloaded with extra thread information)
into the integer thread id (GDB's homegrown id, not the system's). */
-extern int pid_to_thread_id (ptid_t ptid);
+extern int ptid_to_global_thread_id (ptid_t ptid);
+
+const char *print_thread_id (struct thread_info *thr);
/* Boolean test for an already-known pid (which may be overloaded with
extra thread information). */
extern int in_thread_list (ptid_t ptid);
-/* Boolean test for an already-known thread id (GDB's homegrown id,
- not the system's). */
-extern int valid_thread_id (int thread);
+/* Boolean test for an already-known thread id (GDB's homegrown global
+ id, not the system's). */
+extern int valid_global_thread_id (int thread);
+
+/* Parse TIDSTR as a per-inferior thread ID, in either INF_NUM.THR_NUM
+ or THR_NUM form. In the latter case, the missing INF_NUM is filled
+ in from the current inferior. If ENDPTR is not NULL,
+ parse_thread_id stores the address of the first character after the
+ thread ID. Either a valid thread is returned, or an error is
+ thrown. */
+struct thread_info *parse_thread_id (const char *tidstr, const char **end);
/* Search function to lookup a thread by 'pid'. */
extern struct thread_info *find_thread_ptid (ptid_t ptid);
/* Find thread by GDB user-visible thread number. */
-struct thread_info *find_thread_id (int num);
+struct thread_info *find_thread_global_id (int num);
/* Finds the first thread of the inferior given by PID. If PID is -1,
returns the first thread in the list. */
@@ -402,6 +439,9 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
for (T = thread_list; T; T = T->next) \
if ((T)->state != THREAD_EXITED)
+#define ALL_THREADS(T) \
+ for (T = thread_list; T; T = T->next) \
+
/* Traverse all threads, including those that have THREAD_EXITED
state. Allows deleting the currently iterated thread. */
#define ALL_THREADS_SAFE(T, TMP) \
@@ -500,7 +540,15 @@ extern void thread_command (char *tidstr, int from_tty);
`set print thread-events'. */
extern int print_thread_events;
-extern void print_thread_info (struct ui_out *uiout, char *threads,
+/* Prints the list of threads and their details on UIOUT. If
+ REQUESTED_THREADS is not NULL, it's a list of GDB ids 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_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. */
+extern void print_thread_info (struct ui_out *uiout, char *requested_threads,
int pid);
extern struct cleanup *make_cleanup_restore_current_thread (void);
@@ -745,7 +745,7 @@ gdbscm_set_breakpoint_thread_x (SCM self, SCM newvalue)
if (scm_is_signed_integer (newvalue, LONG_MIN, LONG_MAX))
{
id = scm_to_long (newvalue);
- if (! valid_thread_id (id))
+ if (!valid_global_thread_id (id))
{
gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, newvalue,
_("invalid thread id"));
@@ -1273,14 +1273,14 @@ Set the breakpoint's \"hit\" count. The value must be zero.\n\
{ "breakpoint-thread", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_thread),
"\
-Return the breakpoint's thread id or #f if there isn't one." },
+Return the breakpoint's global thread id or #f if there isn't one." },
{ "set-breakpoint-thread!", 2, 0, 0,
as_a_scm_t_subr (gdbscm_set_breakpoint_thread_x),
"\
-Set the thread id for this breakpoint.\n\
+Set the global thread id for this breakpoint.\n\
\n\
- Arguments: <gdb:breakpoint> thread-id" },
+ Arguments: <gdb:breakpoint> global-thread-id" },
{ "breakpoint-task", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_task),
"\
@@ -960,7 +960,7 @@ step_command_fsm_prepare (struct step_command_fsm *sm,
sm->skip_subroutines = skip_subroutines;
sm->single_inst = single_inst;
sm->count = count;
- sm->thread = thread->num;
+ sm->thread = thread->global_id;
/* Leave the si command alone. */
if (!sm->single_inst || sm->skip_subroutines)
@@ -1032,7 +1032,7 @@ static int
step_command_fsm_should_stop (struct thread_fsm *self)
{
struct step_command_fsm *sm = (struct step_command_fsm *) self;
- struct thread_info *tp = find_thread_id (sm->thread);
+ struct thread_info *tp = find_thread_global_id (sm->thread);
if (tp->control.stop_step)
{
@@ -1316,8 +1316,8 @@ signal_command (char *signum_exp, int from_tty)
{
if (!must_confirm)
printf_unfiltered (_("Note:\n"));
- printf_unfiltered (_(" Thread %d previously stopped with signal %s, %s.\n"),
- tp->num,
+ printf_unfiltered (_(" Thread %s previously stopped with signal %s, %s.\n"),
+ print_thread_id (tp),
gdb_signal_to_name (tp->suspend.stop_signal),
gdb_signal_to_string (tp->suspend.stop_signal));
must_confirm = 1;
@@ -1325,10 +1325,10 @@ signal_command (char *signum_exp, int from_tty)
}
if (must_confirm
- && !query (_("Continuing thread %d (the current thread) with specified signal will\n"
+ && !query (_("Continuing thread %s (the current thread) with specified signal will\n"
"still deliver the signals noted above to their respective threads.\n"
"Continue anyway? "),
- inferior_thread ()->num))
+ print_thread_id (inferior_thread ())))
error (_("Not confirmed."));
}
@@ -1478,7 +1478,7 @@ until_next_command (int from_tty)
struct symbol *func;
struct symtab_and_line sal;
struct thread_info *tp = inferior_thread ();
- int thread = tp->num;
+ int thread = tp->global_id;
struct cleanup *old_chain;
struct until_next_fsm *sm;
@@ -1520,12 +1520,11 @@ until_next_command (int from_tty)
set_longjmp_breakpoint (tp, get_frame_id (frame));
old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
- sm = new_until_next_fsm (tp->num);
+ sm = new_until_next_fsm (tp->global_id);
tp->thread_fsm = &sm->thread_fsm;
discard_cleanups (old_chain);
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
-
}
static void
@@ -1774,7 +1773,7 @@ finish_command_fsm_should_stop (struct thread_fsm *self)
{
struct finish_command_fsm *f = (struct finish_command_fsm *) self;
struct return_value_info *rv = &f->return_value;
- struct thread_info *tp = find_thread_id (f->thread);
+ struct thread_info *tp = find_thread_global_id (f->thread);
if (f->function != NULL
&& bpstat_find_breakpoint (tp->control.stop_bpstat,
@@ -1967,7 +1966,7 @@ finish_command (char *arg, int from_tty)
tp = inferior_thread ();
- sm = new_finish_command_fsm (tp->num);
+ sm = new_finish_command_fsm (tp->global_id);
tp->thread_fsm = &sm->thread_fsm;
@@ -2715,7 +2714,8 @@ attach_post_wait (char *args, int from_tty, enum attach_post_wait_mode mode)
{
if (ptid_get_pid (thread->ptid) == pid)
{
- if (thread->num < lowest->num)
+ if (thread->inf->num < lowest->inf->num
+ || thread->per_inf_id < lowest->per_inf_id)
lowest = thread;
}
}
@@ -531,6 +531,15 @@ inferior_pid_to_str (int pid)
return _("<null>");
}
+static int
+should_print_inferior (const char *requested_inferiors, struct inferior *inf)
+{
+ if (requested_inferiors != NULL && *requested_inferiors != '\0')
+ return number_is_in_list (requested_inferiors, inf->num);
+ else
+ return 1;
+}
+
/* Prints the list of inferiors and their details on UIOUT. This is a
version of 'info_inferior_command' suitable for use from MI.
@@ -548,7 +557,7 @@ print_inferior (struct ui_out *uiout, char *requested_inferiors)
/* Compute number of inferiors we will print. */
for (inf = inferior_list; inf; inf = inf->next)
{
- if (!number_is_in_list (requested_inferiors, inf->num))
+ if (!should_print_inferior (requested_inferiors, inf))
continue;
++inf_count;
@@ -572,7 +581,7 @@ print_inferior (struct ui_out *uiout, char *requested_inferiors)
{
struct cleanup *chain2;
- if (!number_is_in_list (requested_inferiors, inf->num))
+ if (!should_print_inferior (requested_inferiors, inf))
continue;
chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
@@ -729,8 +738,8 @@ inferior_command (char *args, int from_tty)
switch_to_thread (tp->ptid);
}
- printf_filtered (_("[Switching to thread %d (%s)] "),
- pid_to_thread_id (inferior_ptid),
+ printf_filtered (_("[Switching to thread %s (%s)] "),
+ print_thread_id (inferior_thread ()),
target_pid_to_str (inferior_ptid));
}
else
@@ -989,6 +998,26 @@ show_print_inferior_events (struct ui_file *file, int from_tty,
fprintf_filtered (file, _("Printing of inferior events is %s.\n"), value);
}
+/* Return a new value for the selected inferior's id. */
+
+static struct value *
+inferior_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
+{
+ struct inferior *inf = current_inferior ();
+
+ return value_from_longest (builtin_type (gdbarch)->builtin_int, inf->num);
+}
+
+/* Implementation of `$_inferior' variable. */
+
+static const struct internalvar_funcs inferior_funcs =
+{
+ inferior_id_make_value,
+ NULL,
+ NULL
+};
+
void
@@ -1052,4 +1081,5 @@ Show printing of inferior events (e.g., inferior start and exit)."), NULL,
show_print_inferior_events,
&setprintlist, &showprintlist);
+ create_internalvar_type_lazy ("_inferior", &inferior_funcs, NULL);
}
@@ -304,6 +304,8 @@ struct inferior
/* True if the PID was actually faked by GDB. */
int fake_pid_p;
+ int highest_thread_num;
+
/* State of GDB control of inferior process execution.
See `struct inferior_control_state'. */
struct inferior_control_state control;
@@ -5702,7 +5702,7 @@ handle_signal_stop (struct execution_control_state *ecs)
context_switch (ecs->ptid);
if (deprecated_context_hook)
- deprecated_context_hook (pid_to_thread_id (ecs->ptid));
+ deprecated_context_hook (ptid_to_global_thread_id (ecs->ptid));
}
/* At this point, get hold of the now-current thread's frame. */
@@ -7510,7 +7510,7 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
/* set_momentary_breakpoint_at_pc invalidates FRAME. */
frame = NULL;
- bp->thread = tp->num;
+ bp->thread = tp->global_id;
inferior_thread ()->control.exception_resume_breakpoint = bp;
}
}
@@ -7547,7 +7547,7 @@ insert_exception_resume_from_probe (struct thread_info *tp,
bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
handler, bp_exception_resume);
- bp->thread = tp->num;
+ bp->thread = tp->global_id;
inferior_thread ()->control.exception_resume_breakpoint = bp;
}
@@ -7905,7 +7905,7 @@ print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
ui_out_text (uiout, "\n[");
ui_out_field_string (uiout, "thread-name",
target_pid_to_str (t->ptid));
- ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num);
+ ui_out_field_fmt (uiout, "thread-id", "] #%d", t->global_id);
ui_out_text (uiout, " stopped");
}
else
@@ -662,7 +662,7 @@ mi_cmd_var_update_iter (struct varobj *var, void *data_pointer)
thread_stopped = 1;
else
{
- struct thread_info *tp = find_thread_id (thread_id);
+ struct thread_info *tp = find_thread_global_id (thread_id);
if (tp)
thread_stopped = is_stopped (tp->ptid);
@@ -362,7 +362,7 @@ mi_new_thread (struct thread_info *t)
fprintf_unfiltered (mi->event_channel,
"thread-created,id=\"%d\",group-id=\"i%d\"",
- t->num, inf->num);
+ t->global_id, inf->num);
gdb_flush (mi->event_channel);
}
@@ -383,7 +383,7 @@ mi_thread_exit (struct thread_info *t, int silent)
target_terminal_ours ();
fprintf_unfiltered (mi->event_channel,
"thread-exited,id=\"%d\",group-id=\"i%d\"",
- t->num, inf->num);
+ t->global_id, inf->num);
gdb_flush (mi->event_channel);
do_cleanups (old_chain);
@@ -617,15 +617,14 @@ mi_on_normal_stop (struct bpstats *bs, int print_frame)
print_stop_event (mi->cli_uiout);
}
- ui_out_field_int (mi_uiout, "thread-id",
- pid_to_thread_id (inferior_ptid));
+ tp = inferior_thread ();
+ ui_out_field_int (mi_uiout, "thread-id", tp->global_id);
if (non_stop)
{
struct cleanup *back_to = make_cleanup_ui_out_list_begin_end
(mi_uiout, "stopped-threads");
- ui_out_field_int (mi_uiout, NULL,
- pid_to_thread_id (inferior_ptid));
+ ui_out_field_int (mi_uiout, NULL, tp->global_id);
do_cleanups (back_to);
}
else
@@ -859,7 +858,7 @@ mi_output_running_pid (struct thread_info *info, void *arg)
if (ptid_get_pid (*ptid) == ptid_get_pid (info->ptid))
fprintf_unfiltered (raw_stdout,
"*running,thread-id=\"%d\"\n",
- info->num);
+ info->global_id);
return 0;
}
@@ -925,7 +924,8 @@ mi_on_resume (ptid_t ptid)
struct thread_info *ti = find_thread_ptid (ptid);
gdb_assert (ti);
- fprintf_unfiltered (raw_stdout, "*running,thread-id=\"%d\"\n", ti->num);
+ fprintf_unfiltered (raw_stdout, "*running,thread-id=\"%d\"\n",
+ ti->global_id);
}
if (!running_result_record_printed && mi_proceeded)
@@ -2165,7 +2165,7 @@ mi_execute_command (const char *cmd, int from_tty)
{
struct thread_info *ti = inferior_thread ();
- report_change = (ti->num != command->thread);
+ report_change = (ti->global_id != command->thread);
}
if (report_change)
@@ -2175,7 +2175,7 @@ mi_execute_command (const char *cmd, int from_tty)
target_terminal_ours ();
fprintf_unfiltered (mi->event_channel,
"thread-selected,id=\"%d\"",
- ti->num);
+ ti->global_id);
gdb_flush (mi->event_channel);
}
}
@@ -2226,7 +2226,7 @@ mi_cmd_execute (struct mi_parse *parse)
if (parse->thread != -1)
{
- struct thread_info *tp = find_thread_id (parse->thread);
+ struct thread_info *tp = find_thread_global_id (parse->thread);
if (!tp)
error (_("Invalid thread id: %d"), parse->thread);
@@ -203,7 +203,7 @@ bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure)
if (! gdb_py_int_as_long (newvalue, &id))
return -1;
- if (! valid_thread_id (id))
+ if (!valid_global_thread_id (id))
{
PyErr_SetString (PyExc_RuntimeError,
_("Invalid thread ID."));
@@ -221,7 +221,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
if (PyErr_Occurred ())
return -1;
- thread = pid_to_thread_id (inferior_ptid);
+ thread = ptid_to_global_thread_id (inferior_ptid);
if (thread == 0)
{
PyErr_SetString (PyExc_ValueError,
@@ -115,6 +115,8 @@ thpy_set_name (PyObject *self, PyObject *newvalue, void *ignore)
return 0;
}
+/* Getter for InferiorThread.num. */
+
static PyObject *
thpy_get_num (PyObject *self, void *closure)
{
@@ -122,7 +124,19 @@ thpy_get_num (PyObject *self, void *closure)
THPY_REQUIRE_VALID (thread_obj);
- return PyLong_FromLong (thread_obj->thread->num);
+ return PyLong_FromLong (thread_obj->thread->per_inf_id);
+}
+
+/* Getter for InferiorThread.global_num. */
+
+static PyObject *
+thpy_get_global_num (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ return PyLong_FromLong (thread_obj->thread->global_id);
}
/* Getter for InferiorThread.ptid -> (pid, lwp, tid).
@@ -140,6 +154,18 @@ thpy_get_ptid (PyObject *self, void *closure)
return gdbpy_create_ptid_object (thread_obj->thread->ptid);
}
+/* Getter for InferiorThread.inferior -> Inferior. */
+
+static PyObject *
+thpy_get_inferior (PyObject *self, void *ignore)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ return inferior_to_inferior_object (thread_obj->thread->inf);
+}
+
/* Implementation of InferiorThread.switch ().
Makes this the GDB selected thread. */
@@ -282,9 +308,14 @@ static PyGetSetDef thread_object_getset[] =
{
{ "name", thpy_get_name, thpy_set_name,
"The name of the thread, as set by the user or the OS.", NULL },
- { "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL },
+ { "num", thpy_get_num, NULL,
+ "Per-inferior ID of the thread, as assigned by GDB.", NULL },
+ { "global_num", thpy_get_global_num, NULL,
+ "Global ID of the thread, as assigned by GDB.", NULL },
{ "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.",
NULL },
+ { "inferior", thpy_get_inferior, NULL,
+ "The Inferior object this thread belongs to.", NULL },
{ NULL }
};
@@ -218,7 +218,7 @@ record_btrace_open (const char *args, int from_tty)
disable_chain = make_cleanup (null_cleanup, NULL);
ALL_NON_EXITED_THREADS (tp)
- if (args == NULL || *args == 0 || number_is_in_list (args, tp->num))
+ if (args == NULL || *args == 0 || number_is_in_list (args, tp->global_id))
{
btrace_enable (tp, &record_btrace_conf);
@@ -438,8 +438,8 @@ record_btrace_info (struct target_ops *self)
}
printf_unfiltered (_("Recorded %u instructions in %u functions (%u gaps) "
- "for thread %d (%s).\n"), insns, calls, gaps,
- tp->num, target_pid_to_str (tp->ptid));
+ "for thread %s (%s).\n"), insns, calls, gaps,
+ print_thread_id (tp), target_pid_to_str (tp->ptid));
if (btrace_is_replaying (tp))
printf_unfiltered (_("Replay in progress. At instruction %u.\n"),
@@ -1864,7 +1864,7 @@ record_btrace_resume_thread (struct thread_info *tp,
{
struct btrace_thread_info *btinfo;
- DEBUG ("resuming thread %d (%s): %x (%s)", tp->num,
+ DEBUG ("resuming thread %s (%s): %x (%s)", print_thread_id (tp),
target_pid_to_str (tp->ptid), flag, btrace_thread_flag_to_str (flag));
btinfo = &tp->btrace;
@@ -2131,7 +2131,8 @@ record_btrace_cancel_resume (struct thread_info *tp)
if (flags == 0)
return;
- DEBUG ("cancel resume thread %d (%s): %x (%s)", tp->num,
+ DEBUG ("cancel resume thread %s (%s): %x (%s)",
+ print_thread_id (tp),
target_pid_to_str (tp->ptid), flags,
btrace_thread_flag_to_str (flags));
@@ -2354,7 +2355,7 @@ record_btrace_step_thread (struct thread_info *tp)
flags = btinfo->flags & (BTHR_MOVE | BTHR_STOP);
btinfo->flags &= ~(BTHR_MOVE | BTHR_STOP);
- DEBUG ("stepping thread %d (%s): %x (%s)", tp->num,
+ DEBUG ("stepping thread %s (%s): %x (%s)", print_thread_id (tp),
target_pid_to_str (tp->ptid), flags,
btrace_thread_flag_to_str (flags));
@@ -2563,7 +2564,8 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
/* We moved the replay position but did not update registers. */
registers_changed_ptid (eventing->ptid);
- DEBUG ("wait ended by thread %d (%s): %s", eventing->num,
+ DEBUG ("wait ended by thread %s (%s): %s",
+ print_thread_id (eventing),
target_pid_to_str (eventing->ptid),
target_waitstatus_to_string (status));
@@ -3880,7 +3880,9 @@ process_initial_stop_replies (int from_tty)
&& thread->suspend.waitstatus_pending_p)
selected = thread;
- if (lowest_stopped == NULL || thread->num < lowest_stopped->num)
+ if (lowest_stopped == NULL
+ || thread->inf->num < lowest_stopped->inf->num
+ || thread->per_inf_id < lowest_stopped->per_inf_id)
lowest_stopped = thread;
if (non_stop)
@@ -2157,6 +2157,8 @@ target_pre_inferior (int from_tty)
the inferior was attached to. */
current_inferior ()->attach_flag = 0;
+ current_inferior ()->highest_thread_num = 0;
+
agent_capability_invalidate ();
}
@@ -590,7 +590,7 @@ gdb_test "break $bp_location12 thread 999" "Unknown thread 999.*" \
"thread-specific breakpoint on non-existent thread disallowed"
gdb_test "break $bp_location12 thread foo" \
- "Junk after thread keyword.*" \
+ "Bad thread spec.*" \
"thread-specific breakpoint on bogus thread ID disallowed"
# Verify that GDB responds gracefully to a breakpoint command with
@@ -587,6 +587,8 @@ set show_conv_list \
{$_sdata = void} \
{$_siginfo = void} \
{$_thread = 0} \
+ {$_gthread = 0} \
+ {$_inferior = 1} \
{$_exception = <error: No frame selected>} \
{$_probe_argc = <error: No frame selected>} \
{$_probe_arg0 = <error: No frame selected>} \
@@ -347,7 +347,7 @@ gdb_test "hbreak $bp_location12 thread 999" "Unknown thread 999.*" \
"thread-specific hardware breakpoint on non-existent thread disallowed"
gdb_test "hbreak $bp_location12 thread foo" \
- "Junk after thread keyword.*" \
+ "Bad thread spec.*" \
"thread-specific hardware breakpoint on bogus thread ID disallowed"
# Verify that GDB responds gracefully to a breakpoint command with
@@ -389,7 +389,7 @@ gdb_test "break $bp_location12 thread 999" "Unknown thread 999.*" \
"thread-specific breakpoint on non-existent thread disallowed"
gdb_test "break $bp_location12 thread foo" \
- "Junk after thread keyword.*" \
+ "Bad thread spec.*" \
"thread-specific breakpoint on bogus thread ID disallowed"
# Verify that GDB responds gracefully to a breakpoint command with
@@ -46,7 +46,7 @@ if { ![runto main] } then {
return
}
-gdb_test "watch shared_var thread 0" "Unknown thread 0\." "Watchpoint on invalid thread"
+gdb_test "watch shared_var thread 0" "Bad thread spec.*" "Watchpoint on invalid thread"
gdb_test "watch shared_var thread" "A syntax error in expression, near `thread'\." "Invalid watch syntax"
set bpexitline [gdb_get_line_number "all threads started"]
@@ -54,16 +54,16 @@ with_test_prefix "trailing whitespace" {
# break {thread,task} NUMBER --> invalid thread/task
# break {thread,task} STUFF --> "junk" after keyword (STUFF is not numeric)
gdb_test "break thread 123" "Unknown thread 123\\."
-gdb_test "break thread foo" "Junk after thread keyword\\."
+gdb_test "break thread foo" "Bad thread spec 'foo'"
gdb_test "break task 123" "Unknown task 123\\."
gdb_test "break task foo" "Junk after task keyword\\."
gdb_breakpoint "thread if 0" "message"
# These are also NULL locations, but using a subsequent keyword
# as the "junk".
-gdb_test "break thread thread" "Junk after thread keyword\\."
-gdb_test "break thread task" "Junk after thread keyword\\."
-gdb_test "break thread if" "Junk after thread keyword\\."
+gdb_test "break thread thread" "Bad thread spec 'thread'"
+gdb_test "break thread task" "Bad thread spec 'task'"
+gdb_test "break thread if" "Bad thread spec 'if'"
gdb_test "break task task" "Junk after task keyword\\."
gdb_test "break task thread" "Junk after task keyword\\."
gdb_test "break task if" "Junk after task keyword\\."
@@ -44,12 +44,16 @@ if { [build_executable ${testfile}.exp ${exec3} "${srcfile3}" {debug}] == -1 } {
clean_restart ${exec1}
+gdb_test {print $_inferior} " = 1"
+
# Add an empty inferior, switch to it, and load a main executable into
# it.
gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2"
gdb_test "inferior 2" "Switching to inferior 2.*" "switch to inferior 2"
gdb_test "file ${binfile2}" ".*" "load ${exec2} file in inferior 2"
+gdb_test {print $_inferior} " = 2" "print \$_inferior after switching"
+
# Add a new inferior and load a main executable into it in one
# command.
gdb_test "add-inferior -exec ${binfile3}" \
@@ -36,4 +36,4 @@ gdb_test "inferior 2" "Switching to inferior 2.*" "switch to inferior 2"
# "info threads" while inferior 1 has execution and inferior 2 is not
# running yet should show inferior 1's thread, and give no error.
-gdb_test "info threads" "1 .* main .* at .*$srcfile:.*No selected thread.*"
+gdb_test "info threads" "1\.1 .* main .* at .*$srcfile:.*No selected thread.*"
new file mode 100644
@@ -0,0 +1,40 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2015 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 <unistd.h>
+#include <pthread.h>
+
+void *
+thread_function (void *arg)
+{
+ while (1)
+ sleep (1);
+}
+
+int
+main (void)
+{
+ pthread_t child_thread;
+ int i;
+
+ alarm (300);
+
+ pthread_create (&child_thread, NULL, thread_function, NULL);
+ pthread_join (child_thread, NULL);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,153 @@
+# Copyright 2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+load_lib gdb-python.exp
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} {pthreads debug}] } {
+ return -1
+}
+
+clean_restart ${testfile}
+
+if { ![runto_main] } then {
+ return -1
+}
+
+# "info threads" while there's only inferior 1 should show
+# single-number thread IDs.
+with_test_prefix "single inferior" {
+ gdb_test "info threads" " 1 .* main .* at .*$srcfile:.*"
+
+ gdb_test "thread" "Current thread is 1 .*"
+}
+
+# "info threads" while there are multiple inferior should show
+# expanded thread IDs.
+with_test_prefix "two inferiors" {
+ # Add another inferior.
+ gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2"
+
+ # Now that we'd added another inferior, thread IDs now show the
+ # inferior number.
+ gdb_test "info threads" " 1\.1 .* main .* at .*$srcfile:.*"
+
+ gdb_test "thread" "Current thread is 1\.1 .*"
+
+ gdb_test "inferior 2" "Switching to inferior 2 .*" "switch to inferior 2"
+ gdb_test "file ${binfile}" ".*" "load file in inferior 2"
+
+ runto_main
+
+ # Now that we'd added another inferior, thread IDs now show the
+ # inferior number.
+ gdb_test "info threads" \
+ [multi_line \
+ " 1\.1 .* main .* at .*$srcfile:.*" \
+ "\\* 2\.1 .* main .* at .*$srcfile:.*"] \
+ "info threads show inferior numbers"
+
+ gdb_test "thread" "Current thread is 2\.1 .*" \
+ "switch to thread using extended thread ID"
+
+ gdb_breakpoint "thread_function"
+
+ gdb_continue_to_breakpoint "once"
+ gdb_test "inferior 1" "Switching to inferior 1 .*"
+ gdb_continue_to_breakpoint "twice"
+
+ gdb_test "info threads" \
+ [multi_line \
+ " 1\.1 .*" \
+ "\\* 1\.2 .* thread_function .* at .*$srcfile:.*" \
+ " 2\.1 .*" \
+ " 2\.2 .* thread_function .* at .*$srcfile:.*"] \
+ "info threads again"
+
+ # Same, but show the global ID.
+ gdb_test "info threads -gid" \
+ [multi_line \
+ " 1\.1 +1 +.*" \
+ "\\* 1\.2 +4 +.* thread_function .* at .*$srcfile:.*" \
+ " 2\.1 +2 +.*" \
+ " 2\.2 +3 +.* thread_function .* at .*$srcfile:.*"]
+
+ # Confirm the convenience variables show the expected numbers.
+ gdb_test "p \$_thread == 2" " = 1"
+ gdb_test "p \$_gthread == 4" " = 1"
+
+ # Without an explicit inferior component, GDB defaults to the
+ # current inferior. Make sure we don't refer to a thread by
+ # global ID by mistake.
+ gdb_test "thread 4" "Unknown thread 1.4\\."
+
+ # If Python is configured, check that InferiorThread.global_num
+ # returns the expected number.
+ if { ![skip_python_tests] } {
+ gdb_py_test_silent_cmd "python t0 = gdb.selected_thread ()" "test gdb.selected_thread" 1
+ gdb_test "python print ('result = %s' % t0.num)" " = 2" "test InferiorThread.num"
+ gdb_test "python print ('result = %s' % t0.global_num)" " = 4" "test InferiorThread.global_num"
+ }
+}
+
+# Remove the second inferior and confirm that GDB goes back to showing
+# single-number thread IDs.
+with_test_prefix "back to one inferior" {
+ gdb_test "kill inferior 2" "" "kill inferior 2" "Kill the program being debugged.*" "y"
+ gdb_test "thread 1.1" "Switching to thread 1\.1 .*"
+ gdb_test "remove-inferior 2" ".*" "remove inferior 2"
+
+ # "info threads" while there's only inferior 1 should show
+ # single-number thread IDs.
+ gdb_test "info threads" \
+ [multi_line \
+ "\\* 1 .*" \
+ " 2 .* thread_function .* at .*$srcfile:.*"]
+
+ gdb_test "thread" "Current thread is 1 .*"
+}
+
+# Add another inferior and remove inferior 1. Since even though
+# there's a single inferior, it's number is not 1, GDB should show
+# extended thread IDs that include the inferior number.
+with_test_prefix "single-inferior but not initial" {
+ # Add another inferior.
+ gdb_test "add-inferior" "Added inferior 3.*" "add empty inferior"
+
+ # Now that we'd added another inferior, thread IDs should show the
+ # inferior number.
+ gdb_test "info threads" \
+ [multi_line \
+ "\\* 1\.1 .*" \
+ " 1\.2 .* thread_function .* at .*$srcfile:.*"] \
+ "info threads with multiple inferiors"
+
+ gdb_test "thread" "Current thread is 1\.1 .*"
+
+ gdb_test "inferior 3" "Switching to inferior 3 .*" "switch to inferior 3"
+ gdb_test "file ${binfile}" ".*" "load file in inferior 3"
+
+ runto_main
+
+ gdb_test "remove-inferior 1" ".*" "remove inferior 1"
+
+ # Even though we have a single inferior, its number is > 1, so
+ # thread IDs should show the inferior number.
+ gdb_test "info threads" " 3\.1 .* main .* at .*$srcfile:.*" \
+ "info threads with single inferior"
+
+ gdb_test "thread" "Current thread is 3\.1 .*" "thread again"
+}
@@ -41,9 +41,13 @@ if ![runto_main] then {
gdb_py_test_silent_cmd "python t0 = gdb.selected_thread ()" "test gdb.selected_thread" 1
gdb_test "python print (t0)" "\\<gdb.InferiorThread object at 0x\[\[:xdigit:\]\]+>" "verify InferiorThread object"
-gdb_test "python print ('result = %s' % t0.num)" " = \[0-9\]+" "test Inferior.num"
+gdb_test "python print ('result = %s' % t0.num)" " = 1" "test InferiorThread.num"
+gdb_test "python print ('result = %s' % t0.global_num)" " = 1" "test InferiorThread.global_num"
gdb_test "python print ('result = %s' % str (t0.ptid))" " = \\(\[0-9\]+, \[0-9\]+, \[0-9\]+\\)" "test InferiorThread.ptid"
+gdb_py_test_silent_cmd "python i0 = t0.inferior" "test InferiorThread.inferior" 1
+gdb_test "python print ('result = %s' % i0.num)" " = 1" "test Inferior.num"
+
gdb_py_test_silent_cmd "python name = gdb.selected_thread().name" \
"get supplied name of current thread" 1
gdb_py_test_silent_cmd "python gdb.selected_thread().name = 'hibob'" \
@@ -66,7 +66,10 @@ clean_restart ${binfile}
gdb_test_no_output "set print sevenbit-strings"
gdb_test_no_output "set width 0"
+# As this test only runs a single inferior, $_thread and $_gthread
+# should match throughout.
gdb_test {print $_thread} ".* = 0" "thread var when not running"
+gdb_test {print $_gthread} ".* = 0" "gthread var when not running"
runto_main
@@ -82,6 +85,7 @@ if {[llength $threads] == 0} {
}
gdb_test {print $_thread} ".* = [lindex $threads 0]" "thread var in main"
+gdb_test {print $_gthread} ".* = [lindex $threads 0]" "gthread var in main"
gdb_test_multiple "break $line thread [lindex $threads 0]" \
"breakpoint $line main thread" {
@@ -120,6 +124,7 @@ if { $this_breakpoint != -1 } {
if { $this_thread != -1 } {
gdb_test {print $_thread} ".* = $this_thread" "thread var at break"
+ gdb_test {print $_gthread} ".* = $this_thread" "gthread var at break"
} else {
untested "thread var at break"
}
@@ -182,7 +182,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_id);
bpstat_clear (&tp->control.stop_bpstat);
@@ -230,12 +230,18 @@ init_thread_list (void)
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_id = ++highest_thread_num;
+ tp->inf = inf;
+ tp->per_inf_id = ++inf->highest_thread_num;
if (thread_list == NULL)
thread_list = tp;
@@ -260,6 +266,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 +285,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 +309,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 +489,24 @@ delete_thread_silent (ptid_t ptid)
}
struct thread_info *
-find_thread_id (int num)
+find_thread_global_id (int id)
{
struct thread_info *tp;
for (tp = thread_list; tp; tp = tp->next)
- if (tp->num == num)
+ if (tp->global_id == id)
+ return tp;
+
+ return NULL;
+}
+
+static struct thread_info *
+find_thread_id (struct inferior *inf, int id)
+{
+ struct thread_info *tp;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (tp->inf == inf && tp->per_inf_id == id)
return tp;
return NULL;
@@ -548,38 +568,38 @@ thread_count (void)
}
int
-valid_thread_id (int num)
+valid_global_thread_id (int id)
{
struct thread_info *tp;
for (tp = thread_list; tp; tp = tp->next)
- if (tp->num == num)
+ if (tp->global_id == 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_id;
return 0;
}
ptid_t
-thread_id_to_pid (int num)
+global_thread_id_to_ptid (int num)
{
- struct thread_info *thread = find_thread_id (num);
+ struct thread_info *thread = find_thread_global_id (num);
if (thread)
return thread->ptid;
else
- return pid_to_ptid (-1);
+ return minus_one_ptid;
}
int
@@ -604,7 +624,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_id < ret->global_id)
ret = tp;
return ret;
@@ -688,10 +708,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_id;
num++;
- ui_out_field_int (uiout, "thread-id", tp->num);
+ ui_out_field_int (uiout, "thread-id", tp->global_id);
}
do_cleanups (cleanup_chain);
@@ -1105,25 +1125,51 @@ 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)
+static int
+should_print_thread (const char *requested_threads, int global_ids,
+ int pid, struct thread_info *thr)
+{
+ if (pid != -1 && ptid_get_pid (thr->ptid) != pid
+ && requested_threads != NULL && *requested_threads != '\0')
+ error (_("Requested thread not found in requested process"));
+
+ if (requested_threads != NULL && *requested_threads != '\0')
+ {
+ int id = global_ids ? thr->global_id : thr->per_inf_id;
+
+ if (number_is_in_list (requested_threads, id))
+ {
+ if (pid != -1 && ptid_get_pid (thr->ptid) != pid)
+ error (_("Requested thread not found in requested process"));
+
+ return 1;
+ }
+
+ return 0;
+ }
+ else if (pid != -1)
+ return ptid_get_pid (thr->ptid) == pid;
+ else if (thr->state == THREAD_EXITED)
+ return 0;
+ else
+ return 1;
+}
+
+/* Like print_thread_info, but in addition, GLOBAL_IDS specified
+ whether REQUESTED_THREADS indicated 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;
update_thread_list ();
current_ptid = inferior_ptid;
@@ -1142,13 +1188,7 @@ 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, global_ids, pid, tp))
continue;
++n_threads;
@@ -1165,34 +1205,37 @@ 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);
}
+ ALL_INFERIORS (inf)
+ {
+
for (tp = thread_list; tp; tp = tp->next)
{
struct cleanup *chain2;
int core;
- if (!number_is_in_list (requested_threads, tp->num))
+ if (inf->pid != ptid_get_pid (tp->ptid))
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_id;
- if (tp->state == THREAD_EXITED)
+ if (!should_print_thread (requested_threads, global_ids, pid, tp))
continue;
chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
@@ -1213,7 +1256,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_id);
/* For the CLI, we stuff everything into the target-id field.
This is a gross hack to make the output come out looking
@@ -1282,6 +1329,7 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
do_cleanups (chain2);
}
+ }
/* Restores the current thread and the frame selected before
the "info threads" command. */
@@ -1289,27 +1337,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
+The current thread <Thread ID %s> has terminated. See `help thread'.\n",
+ print_thread_id (inferior_thread ()));
+ else if (thread_list != NULL
&& ptid_equal (current_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. */
+
+void
+print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
+{
+ print_thread_info_1 (uiout, requested_threads, 1, pid, 0);
+}
- Optional ARG is a thread id, or list of thread ids.
+/* Implementation of the "info threads" command.
Note: this has the drawback that it _really_ switches
threads, which frees the frame cache. A no-side
@@ -1318,7 +1374,16 @@ No selected thread. See `help thread'.\n");
static void
info_threads_command (char *arg, int from_tty)
{
- print_thread_info (current_uiout, arg, -1);
+ int show_global_ids = 0;
+
+ if (arg != NULL
+ && check_for_argument (&arg, "-gid", sizeof ("-gid") - 1))
+ {
+ arg = skip_spaces (arg);
+ show_global_ids = 1;
+ }
+
+ print_thread_info_1 (current_uiout, arg, 0, -1, show_global_ids);
}
/* See gdbthread.h. */
@@ -1593,18 +1658,24 @@ make_cleanup_restore_current_thread (void)
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, and then by per-inferior ID). 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;
- return ((((*ap)->num > (*bp)->num) - ((*ap)->num < (*bp)->num))
+ 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 (((a->per_inf_id > b->per_inf_id)
+ - (a->per_inf_id < b->per_inf_id))
* (tp_array_compar_ascending ? +1 : -1));
}
@@ -1678,8 +1749,8 @@ thread_apply_all_command (char *cmd, int from_tty)
if (thread_alive (tp_array[k]))
{
switch_to_thread (tp_array[k]->ptid);
- printf_filtered (_("\nThread %d (%s):\n"),
- tp_array[k]->num,
+ printf_filtered (_("\nThread %s (%s):\n"),
+ print_thread_id (tp_array[k]),
target_pid_to_str (inferior_ptid));
execute_command (cmd, from_tty);
@@ -1691,6 +1762,18 @@ thread_apply_all_command (char *cmd, int from_tty)
do_cleanups (old_chain);
}
+const char *
+print_thread_id (struct thread_info *thr)
+{
+ char *s = get_print_cell ();
+
+ if (inferior_list->next != NULL || inferior_list->num != 1)
+ xsnprintf (s, PRINT_CELL_SIZE, "%d.%d", thr->inf->num, thr->per_inf_id);
+ else
+ xsnprintf (s, PRINT_CELL_SIZE, "%d", thr->per_inf_id);
+ return s;
+}
+
static void
thread_apply_command (char *tidlist, int from_tty)
{
@@ -1722,7 +1805,7 @@ thread_apply_command (char *tidlist, int from_tty)
make_cleanup_restore_current_thread ();
- tp = find_thread_id (start);
+ tp = find_thread_id (current_inferior (), start);
if (!tp)
warning (_("Unknown thread %d."), start);
@@ -1732,7 +1815,7 @@ thread_apply_command (char *tidlist, int from_tty)
{
switch_to_thread (tp->ptid);
- printf_filtered (_("\nThread %d (%s):\n"), tp->num,
+ printf_filtered (_("\nThread %s (%s):\n"), print_thread_id (tp),
target_pid_to_str (inferior_ptid));
execute_command (cmd, from_tty);
@@ -1757,13 +1840,15 @@ thread_command (char *tidstr, int from_tty)
if (target_has_stack)
{
+ struct thread_info *tp = inferior_thread ();
+
if (is_exited (inferior_ptid))
- printf_filtered (_("[Current thread is %d (%s) (exited)]\n"),
- pid_to_thread_id (inferior_ptid),
+ printf_filtered (_("[Current thread is %s (%s) (exited)]\n"),
+ print_thread_id (tp),
target_pid_to_str (inferior_ptid));
else
- printf_filtered (_("[Current thread is %d (%s)]\n"),
- pid_to_thread_id (inferior_ptid),
+ printf_filtered (_("[Current thread is %s (%s)]\n"),
+ print_thread_id (tp),
target_pid_to_str (inferior_ptid));
}
else
@@ -1812,32 +1897,32 @@ thread_find_command (char *arg, int from_tty)
{
if (tp->name != NULL && re_exec (tp->name))
{
- printf_filtered (_("Thread %d has name '%s'\n"),
- tp->num, tp->name);
+ printf_filtered (_("Thread %s has name '%s'\n"),
+ print_thread_id (tp), tp->name);
match++;
}
tmp = target_thread_name (tp);
if (tmp != NULL && re_exec (tmp))
{
- printf_filtered (_("Thread %d has target name '%s'\n"),
- tp->num, tmp);
+ printf_filtered (_("Thread %s has target name '%s'\n"),
+ print_thread_id (tp), tmp);
match++;
}
tmp = target_pid_to_str (tp->ptid);
if (tmp != NULL && re_exec (tmp))
{
- printf_filtered (_("Thread %d has target id '%s'\n"),
- tp->num, tmp);
+ printf_filtered (_("Thread %s has target id '%s'\n"),
+ print_thread_id (tp), tmp);
match++;
}
tmp = target_extra_thread_info (tp);
if (tmp != NULL && re_exec (tmp))
{
- printf_filtered (_("Thread %d has extra info '%s'\n"),
- tp->num, tmp);
+ printf_filtered (_("Thread %s has extra info '%s'\n"),
+ print_thread_id (tp), tmp);
match++;
}
}
@@ -1856,31 +1941,105 @@ show_print_thread_events (struct ui_file *file, int from_tty,
value);
}
-static int
-do_captured_thread_select (struct ui_out *uiout, void *tidstr)
+struct thread_info *
+parse_thread_id (const char *tidstr, const char **end)
{
- int num;
+ const char *number = tidstr;
+ const char *dot, *p1;
struct thread_info *tp;
+ struct inferior *inf;
+ int thr_num;
+ int explicit_inf_id = 0;
- num = value_as_long (parse_and_eval ((const char *) tidstr));
+ dot = strchr (number, '.');
- tp = find_thread_id (num);
+ if (dot != NULL)
+ {
+ /* Parse number to the left of the dot. */
+ int inf_num;
- if (!tp)
- error (_("Thread ID %d not known."), num);
+ p1 = number;
+ inf_num = get_number_trailer (&p1, '.');
+ if (inf_num == 0)
+ error (_("Bad thread spec '%s'"), number);
+
+ inf = find_inferior_id (inf_num);
+ if (inf == NULL)
+ error (_("No inferior number '%d'"), inf_num);
+
+ explicit_inf_id = 1;
+ p1 = dot + 1;
+ }
+ else
+ {
+ inf = current_inferior ();
+
+ p1 = number;
+ }
+
+ thr_num = get_number_const (&p1);
+ if (thr_num == 0)
+ error (_("Bad thread spec '%s'"), number);
+
+ ALL_THREADS (tp)
+ {
+ if (ptid_get_pid (tp->ptid) == inf->pid
+ && tp->per_inf_id == thr_num)
+ break;
+ }
+
+ if (tp == NULL)
+ {
+ if (inferior_list->next != NULL || inferior_list->num != 1
+ || explicit_inf_id)
+ error (_("Unknown thread %d.%d."), inf->num, thr_num);
+ else
+ error (_("Unknown thread %d."), thr_num);
+ }
+
+ if (end != NULL)
+ *end = p1;
+
+ return tp;
+}
+
+static int
+do_captured_thread_select (struct ui_out *uiout, void *tidstr_v)
+{
+ const char *tidstr = tidstr_v;
+ struct thread_info *tp;
+
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ int num = value_as_long (parse_and_eval (tidstr));
+
+ 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_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid));
- 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_id);
+ else
+ {
+ ui_out_text (uiout, "[Switching to thread ");
+ ui_out_text (uiout, print_thread_id (inferior_thread ()));
+ 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. */
@@ -1934,17 +2093,44 @@ 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 id. Return a value of
+ 0 if no thread is selected. If GLOBAL is true, return the thread's
+ global ID. Otherwise return the per-inferior ID. */
static struct value *
-thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
- void *ignore)
+thread_id_make_value_helper (struct gdbarch *gdbarch, int global)
{
struct thread_info *tp = find_thread_ptid (inferior_ptid);
+ int int_val;
+
+ if (tp == NULL)
+ int_val = 0;
+ else if (global)
+ int_val = tp->global_id;
+ else
+ int_val = tp->per_inf_id;
- return value_from_longest (builtin_type (gdbarch)->builtin_int,
- (tp ? tp->num : 0));
+ return value_from_longest (builtin_type (gdbarch)->builtin_int, int_val);
+}
+
+/* Return a new value for the selected thread's id. 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,
+ void *ignore)
+{
+ return thread_id_make_value_helper (gdbarch, 0);
+}
+
+/* Return a new value for the selected thread's global id. Return a
+ value of 0 if no thread is selected, or no threads exist. */
+
+static struct value *
+global_thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
+{
+ return thread_id_make_value_helper (gdbarch, 1);
}
/* Commands with a prefix of `thread'. */
@@ -1959,6 +2145,15 @@ static const struct internalvar_funcs thread_funcs =
NULL
};
+/* Implementation of `gthread' variable. */
+
+static const struct internalvar_funcs gthread_funcs =
+{
+ global_thread_id_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_thread (void)
{
@@ -1966,9 +2161,10 @@ _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."));
+Usage: info threads [-gid] [ID]...\n\
+-gid: Show global thread IDs.\n\
+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\
@@ -2011,6 +2207,7 @@ Show printing of thread events (such as thread start and exit)."), NULL,
&setprintlist, &showprintlist);
create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
+ create_internalvar_type_lazy ("_gthread", >hread_funcs, NULL);
observer_attach_thread_ptid_changed (restore_current_thread_ptid_changed);
}
@@ -78,7 +78,7 @@ struct varobj_root
not NULL. */
struct frame_id frame;
- /* The thread ID that this varobj_root belong to. This field
+ /* The global thread ID that this varobj_root belong to. This field
is only valid if valid_block is not NULL.
When not 0, indicates which thread 'frame' belongs to.
When 0, indicates that the thread list was empty when the varobj_root
@@ -380,7 +380,7 @@ varobj_create (char *objname,
error (_("Failed to find the specified frame"));
var->root->frame = get_frame_id (fi);
- var->root->thread_id = pid_to_thread_id (inferior_ptid);
+ var->root->thread_id = ptid_to_global_thread_id (inferior_ptid);
old_id = get_frame_id (get_selected_frame (NULL));
select_frame (fi);
}
@@ -2363,8 +2363,9 @@ value_of_root_1 (struct varobj **var_handle)
}
else
{
- ptid_t ptid = thread_id_to_pid (var->root->thread_id);
- if (in_thread_list (ptid))
+ ptid_t ptid = global_thread_id_to_ptid (var->root->thread_id);
+
+ if (!ptid_equal (minus_one_ptid, ptid))
{
switch_to_thread (ptid);
within_scope = check_scope (var);