GCC Code Coverage Report


Directory: ./
File: libs/capy/src/ex/thread_pool.cpp
Date: 2026-01-19 05:31:50
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 122 explicit work(any_coro h) noexcept
31 122 : h_(h)
32 {
33 122 }
34
35 122 void run()
36 {
37 // delete before dispatch
38 122 auto h = h_;
39
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 delete this;
40
1/1
✓ Branch 1 taken 122 times.
122 h.resume();
41 122 }
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 49 ~impl()
57 {
58 {
59 49 std::lock_guard<std::mutex> lock(mutex_);
60 49 stop_ = true;
61 49 }
62 49 cv_.notify_all();
63
64
2/2
✓ Branch 5 taken 65 times.
✓ Branch 6 taken 49 times.
114 for(auto& t : threads_)
65 65 t.join();
66
67 // Destroy any work items that were never executed
68
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
49 while(auto* w = q_.pop())
69 w->destroy();
70 49 }
71
72 explicit
73 49 impl(std::size_t num_threads)
74 49 : stop_(false)
75 {
76
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 48 times.
49 if( num_threads == 0)
77 1 num_threads = std::thread::hardware_concurrency();
78 // Fallback
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
49 if( num_threads == 0)
80 num_threads = 1;
81
82
1/1
✓ Branch 1 taken 49 times.
49 threads_.reserve(num_threads);
83
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 49 times.
114 for(std::size_t i = 0; i < num_threads; ++i)
84
1/1
✓ Branch 1 taken 65 times.
130 threads_.emplace_back([this]{ run(); });
85 49 }
86
87 void
88 122 post(any_coro h)
89 {
90 122 auto* w = new work(h);
91 {
92
1/1
✓ Branch 1 taken 122 times.
122 std::lock_guard<std::mutex> lock(mutex_);
93 122 q_.push(w);
94 122 }
95 122 cv_.notify_one();
96 122 }
97
98 private:
99 void
100 65 run()
101 {
102 for(;;)
103 {
104 187 work* w = nullptr;
105 {
106
1/1
✓ Branch 1 taken 187 times.
187 std::unique_lock<std::mutex> lock(mutex_);
107
1/1
✓ Branch 1 taken 187 times.
187 cv_.wait(lock, [this]{
108
4/4
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 67 times.
✓ Branch 3 taken 120 times.
✓ Branch 4 taken 96 times.
283 return stop_ || !q_.empty();
109 });
110
111 // Only exit when stopped AND queue is drained
112
6/6
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 120 times.
✓ Branch 3 taken 65 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 65 times.
✓ Branch 6 taken 122 times.
187 if(stop_ && q_.empty())
113 130 return;
114
115 122 w = q_.pop();
116 187 }
117
118 122 w->run();
119 122 }
120 }
121 };
122
123 //------------------------------------------------------------------------------
124
125 49 thread_pool::
126 ~thread_pool()
127 {
128 // Order matters: shutdown services, then impl, then base
129 49 shutdown();
130
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 delete impl_;
131 49 destroy();
132 49 }
133
134 49 thread_pool::
135 49 thread_pool(std::size_t num_threads)
136
2/4
✓ Branch 2 taken 49 times.
✓ Branch 5 taken 49 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
49 : impl_(new impl(num_threads))
137 {
138 49 }
139
140 //------------------------------------------------------------------------------
141
142 void
143 122 thread_pool::executor_type::
144 post(any_coro h) const
145 {
146 122 pool_->impl_->post(h);
147 122 }
148
149 } // capy
150 } // boost
151