diff options
Diffstat (limited to 'gdb/thread.c')
-rw-r--r-- | gdb/thread.c | 340 |
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\ |