GCC Code Coverage Report


Directory: ./
File: libs/capy/src/ex/thread_pool.cpp
Date: 2026-01-18 18:26:31
Exec Total Coverage
Lines: 56 61 91.8%
Functions: 11 12 91.7%
Branches: 28 36 77.8%

Line Branch Exec Source
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/capy
8 //
9
10 #include <boost/capy/ex/thread_pool.hpp>
11 #include <boost/capy/core/intrusive_queue.hpp>
12 #include <condition_variable>
13 #include <mutex>
14 #include <thread>
15 #include <vector>
16
17 namespace boost {
18 namespace capy {
19
20 //------------------------------------------------------------------------------
21
22 // Pimpl implementation hides threading details from the header
23 class thread_pool::impl
24 {
25 // Wraps a coroutine handle for queue storage
26 struct work : intrusive_queue<work>::node
27 {
28 any_coro h_;
29
30 118 explicit work(any_coro h) noexcept
31 118 : h_(h)
32 {
33 118 }
34
35 118 void run()
36 {
37 // delete before dispatch
38 118 auto h = h_;
39
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 delete this;
40
1/1
✓ Branch 1 taken 118 times.
118 h.resume();
41 118 }
42
43 void destroy()
44 {
45 delete this;
46 }
47 };
48
49 std::mutex mutex_;
50 std::condition_variable cv_;
51 intrusive_queue<work> q_;
52 std::vector<std::thread> threads_;
53 bool stop_;
54
55 public:
56 38 ~impl()
57 {
58 {
59 38 std::lock_guard<std::mutex> lock(mutex_);
60 38 stop_ = true;
61 38 }
62 38 cv_.notify_all();
63
64
2/2
✓ Branch 5 taken 53 times.
✓ Branch 6 taken 38 times.
91 for(auto& t : threads_)
65 53 t.join();
66
67 // Destroy any work items that were never executed
68
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
38 while(auto* w = q_.pop())
69 w->destroy();
70 38 }
71
72 explicit
73 38 impl(std::size_t num_threads)
74 38 : stop_(false)
75 {
76
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 37 times.
38 if( num_threads == 0)
77 1 num_threads = std::thread::hardware_concurrency();
78 // Fallback
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if( num_threads == 0)
80 num_threads = 1;
81
82
1/1
✓ Branch 1 taken 38 times.
38 threads_.reserve(num_threads);
83
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 38 times.
91 for(std::size_t i = 0; i < num_threads; ++i)
84
1/1
✓ Branch 1 taken 53 times.
106 threads_.emplace_back([this]{ run(); });
85 38 }
86
87 void
88 118 post(any_coro h)
89 {
90 118 auto* w = new work(h);
91 {
92
1/1
✓ Branch 1 taken 118 times.
118 std::lock_guard<std::mutex> lock(mutex_);
93 118 q_.push(w);
94 118 }
95 118 cv_.notify_one();
96 118 }
97
98 private:
99 void
100 53 run()
101 {
102 for(;;)
103 {
104 171 work* w = nullptr;
105 {
106
1/1
✓ Branch 1 taken 171 times.
171 std::unique_lock<std::mutex> lock(mutex_);
107
1/1
✓ Branch 1 taken 171 times.
171 cv_.wait(lock, [this]{
108
4/4
✓ Branch 0 taken 227 times.
✓ Branch 1 taken 55 times.
✓ Branch 3 taken 116 times.
✓ Branch 4 taken 111 times.
282 return stop_ || !q_.empty();
109 });
110
111 // Only exit when stopped AND queue is drained
112
6/6
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 116 times.
✓ Branch 3 taken 53 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 53 times.
✓ Branch 6 taken 118 times.
171 if(stop_ && q_.empty())
113 106 return;
114
115 118 w = q_.pop();
116 171 }
117
118 118 w->run();
119 118 }
120 }
121 };
122
123 //------------------------------------------------------------------------------
124
125 38 thread_pool::
126 ~thread_pool()
127 {
128 // Order matters: shutdown services, then impl, then base
129 38 shutdown();
130
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 delete impl_;
131 38 destroy();
132 38 }
133
134 38 thread_pool::
135 38 thread_pool(std::size_t num_threads)
136
2/4
✓ Branch 2 taken 38 times.
✓ Branch 5 taken 38 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
38 : impl_(new impl(num_threads))
137 {
138 38 }
139
140 //------------------------------------------------------------------------------
141
142 void
143 118 thread_pool::executor_type::
144 post(any_coro h) const
145 {
146 118 pool_->impl_->post(h);
147 118 }
148
149 } // capy
150 } // boost
151