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