Skip to content

Commit 4175924

Browse files
committed
Move post_resume from the public interface to test helpers
1 parent 37d9790 commit 4175924

File tree

2 files changed

+27
-81
lines changed

2 files changed

+27
-81
lines changed

include/boost/capy/ex/io_env.hpp

Lines changed: 1 addition & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -20,32 +20,6 @@
2020
namespace boost {
2121
namespace capy {
2222

23-
/** Callable that posts a continuation to an executor.
24-
25-
Use this as the callback type for `std::stop_callback` instead
26-
of resuming a coroutine handle directly. Direct resumption runs
27-
the coroutine inline on whatever thread calls `request_stop()`,
28-
which bypasses the executor and corrupts the thread-local
29-
frame allocator.
30-
31-
Prefer @ref io_env::post_resume and the @ref stop_resume_callback
32-
alias to construct these—see examples there.
33-
34-
@see io_env::post_resume, stop_resume_callback
35-
*/
36-
struct resume_via_post
37-
{
38-
executor_ref ex;
39-
mutable continuation cont;
40-
41-
// post() must not throw; stop_callback requires a
42-
// non-throwing invocable.
43-
void operator()() const noexcept
44-
{
45-
ex.post(cont);
46-
}
47-
};
48-
4923
/** Execution environment for IoAwaitables.
5024
5125
This struct bundles the execution context passed through
@@ -60,27 +34,11 @@ struct resume_via_post
6034
chain. Awaitables receive `io_env const*` in `await_suspend`
6135
and should store it directly, never copy the pointed-to object.
6236
63-
@par Stop Callback Contract
64-
65-
Awaitables that register a `std::stop_callback` **must not**
66-
resume the coroutine handle directly. The callback fires
67-
synchronously on the thread that calls `request_stop()`, which
68-
may not be an executor-managed thread. Resuming inline poisons
69-
that thread's TLS frame allocator with the pool's allocator,
70-
causing use-after-free on the next coroutine allocation.
71-
72-
Use @ref io_env::post_resume and @ref stop_resume_callback:
73-
@code
74-
std::optional<stop_resume_callback> stop_cb_;
75-
// In await_suspend:
76-
stop_cb_.emplace(env->stop_token, env->post_resume(h));
77-
@endcode
78-
7937
@par Thread Safety
8038
The referenced executor and allocator must remain valid
8139
for the lifetime of any coroutine using this environment.
8240
83-
@see IoAwaitable, IoRunnable, resume_via_post
41+
@see IoAwaitable, IoRunnable
8442
*/
8543
struct io_env
8644
{
@@ -96,45 +54,8 @@ struct io_env
9654
*/
9755
std::pmr::memory_resource* frame_allocator = nullptr;
9856

99-
/** Create a resume_via_post callable for this environment.
100-
101-
Convenience method for registering @ref stop_resume_callback
102-
instances. Wraps the coroutine handle in a @ref continuation
103-
and pairs it with this environment's executor. Equivalent to
104-
`resume_via_post{executor, continuation{h}}`.
105-
106-
@par Example
107-
@code
108-
stop_cb_.emplace(env->stop_token, env->post_resume(h));
109-
@endcode
110-
111-
@param h The coroutine handle to wrap in a continuation
112-
and post on cancellation.
113-
114-
@return A @ref resume_via_post callable that holds a
115-
non-owning @ref executor_ref and a @ref continuation.
116-
The callable must not outlive the executor it references.
117-
118-
@see resume_via_post, stop_resume_callback
119-
*/
120-
resume_via_post
121-
post_resume(std::coroutine_handle<> h) const noexcept
122-
{
123-
return resume_via_post{executor, continuation{h}};
124-
}
12557
};
12658

127-
/** Type alias for a stop callback that posts through the executor.
128-
129-
Use this to declare the stop callback member in your awaitable:
130-
@code
131-
std::optional<stop_resume_callback> stop_cb_;
132-
@endcode
133-
134-
@see resume_via_post, io_env::post_resume
135-
*/
136-
using stop_resume_callback = std::stop_callback<resume_via_post>;
137-
13859
} // capy
13960
} // boost
14061

test/unit/test_helpers.hpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,31 @@ struct self_destroy_awaitable
256256
};
257257

258258

259+
// Callable that posts a continuation to an executor instead of
260+
// resuming a coroutine handle inline. Use as the callback type
261+
// for std::stop_callback — direct resumption runs the coroutine
262+
// on whatever thread calls request_stop(), bypassing the executor.
263+
struct resume_via_post
264+
{
265+
executor_ref ex;
266+
mutable continuation cont;
267+
268+
void operator()() const noexcept
269+
{
270+
ex.post(cont);
271+
}
272+
};
273+
274+
using stop_resume_callback = std::stop_callback<resume_via_post>;
275+
276+
inline resume_via_post
277+
post_resume(
278+
io_env const& env,
279+
std::coroutine_handle<> h) noexcept
280+
{
281+
return resume_via_post{env.executor, continuation{h}};
282+
}
283+
259284
// test awaitable that must be stopped in order to resume.
260285
// Uses resume_via_post to ensure the coroutine resumes on the
261286
// executor's thread, not on whatever thread calls request_stop().
@@ -293,7 +318,7 @@ struct stop_only_awaitable
293318
if (env->stop_token.stop_requested())
294319
return h;
295320
::new(stop_cb_buf_) stop_resume_callback(
296-
env->stop_token, env->post_resume(h));
321+
env->stop_token, post_resume(*env, h));
297322
active_.store(true, std::memory_order_release);
298323
return std::noop_coroutine();
299324
}

0 commit comments

Comments
 (0)