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