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