+ return 1;
+}
+
+/* Return the string to display in "info threads"'s "Target Id"
+ column, for TP. */
+
+static std::string
+thread_target_id_str (thread_info *tp)
+{
+ std::string target_id = target_pid_to_str (tp->ptid);
+ const char *extra_info = target_extra_thread_info (tp);
+ const char *name = tp->name != nullptr ? tp->name : target_thread_name (tp);
+
+ if (extra_info != nullptr && name != nullptr)
+ return string_printf ("%s \"%s\" (%s)", target_id.c_str (), name,
+ extra_info);
+ else if (extra_info != nullptr)
+ return string_printf ("%s (%s)", target_id.c_str (), extra_info);
+ else if (name != nullptr)
+ return string_printf ("%s \"%s\"", target_id.c_str (), name);
+ else
+ return target_id;
+}
+
+/* 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, const char *requested_threads,
+ int global_ids, int pid,
+ int show_global_ids)
+{
+ int default_inf_num = current_inferior ()->num;
+
+ update_thread_list ();
+
+ /* Whether we saw any thread. */
+ bool any_thread = false;
+ /* Whether the current thread is exited. */
+ bool current_exited = false;
+
+ thread_info *current_thread = (inferior_ptid != null_ptid
+ ? inferior_thread () : NULL);
+
+ {
+ /* For backward compatibility, we make a list for MI. A table is
+ preferable for the CLI, though, because it shows table
+ headers. */
+ gdb::optional<ui_out_emit_list> list_emitter;
+ gdb::optional<ui_out_emit_table> table_emitter;
+
+ /* We'll be switching threads temporarily below. */
+ scoped_restore_current_thread restore_thread;
+
+ if (uiout->is_mi_like_p ())
+ list_emitter.emplace (uiout, "threads");
+ else
+ {
+ int n_threads = 0;
+ /* The width of the "Target Id" column. Grown below to
+ accommodate the largest entry. */
+ size_t target_id_col_width = 17;
+
+ for (thread_info *tp : all_threads ())
+ {
+ if (!should_print_thread (requested_threads, default_inf_num,
+ global_ids, pid, tp))
+ continue;
+
+ if (!uiout->is_mi_like_p ())
+ {
+ /* Switch inferiors so we're looking at the right
+ target stack. */
+ switch_to_inferior_no_thread (tp->inf);
+
+ target_id_col_width
+ = std::max (target_id_col_width,
+ thread_target_id_str (tp).size ());
+ }
+
+ ++n_threads;
+ }
+
+ if (n_threads == 0)
+ {
+ if (requested_threads == NULL || *requested_threads == '\0')
+ uiout->message (_("No threads.\n"));
+ else
+ uiout->message (_("No threads match '%s'.\n"),
+ requested_threads);
+ return;
+ }
+
+ table_emitter.emplace (uiout, show_global_ids ? 5 : 4,
+ n_threads, "threads");
+
+ uiout->table_header (1, ui_left, "current", "");
+ uiout->table_header (4, ui_left, "id-in-tg", "Id");
+ if (show_global_ids)
+ uiout->table_header (4, ui_left, "id", "GId");
+ uiout->table_header (target_id_col_width, ui_left,
+ "target-id", "Target Id");
+ uiout->table_header (1, ui_left, "frame", "Frame");
+ uiout->table_body ();
+ }
+
+ for (inferior *inf : all_inferiors ())
+ for (thread_info *tp : inf->threads ())