Condy v1.8
C++ Asynchronous System Call Layer for Linux
Loading...
Searching...
No Matches
finish_handles.hpp
Go to the documentation of this file.
1
8
9#pragma once
10
11#include "condy/concepts.hpp"
15#include "condy/runtime.hpp"
16#include <cassert>
17#include <cerrno>
18#include <optional>
19#include <utility>
20
21namespace condy {
22namespace detail {
23
24template <CQEHandlerLike CQEHandler, typename Receiver>
25class OpFinishHandle : public OpFinishHandleBase {
26public:
27 OpFinishHandle(CQEHandler cqe_handler, Receiver receiver)
28 : cqe_handler_(std::move(cqe_handler)), receiver_(std::move(receiver)) {
29 this->handle_func_ = handle_static_;
30 }
31
32 CONDY_DELETE_COPY_MOVE(OpFinishHandle);
33
34public:
35 void maybe_set_cancel(Runtime *runtime) noexcept {
36 auto stop_token = receiver_.get_stop_token();
37 if (stop_token.stop_possible()) {
38 stop_callback_.emplace(std::move(stop_token),
39 Cancellation{this, runtime});
40 }
41 }
42
43private:
44 static bool handle_static_(void *data, io_uring_cqe *cqe) noexcept {
45 auto *self = static_cast<OpFinishHandle *>(data);
46 return self->handle_impl_(cqe);
47 }
48
49 bool handle_impl_(io_uring_cqe *cqe) noexcept {
50 finish_(cqe);
51 return true;
52 }
53
54 struct Cancellation {
55 OpFinishHandle *self;
56 Runtime *runtime;
57 void operator()() noexcept {
58 runtime->cancel_internal(encode_work(self, WorkType::Common));
59 }
60 };
61
62 using StopCallbackType =
63 stop_callback_t<stop_token_t<Receiver>, Cancellation>;
64
65protected:
66 void finish_(io_uring_cqe *cqe) noexcept {
67 stop_callback_.reset();
68 std::move(receiver_)(cqe_handler_(cqe));
69 }
70
71 CQEHandler cqe_handler_;
72 Receiver receiver_;
73 std::optional<StopCallbackType> stop_callback_;
74};
75
76template <CQEHandlerLike CQEHandler, typename Func, typename Receiver>
77class MultiShotOpFinishHandle : public OpFinishHandle<CQEHandler, Receiver> {
78public:
79 MultiShotOpFinishHandle(CQEHandler cqe_handler, Receiver receiver,
80 Func func)
81 : OpFinishHandle<CQEHandler, Receiver>(std::move(cqe_handler),
82 std::move(receiver)),
83 func_(std::move(func)) {
84 this->handle_func_ = handle_static_;
85 }
86
87private:
88 static bool handle_static_(void *data, io_uring_cqe *cqe) noexcept {
89 auto *self = static_cast<MultiShotOpFinishHandle *>(data);
90 return self->handle_impl_(cqe);
91 }
92
93 bool handle_impl_(io_uring_cqe *cqe) noexcept
94 /* fake override */ {
95 if (cqe->flags & IORING_CQE_F_MORE) {
96 func_(this->cqe_handler_(cqe));
97 return false;
98 } else {
99 this->finish_(cqe);
100 return true;
101 }
102 }
103
104protected:
105 Func func_;
106};
107
108template <CQEHandlerLike CQEHandler, typename Func, typename Receiver>
109class ZeroCopyOpFinishHandle : public OpFinishHandle<CQEHandler, Receiver> {
110public:
111 ZeroCopyOpFinishHandle(CQEHandler cqe_handler, Receiver receiver, Func func)
112 : OpFinishHandle<CQEHandler, Receiver>(std::move(cqe_handler),
113 std::move(receiver)),
114 free_func_(std::move(func)) {
115 this->handle_func_ = handle_static_;
116 }
117
118private:
119 static bool handle_static_(void *data, io_uring_cqe *cqe) noexcept {
120 auto *self = static_cast<ZeroCopyOpFinishHandle *>(data);
121 return self->handle_impl_(cqe);
122 }
123
124 bool handle_impl_(io_uring_cqe *cqe) noexcept
125 /* fake override */ {
126 if (cqe->flags & IORING_CQE_F_MORE) {
127 this->finish_(cqe);
128 return false;
129 } else {
130 if (cqe->flags & IORING_CQE_F_NOTIF) {
131 notify_(cqe->res);
132 return true;
133 } else {
134 // Only one cqe means the operation is finished without
135 // notification. This is rare but possible.
136 // https://github.com/axboe/liburing/issues/1462
137 this->finish_(cqe);
138 notify_(0);
139 return true;
140 }
141 }
142 }
143
144 void notify_(int32_t res) noexcept {
145 free_func_(res);
146 delete this;
147 }
148
149protected:
150 Func free_func_;
151};
152
153template <typename Handle> class HandleBox {
154public:
155 template <typename... Args>
156 HandleBox(Args &&...args) : handle_(std::forward<Args>(args)...) {}
157
158 CONDY_DELETE_COPY_MOVE(HandleBox);
159
160public:
161 Handle &get() noexcept { return handle_; }
162
163private:
164 Handle handle_;
165};
166
167template <CQEHandlerLike CQEHandler, typename Func, typename Receiver>
168class HandleBox<ZeroCopyOpFinishHandle<CQEHandler, Func, Receiver>> {
169public:
170 using Handle = ZeroCopyOpFinishHandle<CQEHandler, Func, Receiver>;
171
172 template <typename... Args>
173 HandleBox(Args &&...args)
174 : handle_ptr_(new Handle(std::forward<Args>(args)...)) {}
175
176 CONDY_DELETE_COPY_MOVE(HandleBox);
177
178public:
179 Handle &get() noexcept { return *handle_ptr_; }
180
181private:
182 Handle *handle_ptr_;
183};
184
185} // namespace detail
186} // namespace condy
The main namespace for the Condy library.
Definition condy.hpp:37
Runtime type for running the io_uring event loop.
Internal utility classes and functions used by Condy.