tokio_uring/runtime/driver/op/
mod.rs1use std::future::Future;
2use std::io;
3use std::marker::PhantomData;
4use std::pin::Pin;
5use std::task::{Context, Poll, Waker};
6
7use io_uring::{cqueue, squeue};
8
9mod slab_list;
10
11use slab::Slab;
12use slab_list::{SlabListEntry, SlabListIndices};
13
14use crate::runtime::{driver, CONTEXT};
15
16pub(crate) type Completion = SlabListEntry<CqeResult>;
22
23pub struct UnsubmittedOneshot<D: 'static, T: OneshotOutputTransform<StoredData = D>> {
25 stable_data: D,
26 post_op: T,
27 sqe: squeue::Entry,
28}
29
30impl<D, T: OneshotOutputTransform<StoredData = D>> UnsubmittedOneshot<D, T> {
31 pub fn new(stable_data: D, post_op: T, sqe: squeue::Entry) -> Self {
33 Self {
34 stable_data,
35 post_op,
36 sqe,
37 }
38 }
39
40 pub fn submit(self) -> InFlightOneshot<D, T> {
42 let handle = CONTEXT
43 .with(|x| x.handle())
44 .expect("Could not submit op; not in runtime context");
45
46 self.submit_with_driver(&handle)
47 }
48
49 fn submit_with_driver(self, driver: &driver::Handle) -> InFlightOneshot<D, T> {
50 let index = driver.submit_op_2(self.sqe);
51
52 let driver = driver.into();
53
54 let inner = InFlightOneshotInner {
55 index,
56 driver,
57 stable_data: self.stable_data,
58 post_op: self.post_op,
59 };
60
61 InFlightOneshot { inner: Some(inner) }
62 }
63}
64
65pub struct InFlightOneshot<D: 'static, T: OneshotOutputTransform<StoredData = D>> {
67 inner: Option<InFlightOneshotInner<D, T>>,
68}
69
70struct InFlightOneshotInner<D, T: OneshotOutputTransform<StoredData = D>> {
71 driver: driver::WeakHandle,
72 index: usize,
73 stable_data: D,
74 post_op: T,
75}
76
77impl<D: Unpin, T: OneshotOutputTransform<StoredData = D> + Unpin> Future for InFlightOneshot<D, T> {
78 type Output = T::Output;
79
80 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
81 let this = self.get_mut();
82
83 let inner = this
84 .inner
85 .as_mut()
86 .expect("Cannot poll already-completed operation");
87
88 let index = inner.index;
89
90 let upgraded = inner
91 .driver
92 .upgrade()
93 .expect("Failed to poll op: driver no longer exists");
94
95 let cqe = ready!(upgraded.poll_op_2(index, cx));
96
97 let inner = this.inner.take().unwrap();
98
99 Poll::Ready(
100 inner
101 .post_op
102 .transform_oneshot_output(inner.stable_data, cqe),
103 )
104 }
105}
106
107impl<D: 'static, T: OneshotOutputTransform<StoredData = D>> Drop for InFlightOneshot<D, T> {
108 fn drop(&mut self) {
109 if let Some(inner) = self.inner.take() {
110 if let Some(driver) = inner.driver.upgrade() {
111 driver.remove_op_2(inner.index, inner.stable_data)
112 }
113 }
114 }
115}
116
117pub trait OneshotOutputTransform {
119 type Output;
121 type StoredData;
123 fn transform_oneshot_output(self, data: Self::StoredData, cqe: cqueue::Entry) -> Self::Output;
125}
126
127pub(crate) struct Op<T: 'static, CqeType = SingleCQE> {
129 driver: driver::WeakHandle,
130 index: usize,
132
133 data: Option<T>,
135
136 _cqe_type: PhantomData<CqeType>,
138}
139
140pub(crate) struct SingleCQE;
142
143pub(crate) struct MultiCQEFuture;
146
147pub(crate) trait Completable {
148 type Output;
149 fn complete(self, cqe: CqeResult) -> Self::Output;
151}
152
153pub(crate) trait Updateable: Completable {
154 fn update(&mut self, cqe: CqeResult);
157}
158
159#[allow(dead_code)]
160pub(crate) enum Lifecycle {
161 Submitted,
163
164 Waiting(Waker),
166
167 Ignored(Box<dyn std::any::Any>),
170
171 Completed(cqueue::Entry),
173
174 CompletionList(SlabListIndices),
177}
178
179pub(crate) struct CqeResult {
181 pub(crate) result: io::Result<u32>,
182 pub(crate) flags: u32,
183}
184
185impl From<cqueue::Entry> for CqeResult {
186 fn from(cqe: cqueue::Entry) -> Self {
187 let res = cqe.result();
188 let flags = cqe.flags();
189 let result = if res >= 0 {
190 Ok(res as u32)
191 } else {
192 Err(io::Error::from_raw_os_error(-res))
193 };
194 CqeResult { result, flags }
195 }
196}
197
198impl<T, CqeType> Op<T, CqeType> {
199 pub(super) fn new(driver: driver::WeakHandle, data: T, index: usize) -> Self {
201 Op {
202 driver,
203 index,
204 data: Some(data),
205 _cqe_type: PhantomData,
206 }
207 }
208
209 pub(super) fn index(&self) -> usize {
210 self.index
211 }
212
213 pub(super) fn take_data(&mut self) -> Option<T> {
214 self.data.take()
215 }
216
217 pub(super) fn insert_data(&mut self, data: T) {
218 self.data = Some(data);
219 }
220}
221
222impl<T> Future for Op<T, SingleCQE>
223where
224 T: Unpin + 'static + Completable,
225{
226 type Output = T::Output;
227
228 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
229 self.driver
230 .upgrade()
231 .expect("Not in runtime context")
232 .poll_op(self.get_mut(), cx)
233 }
234}
235
236impl<T> Future for Op<T, MultiCQEFuture>
237where
238 T: Unpin + 'static + Completable + Updateable,
239{
240 type Output = T::Output;
241
242 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
243 self.driver
244 .upgrade()
245 .expect("Not in runtime context")
246 .poll_multishot_op(self.get_mut(), cx)
247 }
248}
249
250impl<T, CqeType> Drop for Op<T, CqeType> {
255 fn drop(&mut self) {
256 self.driver
257 .upgrade()
258 .expect("Not in runtime context")
259 .remove_op(self)
260 }
261}
262
263impl Lifecycle {
264 pub(crate) fn complete(
265 &mut self,
266 completions: &mut Slab<Completion>,
267 cqe: cqueue::Entry,
268 ) -> bool {
269 use std::mem;
270
271 match mem::replace(self, Lifecycle::Submitted) {
272 x @ Lifecycle::Submitted | x @ Lifecycle::Waiting(..) => {
273 if io_uring::cqueue::more(cqe.flags()) {
274 let mut list = SlabListIndices::new().into_list(completions);
275 list.push(cqe.into());
276 *self = Lifecycle::CompletionList(list.into_indices());
277 } else {
278 *self = Lifecycle::Completed(cqe);
279 }
280 if let Lifecycle::Waiting(waker) = x {
281 waker.wake();
284 }
285 false
286 }
287
288 lifecycle @ Lifecycle::Ignored(..) => {
289 if io_uring::cqueue::more(cqe.flags()) {
290 *self = lifecycle;
293 false
294 } else {
295 true
297 }
298 }
299
300 Lifecycle::Completed(..) => {
301 unreachable!("invalid operation state")
306 }
307
308 Lifecycle::CompletionList(indices) => {
309 let mut list = indices.into_list(completions);
312 list.push(cqe.into());
313 *self = Lifecycle::CompletionList(list.into_indices());
314 false
315 }
316 }
317 }
318}