#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 <mutex>
-#endif
/* Map format strings to 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. */
va_list args;
{
-#if CXX_STD_THREAD
- std::lock_guard<std::mutex> guard (complaint_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> guard (complaint_mutex);
if (++counters[fmt] > stop_whining)
return;
}
void
complaint_interceptor::warn (const char *fmt, va_list args)
{
-#if CXX_STD_THREAD
- std::lock_guard<std::mutex> guard (complaint_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> guard (complaint_mutex);
g_complaint_interceptor->m_complaints.insert (string_vprintf (fmt, args));
}
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);
+ gdb::unique_lock<gdb::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
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
}
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. */
{
gdb_assert (desired_state != cooked_state::INITIAL);
-#if CXX_STD_THREAD
- std::lock_guard<std::mutex> guard (m_mutex);
+ gdb::lock_guard<gdb::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 */
}
/* See cooked-index-worker.h. */
#include "dwarf2/read.h"
#include "maint.h"
#include "run-on-main-thread.h"
-
-#if CXX_STD_THREAD
-#include <mutex>
-#include <condition_variable>
-#endif /* CXX_STD_THREAD */
+#include "gdbsupport/cxx-thread.h"
using cutu_reader_up = std::unique_ptr<cutu_reader>;
/* Result of each worker task. */
std::vector<cooked_index_worker_result> 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
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. */
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. */
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<std::mutex> lock (m_parent->m_results_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> lock (m_parent->m_results_mutex);
m_parent->m_results.emplace_back (std::move (m_thread_storage));
}
lookup_dwo_file (dwarf2_per_bfd *per_bfd, const char *dwo_name,
const char *comp_dir)
{
-#if CXX_STD_THREAD
- std::lock_guard<std::mutex> guard (per_bfd->dwo_files_lock);
-#endif
-
+ gdb::lock_guard<gdb::mutex> 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;
}
static dwo_file *
add_dwo_file (dwarf2_per_bfd *per_bfd, dwo_file_up dwo_file)
{
-#if CXX_STD_THREAD
- std::lock_guard<std::mutex> lock (per_bfd->dwo_files_lock);
-#endif
-
+ gdb::lock_guard<gdb::mutex> lock (per_bfd->dwo_files_lock);
return per_bfd->dwo_files.emplace (std::move (dwo_file)).first->get ();
}
= is_debug_types ? dwp_file->loaded_tus : dwp_file->loaded_cus;
{
-#if CXX_STD_THREAD
- std::lock_guard<std::mutex> guard (dwp_file->loaded_cutus_lock);
-#endif
-
+ gdb::lock_guard<gdb::mutex> guard (dwp_file->loaded_cutus_lock);
if (auto it = dwo_unit_set.find (signature);
it != dwo_unit_set.end ())
return it->get ();
/* 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<std::mutex> guard (dwp_file->loaded_cutus_lock);
-#endif
-
+ gdb::lock_guard<gdb::mutex> guard (dwp_file->loaded_cutus_lock);
auto it = dwo_unit_set.emplace (std::move (dwo_unit)).first;
return it->get ();
}
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<std::mutex> lock (mutex);
-#endif
+ static gdb::mutex mutex;
+ gdb::lock_guard<gdb::mutex> lock (mutex);
if (!bfd_check_format (sym_bfd.get (), bfd_object))
return NULL;
#ifndef GDB_DWARF2_READ_H
#define GDB_DWARF2_READ_H
-#if CXX_STD_THREAD
-#include <mutex>
-#endif
#include <queue>
#include "dwarf2/abbrev.h"
#include "dwarf2/unit-head.h"
#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"
/* 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;
#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 <mutex>
-
/* 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. */
return true;
}
-#endif /* CXX_STD_THREAD */
-
/* An object of this type is stored in the section's user data when
mapping a section. */
/* The registry. */
registry<bfd> 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
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<bfd> *
name += strlen (TARGET_SYSROOT_PREFIX);
}
-#if CXX_STD_THREAD
- std::lock_guard<std::recursive_mutex> guard (gdb_bfd_mutex);
-#endif
+ gdb::lock_guard<gdb::recursive_mutex> guard (gdb_bfd_mutex);
if (fd == -1)
{
if (abfd == NULL)
return;
-#if CXX_STD_THREAD
- std::lock_guard<std::recursive_mutex> guard (gdb_bfd_mutex);
-#endif
+ gdb::lock_guard<gdb::recursive_mutex> guard (gdb_bfd_mutex);
gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
if (abfd == NULL)
return;
-#if CXX_STD_THREAD
- std::lock_guard<std::recursive_mutex> guard (gdb_bfd_mutex);
-#endif
+ gdb::lock_guard<gdb::recursive_mutex> guard (gdb_bfd_mutex);
gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
gdb_assert (gdata->refc >= 1);
abfd = sectp->owner;
-#if CXX_STD_THREAD
gdb_bfd_data *gdata = (gdb_bfd_data *) bfd_usrdata (abfd);
- std::lock_guard<std::mutex> guard (gdata->per_bfd_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> guard (gdata->per_bfd_mutex);
descriptor = get_section_descriptor (sectp);
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<std::mutex> guard (gdata->per_bfd_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> guard (gdata->per_bfd_mutex);
bfd_size_type section_size = bfd_section_size (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<std::mutex> guard (gdata->per_bfd_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> guard (gdata->per_bfd_mutex);
return bfd_stat (abfd, 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<std::mutex> guard (gdata->per_bfd_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> guard (gdata->per_bfd_mutex);
return bfd_get_mtime (abfd);
}
static unsigned long
increment_bfd_error_count (const std::string &str)
{
-#if CXX_STD_THREAD
- std::lock_guard<std::recursive_mutex> guard (gdb_bfd_mutex);
-#endif
+ gdb::lock_guard<gdb::recursive_mutex> guard (gdb_bfd_mutex);
struct bfd_inferior_data *bid = get_bfd_inferior_data (current_inferior ());
auto &map = bid->bfd_error_string_counts;
{
if (bfd_init () == BFD_INIT_MAGIC)
{
-#if CXX_STD_THREAD
if (bfd_thread_init (gdb_bfd_lock, gdb_bfd_unlock, nullptr))
-#endif
return;
}
#include "cli/cli-utils.h"
#include "gdbsupport/symbol.h"
#include <algorithm>
+#include "gdbsupport/cxx-thread.h"
#include "gdbsupport/parallel-for.h"
#include "inferior.h"
-#if CXX_STD_THREAD
-#include <mutex>
-#endif
-
/* Return true if MINSYM is a cold clone symbol.
Recognize f.i. these symbols (mangled/demangled):
- _ZL3foov.cold
minimal_symbol_install_worker
(minimal_symbol *msymbols,
gdb::array_view<computed_hash_values> 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<minimal_symbol *> msym_range) noexcept
{
/* 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<std::mutex> guard (m_demangled_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> guard (m_demangled_mutex);
for (minimal_symbol &msym : msym_range)
{
size_t idx = &msym - m_msymbols;
minimal_symbol *m_msymbols;
gdb::array_view<computed_hash_values> 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
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<computed_hash_values> hash_values (mcount);
gdb::parallel_for_each<1000, minimal_symbol *, minimal_symbol_install_worker>
(&msymbols[0], &msymbols[mcount], msymbols,
gdb::array_view<computed_hash_values> (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);
}
#include "run-on-main-thread.h"
#include "ser-event.h"
-#if CXX_STD_THREAD
-#include <thread>
-#include <mutex>
-#endif
#include "gdbsupport/cleanups.h"
+#include "gdbsupport/cxx-thread.h"
#include "gdbsupport/event-loop.h"
/* The serial event used when posting runnables. */
static std::vector<std::function<void ()>> 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. */
/* Hold the lock while changing the globals, but not while running
the runnables. */
{
-#if CXX_STD_THREAD
- std::lock_guard<std::mutex> lock (runnable_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> 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
void
run_on_main_thread (std::function<void ()> &&func)
{
-#if CXX_STD_THREAD
- std::lock_guard<std::mutex> lock (runnable_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> 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");
languages are shut down. */
add_final_cleanup ([] ()
{
-#if CXX_STD_THREAD
- std::lock_guard<std::mutex> lock (runnable_mutex);
-#endif
+ gdb::lock_guard<gdb::mutex> lock (runnable_mutex);
runnables.clear ();
});
}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#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 <thread>
+#include <mutex>
+#include <condition_variable>
+#include <future>
+
+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<typename T>
+using lock_guard = std::lock_guard<T>;
+
+template<typename T>
+using unique_lock = std::unique_lock<T>;
+
+template<typename T>
+using future = std::future<T>;
+
+} /* namespace gdb*/
+
+#else
+
+#include <chrono>
+
+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<typename T>
+struct lock_guard
+{
+ explicit lock_guard (T &m)
+ {
+ }
+
+ DISABLE_COPY_AND_ASSIGN (lock_guard);
+};
+
+/* A do-nothing replacement for std::unique_lock. */
+template<typename T>
+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<mutex> &lock)
+ {
+ }
+
+ template<class Rep, class Period>
+ cv_status wait_for (unique_lock<mutex> &lock,
+ const std::chrono::duration<Rep, Period> &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<typename T>
+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<class Rep, class Period>
+ future_status wait_for (const std::chrono::duration<Rep,Period> &duration)
+ const
+ {
+ return future_status::ready;
+ }
+
+ T get () { return std::move (m_value); }
+
+private:
+
+ T m_value;
+};
+
+/* A specialization for void. */
+
+template<>
+class future<void>
+{
+public:
+ void wait () const { }
+
+ template<class Rep, class Period>
+ future_status wait_for (const std::chrono::duration<Rep,Period> &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 */
#include <vector>
#include <functional>
#include <chrono>
-#if CXX_STD_THREAD
-#include <thread>
-#include <mutex>
-#include <condition_variable>
-#include <future>
-#endif
#include <optional>
-namespace gdb
-{
-
-#if CXX_STD_THREAD
-
-/* Simply use the standard future. */
-template<typename T>
-using future = std::future<T>;
-
-/* ... 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 <thread> and
- <future> 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<typename T>
-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<class Rep, class Period>
- future_status wait_for (const std::chrono::duration<Rep,Period> &duration)
- const
- {
- return future_status::ready;
- }
-
- T get () { return std::move (m_value); }
-
-private:
-
- T m_value;
-};
-
-/* A specialization for void. */
-
-template<>
-class future<void>
+namespace gdb
{
-public:
- void wait () const { }
-
- template<class Rep, class Period>
- future_status wait_for (const std::chrono::duration<Rep,Period> &duration)
- const
- {
- return future_status::ready;
- }
-
- void get () { }
-};
-
-#endif /* CXX_STD_THREAD */
-
/* A thread pool.