From: Tom Tromey Date: Mon, 24 Mar 2025 21:34:39 +0000 (-0600) Subject: Move cooked_index_worker to cooked-index-worker.[ch] X-Git-Tag: binutils-2_45~1000 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=51b142159423298b9ed756fd2b913f89ae4b94a9;p=thirdparty%2Fbinutils-gdb.git Move cooked_index_worker to cooked-index-worker.[ch] This moves the cooked_index_worker class to cooked-index-worker.[ch]. Approved-By: Simon Marchi --- diff --git a/gdb/dwarf2/cooked-index-worker.c b/gdb/dwarf2/cooked-index-worker.c index 8a074a8952f..0ce4987658f 100644 --- a/gdb/dwarf2/cooked-index-worker.c +++ b/gdb/dwarf2/cooked-index-worker.c @@ -18,6 +18,11 @@ along with this program. If not, see . */ #include "dwarf2/cooked-index-worker.h" +#include "dwarf2/cooked-index.h" +#include "gdbsupport/thread-pool.h" +#include "run-on-main-thread.h" +#include "event-top.h" +#include "exceptions.h" /* See cooked-index-worker.h. */ @@ -82,3 +87,144 @@ bool cooked_index_worker_result::cutu_reader_eq::operator() { return per_cu.index == reader->cu ()->per_cu->index; } + +/* See cooked-index.h. */ + +void +cooked_index_worker::start () +{ + gdb::thread_pool::g_thread_pool->post_task ([this] () + { + try + { + do_reading (); + } + catch (const gdb_exception &exc) + { + m_failed = exc; + set (cooked_state::CACHE_DONE); + } + + bfd_thread_cleanup (); + }); +} + +/* 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 = desired_state == cooked_state::CACHE_DONE; +#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 ()) + { + /* do_reading failed -- report it. */ + exception_print (gdb_stderr, *m_failed); + m_failed.reset (); + return done; + } + + /* Only show a given exception a single time. */ + gdb::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 */ +} + +/* See cooked-index.h. */ + +void +cooked_index_worker::write_to_cache (const cooked_index *idx, + deferred_warnings *warn) const +{ + if (idx != nullptr) + { + /* Writing to the index cache may cause a warning to be emitted. + See PR symtab/30837. This arranges to capture all such + warnings. This is safe because we know the deferred_warnings + object isn't in use by any other thread at this point. */ + scoped_restore_warning_hook defer (warn); + m_cache_store.store (); + } +} diff --git a/gdb/dwarf2/cooked-index-worker.h b/gdb/dwarf2/cooked-index-worker.h index 0f2fa6cb9de..514487b80d6 100644 --- a/gdb/dwarf2/cooked-index-worker.h +++ b/gdb/dwarf2/cooked-index-worker.h @@ -26,6 +26,11 @@ #include "dwarf2/types.h" #include "dwarf2/read.h" +#if CXX_STD_THREAD +#include +#include +#endif /* CXX_STD_THREAD */ + using cutu_reader_up = std::unique_ptr; /* An instance of this is created when scanning DWARF to create a @@ -131,4 +136,122 @@ private: addrmap_mutable m_addrmap; }; +/* The possible states of the index. See the explanatory comment + before cooked_index for more details. */ +enum class cooked_state +{ + /* The default state. This is not a valid argument to 'wait'. */ + INITIAL, + /* The initial scan has completed. The name of "main" is now + available (if known). The addrmaps are usable now. + Finalization has started but is not complete. */ + MAIN_AVAILABLE, + /* Finalization has completed. This means the index is fully + available for queries. */ + FINALIZED, + /* Writing to the index cache has finished. */ + CACHE_DONE, +}; + +/* 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. + + 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) + : m_per_objfile (per_objfile), + m_cache_store (global_index_cache, per_objfile->per_bfd) + { } + virtual ~cooked_index_worker () + { } + DISABLE_COPY_AND_ASSIGN (cooked_index_worker); + + /* Start reading. */ + void start (); + + /* Wait for a particular state to be achieved. If ALLOW_QUIT is + true, then the loop will check the QUIT flag. Normally this + method may only be called from the main thread; however, it can + be called from a worker thread provided that the desired state + has already been attained. (This oddity is used by the index + cache writer.) */ + bool wait (cooked_state desired_state, bool allow_quit); + +protected: + + /* Let cooked_index call the 'set' and 'write_to_cache' methods. */ + friend class cooked_index; + + /* Set the current state. */ + void set (cooked_state desired_state); + + /* Write to the index cache. */ + void write_to_cache (const cooked_index *idx, + deferred_warnings *warn) const; + + /* Helper function that does the work of reading. This must be able + to be run in a worker thread without problems. */ + virtual void do_reading () = 0; + + /* 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, a vector of errors that should be printed, and a + parent map. + + The errors are retained because GDB's I/O system is not + thread-safe. run_on_main_thread could be used, but that would + mean the messages are printed after the prompt, which looks + weird. */ + using result_type = std::tuple, + parent_map>; + + /* The per-objfile object. */ + dwarf2_per_objfile *m_per_objfile; + /* Result of each worker task. */ + std::vector m_results; + /* Any warnings emitted. This is not in 'result_type' because (for + the time being at least), it's only needed in do_reading, not in + every worker. Note that deferred_warnings uses gdb_stderr in its + constructor, and this should only be done from the main thread. + This is enforced in the cooked_index_worker constructor. */ + deferred_warnings m_warnings; + + /* A map of all parent maps. Used during finalization to fix up + parent relationships. */ + parent_map_map m_all_parents_map; + +#if CXX_STD_THREAD + /* Current state of this object. */ + cooked_state m_state = cooked_state::INITIAL; + /* Mutex and condition variable used to synchronize. */ + std::mutex m_mutex; + std::condition_variable m_cond; +#endif /* CXX_STD_THREAD */ + /* This flag indicates whether any complaints or exceptions that + arose during scanning have been reported by 'wait'. This may + only be modified on the main thread. */ + bool m_reported = false; + /* If set, an exception occurred during reading; in this case the + scanning is stopped and this exception will later be reported by + the 'wait' method. */ + std::optional m_failed; + /* An object used to write to the index cache. */ + index_cache_store_context m_cache_store; +}; + +using cooked_index_worker_up = std::unique_ptr; + #endif /* GDB_DWARF2_COOKED_INDEX_WORKER_H */ diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c index 5d205a83d09..a632474dff8 100644 --- a/gdb/dwarf2/cooked-index.c +++ b/gdb/dwarf2/cooked-index.c @@ -22,13 +22,11 @@ #include "dwarf2/stringify.h" #include "dwarf2/index-cache.h" #include "event-top.h" -#include "exceptions.h" #include "split-name.h" #include "observable.h" #include "run-on-main-thread.h" #include #include "gdbsupport/task-group.h" -#include "gdbsupport/thread-pool.h" #include #include "cli/cli-cmds.h" @@ -50,147 +48,6 @@ language_requires_canonicalization (enum language lang) || lang == language_cplus); } -/* See cooked-index.h. */ - -void -cooked_index_worker::start () -{ - gdb::thread_pool::g_thread_pool->post_task ([this] () - { - try - { - do_reading (); - } - catch (const gdb_exception &exc) - { - m_failed = exc; - set (cooked_state::CACHE_DONE); - } - - bfd_thread_cleanup (); - }); -} - -/* 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 = desired_state == cooked_state::CACHE_DONE; -#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 ()) - { - /* do_reading failed -- report it. */ - exception_print (gdb_stderr, *m_failed); - m_failed.reset (); - return done; - } - - /* Only show a given exception a single time. */ - gdb::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 */ -} - -/* See cooked-index.h. */ - -void -cooked_index_worker::write_to_cache (const cooked_index *idx, - deferred_warnings *warn) const -{ - if (idx != nullptr) - { - /* Writing to the index cache may cause a warning to be emitted. - See PR symtab/30837. This arranges to capture all such - warnings. This is safe because we know the deferred_warnings - object isn't in use by any other thread at this point. */ - scoped_restore_warning_hook defer (warn); - m_cache_store.store (); - } -} - cooked_index::cooked_index (cooked_index_worker_up &&worker) : m_state (std::move (worker)) { diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h index beef8ff588f..1848798bfad 100644 --- a/gdb/dwarf2/cooked-index.h +++ b/gdb/dwarf2/cooked-index.h @@ -34,136 +34,7 @@ #include "gdbsupport/range-chain.h" #include "complaints.h" #include "dwarf2/cooked-index-shard.h" - -#if CXX_STD_THREAD -#include -#include -#endif /* CXX_STD_THREAD */ - -struct dwarf2_per_cu; -struct dwarf2_per_bfd; -struct index_cache_store_context; -struct cooked_index_entry; - -class cooked_index; - -/* The possible states of the index. See the explanatory comment - before cooked_index for more details. */ -enum class cooked_state -{ - /* The default state. This is not a valid argument to 'wait'. */ - INITIAL, - /* The initial scan has completed. The name of "main" is now - available (if known). The addrmaps are usable now. - Finalization has started but is not complete. */ - MAIN_AVAILABLE, - /* Finalization has completed. This means the index is fully - available for queries. */ - FINALIZED, - /* Writing to the index cache has finished. */ - CACHE_DONE, -}; - -/* 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. - - 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) - : m_per_objfile (per_objfile), - m_cache_store (global_index_cache, per_objfile->per_bfd) - { } - virtual ~cooked_index_worker () - { } - DISABLE_COPY_AND_ASSIGN (cooked_index_worker); - - /* Start reading. */ - void start (); - - /* Wait for a particular state to be achieved. If ALLOW_QUIT is - true, then the loop will check the QUIT flag. Normally this - method may only be called from the main thread; however, it can - be called from a worker thread provided that the desired state - has already been attained. (This oddity is used by the index - cache writer.) */ - bool wait (cooked_state desired_state, bool allow_quit); - -protected: - - /* Let cooked_index call the 'set' and 'write_to_cache' methods. */ - friend class cooked_index; - - /* Set the current state. */ - void set (cooked_state desired_state); - - /* Write to the index cache. */ - void write_to_cache (const cooked_index *idx, - deferred_warnings *warn) const; - - /* Helper function that does the work of reading. This must be able - to be run in a worker thread without problems. */ - virtual void do_reading () = 0; - - /* 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, a vector of errors that should be printed, and a - parent map. - - The errors are retained because GDB's I/O system is not - thread-safe. run_on_main_thread could be used, but that would - mean the messages are printed after the prompt, which looks - weird. */ - using result_type = std::tuple, - parent_map>; - - /* The per-objfile object. */ - dwarf2_per_objfile *m_per_objfile; - /* Result of each worker task. */ - std::vector m_results; - /* Any warnings emitted. This is not in 'result_type' because (for - the time being at least), it's only needed in do_reading, not in - every worker. Note that deferred_warnings uses gdb_stderr in its - constructor, and this should only be done from the main thread. - This is enforced in the cooked_index_worker constructor. */ - deferred_warnings m_warnings; - - /* A map of all parent maps. Used during finalization to fix up - parent relationships. */ - parent_map_map m_all_parents_map; - -#if CXX_STD_THREAD - /* Current state of this object. */ - cooked_state m_state = cooked_state::INITIAL; - /* Mutex and condition variable used to synchronize. */ - std::mutex m_mutex; - std::condition_variable m_cond; -#endif /* CXX_STD_THREAD */ - /* This flag indicates whether any complaints or exceptions that - arose during scanning have been reported by 'wait'. This may - only be modified on the main thread. */ - bool m_reported = false; - /* If set, an exception occurred during reading; in this case the - scanning is stopped and this exception will later be reported by - the 'wait' method. */ - std::optional m_failed; - /* An object used to write to the index cache. */ - index_cache_store_context m_cache_store; -}; - -using cooked_index_worker_up = std::unique_ptr; +#include "dwarf2/cooked-index-worker.h" /* The main index of DIEs.