gdb: add ptid -> thread map in inferior
authorSimon Marchi <simon.marchi@efficios.com>
Thu, 19 Dec 2019 19:19:41 +0000 (14:19 -0500)
committerSimon Marchi <simon.marchi@efficios.com>
Wed, 1 Jul 2020 00:01:10 +0000 (20:01 -0400)
Add a ptid to thread_info pointer map in the inferior object, in order
to accelerate thread lookups by ptid.  This map is in addition to the
`thread_list` linked list.  But unlike that list, it only contains
non-exited threads.

Change-Id: I81f3651966ebef8425f999a55a146390579baea2

gdb/inferior.c
gdb/inferior.h
gdb/scoped-mock-context.h
gdb/thread-map.h [new file with mode: 0644]
gdb/thread.c

index f775938721db5f5136b5693f095d20c6e05c3a56..2d7d7167916d3aae35739b60a1f8409eb86404b8 100644 (file)
@@ -204,6 +204,8 @@ exit_inferior_1 (struct inferior *inftoex, int silent)
        delete_thread (tp);
     }
 
+  inf->thread_map.clear ();
+
   gdb::observers::inferior_exit.notify (inf);
 
   inf->pid = 0;
index 572c5f3ae72dcf5e571a7a1433f668846b29e961..6c139b0a102bdd1d249a76c1a091cf21b8a3cb47 100644 (file)
@@ -56,6 +56,7 @@ struct thread_info;
 
 #include "gdbsupport/common-inferior.h"
 #include "gdbthread.h"
+#include "thread-map.h"
 
 #include "process-stratum-target.h"
 
@@ -377,6 +378,9 @@ public:
   /* This inferior's thread list.  */
   thread_info *thread_list = nullptr;
 
+  /* This inferior's ptid to thread map, only contains non exited threads.  */
+  ptid_thread_map thread_map;
+
   /* Returns a range adapter covering the inferior's threads,
      including exited threads.  Used like this:
 
index 461c2a353881136f1613c43edc430e4659215257..2524dcf2ed8d65278690e349c3370393b8bdbbc9 100644 (file)
@@ -44,6 +44,9 @@ struct scoped_mock_context
 
   scoped_restore_current_pspace_and_thread restore_pspace_thread;
 
+  scoped_restore restore_thread_map
+    = make_scoped_restore (&mock_inferior.thread_map, ptid_thread_map ({{mock_ptid, &mock_thread}}));
+
   scoped_restore_tmpl<thread_info *> restore_thread_list
     {&mock_inferior.thread_list, &mock_thread};
 
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 f0722d358888550d5786a3ff532717e07cf92846..a23884df80d033c5602b706851b75064ad21d189 100644 (file)
@@ -236,6 +236,7 @@ init_thread_list (void)
        set_thread_exited (tp, 1);
 
       inf->thread_list = NULL;
+      inf->thread_map.clear();
     }
 }
 
@@ -247,6 +248,7 @@ new_thread (struct inferior *inf, ptid_t ptid)
 {
   thread_info *tp = new thread_info (inf, ptid);
 
+  /* Add to thread_list linked list.  */
   if (inf->thread_list == NULL)
     inf->thread_list = tp;
   else
@@ -263,6 +265,11 @@ new_thread (struct inferior *inf, ptid_t ptid)
       last->next = tp;
     }
 
+  /* Add to ptid -> thread map.  A non-exited thread with this ptid should not
+     exist yet.  */
+  gdb_assert (inf->thread_map.find (ptid) == inf->thread_map.end ());
+  inf->thread_map[ptid] = tp;
+
   return tp;
 }
 
@@ -436,7 +443,27 @@ delete_thread_1 (thread_info *thr, bool silent)
   if (!tp)
     return;
 
-  set_thread_exited (tp, silent);
+  /* Remove from ptid -> thread map in any case, as it contains only non-exited
+     threads.  */
+  if (tp->state != THREAD_EXITED)
+    {
+      /* If the thread is not exited yet, it is in the thread map, remove it.  */
+      size_t nr_deleted = thr->inf->thread_map.erase (thr->ptid);
+
+      gdb_assert (nr_deleted == 1);
+
+      set_thread_exited (tp, silent);
+    }
+  else
+    {
+      /* If the thread is already marked as existed, it is not in the thread
+         map (but a more recent thread with the same ptid could be).  */
+
+      /* Sanity check.  */
+      for (const auto &item : thr->inf->thread_map)
+       gdb_assert (thr != item.second);
+    }
+
 
   if (!tp->deletable ())
     {
@@ -773,7 +800,14 @@ thread_change_ptid (process_stratum_target *targ,
   inf->pid = new_ptid.pid ();
 
   tp = find_thread_ptid (inf, old_ptid);
+  gdb_assert (tp != nullptr);
+
+  /* Update entry in ptid -> thread map.  */
+  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);
 }
This page took 0.027249 seconds and 4 git commands to generate.