From: Tom Tromey Date: Sun, 3 Dec 2023 19:34:49 +0000 (-0700) Subject: Change cooked_index_worker to abstract base class X-Git-Tag: gdb-15-branchpoint~1225 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=47efef8f2d8a10b63d2c6125aded1d2da69d8a04;p=thirdparty%2Fbinutils-gdb.git Change cooked_index_worker to abstract base class 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. --- 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 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 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 + (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 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 (per_objfile)), +cooked_index::cooked_index (dwarf2_per_objfile *per_objfile, + std::unique_ptr &&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 @@ public: 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 @@ private: 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::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 @@ private: /* 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 m_results; /* Any warnings emitted. This is not in 'result_type' because (for @@ -648,7 +646,8 @@ public: object. */ using vec_type = std::vector>; - explicit cooked_index (dwarf2_per_objfile *per_objfile); + cooked_index (dwarf2_per_objfile *per_objfile, + std::unique_ptr &&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::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 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 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 - (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 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 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. */