Home | History | Annotate | Line # | Download | only in gdbsupport
thread-pool.h revision 1.1.1.2.2.1
      1          1.1  christos /* Thread pool
      2          1.1  christos 
      3  1.1.1.2.2.1  perseant    Copyright (C) 2019-2024 Free Software Foundation, Inc.
      4          1.1  christos 
      5          1.1  christos    This file is part of GDB.
      6          1.1  christos 
      7          1.1  christos    This program is free software; you can redistribute it and/or modify
      8          1.1  christos    it under the terms of the GNU General Public License as published by
      9          1.1  christos    the Free Software Foundation; either version 3 of the License, or
     10          1.1  christos    (at your option) any later version.
     11          1.1  christos 
     12          1.1  christos    This program is distributed in the hope that it will be useful,
     13          1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14          1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15          1.1  christos    GNU General Public License for more details.
     16          1.1  christos 
     17          1.1  christos    You should have received a copy of the GNU General Public License
     18          1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19          1.1  christos 
     20          1.1  christos #ifndef GDBSUPPORT_THREAD_POOL_H
     21          1.1  christos #define GDBSUPPORT_THREAD_POOL_H
     22          1.1  christos 
     23          1.1  christos #include <queue>
     24          1.1  christos #include <vector>
     25          1.1  christos #include <functional>
     26  1.1.1.2.2.1  perseant #include <chrono>
     27      1.1.1.2  christos #if CXX_STD_THREAD
     28      1.1.1.2  christos #include <thread>
     29          1.1  christos #include <mutex>
     30          1.1  christos #include <condition_variable>
     31          1.1  christos #include <future>
     32      1.1.1.2  christos #endif
     33  1.1.1.2.2.1  perseant #include <optional>
     34          1.1  christos 
     35          1.1  christos namespace gdb
     36          1.1  christos {
     37          1.1  christos 
     38      1.1.1.2  christos #if CXX_STD_THREAD
     39      1.1.1.2  christos 
     40      1.1.1.2  christos /* Simply use the standard future.  */
     41      1.1.1.2  christos template<typename T>
     42      1.1.1.2  christos using future = std::future<T>;
     43      1.1.1.2  christos 
     44  1.1.1.2.2.1  perseant /* ... and the standard future_status.  */
     45  1.1.1.2.2.1  perseant using future_status = std::future_status;
     46  1.1.1.2.2.1  perseant 
     47      1.1.1.2  christos #else /* CXX_STD_THREAD */
     48      1.1.1.2  christos 
     49  1.1.1.2.2.1  perseant /* A compatibility enum for std::future_status.  This is just the
     50  1.1.1.2.2.1  perseant    subset needed by gdb.  */
     51  1.1.1.2.2.1  perseant enum class future_status
     52  1.1.1.2.2.1  perseant {
     53  1.1.1.2.2.1  perseant   ready,
     54  1.1.1.2.2.1  perseant   timeout,
     55  1.1.1.2.2.1  perseant };
     56  1.1.1.2.2.1  perseant 
     57      1.1.1.2  christos /* A compatibility wrapper for std::future.  Once <thread> and
     58      1.1.1.2  christos    <future> are available in all GCC builds -- should that ever happen
     59      1.1.1.2  christos    -- this can be removed.  GCC does not implement threading for
     60      1.1.1.2  christos    MinGW, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93687.
     61      1.1.1.2  christos 
     62      1.1.1.2  christos    Meanwhile, in this mode, there are no threads.  Tasks submitted to
     63      1.1.1.2  christos    the thread pool are invoked immediately and their result is stored
     64      1.1.1.2  christos    here.  The base template here simply wraps a T and provides some
     65      1.1.1.2  christos    std::future compatibility methods.  The provided methods are chosen
     66      1.1.1.2  christos    based on what GDB needs presently.  */
     67      1.1.1.2  christos 
     68      1.1.1.2  christos template<typename T>
     69      1.1.1.2  christos class future
     70      1.1.1.2  christos {
     71      1.1.1.2  christos public:
     72      1.1.1.2  christos 
     73      1.1.1.2  christos   explicit future (T value)
     74      1.1.1.2  christos     : m_value (std::move (value))
     75      1.1.1.2  christos   {
     76      1.1.1.2  christos   }
     77      1.1.1.2  christos 
     78      1.1.1.2  christos   future () = default;
     79      1.1.1.2  christos   future (future &&other) = default;
     80      1.1.1.2  christos   future (const future &other) = delete;
     81      1.1.1.2  christos   future &operator= (future &&other) = default;
     82      1.1.1.2  christos   future &operator= (const future &other) = delete;
     83      1.1.1.2  christos 
     84      1.1.1.2  christos   void wait () const { }
     85      1.1.1.2  christos 
     86  1.1.1.2.2.1  perseant   template<class Rep, class Period>
     87  1.1.1.2.2.1  perseant   future_status wait_for (const std::chrono::duration<Rep,Period> &duration)
     88  1.1.1.2.2.1  perseant     const
     89  1.1.1.2.2.1  perseant   {
     90  1.1.1.2.2.1  perseant     return future_status::ready;
     91  1.1.1.2.2.1  perseant   }
     92  1.1.1.2.2.1  perseant 
     93      1.1.1.2  christos   T get () { return std::move (m_value); }
     94      1.1.1.2  christos 
     95      1.1.1.2  christos private:
     96      1.1.1.2  christos 
     97      1.1.1.2  christos   T m_value;
     98      1.1.1.2  christos };
     99      1.1.1.2  christos 
    100      1.1.1.2  christos /* A specialization for void.  */
    101      1.1.1.2  christos 
    102      1.1.1.2  christos template<>
    103      1.1.1.2  christos class future<void>
    104      1.1.1.2  christos {
    105      1.1.1.2  christos public:
    106      1.1.1.2  christos   void wait () const { }
    107  1.1.1.2.2.1  perseant 
    108  1.1.1.2.2.1  perseant   template<class Rep, class Period>
    109  1.1.1.2.2.1  perseant   future_status wait_for (const std::chrono::duration<Rep,Period> &duration)
    110  1.1.1.2.2.1  perseant     const
    111  1.1.1.2.2.1  perseant   {
    112  1.1.1.2.2.1  perseant     return future_status::ready;
    113  1.1.1.2.2.1  perseant   }
    114  1.1.1.2.2.1  perseant 
    115      1.1.1.2  christos   void get () { }
    116      1.1.1.2  christos };
    117      1.1.1.2  christos 
    118      1.1.1.2  christos #endif /* CXX_STD_THREAD */
    119      1.1.1.2  christos 
    120      1.1.1.2  christos 
    121          1.1  christos /* A thread pool.
    122          1.1  christos 
    123          1.1  christos    There is a single global thread pool, see g_thread_pool.  Tasks can
    124          1.1  christos    be submitted to the thread pool.  They will be processed in worker
    125          1.1  christos    threads as time allows.  */
    126          1.1  christos class thread_pool
    127          1.1  christos {
    128          1.1  christos public:
    129          1.1  christos   /* The sole global thread pool.  */
    130          1.1  christos   static thread_pool *g_thread_pool;
    131          1.1  christos 
    132          1.1  christos   ~thread_pool ();
    133          1.1  christos   DISABLE_COPY_AND_ASSIGN (thread_pool);
    134          1.1  christos 
    135          1.1  christos   /* Set the thread count of this thread pool.  By default, no threads
    136          1.1  christos      are created -- the thread count must be set first.  */
    137          1.1  christos   void set_thread_count (size_t num_threads);
    138          1.1  christos 
    139          1.1  christos   /* Return the number of executing threads.  */
    140          1.1  christos   size_t thread_count () const
    141          1.1  christos   {
    142      1.1.1.2  christos #if CXX_STD_THREAD
    143          1.1  christos     return m_thread_count;
    144      1.1.1.2  christos #else
    145      1.1.1.2  christos     return 0;
    146      1.1.1.2  christos #endif
    147          1.1  christos   }
    148          1.1  christos 
    149          1.1  christos   /* Post a task to the thread pool.  A future is returned, which can
    150          1.1  christos      be used to wait for the result.  */
    151      1.1.1.2  christos   future<void> post_task (std::function<void ()> &&func)
    152      1.1.1.2  christos   {
    153      1.1.1.2  christos #if CXX_STD_THREAD
    154      1.1.1.2  christos     std::packaged_task<void ()> task (std::move (func));
    155      1.1.1.2  christos     future<void> result = task.get_future ();
    156      1.1.1.2  christos     do_post_task (std::packaged_task<void ()> (std::move (task)));
    157      1.1.1.2  christos     return result;
    158      1.1.1.2  christos #else
    159      1.1.1.2  christos     func ();
    160      1.1.1.2  christos     return {};
    161      1.1.1.2  christos #endif /* CXX_STD_THREAD */
    162      1.1.1.2  christos   }
    163      1.1.1.2  christos 
    164      1.1.1.2  christos   /* Post a task to the thread pool.  A future is returned, which can
    165      1.1.1.2  christos      be used to wait for the result.  */
    166      1.1.1.2  christos   template<typename T>
    167      1.1.1.2  christos   future<T> post_task (std::function<T ()> &&func)
    168      1.1.1.2  christos   {
    169      1.1.1.2  christos #if CXX_STD_THREAD
    170      1.1.1.2  christos     std::packaged_task<T ()> task (std::move (func));
    171      1.1.1.2  christos     future<T> result = task.get_future ();
    172      1.1.1.2  christos     do_post_task (std::packaged_task<void ()> (std::move (task)));
    173      1.1.1.2  christos     return result;
    174      1.1.1.2  christos #else
    175      1.1.1.2  christos     return future<T> (func ());
    176      1.1.1.2  christos #endif /* CXX_STD_THREAD */
    177      1.1.1.2  christos   }
    178          1.1  christos 
    179          1.1  christos private:
    180          1.1  christos 
    181          1.1  christos   thread_pool () = default;
    182          1.1  christos 
    183      1.1.1.2  christos #if CXX_STD_THREAD
    184          1.1  christos   /* The callback for each worker thread.  */
    185          1.1  christos   void thread_function ();
    186          1.1  christos 
    187      1.1.1.2  christos   /* Post a task to the thread pool.  A future is returned, which can
    188      1.1.1.2  christos      be used to wait for the result.  */
    189      1.1.1.2  christos   void do_post_task (std::packaged_task<void ()> &&func);
    190      1.1.1.2  christos 
    191          1.1  christos   /* The current thread count.  */
    192          1.1  christos   size_t m_thread_count = 0;
    193          1.1  christos 
    194          1.1  christos   /* A convenience typedef for the type of a task.  */
    195      1.1.1.2  christos   typedef std::packaged_task<void ()> task_t;
    196          1.1  christos 
    197          1.1  christos   /* The tasks that have not been processed yet.  An optional is used
    198          1.1  christos      to represent a task.  If the optional is empty, then this means
    199          1.1  christos      that the receiving thread should terminate.  If the optional is
    200          1.1  christos      non-empty, then it is an actual task to evaluate.  */
    201  1.1.1.2.2.1  perseant   std::queue<std::optional<task_t>> m_tasks;
    202          1.1  christos 
    203          1.1  christos   /* A condition variable and mutex that are used for communication
    204          1.1  christos      between the main thread and the worker threads.  */
    205          1.1  christos   std::condition_variable m_tasks_cv;
    206          1.1  christos   std::mutex m_tasks_mutex;
    207  1.1.1.2.2.1  perseant   bool m_sized_at_least_once = false;
    208      1.1.1.2  christos #endif /* CXX_STD_THREAD */
    209          1.1  christos };
    210          1.1  christos 
    211          1.1  christos }
    212          1.1  christos 
    213          1.1  christos #endif /* GDBSUPPORT_THREAD_POOL_H */
    214