public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tom Tromey <tom@tromey.com>
To: gdb-patches@sourceware.org
Subject: [PATCH v2 08/17] Change cooked_index_worker to abstract base class
Date: Wed, 17 Jan 2024 09:39:36 -0700	[thread overview]
Message-ID: <20240117-debug-names-fix-v2-8-dbd5971a9c31@tromey.com> (raw)
In-Reply-To: <20240117-debug-names-fix-v2-0-dbd5971a9c31@tromey.com>

This changes cooked_index_worker to be an abstract base class.  The
base class implementation is moved to cooked-index.c, and a concrete
subclass is added to read.c.

This change is preparation for the new .debug_names reader, which will
supply its own concrete implementation of the worker.
---
 gdb/dwarf2/cooked-index.c | 136 ++++++++++++++++++++++++++++++++-
 gdb/dwarf2/cooked-index.h |  43 ++++++-----
 gdb/dwarf2/read.c         | 186 ++++++++++++----------------------------------
 3 files changed, 204 insertions(+), 161 deletions(-)

diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c
index d63fd0ab5bc..97a749f97e8 100644
--- a/gdb/dwarf2/cooked-index.c
+++ b/gdb/dwarf2/cooked-index.c
@@ -442,9 +442,141 @@ cooked_index_shard::find (const std::string &name, bool completing) const
   return range (lower, upper);
 }
 
+/* See cooked-index.h.  */
+
+void
+cooked_index_worker::start ()
+{
+  gdb::thread_pool::g_thread_pool->post_task ([=] ()
+  {
+    this->start_reading ();
+  });
+}
+
+/* See cooked-index.h.  */
+
+void
+cooked_index_worker::start_reading ()
+{
+  SCOPE_EXIT { bfd_thread_cleanup (); };
+
+  try
+    {
+      do_reading ();
+    }
+  catch (const gdb_exception &exc)
+    {
+      m_failed = exc;
+      set (cooked_state::CACHE_DONE);
+    }
+}
+
+/* See cooked-index.h.  */
+
+bool
+cooked_index_worker::wait (cooked_state desired_state, bool allow_quit)
+{
+  bool done;
+#if CXX_STD_THREAD
+  {
+    std::unique_lock<std::mutex> lock (m_mutex);
+
+    /* This may be called from a non-main thread -- this functionality
+       is needed for the index cache -- but in this case we require
+       that the desired state already have been attained.  */
+    gdb_assert (is_main_thread () || desired_state <= m_state);
+
+    while (desired_state > m_state)
+      {
+	if (allow_quit)
+	  {
+	    std::chrono::milliseconds duration { 15 };
+	    if (m_cond.wait_for (lock, duration) == std::cv_status::timeout)
+	      QUIT;
+	  }
+	else
+	  m_cond.wait (lock);
+      }
+    done = m_state == cooked_state::CACHE_DONE;
+  }
+#else
+  /* Without threads, all the work is done immediately on the main
+     thread, and there is never anything to wait for.  */
+  done = true;
+#endif /* CXX_STD_THREAD */
+
+  /* Only the main thread is allowed to report complaints and the
+     like.  */
+  if (!is_main_thread ())
+    return false;
+
+  if (m_reported)
+    return done;
+  m_reported = true;
+
+  /* Emit warnings first, maybe they were emitted before an exception
+     (if any) was thrown.  */
+  m_warnings.emit ();
+
+  if (m_failed.has_value ())
+    {
+      /* start_reading failed -- report it.  */
+      exception_print (gdb_stderr, *m_failed);
+      m_failed.reset ();
+      return done;
+    }
+
+  /* Only show a given exception a single time.  */
+  std::unordered_set<gdb_exception> seen_exceptions;
+  for (auto &one_result : m_results)
+    {
+      re_emit_complaints (std::get<1> (one_result));
+      for (auto &one_exc : std::get<2> (one_result))
+	if (seen_exceptions.insert (one_exc).second)
+	  exception_print (gdb_stderr, one_exc);
+    }
+
+  print_stats ();
+
+  struct objfile *objfile = m_per_objfile->objfile;
+  dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
+  cooked_index *table
+    = (gdb::checked_static_cast<cooked_index *>
+       (per_bfd->index_table.get ()));
+
+  auto_obstack temp_storage;
+  enum language lang = language_unknown;
+  const char *main_name = table->get_main_name (&temp_storage, &lang);
+  if (main_name != nullptr)
+    set_objfile_main_name (objfile, main_name, lang);
+
+  /* dwarf_read_debug_printf ("Done building psymtabs of %s", */
+  /* 			   objfile_name (objfile)); */
+
+  return done;
+}
+
+/* See cooked-index.h.  */
+
+void
+cooked_index_worker::set (cooked_state desired_state)
+{
+  gdb_assert (desired_state != cooked_state::INITIAL);
+
+#if CXX_STD_THREAD
+  std::lock_guard<std::mutex> guard (m_mutex);
+  gdb_assert (desired_state > m_state);
+  m_state = desired_state;
+  m_cond.notify_one ();
+#else
+  /* Without threads, all the work is done immediately on the main
+     thread, and there is never anything to do.  */
+#endif /* CXX_STD_THREAD */
+}
 
-cooked_index::cooked_index (dwarf2_per_objfile *per_objfile)
-  : m_state (std::make_unique<cooked_index_worker> (per_objfile)),
+cooked_index::cooked_index (dwarf2_per_objfile *per_objfile,
+			    std::unique_ptr<cooked_index_worker> &&worker)
+  : m_state (std::move (worker)),
     m_per_bfd (per_objfile->per_bfd)
 {
   /* ACTIVE_VECTORS is not locked, and this assert ensures that this
diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h
index 24c83b56e05..f063fe088e8 100644
--- a/gdb/dwarf2/cooked-index.h
+++ b/gdb/dwarf2/cooked-index.h
@@ -500,13 +500,21 @@ enum class cooked_state
 
 /* An object of this type controls the scanning of the DWARF.  It
    schedules the worker tasks and tracks the current state.  Once
-   scanning is done, this object is discarded.  */
+   scanning is done, this object is discarded.
+   
+   This is an abstract base class that defines the basic behavior of
+   scanners.  Separate concrete implementations exist for scanning
+   .debug_names and .debug_info.  */
 
 class cooked_index_worker
 {
 public:
 
-  explicit cooked_index_worker (dwarf2_per_objfile *per_objfile);
+  explicit cooked_index_worker (dwarf2_per_objfile *per_objfile)
+    : m_per_objfile (per_objfile)
+  { }
+  virtual ~cooked_index_worker ()
+  { }
   DISABLE_COPY_AND_ASSIGN (cooked_index_worker);
 
   /* Start reading.  */
@@ -520,7 +528,7 @@ class cooked_index_worker
      cache writer.)  */
   bool wait (cooked_state desired_state, bool allow_quit);
 
-private:
+protected:
 
   /* Let cooked_index call the 'set' method.  */
   friend class cooked_index;
@@ -530,21 +538,15 @@ class cooked_index_worker
      problems.  */
   void start_reading ();
 
-  /* Helper function that does most of the work for start_reading.  */
-  void do_reading ();
-
-  /* After the last DWARF-reading task has finished, this function
-     does the remaining work to finish the scan.  */
-  void done_reading ();
-
-  /* An iterator for the comp units.  */
-  typedef std::vector<dwarf2_per_cu_data_up>::iterator unit_iterator;
+  /* Helper function that does most of the work for start_reading.
+     This must be able to be run in a worker thread without
+     problems.  */
+  virtual void do_reading () = 0;
 
-  /* Process a batch of CUs.  This may be called multiple times in
-     separate threads.  TASK_NUMBER indicates which task this is --
-     the result is stored in that slot of M_RESULTS.  */
-  void process_cus (size_t task_number, unit_iterator first,
- 		    unit_iterator end);
+  /* A callback that can print stats, if needed.  This is called when
+     transitioning to the 'MAIN_AVAILABLE' state.  */
+  virtual void print_stats ()
+  { }
 
   /* Each thread returns a tuple holding a cooked index, any collected
      complaints, and a vector of errors that should be printed.  The
@@ -557,10 +559,6 @@ class cooked_index_worker
 
   /* The per-objfile object.  */
   dwarf2_per_objfile *m_per_objfile;
-  /* A storage object for "leftovers" -- see the 'start' method, but
-     essentially things not parsed during the normal CU parsing
-     passes.  */
-  cooked_index_storage m_index_storage;
   /* Result of each worker task.  */
   std::vector<result_type> m_results;
   /* Any warnings emitted.  This is not in 'result_type' because (for
@@ -648,7 +646,8 @@ class cooked_index : public dwarf_scanner_base
      object.  */
   using vec_type = std::vector<std::unique_ptr<cooked_index_shard>>;
 
-  explicit cooked_index (dwarf2_per_objfile *per_objfile);
+  cooked_index (dwarf2_per_objfile *per_objfile,
+		std::unique_ptr<cooked_index_worker> &&worker);
   ~cooked_index () override;
 
   DISABLE_COPY_AND_ASSIGN (cooked_index);
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 8010c0141f5..7691fe0050b 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -4824,32 +4824,58 @@ process_skeletonless_type_units (dwarf2_per_objfile *per_objfile,
     }
 }
 
-cooked_index_worker::cooked_index_worker (dwarf2_per_objfile *per_objfile)
-  : m_per_objfile (per_objfile)
+/* A subclass of cooked_index_worker that handles scanning
+   .debug_info.  */
+
+class cooked_index_debug_info : public cooked_index_worker
 {
-  gdb_assert (is_main_thread ());
+public:
+  cooked_index_debug_info (dwarf2_per_objfile *per_objfile)
+    : cooked_index_worker (per_objfile)
+  {
+    gdb_assert (is_main_thread ());
 
-  struct objfile *objfile = per_objfile->objfile;
-  dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
+    struct objfile *objfile = per_objfile->objfile;
+    dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
 
-  dwarf_read_debug_printf ("Building psymtabs of objfile %s ...",
-			   objfile_name (objfile));
+    dwarf_read_debug_printf ("Building psymtabs of objfile %s ...",
+			     objfile_name (objfile));
 
-  per_bfd->map_info_sections (objfile);
-}
+    per_bfd->map_info_sections (objfile);
+  }
 
-void
-cooked_index_worker::start ()
-{
-  gdb::thread_pool::g_thread_pool->post_task ([=] ()
+private:
+
+  void do_reading () override;
+
+  void print_stats () override
   {
-    this->start_reading ();
-  });
-}
+    if (dwarf_read_debug > 0)
+      print_tu_stats (m_per_objfile);
+  }
+
+  /* After the last DWARF-reading task has finished, this function
+     does the remaining work to finish the scan.  */
+  void done_reading ();
+
+  /* An iterator for the comp units.  */
+  typedef std::vector<dwarf2_per_cu_data_up>::iterator unit_iterator;
+
+  /* Process a batch of CUs.  This may be called multiple times in
+     separate threads.  TASK_NUMBER indicates which task this is --
+     the result is stored in that slot of M_RESULTS.  */
+  void process_cus (size_t task_number, unit_iterator first,
+ 		    unit_iterator end);
+
+  /* A storage object for "leftovers" -- see the 'start' method, but
+     essentially things not parsed during the normal CU parsing
+     passes.  */
+  cooked_index_storage m_index_storage;
+};
 
 void
-cooked_index_worker::process_cus (size_t task_number, unit_iterator first,
-				  unit_iterator end)
+cooked_index_debug_info::process_cus (size_t task_number, unit_iterator first,
+				      unit_iterator end)
 {
   SCOPE_EXIT { bfd_thread_cleanup (); };
 
@@ -4877,7 +4903,7 @@ cooked_index_worker::process_cus (size_t task_number, unit_iterator first,
 }
 
 void
-cooked_index_worker::done_reading ()
+cooked_index_debug_info::done_reading ()
 {
   /* Only handle the scanning results here.  Complaints and exceptions
      can only be dealt with on the main thread.  */
@@ -4899,23 +4925,7 @@ cooked_index_worker::done_reading ()
 }
 
 void
-cooked_index_worker::start_reading ()
-{
-  SCOPE_EXIT { bfd_thread_cleanup (); };
-
-  try
-    {
-      do_reading ();
-    }
-  catch (const gdb_exception &exc)
-    {
-      m_failed = exc;
-      set (cooked_state::CACHE_DONE);
-    }
-}
-
-void
-cooked_index_worker::do_reading ()
+cooked_index_debug_info::do_reading ()
 {
   dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
 
@@ -4986,106 +4996,6 @@ cooked_index_worker::do_reading ()
   workers.start ();
 }
 
-bool
-cooked_index_worker::wait (cooked_state desired_state, bool allow_quit)
-{
-  bool done;
-#if CXX_STD_THREAD
-  {
-    std::unique_lock<std::mutex> lock (m_mutex);
-
-    /* This may be called from a non-main thread -- this functionality
-       is needed for the index cache -- but in this case we require
-       that the desired state already have been attained.  */
-    gdb_assert (is_main_thread () || desired_state <= m_state);
-
-    while (desired_state > m_state)
-      {
-	if (allow_quit)
-	  {
-	    std::chrono::milliseconds duration { 15 };
-	    if (m_cond.wait_for (lock, duration) == std::cv_status::timeout)
-	      QUIT;
-	  }
-	else
-	  m_cond.wait (lock);
-      }
-    done = m_state == cooked_state::CACHE_DONE;
-  }
-#else
-  /* Without threads, all the work is done immediately on the main
-     thread, and there is never anything to wait for.  */
-  done = true;
-#endif /* CXX_STD_THREAD */
-
-  /* Only the main thread is allowed to report complaints and the
-     like.  */
-  if (!is_main_thread ())
-    return false;
-
-  if (m_reported)
-    return done;
-  m_reported = true;
-
-  /* Emit warnings first, maybe they were emitted before an exception
-     (if any) was thrown.  */
-  m_warnings.emit ();
-
-  if (m_failed.has_value ())
-    {
-      /* start_reading failed -- report it.  */
-      exception_print (gdb_stderr, *m_failed);
-      m_failed.reset ();
-      return done;
-    }
-
-  /* Only show a given exception a single time.  */
-  std::unordered_set<gdb_exception> seen_exceptions;
-  for (auto &one_result : m_results)
-    {
-      re_emit_complaints (std::get<1> (one_result));
-      for (auto &one_exc : std::get<2> (one_result))
-	if (seen_exceptions.insert (one_exc).second)
-	  exception_print (gdb_stderr, one_exc);
-    }
-
-  if (dwarf_read_debug > 0)
-    print_tu_stats (m_per_objfile);
-
-  struct objfile *objfile = m_per_objfile->objfile;
-  dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
-  cooked_index *table
-    = (gdb::checked_static_cast<cooked_index *>
-       (per_bfd->index_table.get ()));
-
-  auto_obstack temp_storage;
-  enum language lang = language_unknown;
-  const char *main_name = table->get_main_name (&temp_storage, &lang);
-  if (main_name != nullptr)
-    set_objfile_main_name (objfile, main_name, lang);
-
-  dwarf_read_debug_printf ("Done building psymtabs of %s",
-			   objfile_name (objfile));
-
-  return done;
-}
-
-void
-cooked_index_worker::set (cooked_state desired_state)
-{
-  gdb_assert (desired_state != cooked_state::INITIAL);
-
-#if CXX_STD_THREAD
-  std::lock_guard<std::mutex> guard (m_mutex);
-  gdb_assert (desired_state > m_state);
-  m_state = desired_state;
-  m_cond.notify_one ();
-#else
-  /* Without threads, all the work is done immediately on the main
-     thread, and there is never anything to do.  */
-#endif /* CXX_STD_THREAD */
-}
-
 static void
 read_comp_units_from_section (dwarf2_per_objfile *per_objfile,
 			      struct dwarf2_section_info *section,
@@ -16818,7 +16728,9 @@ start_debug_info_reader (dwarf2_per_objfile *per_objfile)
   /* Set the index table early so that sharing works even while
      scanning; and then start the scanning.  */
   dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
-  cooked_index *idx = new cooked_index (per_objfile);
+  std::unique_ptr<cooked_index_worker> worker
+    (new cooked_index_debug_info (per_objfile));
+  cooked_index *idx = new cooked_index (per_objfile, std::move (worker));
   per_bfd->index_table.reset (idx);
   /* Don't start reading until after 'index_table' is set.  This
      avoids races.  */

-- 
2.43.0


  parent reply	other threads:[~2024-01-17 16:39 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-17 16:39 [PATCH v2 00/17] Rewrite .debug_names reader and writer Tom Tromey
2024-01-17 16:39 ` [PATCH v2 01/17] Refactor 'maint set dwarf synchronous' handling Tom Tromey
2024-01-17 16:39 ` [PATCH v2 02/17] Refactor quick-function installation in DWARF reader Tom Tromey
2024-01-17 16:39 ` [PATCH v2 03/17] Remove IS_ENUM_CLASS from cooked_index_flag Tom Tromey
2024-01-17 16:39 ` [PATCH v2 04/17] Document GDB extensions to DWARF .debug_names Tom Tromey
2024-01-17 16:39 ` [PATCH v2 05/17] Add language to cooked_index_entry Tom Tromey
2024-01-17 16:39 ` [PATCH v2 06/17] Move cooked_index_functions to cooked-index.h Tom Tromey
2024-01-17 16:39 ` [PATCH v2 07/17] Do not write the index cache from an index Tom Tromey
2024-01-17 16:39 ` Tom Tromey [this message]
2024-01-17 16:39 ` [PATCH v2 09/17] Remove cooked_index_worker::start_reading Tom Tromey
2024-01-17 16:39 ` [PATCH v2 10/17] Empty hash table fix in .debug_names reader Tom Tromey
2024-01-17 16:39 ` [PATCH v2 11/17] Fix dw2-zero-range.exp when an index is in use Tom Tromey
2024-01-17 16:39 ` [PATCH v2 12/17] Explicitly expand CUs in dw2-inline-with-lexical-scope.exp Tom Tromey
2024-01-17 16:39 ` [PATCH v2 13/17] Remove some .debug_names tests Tom Tromey
2024-01-17 16:39 ` [PATCH v2 14/17] Allow other results in DW_TAG_entry_point test Tom Tromey
2024-01-17 16:39 ` [PATCH v2 15/17] Rewrite .debug_names reader Tom Tromey
2024-01-17 16:39 ` [PATCH v2 16/17] Export dwarf5_augmentation Tom Tromey
2024-01-17 16:39 ` [PATCH v2 17/17] Rewrite .debug_names writer Tom Tromey
2024-01-18 10:05 ` [PATCH v2 00/17] Rewrite .debug_names reader and writer Tom de Vries
2024-01-18 15:42   ` Tom Tromey
2024-01-18 20:33     ` Tom Tromey

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240117-debug-names-fix-v2-8-dbd5971a9c31@tromey.com \
    --to=tom@tromey.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).