| /* 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 */ |