include/boost/capy/ex/work_guard.hpp

100.0% Lines (31/0/31) 97.1% List of functions (34/0/35)
work_guard.hpp
f(x) Functions (35)
Function Calls Lines Blocks
boost::capy::work_guard<boost::capy::any_executor>::work_guard(boost::capy::any_executor) :96 4x 100.0% 100.0% boost::capy::work_guard<boost::capy::guard_test_executor>::work_guard(boost::capy::guard_test_executor) :96 10x 100.0% 100.0% boost::capy::work_guard<boost::capy::queue_executor>::work_guard(boost::capy::queue_executor) :96 7x 100.0% 100.0% boost::capy::work_guard<boost::capy::queuing_executor>::work_guard(boost::capy::queuing_executor) :96 1x 100.0% 100.0% boost::capy::work_guard<boost::capy::strand<boost::capy::test::priority_executor<boost::capy::queuing_executor> > >::work_guard(boost::capy::strand<boost::capy::test::priority_executor<boost::capy::queuing_executor> >) :96 1x 100.0% 100.0% boost::capy::work_guard<boost::capy::strand<boost::capy::thread_pool::executor_type> >::work_guard(boost::capy::strand<boost::capy::thread_pool::executor_type>) :96 4x 100.0% 100.0% boost::capy::work_guard<boost::capy::sync_executor>::work_guard(boost::capy::sync_executor) :96 25x 100.0% 100.0% boost::capy::work_guard<boost::capy::test::blocking_executor>::work_guard(boost::capy::test::blocking_executor) :96 1118x 100.0% 100.0% boost::capy::work_guard<boost::capy::test::priority_executor<boost::capy::queuing_executor> >::work_guard(boost::capy::test::priority_executor<boost::capy::queuing_executor>) :96 2x 100.0% 100.0% boost::capy::work_guard<boost::capy::test_executor>::work_guard(boost::capy::test_executor) :96 113x 100.0% 100.0% boost::capy::work_guard<boost::capy::thread_pool::executor_type>::work_guard(boost::capy::thread_pool::executor_type) :96 667x 100.0% 100.0% boost::capy::work_guard<boost::capy::tracking_executor>::work_guard(boost::capy::tracking_executor) :96 1x 100.0% 100.0% boost::capy::work_guard<boost::capy::guard_test_executor>::work_guard(boost::capy::work_guard<boost::capy::guard_test_executor> const&) :117 2x 100.0% 100.0% boost::capy::work_guard<boost::capy::guard_test_executor>::work_guard(boost::capy::work_guard<boost::capy::guard_test_executor>&&) :139 1x 100.0% 100.0% boost::capy::work_guard<boost::capy::any_executor>::~work_guard() :154 4x 100.0% 100.0% boost::capy::work_guard<boost::capy::executor_ref>::~work_guard() :154 0 0.0% 0.0% boost::capy::work_guard<boost::capy::guard_test_executor>::~work_guard() :154 13x 100.0% 100.0% boost::capy::work_guard<boost::capy::queue_executor>::~work_guard() :154 7x 100.0% 100.0% boost::capy::work_guard<boost::capy::queuing_executor>::~work_guard() :154 1x 100.0% 100.0% boost::capy::work_guard<boost::capy::strand<boost::capy::test::priority_executor<boost::capy::queuing_executor> > >::~work_guard() :154 1x 100.0% 100.0% boost::capy::work_guard<boost::capy::strand<boost::capy::thread_pool::executor_type> >::~work_guard() :154 4x 100.0% 100.0% boost::capy::work_guard<boost::capy::sync_executor>::~work_guard() :154 25x 100.0% 100.0% boost::capy::work_guard<boost::capy::test::blocking_executor>::~work_guard() :154 1118x 100.0% 100.0% boost::capy::work_guard<boost::capy::test::priority_executor<boost::capy::queuing_executor> >::~work_guard() :154 2x 100.0% 100.0% boost::capy::work_guard<boost::capy::test_executor>::~work_guard() :154 113x 100.0% 100.0% boost::capy::work_guard<boost::capy::thread_pool::executor_type>::~work_guard() :154 667x 100.0% 100.0% boost::capy::work_guard<boost::capy::tracking_executor>::~work_guard() :154 1x 100.0% 100.0% boost::capy::work_guard<boost::capy::guard_test_executor>::executor() const :183 7x 100.0% 100.0% boost::capy::work_guard<boost::capy::test::blocking_executor>::executor() const :183 1538x 100.0% 100.0% boost::capy::work_guard<boost::capy::thread_pool::executor_type>::executor() const :183 1316x 100.0% 100.0% boost::capy::work_guard<boost::capy::guard_test_executor>::owns_work() const :197 12x 100.0% 100.0% boost::capy::work_guard<boost::capy::guard_test_executor>::reset() :215 4x 100.0% 100.0% boost::capy::work_guard<boost::capy::thread_pool::executor_type>::reset() :215 1x 100.0% 100.0% boost::capy::work_guard<boost::capy::guard_test_executor> boost::capy::make_work_guard<boost::capy::guard_test_executor>(boost::capy::guard_test_executor) :238 1x 100.0% 100.0% boost::capy::work_guard<boost::capy::thread_pool::executor_type> boost::capy::make_work_guard<boost::capy::thread_pool::executor_type>(boost::capy::thread_pool::executor_type) :238 2x 100.0% 100.0%
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2026 Michael Vandeberg
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/capy
9 //
10
11 #ifndef BOOST_CAPY_WORK_GUARD_HPP
12 #define BOOST_CAPY_WORK_GUARD_HPP
13
14 #include <boost/capy/detail/config.hpp>
15 #include <boost/capy/ex/execution_context.hpp>
16 #include <boost/capy/concept/executor.hpp>
17
18 #include <utility>
19
20 namespace boost {
21 namespace capy {
22
23 /** RAII guard that keeps an executor's context from completing.
24
25 This class holds "work" on an executor, preventing the associated
26 execution context's `run()` function from returning due to lack of
27 work. It calls `on_work_started()` on construction and
28 `on_work_finished()` on destruction, ensuring proper work tracking.
29
30 The guard is useful when you need to keep an execution context
31 running while waiting for external events or when work is
32 posted later.
33
34 @par RAII Semantics
35
36 @li Construction calls `ex.on_work_started()`.
37 @li Destruction calls `ex.on_work_finished()` if `owns_work()`.
38 @li Copy construction creates a new work reference (calls
39 `on_work_started()` again).
40 @li Move construction transfers ownership without additional calls.
41
42 @par Thread Safety
43
44 Distinct objects may be accessed concurrently. Access to a single
45 object requires external synchronization.
46
47 @par Example
48 @code
49 thread_pool pool(1);
50
51 // Keep the pool from completing while we set things up
52 auto guard = make_work_guard(pool.get_executor());
53
54 // ... post work to pool ...
55
56 // Allow the pool to complete when work is done
57 guard.reset();
58
59 pool.join();
60 @endcode
61
62 @note The executor is returned by reference, allowing callers to
63 manage the executor's lifetime directly. This is essential in
64 coroutine-first designs where the executor often outlives individual
65 coroutine frames.
66
67 @tparam Ex A type satisfying the Executor concept.
68
69 @see make_work_guard, Executor
70 */
71 template<Executor Ex>
72 class work_guard
73 {
74 Ex ex_;
75 bool owns_;
76
77 public:
78 /** Names the executor type this `work_guard<Ex>` guards. */
79 using executor_type = Ex;
80
81 /** Construct a work guard.
82
83 Calls `ex.on_work_started()` to inform the executor that
84 work is outstanding.
85
86 @par Exception Safety
87 No-throw guarantee.
88
89 @par Postconditions
90 @li `owns_work() == true`
91 @li `executor() == ex`
92
93 @param ex The executor to hold work on. Moved into the guard.
94 */
95 explicit
96 1953x work_guard(Ex ex) noexcept
97 1953x : ex_(std::move(ex))
98 1953x , owns_(true)
99 {
100 1953x ex_.on_work_started();
101 1953x }
102
103 /** Construct a copy.
104
105 Creates a new work guard holding work on the same executor.
106 Calls `on_work_started()` on the executor.
107
108 @par Exception Safety
109 No-throw guarantee.
110
111 @par Postconditions
112 @li `owns_work() == other.owns_work()`
113 @li `executor() == other.executor()`
114
115 @param other The work guard to copy from.
116 */
117 2x work_guard(work_guard const& other) noexcept
118 2x : ex_(other.ex_)
119 2x , owns_(other.owns_)
120 {
121 2x if(owns_)
122 1x ex_.on_work_started();
123 2x }
124
125 /** Construct by moving.
126
127 Transfers work ownership from `other` to `*this`. Does not
128 call `on_work_started()` or `on_work_finished()`.
129
130 @par Exception Safety
131 No-throw guarantee.
132
133 @par Postconditions
134 @li `owns_work()` equals the prior value of `other.owns_work()`
135 @li `other.owns_work() == false`
136
137 @param other The work guard to move from.
138 */
139 1x work_guard(work_guard&& other) noexcept
140 1x : ex_(std::move(other.ex_))
141 1x , owns_(other.owns_)
142 {
143 1x other.owns_ = false;
144 1x }
145
146 /** Destructor.
147
148 If `owns_work()` is `true`, calls `on_work_finished()` on
149 the executor.
150
151 @par Exception Safety
152 No-throw guarantee.
153 */
154 1956x ~work_guard()
155 {
156 1956x if(owns_)
157 1950x ex_.on_work_finished();
158 1956x }
159
160 /** Copy assignment is disabled.
161
162 A guard takes its work reference at construction and releases it at
163 destruction or through @ref reset. No operation rebinds an existing
164 guard to a different executor.
165
166 @param other The work guard that would be assigned from.
167
168 @return A reference to `*this`.
169 */
170 work_guard& operator=(work_guard const& other) = delete;
171
172 /** Return the underlying executor by reference.
173
174 The reference remains valid for the lifetime of this guard,
175 enabling callers to manage executor lifetime explicitly.
176
177 @par Exception Safety
178 No-throw guarantee.
179
180 @return A reference to the stored executor.
181 */
182 executor_type const&
183 3889x executor() const noexcept
184 {
185 3889x return ex_;
186 }
187
188 /** Return whether the guard owns work.
189
190 @par Exception Safety
191 No-throw guarantee.
192
193 @return `true` if this guard calls `on_work_finished()`
194 on destruction, `false` otherwise.
195 */
196 bool
197 12x owns_work() const noexcept
198 {
199 12x return owns_;
200 }
201
202 /** Release ownership of the work.
203
204 If `owns_work()` is `true`, calls `on_work_finished()` on
205 the executor and sets ownership to `false`. Otherwise, has
206 no effect.
207
208 @par Exception Safety
209 No-throw guarantee.
210
211 @par Postconditions
212 @li `owns_work() == false`
213 */
214 void
215 5x reset() noexcept
216 {
217 5x if(owns_)
218 {
219 4x ex_.on_work_finished();
220 4x owns_ = false;
221 }
222 5x }
223 };
224
225 /** Create a work guard from an executor.
226
227 @par Exception Safety
228 No-throw guarantee.
229
230 @param ex The executor to create the guard for.
231
232 @return A `work_guard` holding work on `ex`.
233
234 @see work_guard
235 */
236 template<Executor Ex>
237 work_guard<Ex>
238 3x make_work_guard(Ex ex)
239 {
240 3x return work_guard<Ex>(std::move(ex));
241 }
242
243 } // capy
244 } // boost
245
246 #endif
247