X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdbsupport%2Fthread-pool.h;h=cb8696e1fa46e29bc546e9899087ebfde86213d7;hb=199cfcc4754cea6f4c42dcbb8d8d5161f5b2d186;hp=2fb44536545ebf6512cedb0a3b5436949868d95d;hpb=01027315f54048dbaf03ac37455c2528c72a6d9b;p=binutils-gdb.git diff --git a/gdbsupport/thread-pool.h b/gdbsupport/thread-pool.h index 2fb44536545..cb8696e1fa4 100644 --- a/gdbsupport/thread-pool.h +++ b/gdbsupport/thread-pool.h @@ -1,6 +1,6 @@ /* Thread pool - Copyright (C) 2019-2020 Free Software Foundation, Inc. + Copyright (C) 2019-2023 Free Software Foundation, Inc. This file is part of GDB. @@ -21,17 +21,103 @@ #define GDBSUPPORT_THREAD_POOL_H #include -#include #include #include +#include +#if CXX_STD_THREAD +#include #include #include #include +#endif #include "gdbsupport/gdb_optional.h" 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; + + 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 () { } +}; + +#endif /* CXX_STD_THREAD */ + + /* A thread pool. There is a single global thread pool, see g_thread_pool. Tasks can @@ -53,36 +139,72 @@ public: /* Return the number of executing threads. */ size_t thread_count () const { +#if CXX_STD_THREAD return m_thread_count; +#else + return 0; +#endif + } + + /* Post a task to the thread pool. A future is returned, which can + be used to wait for the result. */ + future post_task (std::function &&func) + { +#if CXX_STD_THREAD + std::packaged_task task (std::move (func)); + future result = task.get_future (); + do_post_task (std::packaged_task (std::move (task))); + return result; +#else + func (); + return {}; +#endif /* CXX_STD_THREAD */ } /* Post a task to the thread pool. A future is returned, which can be used to wait for the result. */ - std::future post_task (std::function func); + template + future post_task (std::function &&func) + { +#if CXX_STD_THREAD + std::packaged_task task (std::move (func)); + future result = task.get_future (); + do_post_task (std::packaged_task (std::move (task))); + return result; +#else + return future (func ()); +#endif /* CXX_STD_THREAD */ + } private: thread_pool () = default; +#if CXX_STD_THREAD /* The callback for each worker thread. */ void thread_function (); + /* Post a task to the thread pool. A future is returned, which can + be used to wait for the result. */ + void do_post_task (std::packaged_task &&func); + /* The current thread count. */ size_t m_thread_count = 0; /* A convenience typedef for the type of a task. */ - typedef std::packaged_task task; + typedef std::packaged_task task_t; /* The tasks that have not been processed yet. An optional is used to represent a task. If the optional is empty, then this means that the receiving thread should terminate. If the optional is non-empty, then it is an actual task to evaluate. */ - std::queue> m_tasks; + std::queue> m_tasks; /* A condition variable and mutex that are used for communication between the main thread and the worker threads. */ std::condition_variable m_tasks_cv; std::mutex m_tasks_mutex; +#endif /* CXX_STD_THREAD */ }; }