tokio_uring/buf/fixed/
handle.rs

1use super::FixedBuffers;
2use crate::buf::{IoBuf, IoBufMut};
3
4use libc::iovec;
5use std::cell::RefCell;
6use std::fmt::{self, Debug};
7use std::ops::{Deref, DerefMut};
8use std::rc::Rc;
9
10// Data to construct a `FixedBuf` handle from.
11pub(crate) struct CheckedOutBuf {
12    // Pointer and size of the buffer.
13    pub iovec: iovec,
14    // Length of the initialized part.
15    pub init_len: usize,
16    // Buffer index.
17    pub index: u16,
18}
19
20/// A unique handle to a memory buffer that can be pre-registered with
21/// the kernel for `io-uring` operations.
22///
23/// `FixedBuf` handles can be obtained from a collection of fixed buffers,
24/// either [`FixedBufRegistry`] or [`FixedBufPool`].
25/// For each buffer, only a single `FixedBuf` handle can be either used by the
26/// application code or owned by an I/O operation at any given time,
27/// thus avoiding data races between `io-uring` operations in flight and
28/// the application accessing buffer data.
29///
30/// [`FixedBufRegistry`]: super::FixedBufRegistry
31/// [`FixedBufPool`]:     super::FixedBufPool
32///
33pub struct FixedBuf {
34    registry: Rc<RefCell<dyn FixedBuffers>>,
35    buf: CheckedOutBuf,
36}
37
38impl Drop for FixedBuf {
39    fn drop(&mut self) {
40        let mut registry = self.registry.borrow_mut();
41        // Safety: the length of the initialized data in the buffer has been
42        // maintained accordingly to the safety contracts on
43        // Self::new and IoBufMut.
44        unsafe {
45            registry.check_in(self.buf.index, self.buf.init_len);
46        }
47    }
48}
49
50impl FixedBuf {
51    // Safety: Validity constraints must apply to CheckedOutBuf members:
52    // - the array will not be deallocated until the buffer is checked in;
53    // - the data in the array must be initialized up to the number of bytes
54    //   given in init_len.
55    pub(super) unsafe fn new(registry: Rc<RefCell<dyn FixedBuffers>>, buf: CheckedOutBuf) -> Self {
56        FixedBuf { registry, buf }
57    }
58
59    /// Index of the underlying registry buffer
60    pub fn buf_index(&self) -> u16 {
61        self.buf.index
62    }
63}
64
65unsafe impl IoBuf for FixedBuf {
66    fn stable_ptr(&self) -> *const u8 {
67        self.buf.iovec.iov_base as _
68    }
69
70    fn bytes_init(&self) -> usize {
71        self.buf.init_len
72    }
73
74    fn bytes_total(&self) -> usize {
75        self.buf.iovec.iov_len
76    }
77}
78
79unsafe impl IoBufMut for FixedBuf {
80    fn stable_mut_ptr(&mut self) -> *mut u8 {
81        self.buf.iovec.iov_base as _
82    }
83
84    unsafe fn set_init(&mut self, pos: usize) {
85        if self.buf.init_len < pos {
86            self.buf.init_len = pos
87        }
88    }
89}
90
91impl Deref for FixedBuf {
92    type Target = [u8];
93
94    fn deref(&self) -> &[u8] {
95        // Safety: The iovec points to a slice held  in self.buffers, to which no mutable reference exists.
96        unsafe { std::slice::from_raw_parts(self.buf.iovec.iov_base as _, self.buf.init_len) }
97    }
98}
99
100impl DerefMut for FixedBuf {
101    fn deref_mut(&mut self) -> &mut [u8] {
102        // Safety: The iovec points to a slice held in self.buffers, to which no other reference exists.
103        unsafe { std::slice::from_raw_parts_mut(self.buf.iovec.iov_base as _, self.buf.init_len) }
104    }
105}
106
107impl Debug for FixedBuf {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        let buf: &[u8] = self;
110        f.debug_struct("FixedBuf")
111            .field("buf", &buf) // as slice
112            .field("index", &self.buf.index)
113            .finish_non_exhaustive()
114    }
115}