From: Tom Tromey Date: Wed, 1 Oct 2025 16:27:15 +0000 (-0600) Subject: Introduce gdbsupport/cxx-thread.h and use it X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2caf7b168912aaff869d4b13f6130baeaa45cb76;p=thirdparty%2Fbinutils-gdb.git Introduce gdbsupport/cxx-thread.h and use it This introduces a new file, gdbsupport/cxx-thread.h, which provides stubs for the C++ threading functionality on systems that don't support it. On fully-working ports, this header just supplies a number of aliases in the gdb namespace. So, for instance, gdb::mutex is just an alias for std::mutex. For non-working ports, compatibility stubs are provided for the subset of threading functionality that's used in gdb. These generally do nothing and assume single-threaded operation. The idea behind this is to reduce the number of checks of CXX_STD_THREAD, making the code cleaner. Not all spots using CXX_STD_THREAD could readily be converted. In particular: * Unit tests * --config output * Code manipulating threads themselves * The extension interrupting handling code These all seem fine to me. Note there's also a check in py-dap.c. This one is perhaps slightly subtle: DAP starts threads on the Python side, but it relies on gdb itself being thread-savvy, for instance in gdb.post_event. Approved-By: Simon Marchi --- diff --git a/gdb/complaints.c b/gdb/complaints.c index 3c7f9bc7c89..03d27d615a5 100644 --- a/gdb/complaints.c +++ b/gdb/complaints.c @@ -22,11 +22,9 @@ #include "cli/cli-cmds.h" #include "run-on-main-thread.h" #include "top.h" +#include "gdbsupport/cxx-thread.h" #include "gdbsupport/selftest.h" #include "gdbsupport/unordered_map.h" -#if CXX_STD_THREAD -#include -#endif /* Map format strings to counters. */ @@ -38,9 +36,7 @@ static gdb::unordered_map counters; int stop_whining = 0; -#if CXX_STD_THREAD -static std::mutex complaint_mutex; -#endif /* CXX_STD_THREAD */ +static gdb::mutex complaint_mutex; /* See complaints.h. */ @@ -50,9 +46,7 @@ complaint_internal (const char *fmt, ...) va_list args; { -#if CXX_STD_THREAD - std::lock_guard guard (complaint_mutex); -#endif + gdb::lock_guard guard (complaint_mutex); if (++counters[fmt] > stop_whining) return; } @@ -126,9 +120,7 @@ re_emit_complaints (const complaint_collection &complaints) void complaint_interceptor::warn (const char *fmt, va_list args) { -#if CXX_STD_THREAD - std::lock_guard guard (complaint_mutex); -#endif + gdb::lock_guard guard (complaint_mutex); g_complaint_interceptor->m_complaints.insert (string_vprintf (fmt, args)); } diff --git a/gdb/dwarf2/cooked-index-worker.c b/gdb/dwarf2/cooked-index-worker.c index 09d80eff629..abaf41fb00c 100644 --- a/gdb/dwarf2/cooked-index-worker.c +++ b/gdb/dwarf2/cooked-index-worker.c @@ -132,9 +132,8 @@ bool cooked_index_worker::wait (cooked_state desired_state, bool allow_quit) { bool done; -#if CXX_STD_THREAD { - std::unique_lock lock (m_mutex); + gdb::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 @@ -146,7 +145,7 @@ cooked_index_worker::wait (cooked_state desired_state, bool allow_quit) if (allow_quit) { std::chrono::milliseconds duration { 15 }; - if (m_cond.wait_for (lock, duration) == std::cv_status::timeout) + if (m_cond.wait_for (lock, duration) == gdb::cv_status::timeout) QUIT; } else @@ -154,11 +153,6 @@ cooked_index_worker::wait (cooked_state desired_state, bool allow_quit) } 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. */ @@ -213,15 +207,10 @@ 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::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-worker.h. */ diff --git a/gdb/dwarf2/cooked-index-worker.h b/gdb/dwarf2/cooked-index-worker.h index dfdc82f5274..4213b4e12b7 100644 --- a/gdb/dwarf2/cooked-index-worker.h +++ b/gdb/dwarf2/cooked-index-worker.h @@ -27,11 +27,7 @@ #include "dwarf2/read.h" #include "maint.h" #include "run-on-main-thread.h" - -#if CXX_STD_THREAD -#include -#include -#endif /* CXX_STD_THREAD */ +#include "gdbsupport/cxx-thread.h" using cutu_reader_up = std::unique_ptr; @@ -300,11 +296,9 @@ protected: /* Result of each worker task. */ std::vector m_results; -#if CXX_STD_THREAD /* Mutex to synchronize access to M_RESULTS when workers append their result. */ - std::mutex m_results_mutex; -#endif /* CXX_STD_THREAD */ + gdb::mutex m_results_mutex; /* Any warnings emitted. For the time being at least, this only needed in do_reading, not in every worker. Note that @@ -317,13 +311,12 @@ protected: 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 */ + gdb::mutex m_mutex; + gdb::condition_variable m_cond; + /* 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. */ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index db535bcf669..955893c5f0c 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -604,10 +604,8 @@ struct dwp_file dwo_unit_set loaded_cus; dwo_unit_set loaded_tus; -#if CXX_STD_THREAD /* Mutex to synchronize access to LOADED_CUS and LOADED_TUS. */ - std::mutex loaded_cutus_lock; -#endif + gdb::mutex loaded_cutus_lock; /* Table to map ELF section numbers to their sections. This is only needed for the DWP V1 file format. */ @@ -3326,9 +3324,7 @@ private: m_thread_storage.done_reading (m_complaint_handler.release ()); /* Append the results of this worker to the parent instance. */ -#if CXX_STD_THREAD - std::lock_guard lock (m_parent->m_results_mutex); -#endif + gdb::lock_guard lock (m_parent->m_results_mutex); m_parent->m_results.emplace_back (std::move (m_thread_storage)); } @@ -6317,12 +6313,8 @@ static dwo_file * lookup_dwo_file (dwarf2_per_bfd *per_bfd, const char *dwo_name, const char *comp_dir) { -#if CXX_STD_THREAD - std::lock_guard guard (per_bfd->dwo_files_lock); -#endif - + gdb::lock_guard guard (per_bfd->dwo_files_lock); auto it = per_bfd->dwo_files.find (dwo_file_search {dwo_name, comp_dir}); - return it != per_bfd->dwo_files.end () ? it->get() : nullptr; } @@ -6337,10 +6329,7 @@ lookup_dwo_file (dwarf2_per_bfd *per_bfd, const char *dwo_name, static dwo_file * add_dwo_file (dwarf2_per_bfd *per_bfd, dwo_file_up dwo_file) { -#if CXX_STD_THREAD - std::lock_guard lock (per_bfd->dwo_files_lock); -#endif - + gdb::lock_guard lock (per_bfd->dwo_files_lock); return per_bfd->dwo_files.emplace (std::move (dwo_file)).first->get (); } @@ -7472,10 +7461,7 @@ lookup_dwo_unit_in_dwp (dwarf2_per_bfd *per_bfd, = is_debug_types ? dwp_file->loaded_tus : dwp_file->loaded_cus; { -#if CXX_STD_THREAD - std::lock_guard guard (dwp_file->loaded_cutus_lock); -#endif - + gdb::lock_guard guard (dwp_file->loaded_cutus_lock); if (auto it = dwo_unit_set.find (signature); it != dwo_unit_set.end ()) return it->get (); @@ -7510,10 +7496,7 @@ lookup_dwo_unit_in_dwp (dwarf2_per_bfd *per_bfd, /* If another thread raced with this one, opening the exact same DWO unit, then we'll keep that other thread's copy. */ -#if CXX_STD_THREAD - std::lock_guard guard (dwp_file->loaded_cutus_lock); -#endif - + gdb::lock_guard guard (dwp_file->loaded_cutus_lock); auto it = dwo_unit_set.emplace (std::move (dwo_unit)).first; return it->get (); } @@ -7593,12 +7576,10 @@ try_open_dwop_file (dwarf2_per_bfd *per_bfd, const char *file_name, int is_dwp, return NULL; { -#if CXX_STD_THREAD /* The operations below are not thread-safe, use a lock to synchronize concurrent accesses. */ - static std::mutex mutex; - std::lock_guard lock (mutex); -#endif + static gdb::mutex mutex; + gdb::lock_guard lock (mutex); if (!bfd_check_format (sym_bfd.get (), bfd_object)) return NULL; diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 2f9ad05b792..f0d46f6acc6 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -20,9 +20,6 @@ #ifndef GDB_DWARF2_READ_H #define GDB_DWARF2_READ_H -#if CXX_STD_THREAD -#include -#endif #include #include "dwarf2/abbrev.h" #include "dwarf2/unit-head.h" @@ -32,6 +29,7 @@ #include "dwarf2/section.h" #include "dwarf2/cu.h" #include "dwarf2/dwz.h" +#include "gdbsupport/cxx-thread.h" #include "gdbsupport/gdb_obstack.h" #include "gdbsupport/function-view.h" #include "gdbsupport/packed.h" @@ -618,10 +616,8 @@ public: /* Set of dwo_file objects. */ dwo_file_up_set dwo_files; -#if CXX_STD_THREAD /* Mutex to synchronize access to DWO_FILES. */ - std::mutex dwo_files_lock; -#endif + gdb::mutex dwo_files_lock; /* The DWP file if there is one, or NULL. */ dwp_file_up dwp_file; diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c index 2e477eba6a9..4c641fe4c7b 100644 --- a/gdb/gdb_bfd.c +++ b/gdb/gdb_bfd.c @@ -33,18 +33,15 @@ #include "gdbsupport/fileio.h" #include "inferior.h" #include "cli/cli-style.h" +#include "gdbsupport/cxx-thread.h" #include "gdbsupport/unordered_map.h" #include "gdbsupport/unordered_set.h" -#if CXX_STD_THREAD - -#include - /* Lock held when doing BFD operations. A recursive mutex is used because we use this mutex internally and also for BFD, just to make life a bit simpler, and we may sometimes hold it while calling into BFD. */ -static std::recursive_mutex gdb_bfd_mutex; +static gdb::recursive_mutex gdb_bfd_mutex; /* BFD locking function. */ @@ -64,8 +61,6 @@ gdb_bfd_unlock (void *ignore) return true; } -#endif /* CXX_STD_THREAD */ - /* An object of this type is stored in the section's user data when mapping a section. */ @@ -153,7 +148,6 @@ struct gdb_bfd_data /* The registry. */ registry registry_fields; -#if CXX_STD_THREAD /* Most of the locking needed for multi-threaded operation is handled by BFD itself. However, the current BFD model is that locking is only needed for global operations -- but it turned out @@ -163,8 +157,7 @@ struct gdb_bfd_data This lock is the fix: wrappers for important BFD functions will acquire this lock before performing operations that might modify the state of this BFD. */ - std::mutex per_bfd_mutex; -#endif + gdb::mutex per_bfd_mutex; }; registry * @@ -548,9 +541,7 @@ gdb_bfd_open (const char *name, const char *target, int fd, name += strlen (TARGET_SYSROOT_PREFIX); } -#if CXX_STD_THREAD - std::lock_guard guard (gdb_bfd_mutex); -#endif + gdb::lock_guard guard (gdb_bfd_mutex); if (fd == -1) { @@ -677,9 +668,7 @@ gdb_bfd_ref (struct bfd *abfd) if (abfd == NULL) return; -#if CXX_STD_THREAD - std::lock_guard guard (gdb_bfd_mutex); -#endif + gdb::lock_guard guard (gdb_bfd_mutex); gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd); @@ -709,9 +698,7 @@ gdb_bfd_unref (struct bfd *abfd) if (abfd == NULL) return; -#if CXX_STD_THREAD - std::lock_guard guard (gdb_bfd_mutex); -#endif + gdb::lock_guard guard (gdb_bfd_mutex); gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd); gdb_assert (gdata->refc >= 1); @@ -779,10 +766,8 @@ gdb_bfd_map_section (asection *sectp, bfd_size_type *size) abfd = sectp->owner; -#if CXX_STD_THREAD gdb_bfd_data *gdata = (gdb_bfd_data *) bfd_usrdata (abfd); - std::lock_guard guard (gdata->per_bfd_mutex); -#endif + gdb::lock_guard guard (gdata->per_bfd_mutex); descriptor = get_section_descriptor (sectp); @@ -1115,10 +1100,8 @@ bool gdb_bfd_get_full_section_contents (bfd *abfd, asection *section, gdb::byte_vector *contents) { -#if CXX_STD_THREAD gdb_bfd_data *gdata = (gdb_bfd_data *) bfd_usrdata (abfd); - std::lock_guard guard (gdata->per_bfd_mutex); -#endif + gdb::lock_guard guard (gdata->per_bfd_mutex); bfd_size_type section_size = bfd_section_size (section); @@ -1133,10 +1116,8 @@ gdb_bfd_get_full_section_contents (bfd *abfd, asection *section, int gdb_bfd_stat (bfd *abfd, struct stat *sbuf) { -#if CXX_STD_THREAD gdb_bfd_data *gdata = (gdb_bfd_data *) bfd_usrdata (abfd); - std::lock_guard guard (gdata->per_bfd_mutex); -#endif + gdb::lock_guard guard (gdata->per_bfd_mutex); return bfd_stat (abfd, sbuf); } @@ -1146,10 +1127,8 @@ gdb_bfd_stat (bfd *abfd, struct stat *sbuf) long gdb_bfd_get_mtime (bfd *abfd) { -#if CXX_STD_THREAD gdb_bfd_data *gdata = (gdb_bfd_data *) bfd_usrdata (abfd); - std::lock_guard guard (gdata->per_bfd_mutex); -#endif + gdb::lock_guard guard (gdata->per_bfd_mutex); return bfd_get_mtime (abfd); } @@ -1290,9 +1269,7 @@ get_bfd_inferior_data (struct inferior *inf) static unsigned long increment_bfd_error_count (const std::string &str) { -#if CXX_STD_THREAD - std::lock_guard guard (gdb_bfd_mutex); -#endif + gdb::lock_guard guard (gdb_bfd_mutex); struct bfd_inferior_data *bid = get_bfd_inferior_data (current_inferior ()); auto &map = bid->bfd_error_string_counts; @@ -1337,9 +1314,7 @@ gdb_bfd_init () { if (bfd_init () == BFD_INIT_MAGIC) { -#if CXX_STD_THREAD if (bfd_thread_init (gdb_bfd_lock, gdb_bfd_unlock, nullptr)) -#endif return; } diff --git a/gdb/minsyms.c b/gdb/minsyms.c index d3a8d670d1b..c23d1706637 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -51,13 +51,10 @@ #include "cli/cli-utils.h" #include "gdbsupport/symbol.h" #include +#include "gdbsupport/cxx-thread.h" #include "gdbsupport/parallel-for.h" #include "inferior.h" -#if CXX_STD_THREAD -#include -#endif - /* Return true if MINSYM is a cold clone symbol. Recognize f.i. these symbols (mangled/demangled): - _ZL3foov.cold @@ -1398,18 +1395,13 @@ public: minimal_symbol_install_worker (minimal_symbol *msymbols, gdb::array_view hash_values, - objfile_per_bfd_storage *per_bfd -#if CXX_STD_THREAD - , std::mutex &demangled_mutex -#endif - ) + objfile_per_bfd_storage *per_bfd, + gdb::mutex &demangled_mutex) : m_time_it ("minsym install worker"), m_msymbols (msymbols), m_hash_values (hash_values), - m_per_bfd (per_bfd) -#if CXX_STD_THREAD - , m_demangled_mutex (demangled_mutex) -#endif + m_per_bfd (per_bfd), + m_demangled_mutex (demangled_mutex) {} void operator() (iterator_range msym_range) noexcept @@ -1447,9 +1439,7 @@ public: { /* To limit how long we hold the lock, we only acquire it here and not while we demangle the names above. */ -#if CXX_STD_THREAD - std::lock_guard guard (m_demangled_mutex); -#endif + gdb::lock_guard guard (m_demangled_mutex); for (minimal_symbol &msym : msym_range) { size_t idx = &msym - m_msymbols; @@ -1467,9 +1457,7 @@ private: minimal_symbol *m_msymbols; gdb::array_view m_hash_values; objfile_per_bfd_storage *m_per_bfd; -#if CXX_STD_THREAD - std::mutex &m_demangled_mutex; -#endif + gdb::mutex &m_demangled_mutex; }; /* Add the minimal symbols in the existing bunches to the objfile's official @@ -1549,11 +1537,9 @@ minimal_symbol_reader::install () m_objfile->per_bfd->minimal_symbol_count = mcount; m_objfile->per_bfd->msymbols = std::move (msym_holder); -#if CXX_STD_THREAD /* Mutex that is used when modifying or accessing the demangled hash table. */ - std::mutex demangled_mutex; -#endif + gdb::mutex demangled_mutex; std::vector hash_values (mcount); @@ -1562,11 +1548,8 @@ minimal_symbol_reader::install () gdb::parallel_for_each<1000, minimal_symbol *, minimal_symbol_install_worker> (&msymbols[0], &msymbols[mcount], msymbols, gdb::array_view (hash_values), - m_objfile->per_bfd -#if CXX_STD_THREAD - , demangled_mutex -#endif - ); + m_objfile->per_bfd, + demangled_mutex); build_minimal_symbol_hash_tables (m_objfile, hash_values); } diff --git a/gdb/run-on-main-thread.c b/gdb/run-on-main-thread.c index 0cfe4716c24..d68811bebdd 100644 --- a/gdb/run-on-main-thread.c +++ b/gdb/run-on-main-thread.c @@ -18,11 +18,8 @@ #include "run-on-main-thread.h" #include "ser-event.h" -#if CXX_STD_THREAD -#include -#include -#endif #include "gdbsupport/cleanups.h" +#include "gdbsupport/cxx-thread.h" #include "gdbsupport/event-loop.h" /* The serial event used when posting runnables. */ @@ -33,17 +30,13 @@ static struct serial_event *runnable_event; static std::vector> runnables; -#if CXX_STD_THREAD - /* Mutex to hold when handling RUNNABLE_EVENT or RUNNABLES. */ -static std::mutex runnable_mutex; +static gdb::mutex runnable_mutex; /* The main thread's thread id. */ -static std::thread::id main_thread_id; - -#endif +static gdb::thread::id main_thread_id; /* Run all the queued runnables. */ @@ -55,9 +48,7 @@ run_events (int error, gdb_client_data client_data) /* Hold the lock while changing the globals, but not while running the runnables. */ { -#if CXX_STD_THREAD - std::lock_guard lock (runnable_mutex); -#endif + gdb::lock_guard lock (runnable_mutex); /* Clear the event fd. Do this before flushing the events list, so that any new event post afterwards is sure to re-awaken the @@ -100,47 +91,38 @@ run_events (int error, gdb_client_data client_data) void run_on_main_thread (std::function &&func) { -#if CXX_STD_THREAD - std::lock_guard lock (runnable_mutex); -#endif + gdb::lock_guard lock (runnable_mutex); runnables.emplace_back (std::move (func)); serial_event_set (runnable_event); } -#if CXX_STD_THREAD static bool main_thread_id_initialized = false; -#endif /* See run-on-main-thread.h. */ bool is_main_thread () { -#if CXX_STD_THREAD /* Initialize main_thread_id on first use of is_main_thread. */ if (!main_thread_id_initialized) { main_thread_id_initialized = true; - main_thread_id = std::this_thread::get_id (); + main_thread_id = gdb::this_thread::get_id (); } - return std::this_thread::get_id () == main_thread_id; -#else - return true; -#endif + return gdb::this_thread::get_id () == main_thread_id; } INIT_GDB_FILE (run_on_main_thread) { -#if CXX_STD_THREAD /* The variable main_thread_id should be initialized when entering main, or at an earlier use, so it should already be initialized here. */ gdb_assert (main_thread_id_initialized); /* Assume that we execute this in the main thread. */ gdb_assert (is_main_thread ()); -#endif + runnable_event = make_serial_event (); add_file_handler (serial_event_fd (runnable_event), run_events, nullptr, "run-on-main-thread"); @@ -150,9 +132,7 @@ INIT_GDB_FILE (run_on_main_thread) languages are shut down. */ add_final_cleanup ([] () { -#if CXX_STD_THREAD - std::lock_guard lock (runnable_mutex); -#endif + gdb::lock_guard lock (runnable_mutex); runnables.clear (); }); } diff --git a/gdbsupport/cxx-thread.h b/gdbsupport/cxx-thread.h new file mode 100644 index 00000000000..e4061ebef9d --- /dev/null +++ b/gdbsupport/cxx-thread.h @@ -0,0 +1,243 @@ +/* Wrappers for C++ threading + + Copyright (C) 2025 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 . */ + +#ifndef GDBSUPPORT_CXX_THREAD_H +#define GDBSUPPORT_CXX_THREAD_H + +/* This header implements shims for the parts of the C++ threading + library that are needed by gdb. + + The reason this exists is that some versions of libstdc++ do not + supply a working C++ thread implementation. In particular this was + true for several versions of the Windows compiler. See + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93687. + + For systems where this works, this header just supplies aliases of + the standard functionality, in the "gdb" namespace. For example, + "gdb::mutex" is an alias for "std::mutex". + + For non-working ports, shims are provided. These are just the + subset needed by gdb, and they generally do nothing, or as little + as possible. In particular they all simply assume single-threaded + operation. */ + +#if CXX_STD_THREAD + +#include +#include +#include +#include + +namespace gdb +{ + +using condition_variable = std::condition_variable; +using cv_status = std::cv_status; +using future_status = std::future_status; +using mutex = std::mutex; +using recursive_mutex = std::recursive_mutex; +using thread = std::thread; + +namespace this_thread = std::this_thread; + +template +using lock_guard = std::lock_guard; + +template +using unique_lock = std::unique_lock; + +template +using future = std::future; + +} /* namespace gdb*/ + +#else + +#include + +namespace gdb +{ + +/* A do-nothing replacement for std::mutex. */ +struct mutex +{ + mutex () = default; + + DISABLE_COPY_AND_ASSIGN (mutex); + + void lock () + { + } + + void unlock () + { + } +}; + +/* A do-nothing replacement for std::recursive_mutex. */ +struct recursive_mutex +{ + recursive_mutex () = default; + + DISABLE_COPY_AND_ASSIGN (recursive_mutex); + + void lock () + { + } + + void unlock () + { + } +}; + +/* A do-nothing replacement for std::lock_guard. */ +template +struct lock_guard +{ + explicit lock_guard (T &m) + { + } + + DISABLE_COPY_AND_ASSIGN (lock_guard); +}; + +/* A do-nothing replacement for std::unique_lock. */ +template +struct unique_lock +{ + explicit unique_lock (T &m) + { + } + + DISABLE_COPY_AND_ASSIGN (unique_lock); +}; + +/* A compatibility enum for std::cv_status. */ +enum class cv_status +{ + no_timeout, + timeout, +}; + +/* A do-nothing replacement for std::condition_variable. */ +struct condition_variable +{ + condition_variable () = default; + + DISABLE_COPY_AND_ASSIGN (condition_variable); + + void notify_one () noexcept + { + } + + void wait (unique_lock &lock) + { + } + + template + cv_status wait_for (unique_lock &lock, + const std::chrono::duration &rel_time) + { + return cv_status::no_timeout; + } +}; + +/* A compatibility enum for std::future_status. This is just the + subset needed by gdb. */ +enum class future_status +{ + ready, + timeout, +}; + +/* A compatibility implementation of std::future. */ +template +class future +{ +public: + + explicit future (T value) + : m_value (std::move (value)) + { + } + + future () = default; + future (future &&other) = default; + future (const future &other) = delete; + future &operator= (future &&other) = default; + future &operator= (const future &other) = delete; + + void wait () const { } + + template + future_status wait_for (const std::chrono::duration &duration) + const + { + return future_status::ready; + } + + T get () { return std::move (m_value); } + +private: + + T m_value; +}; + +/* A specialization for void. */ + +template<> +class future +{ +public: + void wait () const { } + + template + future_status wait_for (const std::chrono::duration &duration) + const + { + return future_status::ready; + } + + void get () { } +}; + +/* Rather than try to write a gdb::thread class, we just use a + namespace since only the 'id' type is needed. Code manipulating + actual std::thread objects has to be wrapped in a check anyway. */ +namespace thread +{ +/* Replacement for std::thread::id. */ +using id = int; +} + +/* Replacement for std::this_thread. */ +namespace this_thread +{ +static inline thread::id +get_id () +{ + return 0; +} +} + +} /* namespace gdb */ + +#endif /* CXX_STD_THREAD */ + +#endif /* GDBSUPPORT_CXX_THREAD_H */ diff --git a/gdbsupport/thread-pool.h b/gdbsupport/thread-pool.h index f3ac94bf588..b5b2934b8c3 100644 --- a/gdbsupport/thread-pool.h +++ b/gdbsupport/thread-pool.h @@ -24,99 +24,12 @@ #include #include #include -#if CXX_STD_THREAD -#include -#include -#include -#include -#endif #include -namespace gdb -{ - -#if CXX_STD_THREAD - -/* Simply use the standard future. */ -template -using future = std::future; - -/* ... and the standard future_status. */ -using future_status = std::future_status; - -#else /* CXX_STD_THREAD */ - -/* A compatibility enum for std::future_status. This is just the - subset needed by gdb. */ -enum class future_status -{ - ready, - timeout, -}; - -/* A compatibility wrapper for std::future. Once and - are available in all GCC builds -- should that ever happen - -- this can be removed. GCC does not implement threading for - MinGW, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93687. - - Meanwhile, in this mode, there are no threads. Tasks submitted to - the thread pool are invoked immediately and their result is stored - here. The base template here simply wraps a T and provides some - std::future compatibility methods. The provided methods are chosen - based on what GDB needs presently. */ - -template -class future -{ -public: - - explicit future (T value) - : m_value (std::move (value)) - { - } - - future () = default; - future (future &&other) = default; - future (const future &other) = delete; - future &operator= (future &&other) = default; - future &operator= (const future &other) = delete; +#include "gdbsupport/cxx-thread.h" - void wait () const { } - - template - future_status wait_for (const std::chrono::duration &duration) - const - { - return future_status::ready; - } - - T get () { return std::move (m_value); } - -private: - - T m_value; -}; - -/* A specialization for void. */ - -template<> -class future +namespace gdb { -public: - void wait () const { } - - template - future_status wait_for (const std::chrono::duration &duration) - const - { - return future_status::ready; - } - - void get () { } -}; - -#endif /* CXX_STD_THREAD */ - /* A thread pool.