26template <OpFinishHandleLike Handle>
class HandleBox {
28 HandleBox(Handle h) : handle_(std::move(h)) {}
30 Handle &get() noexcept {
return handle_; }
32 void maybe_release() noexcept { }
38template <CQEHandlerLike CQEHandler,
typename Func>
39class HandleBox<ZeroCopyOpFinishHandle<CQEHandler, Func>> {
41 using Handle = ZeroCopyOpFinishHandle<CQEHandler, Func>;
42 HandleBox(Handle h) : handle_ptr_(std::make_unique<Handle>(std::move(h))) {}
43 HandleBox(
const HandleBox &other)
44 : handle_ptr_(std::make_unique<Handle>(*other.handle_ptr_)) {}
46 Handle &get() noexcept {
return *handle_ptr_; }
48 void maybe_release() noexcept { handle_ptr_.release(); }
51 std::unique_ptr<Handle> handle_ptr_;
54template <OpFinishHandleLike Handle, PrepFuncLike Func>
class OpAwaiterBase {
56 using HandleType = Handle;
58 OpAwaiterBase(HandleBox<Handle> handle, Func func)
59 : prep_func_(func), finish_handle_(std::move(handle)) {}
62 HandleType *get_handle() noexcept {
return &finish_handle_.get(); }
64 void init_finish_handle() noexcept { }
66 void register_operation(
unsigned int flags)
noexcept {
67 auto &context = detail::Context::current();
68 auto *ring = context.ring();
70 context.runtime()->pend_work();
72 io_uring_sqe *sqe = prep_func_(ring);
73 assert(sqe &&
"prep_func must return a valid sqe");
74 io_uring_sqe_set_flags(sqe, sqe->flags | flags);
75 auto *work = encode_work(&finish_handle_.get(), WorkType::Common);
76 io_uring_sqe_set_data(sqe, work);
80 bool await_ready() const noexcept {
return false; }
82 template <
typename PromiseType>
83 void await_suspend(std::coroutine_handle<PromiseType> h)
noexcept {
85 finish_handle_.get().set_invoker(&h.promise());
86 register_operation(0);
89 auto await_resume() noexcept {
90 auto result = finish_handle_.get().extract_result();
91 finish_handle_.maybe_release();
97 HandleBox<Handle> finish_handle_;
100template <PrepFuncLike PrepFunc, CQEHandlerLike CQEHandler>
101class [[nodiscard]] OpAwaiter
102 :
public OpAwaiterBase<OpFinishHandle<CQEHandler>, PrepFunc> {
104 using Base = OpAwaiterBase<OpFinishHandle<CQEHandler>, PrepFunc>;
105 template <
typename... Args>
106 OpAwaiter(PrepFunc func, Args &&...args)
108 OpFinishHandle<CQEHandler>(std::forward<Args>(args)...)),
112template <PrepFuncLike PrepFunc, CQEHandlerLike CQEHandler,
113 typename MultiShotFunc>
114class [[nodiscard]] MultiShotOpAwaiter
115 :
public OpAwaiterBase<MultiShotOpFinishHandle<CQEHandler, MultiShotFunc>,
119 OpAwaiterBase<MultiShotOpFinishHandle<CQEHandler, MultiShotFunc>,
121 template <
typename... Args>
122 MultiShotOpAwaiter(PrepFunc func, MultiShotFunc multishot_func,
124 : Base(HandleBox(MultiShotOpFinishHandle<CQEHandler, MultiShotFunc>(
125 std::move(multishot_func), std::forward<Args>(args)...)),
129template <PrepFuncLike PrepFunc, CQEHandlerLike CQEHandler,
typename FreeFunc>
130class [[nodiscard]] ZeroCopyOpAwaiter
131 :
public OpAwaiterBase<ZeroCopyOpFinishHandle<CQEHandler, FreeFunc>,
135 OpAwaiterBase<ZeroCopyOpFinishHandle<CQEHandler, FreeFunc>, PrepFunc>;
136 template <
typename... Args>
137 ZeroCopyOpAwaiter(PrepFunc func, FreeFunc free_func, Args &&...args)
138 : Base(HandleBox(ZeroCopyOpFinishHandle<CQEHandler, FreeFunc>(
139 std::move(free_func), std::forward<Args>(args)...)),
143template <
unsigned int Flags, AwaiterLike Awaiter>
144class [[nodiscard]] FlaggedOpAwaiter :
public Awaiter {
146 using Base = Awaiter;
147 FlaggedOpAwaiter(Awaiter awaiter) : Base(std::move(awaiter)) {}
149 void register_operation(
unsigned int flags)
noexcept {
150 Base::register_operation(flags | Flags);
153 template <
typename PromiseType>
154 void await_suspend(std::coroutine_handle<PromiseType> h)
noexcept {
155 Base::init_finish_handle();
156 Base::get_handle()->set_invoker(&h.promise());
157 register_operation(0);
161template <HandleLike Handle, AwaiterLike Awaiter>
162class [[nodiscard]] RangedParallelAwaiterBase {
164 using HandleType = Handle;
166 RangedParallelAwaiterBase(std::vector<Awaiter> awaiters)
167 : awaiters_(std::move(awaiters)) {}
170 HandleType *get_handle() noexcept {
return &finish_handle_; }
172 void init_finish_handle() noexcept {
173 using ChildHandle =
typename Awaiter::HandleType;
174 std::vector<ChildHandle *> handles;
175 handles.reserve(awaiters_.size());
176 for (
auto &awaiter : awaiters_) {
177 awaiter.init_finish_handle();
178 handles.push_back(awaiter.get_handle());
180 finish_handle_.init(std::move(handles));
183 void register_operation(
unsigned int flags)
noexcept {
184 for (
auto &awaiter : awaiters_) {
185 awaiter.register_operation(flags);
190 bool await_ready() const noexcept {
return awaiters_.empty(); }
192 template <
typename PromiseType>
193 void await_suspend(std::coroutine_handle<PromiseType> h)
noexcept {
194 init_finish_handle();
195 finish_handle_.set_invoker(&h.promise());
196 register_operation(0);
199 typename Handle::ReturnType
200 await_resume() noexcept(is_nothrow_extract_result_v<Handle>) {
201 return finish_handle_.extract_result();
205 void push(Awaiter awaiter) { awaiters_.push_back(std::move(awaiter)); }
208 HandleType finish_handle_;
209 std::vector<Awaiter> awaiters_;
221template <
typename Awaiter>
223 RangedParallelAllFinishHandle<typename Awaiter::HandleType>, Awaiter>;
234template <
typename Awaiter>
236 RangedParallelAnyFinishHandle<typename Awaiter::HandleType>, Awaiter>;
244template <
typename Awaiter>
246 RangedWhenAllFinishHandle<typename Awaiter::HandleType>, Awaiter>;
256template <
typename Awaiter>
258 RangedWhenAnyFinishHandle<typename Awaiter::HandleType>, Awaiter>;
260template <
unsigned int Flags, AwaiterLike Awaiter>
261class [[nodiscard]] RangedLinkAwaiterBase
267 void register_operation(
unsigned int flags)
noexcept {
268 auto *ring = detail::Context::current().ring();
269 ring->reserve_space(Base::awaiters_.size());
270 for (
int i = 0; i < Base::awaiters_.size() - 1; ++i) {
271 Base::awaiters_[i].register_operation(flags | Flags);
273 Base::awaiters_.back().register_operation(flags);
276 template <
typename PromiseType>
277 void await_suspend(std::coroutine_handle<PromiseType> h)
noexcept {
278 Base::init_finish_handle();
279 Base::finish_handle_.set_invoker(&h.promise());
280 register_operation(0);
290template <
typename Awaiter>
300template <
typename Awaiter>
303template <HandleLike Handle, AwaiterLike... Awaiters>
304class [[nodiscard]] ParallelAwaiterBase {
306 using HandleType = Handle;
308 ParallelAwaiterBase(Awaiters... awaiters)
309 : awaiters_(std::move(awaiters)...) {}
310 template <
typename ParallelAwaiter, AwaiterLike New>
311 ParallelAwaiterBase(ParallelAwaiter &&aws, New &&new_awaiter)
313 std::tuple_cat(std::move(aws.awaiters_),
314 std::make_tuple(std::forward<New>(new_awaiter)))) {
318 HandleType *get_handle()
noexcept {
return &finish_handle_; }
320 void init_finish_handle()
noexcept {
322 [
this](
auto &&...awaiters) {
323 (awaiters.init_finish_handle(), ...);
324 finish_handle_.init(awaiters.get_handle()...);
329 void register_operation(
unsigned int flags)
noexcept {
331 [flags](
auto &&...awaiters) {
332 (awaiters.register_operation(flags), ...);
338 bool await_ready()
const noexcept {
return false; }
340 template <
typename PromiseType>
341 void await_suspend(std::coroutine_handle<PromiseType> h)
noexcept {
342 init_finish_handle();
343 finish_handle_.set_invoker(&h.promise());
344 register_operation(0);
347 typename Handle::ReturnType
348 await_resume()
noexcept(is_nothrow_extract_result_v<Handle>) {
349 return finish_handle_.extract_result();
353 HandleType finish_handle_;
354 std::tuple<Awaiters...> awaiters_;
357 template <HandleLike, AwaiterLike...>
friend class ParallelAwaiterBase;
369template <
typename... Awaiter>
371 ParallelAllFinishHandle<
typename Awaiter::HandleType...>, Awaiter...>;
382template <
typename... Awaiter>
384 ParallelAnyFinishHandle<
typename Awaiter::HandleType...>, Awaiter...>;
392template <
typename... Awaiter>
394 ParallelAwaiterBase<WhenAllFinishHandle<
typename Awaiter::HandleType...>,
404template <
typename... Awaiter>
406 ParallelAwaiterBase<WhenAnyFinishHandle<
typename Awaiter::HandleType...>,
409template <
unsigned int Flags, AwaiterLike... Awaiter>
410class [[nodiscard]] LinkAwaiterBase :
public WhenAllAwaiter<Awaiter...> {
415 void register_operation(
unsigned int flags)
noexcept {
416 auto *ring = detail::Context::current().ring();
417 ring->reserve_space(
sizeof...(Awaiter));
418 foreach_register_operation_(flags);
421 template <
typename PromiseType>
422 void await_suspend(std::coroutine_handle<PromiseType> h)
noexcept {
423 Base::init_finish_handle();
424 Base::finish_handle_.set_invoker(&h.promise());
425 register_operation(0);
429 template <
size_t Idx = 0>
430 void foreach_register_operation_(
unsigned int flags)
noexcept {
431 if constexpr (Idx <
sizeof...(Awaiter)) {
432 auto &awaiter = std::get<Idx>(Base::awaiters_);
433 if constexpr (Idx <
sizeof...(Awaiter) - 1) {
434 awaiter.register_operation(flags | Flags);
436 awaiter.register_operation(flags);
438 foreach_register_operation_<Idx + 1>(flags);
449template <
typename... Awaiter>
458template <
typename... Awaiter>
Definitions of finish handle types for asynchronous operations.
The main namespace for the Condy library.
RangedParallelAwaiterBase< RangedParallelAllFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedParallelAllAwaiter
Awaiter to wait for all operations in a range to complete.
ParallelAwaiterBase< ParallelAllFinishHandle< typename Awaiter::HandleType... >, Awaiter... > ParallelAllAwaiter
Awaiter to wait for all operations to complete in parallel.
RangedLinkAwaiterBase< IOSQE_IO_LINK, Awaiter > RangedLinkAwaiter
Awaiter that links multiple operations in a range using IO_LINK.
RangedParallelAwaiterBase< RangedWhenAnyFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedWhenAnyAwaiter
Awaiter to wait for any operation in a range to complete.
RangedParallelAwaiterBase< RangedParallelAnyFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedParallelAnyAwaiter
Awaiter to wait for any operation in a range to complete.
LinkAwaiterBase< IOSQE_IO_LINK, Awaiter... > LinkAwaiter
Awaiter that links multiple operations using IO_LINK.
RangedParallelAwaiterBase< RangedWhenAllFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedWhenAllAwaiter
Awaiter to wait for all operations in a range to complete.
ParallelAwaiterBase< WhenAllFinishHandle< typename Awaiter::HandleType... >, Awaiter... > WhenAllAwaiter
Awaiter that waits for all operations to complete in parallel.
ParallelAwaiterBase< WhenAnyFinishHandle< typename Awaiter::HandleType... >, Awaiter... > WhenAnyAwaiter
Awaiter that waits for any operation to complete in parallel.
ParallelAwaiterBase< ParallelAnyFinishHandle< typename Awaiter::HandleType... >, Awaiter... > ParallelAnyAwaiter
Awaiter to wait for any operation to complete in parallel.
LinkAwaiterBase< IOSQE_IO_HARDLINK, Awaiter... > HardLinkAwaiter
Awaiter that links multiple operations using IO_HARDLINK.
RangedLinkAwaiterBase< IOSQE_IO_HARDLINK, Awaiter > RangedHardLinkAwaiter
Awaiter that links multiple operations in a range using IO_HARDLINK.
Wrapper classes for liburing interfaces.
Runtime type for running the io_uring event loop.