Change inferior thread list to be a thread map
authorSimon Marchi <simon.marchi@efficios.com>
Thu, 19 Dec 2019 19:19:41 +0000 (14:19 -0500)
committerSimon Marchi <simon.marchi@efficios.com>
Thu, 19 Dec 2019 19:20:52 +0000 (14:20 -0500)
Remove the inferior::thread_list linked list, replace with
inferior::thread_map, an std::map indexed by ptid.  This should make it
faster to look up a thread from its ptid.

gdb/gdbarch-selftests.c
gdb/gdbthread.h
gdb/inferior.c
gdb/inferior.h
gdb/mi/mi-main.c
gdb/regcache.c
gdb/remote.c
gdb/thread-iter.c
gdb/thread-iter.h
gdb/thread-map.h [new file with mode: 0644]
gdb/thread.c

index 0942050479bd82e59ebf7f1ebf0c3feb1b71742c..1a33f5196122ff892f1ac1021c2b577ef741d728 100644 (file)
@@ -86,9 +86,7 @@ register_to_value_test (struct gdbarch *gdbarch)
   mock_inferior.gdbarch = gdbarch;
   mock_inferior.aspace = &mock_aspace;
   thread_info mock_thread (&mock_inferior, mock_ptid);
-
-  scoped_restore restore_thread_list
-    = make_scoped_restore (&mock_inferior.thread_list, &mock_thread);
+  mock_inferior.thread_map[mock_ptid] = &mock_thread;
 
   /* Add the mock inferior to the inferior list so that look ups by
      target+ptid can find it.  */
index 370141e68885370af7099a1e329763eabbbf0d79..8d5981a2ef018c7b63c9f99a358d1f0eedd91074 100644 (file)
@@ -251,7 +251,6 @@ public:
   /* Mark this thread as running and notify observers.  */
   void set_running (bool running);
 
-  struct thread_info *next = NULL;
   ptid_t ptid;                 /* "Actual process id";
                                    In fact, this may be overloaded with 
                                    kernel thread id, etc.  */
@@ -429,14 +428,21 @@ extern struct thread_info *add_thread_silent (ptid_t ptid);
 extern struct thread_info *add_thread_with_info (ptid_t ptid,
                                                 struct private_thread_info *);
 
-/* Delete an existing thread list entry.  */
+/* Delete an existing thread, removing the entry from its inferior's thread
+   map.  */
 extern void delete_thread (struct thread_info *thread);
 
+/* Like the above, but don't remove the entry from the inferior thread map.  */
+extern void delete_thread_noremove(struct thread_info *thread);
+
 /* Delete an existing thread list entry, and be quiet about it.  Used
    after the process this thread having belonged to having already
    exited, for example.  */
 extern void delete_thread_silent (struct thread_info *thread);
 
+/* Like the above, but don't remove the entry from the inferior thread map.  */
+extern void delete_thread_silent_noremove (thread_info *thread);
+
 /* Delete a step_resume_breakpoint from the thread database.  */
 extern void delete_step_resume_breakpoint (struct thread_info *);
 
index 87df193ac392eef2fc2882c1681611057ddc6b07..d268d031e2ca60dfd6276cebae747fd8d7296a10 100644 (file)
@@ -148,8 +148,8 @@ delete_inferior (struct inferior *todel)
   if (!inf)
     return;
 
-  for (thread_info *tp : inf->threads_safe ())
-    delete_thread_silent (tp);
+  for (thread_info *tp : inf->threads ())
+    delete_thread_silent_noremove (tp);
 
   if (infprev)
     infprev->next = inf->next;
@@ -180,14 +180,16 @@ exit_inferior_1 (struct inferior *inftoex, int silent)
   if (!inf)
     return;
 
-  for (thread_info *tp : inf->threads_safe ())
+  for (thread_info *tp : inf->threads ())
     {
       if (silent)
-       delete_thread_silent (tp);
+       delete_thread_silent_noremove (tp);
       else
-       delete_thread (tp);
+       delete_thread_noremove (tp);
     }
 
+  inf->thread_map.clear ();
+
   gdb::observers::inferior_exit.notify (inf);
 
   inf->pid = 0;
@@ -590,7 +592,7 @@ inferior_command (const char *args, int from_tty)
     {
       if (inf != current_inferior ())
        {
-         thread_info *tp = any_thread_of_inferior (inf);
+         thread_info *tp = first_thread_of_inferior (inf);
          if (tp == NULL)
            error (_("Inferior has no threads."));
 
index 3bd9e8c3d747bec12c6c17a430970655022c0f6c..f4b79a68cf80725a26a9350a680584f3caad5296 100644 (file)
@@ -55,6 +55,7 @@ struct thread_info;
 
 #include "gdbsupport/common-inferior.h"
 #include "gdbthread.h"
+#include "thread-map.h"
 
 struct infcall_suspend_state;
 struct infcall_control_state;
@@ -343,7 +344,7 @@ public:
   struct inferior *next = NULL;
 
   /* This inferior's thread list.  */
-  thread_info *thread_list = nullptr;
+  ptid_thread_map thread_map;
 
   /* Returns a range adapter covering the inferior's threads,
      including exited threads.  Used like this:
@@ -351,8 +352,8 @@ public:
        for (thread_info *thr : inf->threads ())
         { .... }
   */
-  inf_threads_range threads ()
-  { return inf_threads_range (this->thread_list); }
+  all_thread_map_range threads ()
+  { return all_thread_map_range (this->thread_map); }
 
   /* Returns a range adapter covering the inferior's non-exited
      threads.  Used like this:
@@ -360,19 +361,8 @@ public:
        for (thread_info *thr : inf->non_exited_threads ())
         { .... }
   */
-  inf_non_exited_threads_range non_exited_threads ()
-  { return inf_non_exited_threads_range (this->thread_list); }
-
-  /* Like inferior::threads(), but returns a range adapter that can be
-     used with range-for, safely.  I.e., it is safe to delete the
-     currently-iterated thread, like this:
-
-     for (thread_info *t : inf->threads_safe ())
-       if (some_condition ())
-        delete f;
-  */
-  inline safe_inf_threads_range threads_safe ()
-  { return safe_inf_threads_range (this->thread_list); }
+  non_exited_thread_map_range non_exited_threads ()
+  { return non_exited_thread_map_range (this->thread_map); }
 
   /* Convenient handle (GDB inferior id).  Unique across all
      inferiors.  */
index c14897a5f719caf48d080be6301ff818a7c3a784..313e7b28841f2e848e24c247efc18f06560bc7a9 100644 (file)
@@ -252,15 +252,6 @@ proceed_thread (struct thread_info *thread, int pid)
   proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
 }
 
-static int
-proceed_thread_callback (struct thread_info *thread, void *arg)
-{
-  int pid = *(int *)arg;
-
-  proceed_thread (thread, pid);
-  return 0;
-}
-
 static void
 exec_continue (char **argv, int argc)
 {
@@ -286,7 +277,24 @@ exec_continue (char **argv, int argc)
 
              pid = inf->pid;
            }
-         iterate_over_threads (proceed_thread_callback, &pid);
+
+         /* Proceed the threads in global number order.  This is not necessary,
+            it's just to avoid breaking some tests like gdb.mi/mi-nsintrall.exp
+            that expect the *running notifications in that order.  In the end,
+            we should instead fix the test to accept the notifications in any
+            order.  */
+         std::vector<thread_info *> threads;
+         for (thread_info *tp : all_threads ())
+           threads.push_back (tp);
+
+         std::sort (threads.begin (), threads.end (),
+                    [] (thread_info *a, thread_info *b)
+                    {
+                      return a->global_num < b->global_num;
+                    });
+
+         for (thread_info *tp : threads)
+           proceed_thread (tp, pid);
        }
       else
        {
index f0f7730f3e4cae204b7dec3444cddd30cf2e840b..6912b14d06e85834c14e55897dd71afdb956f839 100644 (file)
@@ -1535,7 +1535,7 @@ cooked_read_test (struct gdbarch *gdbarch)
   mock_inferior.gdbarch = gdbarch;
   mock_inferior.aspace = &mock_aspace;
   thread_info mock_thread (&mock_inferior, mock_ptid);
-  mock_inferior.thread_list = &mock_thread;
+  mock_inferior.thread_map[mock_ptid] = &mock_thread;
 
   /* Add the mock inferior to the inferior list so that look ups by
      target+ptid can find it.  */
index 3c544502a85a5db4c6ea52fc2aa56f6c8fa8477e..f6fa1661326a88e885df503e4ee943b34f2d67ae 100644 (file)
@@ -4698,7 +4698,7 @@ remote_target::start_remote (int from_tty, int extended_p)
                                    "warning: couldn't determine remote "
                                    "current thread; picking first in list.\n");
 
-             inferior_ptid = inferior_list->thread_list->ptid;
+             inferior_ptid = inferior_list->thread_map.begin ()->second->ptid;
            }
        }
 
index 9a41a46aa66bae9e94a1bb7ea2034e022084dc5e..86823369afe4c0d47d4a0dc86b6b0318805ddbef 100644 (file)
@@ -27,8 +27,13 @@ all_threads_iterator::all_threads_iterator (begin_t)
 {
   /* Advance M_INF/M_THR to the first thread's position.  */
   for (m_inf = inferior_list; m_inf != NULL; m_inf = m_inf->next)
-    if ((m_thr = m_inf->thread_list) != NULL)
-      return;
+    {
+      if (!m_inf->thread_map.empty())
+       {
+         this->m_thr_iter = m_inf->thread_map.cbegin ();
+         return;
+       }
+    }
 }
 
 /* See thread-iter.h.  */
@@ -43,16 +48,24 @@ all_threads_iterator::advance ()
 
   for (; m_inf != NULL; m_inf = m_inf->next)
     {
-      m_thr = m_inf->thread_list;
-      while (m_thr != NULL)
+      m_thr_iter = m_inf->thread_map.cbegin ();
+      while (m_thr_iter != m_inf->thread_map.cend ())
        {
          return;
        start:
-         m_thr = m_thr->next;
+         ++m_thr_iter;
        }
     }
 }
 
+thread_info *all_threads_iterator::operator* () const
+{
+  gdb_assert (m_inf != NULL);
+  gdb_assert (m_thr_iter != m_inf->thread_map.cend ());
+
+  return m_thr_iter->second;
+}
+
 /* See thread-iter.h.  */
 
 bool
@@ -68,12 +81,19 @@ all_matching_threads_iterator::all_matching_threads_iterator
   (ptid_t filter_ptid)
   : m_filter_ptid (filter_ptid)
 {
-  m_thr = nullptr;
   for (m_inf = inferior_list; m_inf != NULL; m_inf = m_inf->next)
-    if (m_inf_matches ())
-      for (m_thr = m_inf->thread_list; m_thr != NULL; m_thr = m_thr->next)
-       if (m_thr->ptid.matches (m_filter_ptid))
-         return;
+    {
+      if (!m_inf->thread_map.empty () && m_inf_matches ())
+       {
+         for (m_thr_iter = m_inf->thread_map.cbegin ();
+              m_thr_iter != m_inf->thread_map.cend ();
+              m_thr_iter++)
+           {
+             if (m_thr_iter->second->ptid.matches (m_filter_ptid))
+               return;
+           }
+       }
+    }
 }
 
 /* See thread-iter.h.  */
@@ -89,13 +109,20 @@ all_matching_threads_iterator::advance ()
   for (; m_inf != NULL; m_inf = m_inf->next)
     if (m_inf_matches ())
       {
-       m_thr = m_inf->thread_list;
-       while (m_thr != NULL)
+       m_thr_iter = m_inf->thread_map.cbegin ();
+       while (m_thr_iter != m_inf->thread_map.cend ())
          {
-           if (m_thr->ptid.matches (m_filter_ptid))
+           if (m_thr_iter->second->ptid.matches (m_filter_ptid))
              return;
          start:
-           m_thr = m_thr->next;
+           ++m_thr_iter;
          }
       }
 }
+
+thread_info *all_matching_threads_iterator::operator* () const
+{
+  gdb_assert (m_inf != nullptr);
+
+  return m_thr_iter->second;
+}
index 72ee9ddcb8441e873a85e0edc1528d0fc9103446..42bf921ae2a473cbd464bacf4d17e664a824d6fa 100644 (file)
@@ -22,6 +22,7 @@
 #include "gdbsupport/filtered-iterator.h"
 #include "gdbsupport/next-iterator.h"
 #include "gdbsupport/safe-iterator.h"
+#include "thread-map.h"
 
 /* A forward iterator that iterates over a given inferior's
    threads.  */
@@ -50,10 +51,10 @@ public:
 
   /* Create a one-past-end iterator.  */
   all_threads_iterator ()
-    : m_thr (nullptr)
+    : m_inf (nullptr)
   {}
 
-  thread_info *operator* () const { return m_thr; }
+  thread_info *operator* () const;
 
   all_threads_iterator &operator++ ()
   {
@@ -62,20 +63,34 @@ public:
   }
 
   bool operator== (const all_threads_iterator &other) const
-  { return m_thr == other.m_thr; }
+  {
+    if (m_inf != other.m_inf)
+      return false;
+
+    /* Inferiors of both iterators are equal.  */
+    if (m_inf == NULL) {
+       /* They are both ended iterators.  */
+       return true;
+    } else {
+       /* Do they both point to the same thread?  */
+       return m_thr_iter == other.m_thr_iter;
+    }
+  }
 
   bool operator!= (const all_threads_iterator &other) const
-  { return m_thr != other.m_thr; }
+  {
+    return !(*this == other);
+  }
 
 private:
   /* Advance to the next thread.  */
   void advance ();
 
 private:
-  /* The current inferior and thread.  M_THR is NULL if we reached the
+  /* The current inferior and thread.  M_INF is NULL if we reached the
      end of the threads list of the last inferior.  */
   inferior *m_inf;
-  thread_info *m_thr;
+  ptid_thread_map::const_iterator m_thr_iter;
 };
 
 /* Iterate over all threads that match a given PTID.  */
@@ -97,11 +112,10 @@ public:
   /* Create a one-past-end iterator.  */
   all_matching_threads_iterator ()
     : m_inf (nullptr),
-      m_thr (nullptr),
       m_filter_ptid (minus_one_ptid)
   {}
 
-  thread_info *operator* () const { return m_thr; }
+  thread_info *operator* () const;
 
   all_matching_threads_iterator &operator++ ()
   {
@@ -110,10 +124,24 @@ public:
   }
 
   bool operator== (const all_matching_threads_iterator &other) const
-  { return m_thr == other.m_thr; }
+  {
+    if (m_inf != other.m_inf)
+      return false;
+
+    /* Inferiors of both iterators are equal.  */
+    if (m_inf == NULL) {
+       /* They are both ended iterators.  */
+       return true;
+    } else {
+       /* Do they both point to the same thread?  */
+       return m_thr_iter == other.m_thr_iter;
+    }
+  }
 
   bool operator!= (const all_matching_threads_iterator &other) const
-  { return m_thr != other.m_thr; }
+  {
+    return !(* this == other);
+  }
 
 private:
   /* Advance to next thread, skipping filtered threads.  */
@@ -128,7 +156,7 @@ private:
   inferior *m_inf;
 
   /* The current thread.  */
-  thread_info *m_thr;
+  ptid_thread_map::const_iterator m_thr_iter;
 
   /* The filter.  */
   ptid_t m_filter_ptid;
diff --git a/gdb/thread-map.h b/gdb/thread-map.h
new file mode 100644 (file)
index 0000000..2b41b73
--- /dev/null
@@ -0,0 +1,133 @@
+/* Thread map type for GDB, the GNU debugger.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef THREAD_MAP_H
+#define THREAD_MAP_H
+
+#include "defs.h"
+
+#include <unordered_map>
+
+struct thread_info;
+
+struct hash_ptid
+{
+  size_t operator() (const ptid_t &ptid) const
+  {
+    std::hash<long> long_hash;
+    return long_hash(ptid.pid()) + long_hash(ptid.lwp()) + long_hash(ptid.tid());
+  }
+};
+
+using ptid_thread_map = std::unordered_map<ptid_t, thread_info *, hash_ptid>;
+
+struct all_thread_map_range_iterator
+{
+  all_thread_map_range_iterator (ptid_thread_map::const_iterator iter)
+    : m_iter (iter)
+  {}
+
+  bool operator!= (const all_thread_map_range_iterator &other)
+  { return this->m_iter != other.m_iter; }
+
+  void operator++ ()
+  { this->m_iter++; }
+
+  thread_info *operator* ()
+  { return this->m_iter->second; }
+
+private:
+  typename ptid_thread_map::const_iterator m_iter;
+};
+
+struct all_thread_map_range
+{
+  all_thread_map_range (const ptid_thread_map &map)
+    : m_map (map)
+  {}
+
+  all_thread_map_range_iterator begin ()
+  {
+    return all_thread_map_range_iterator (this->m_map.begin ());
+  }
+
+  all_thread_map_range_iterator end ()
+  {
+    return all_thread_map_range_iterator (this->m_map.end ());
+  }
+
+private:
+  const ptid_thread_map &m_map;
+};
+
+struct non_exited_thread_map_range_iterator
+{
+  non_exited_thread_map_range_iterator (typename ptid_thread_map::const_iterator iter,
+                                       typename ptid_thread_map::const_iterator end)
+    : m_iter (iter), m_end (end)
+  {
+    advante_to_next_matching ();
+  }
+
+  bool operator!= (const non_exited_thread_map_range_iterator &other)
+  { return this->m_iter != other.m_iter; }
+
+  void operator++ ()
+  {
+    this->m_iter++;
+    advante_to_next_matching ();
+  }
+
+  thread_info *operator* ()
+  { return this->m_iter->second; }
+
+private:
+  typename ptid_thread_map::const_iterator m_iter;
+  typename ptid_thread_map::const_iterator m_end;
+
+  void advante_to_next_matching ()
+  {
+    while (this->m_iter != this->m_end
+          && this->m_iter->second->state == THREAD_EXITED)
+      {
+       this->m_iter++;
+      }
+  }
+};
+
+struct non_exited_thread_map_range
+{
+  non_exited_thread_map_range (const ptid_thread_map &map)
+    : m_map (map)
+  {}
+
+  non_exited_thread_map_range_iterator begin()
+  {
+    return non_exited_thread_map_range_iterator (this->m_map.begin (), this->m_map.end ());
+  }
+
+  non_exited_thread_map_range_iterator end()
+  {
+    return non_exited_thread_map_range_iterator (this->m_map.end (), this->m_map.end ());
+  }
+
+private:
+  const ptid_thread_map &m_map;
+};
+
+#endif
index f80de67d4db3cd6e63fa92cda866101de91f6898..487626619ffa76a6ebee7378637874b6237a0f68 100644 (file)
@@ -235,7 +235,7 @@ init_thread_list (void)
       else
        set_thread_exited (tp, 1);
 
-      inf->thread_list = NULL;
+      inf->thread_map.clear();
     }
 }
 
@@ -247,16 +247,10 @@ new_thread (struct inferior *inf, ptid_t ptid)
 {
   thread_info *tp = new thread_info (inf, ptid);
 
-  if (inf->thread_list == NULL)
-    inf->thread_list = tp;
-  else
-    {
-      struct thread_info *last;
+  /* A thread with this ptid should not exist yet.  */
+  gdb_assert (inf->thread_map.find (ptid) == inf->thread_map.end ());
 
-      for (last = inf->thread_list; last->next != NULL; last = last->next)
-       ;
-      last->next = tp;
-    }
+  inf->thread_map[ptid] = tp;
 
   return tp;
 }
@@ -450,33 +444,25 @@ thread_step_over_chain_remove (struct thread_info *tp)
    THR must not be NULL or a failed assertion will be raised.  */
 
 static void
-delete_thread_1 (thread_info *thr, bool silent)
+delete_thread_1 (thread_info *thr, bool silent, bool remove)
 {
   gdb_assert (thr != nullptr);
 
-  struct thread_info *tp, *tpprev = NULL;
-
-  for (tp = thr->inf->thread_list; tp; tpprev = tp, tp = tp->next)
-    if (tp == thr)
-      break;
+  set_thread_exited (thr, silent);
 
-  if (!tp)
-    return;
-
-  set_thread_exited (tp, silent);
-
-  if (!tp->deletable ())
+  if (!thr->deletable ())
     {
        /* Will be really deleted some other time.  */
        return;
      }
 
-  if (tpprev)
-    tpprev->next = tp->next;
-  else
-    tp->inf->thread_list = tp->next;
+  if (remove)
+    {
+      size_t nr_deleted = thr->inf->thread_map.erase(thr->ptid);
+      gdb_assert (nr_deleted == 1);
+    }
 
-  delete tp;
+  delete thr;
 }
 
 /* Delete thread THREAD and notify of thread exit.  If this is the
@@ -487,13 +473,25 @@ delete_thread_1 (thread_info *thr, bool silent)
 void
 delete_thread (thread_info *thread)
 {
-  delete_thread_1 (thread, false /* not silent */);
+  delete_thread_1 (thread, false /* not silent */, true /* remove */);
+}
+
+void
+delete_thread_noremove (thread_info *thread)
+{
+  delete_thread_1 (thread, false /* silent */, false /* don't remove */);
 }
 
 void
 delete_thread_silent (thread_info *thread)
 {
-  delete_thread_1 (thread, true /* silent */);
+  delete_thread_1 (thread, true /* silent */, true /* remove */);
+}
+
+void
+delete_thread_silent_noremove (thread_info *thread)
+{
+  delete_thread_1 (thread, true /* silent */, false /* don't remove */);
 }
 
 struct thread_info *
@@ -622,7 +620,17 @@ in_thread_list (ptid_t ptid)
 thread_info *
 first_thread_of_inferior (inferior *inf)
 {
-  return inf->thread_list;
+  gdb_assert (!inf->thread_map.empty ());
+
+  auto compare_by_per_inf_num = [] (const ptid_thread_map::value_type &a,
+                                   const ptid_thread_map::value_type &b)
+    {
+      return a.second->per_inf_num < b.second->per_inf_num;
+    };
+  auto it = std::min_element (inf->thread_map.begin (), inf->thread_map.end (),
+                             compare_by_per_inf_num);
+
+  return it->second;
 }
 
 thread_info *
@@ -772,7 +780,13 @@ thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
   inf->pid = new_ptid.pid ();
 
   tp = find_thread_ptid (inf, old_ptid);
+  gdb_assert (tp != nullptr);
+
+  int num_erased = inf->thread_map.erase (old_ptid);
+  gdb_assert (num_erased == 1);
+
   tp->ptid = new_ptid;
+  inf->thread_map[new_ptid] = tp;
 
   gdb::observers::thread_ptid_changed.notify (old_ptid, new_ptid);
 }
@@ -1089,86 +1103,100 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
     scoped_restore_current_thread restore_thread;
 
     for (inferior *inf : all_inferiors ())
-      for (thread_info *tp : inf->threads ())
-       {
-         int core;
+      {
+       /* Print the threads in per-inferior number order.  */
+       std::vector<thread_info *> threads_to_print;
 
-         any_thread = true;
-         if (tp == current_thread && tp->state == THREAD_EXITED)
-           current_exited = true;
+       for (thread_info *tp : inf->threads ())
+         threads_to_print.push_back (tp);
 
-         if (!should_print_thread (requested_threads, default_inf_num,
-                                   global_ids, pid, tp))
-           continue;
+       std::sort (threads_to_print.begin (), threads_to_print.end (),
+                  [] (thread_info *a, thread_info *b)
+         {
+           return a->per_inf_num < b->per_inf_num;
+         });
 
-         ui_out_emit_tuple tuple_emitter (uiout, NULL);
+       for (thread_info *tp : threads_to_print)
+         {
+           int core;
 
-         if (!uiout->is_mi_like_p ())
-           {
-             if (tp == current_thread)
-               uiout->field_string ("current", "*");
-             else
-               uiout->field_skip ("current");
+           any_thread = true;
+           if (tp == current_thread && tp->state == THREAD_EXITED)
+             current_exited = true;
 
-             uiout->field_string ("id-in-tg", print_thread_id (tp));
-           }
+           if (!should_print_thread (requested_threads, default_inf_num,
+                                     global_ids, pid, tp))
+             continue;
 
-         if (show_global_ids || uiout->is_mi_like_p ())
-           uiout->field_signed ("id", tp->global_num);
+           ui_out_emit_tuple tuple_emitter (uiout, NULL);
 
-         /* For the CLI, we stuff everything into the target-id field.
-            This is a gross hack to make the output come out looking
-            correct.  The underlying problem here is that ui-out has no
-            way to specify that a field's space allocation should be
-            shared by several fields.  For MI, we do the right thing
-            instead.  */
+           if (!uiout->is_mi_like_p ())
+             {
+               if (tp == current_thread)
+                 uiout->field_string ("current", "*");
+               else
+                 uiout->field_skip ("current");
 
-         if (uiout->is_mi_like_p ())
-           {
-             uiout->field_string ("target-id", target_pid_to_str (tp->ptid));
+               uiout->field_string ("id-in-tg", print_thread_id (tp));
+             }
 
-             const char *extra_info = target_extra_thread_info (tp);
-             if (extra_info != nullptr)
-               uiout->field_string ("details", extra_info);
+           if (show_global_ids || uiout->is_mi_like_p ())
+             uiout->field_signed ("id", tp->global_num);
 
-             const char *name = (tp->name != nullptr
-                                 ? tp->name
-                                 : target_thread_name (tp));
-             if (name != NULL)
-               uiout->field_string ("name", name);
-           }
-         else
-           {
-             uiout->field_string ("target-id",
-                                  thread_target_id_str (tp).c_str ());
-           }
+           /* For the CLI, we stuff everything into the target-id field.
+              This is a gross hack to make the output come out looking
+              correct.  The underlying problem here is that ui-out has no
+              way to specify that a field's space allocation should be
+              shared by several fields.  For MI, we do the right thing
+              instead.  */
 
-         if (tp->state == THREAD_RUNNING)
-           uiout->text ("(running)\n");
-         else
-           {
-             /* The switch below puts us at the top of the stack (leaf
-                frame).  */
-             switch_to_thread (tp);
-             print_stack_frame (get_selected_frame (NULL),
-                                /* For MI output, print frame level.  */
-                                uiout->is_mi_like_p (),
-                                LOCATION, 0);
-           }
+           if (uiout->is_mi_like_p ())
+             {
+               uiout->field_string ("target-id", target_pid_to_str (tp->ptid));
 
-         if (uiout->is_mi_like_p ())
-           {
-             const char *state = "stopped";
+               const char *extra_info = target_extra_thread_info (tp);
+               if (extra_info != nullptr)
+                 uiout->field_string ("details", extra_info);
 
-             if (tp->state == THREAD_RUNNING)
-               state = "running";
-             uiout->field_string ("state", state);
-           }
+               const char *name = (tp->name != nullptr
+                                   ? tp->name
+                                   : target_thread_name (tp));
+               if (name != NULL)
+                 uiout->field_string ("name", name);
+             }
+           else
+             {
+               uiout->field_string ("target-id",
+                                    thread_target_id_str (tp).c_str ());
+             }
 
-         core = target_core_of_thread (tp->ptid);
-         if (uiout->is_mi_like_p () && core != -1)
-           uiout->field_signed ("core", core);
-       }
+           if (tp->state == THREAD_RUNNING)
+             uiout->text ("(running)\n");
+           else
+             {
+               /* The switch below puts us at the top of the stack (leaf
+                  frame).  */
+               switch_to_thread (tp);
+               print_stack_frame (get_selected_frame (NULL),
+                                  /* For MI output, print frame level.  */
+                                  uiout->is_mi_like_p (),
+                                  LOCATION, 0);
+             }
+
+           if (uiout->is_mi_like_p ())
+             {
+               const char *state = "stopped";
+
+               if (tp->state == THREAD_RUNNING)
+                 state = "running";
+               uiout->field_string ("state", state);
+             }
+
+           core = target_core_of_thread (tp->ptid);
+           if (uiout->is_mi_like_p () && core != -1)
+             uiout->field_signed ("core", core);
+         }
+      }
 
     /* This end scope restores the current thread and the frame
        selected before the "info threads" command, and it finishes the
This page took 0.036582 seconds and 4 git commands to generate.