1mod util;
7mod register;
8mod submit;
9pub mod squeue;
10pub mod cqueue;
11pub mod opcode;
12
13#[cfg(feature = "concurrent")]
14pub mod concurrent;
15
16use std::{ io, cmp, mem };
17use std::convert::TryInto;
18use std::os::unix::io::{ AsRawFd, RawFd };
19use std::mem::ManuallyDrop;
20use linux_io_uring_sys as sys;
21use util::{ Fd, Mmap };
22pub use submit::Submitter;
23pub use squeue::SubmissionQueue;
24pub use cqueue::CompletionQueue;
25pub use register::{ register as reg, unregister as unreg };
26
27
28pub struct IoUring {
30 fd: Fd,
31 params: Parameters,
32 memory: ManuallyDrop<MemoryMap>,
33 sq: SubmissionQueue,
34 cq: CompletionQueue
35}
36
37#[allow(dead_code)]
38struct MemoryMap {
39 sq_mmap: Mmap,
40 sqe_mmap: Mmap,
41 cq_mmap: Option<Mmap>
42}
43
44#[derive(Clone, Default)]
46pub struct Builder(sys::io_uring_params);
47
48#[derive(Clone)]
49pub struct Parameters(sys::io_uring_params);
50
51unsafe impl Send for IoUring {}
52unsafe impl Sync for IoUring {}
53
54impl IoUring {
55 #[inline]
60 pub fn new(entries: u32) -> io::Result<IoUring> {
61 IoUring::with_params(entries, Default::default())
62 }
63
64 fn with_params(entries: u32, mut p: sys::io_uring_params) -> io::Result<IoUring> {
65 #[inline]
70 unsafe fn setup_queue(fd: &Fd, p: &sys::io_uring_params)
71 -> io::Result<(MemoryMap, SubmissionQueue, CompletionQueue)>
72 {
73 let sq_len = p.sq_off.array as usize
74 + p.sq_entries as usize * mem::size_of::<u32>();
75 let cq_len = p.cq_off.cqes as usize
76 + p.cq_entries as usize * mem::size_of::<sys::io_uring_cqe>();
77 let sqe_len = p.sq_entries as usize * mem::size_of::<sys::io_uring_sqe>();
78 let sqe_mmap = Mmap::new(fd, sys::IORING_OFF_SQES as _, sqe_len)?;
79
80 if p.features & sys::IORING_FEAT_SINGLE_MMAP != 0 {
81 let scq_mmap = Mmap::new(fd, sys::IORING_OFF_SQ_RING as _, cmp::max(sq_len, cq_len))?;
82
83 let sq = SubmissionQueue::new(&scq_mmap, &sqe_mmap, p);
84 let cq = CompletionQueue::new(&scq_mmap, p);
85 let mm = MemoryMap {
86 sq_mmap: scq_mmap,
87 cq_mmap: None,
88 sqe_mmap
89 };
90
91 Ok((mm, sq, cq))
92 } else {
93 let sq_mmap = Mmap::new(fd, sys::IORING_OFF_SQ_RING as _, sq_len)?;
94 let cq_mmap = Mmap::new(fd, sys::IORING_OFF_CQ_RING as _, cq_len)?;
95
96 let sq = SubmissionQueue::new(&sq_mmap, &sqe_mmap, p);
97 let cq = CompletionQueue::new(&cq_mmap, p);
98 let mm = MemoryMap {
99 cq_mmap: Some(cq_mmap),
100 sq_mmap, sqe_mmap
101 };
102
103 Ok((mm, sq, cq))
104 }
105 }
106
107 let fd: Fd = unsafe {
108 sys::io_uring_setup(entries, &mut p)
109 .try_into()
110 .map_err(|_| io::Error::last_os_error())?
111 };
112
113 let (mm, sq, cq) = unsafe { setup_queue(&fd, &p)? };
114
115 Ok(IoUring {
116 fd, sq, cq,
117 params: Parameters(p),
118 memory: ManuallyDrop::new(mm)
119 })
120 }
121
122 const fn as_submit(&self) -> Submitter<'_> {
123 Submitter::new(&self.fd, self.params.0.flags, &self.sq)
124 }
125
126 pub fn params(&self) -> &Parameters {
127 &self.params
128 }
129
130 #[inline]
132 pub unsafe fn register(&self, target: reg::Target<'_>) -> io::Result<()> {
133 self.as_submit().register(target)
134 }
135
136 #[inline]
138 pub fn unregister(&self, target: unreg::Target) -> io::Result<()> {
139 self.as_submit().unregister(target)
140 }
141
142 #[inline]
148 pub unsafe fn enter(&self, to_submit: u32, min_complete: u32, flag: u32, sig: Option<&libc::sigset_t>)
149 -> io::Result<usize>
150 {
151 self.as_submit().enter(to_submit, min_complete, flag, sig)
152 }
153
154 #[inline]
156 pub fn submit(&self) -> io::Result<usize> {
157 self.as_submit().submit()
158 }
159
160 #[inline]
162 pub fn submit_and_wait(&self, want: usize) -> io::Result<usize> {
163 self.as_submit().submit_and_wait(want)
164 }
165
166 pub fn split(&mut self)
168 -> (Submitter<'_>, &mut SubmissionQueue, &mut CompletionQueue)
169 {
170 let submit = Submitter::new(&self.fd, self.params.0.flags, &self.sq);
171 (submit, &mut self.sq, &mut self.cq)
172 }
173
174 pub fn submission(&mut self) -> &mut SubmissionQueue {
176 &mut self.sq
177 }
178
179 pub fn completion(&mut self) -> &mut CompletionQueue {
181 &mut self.cq
182 }
183
184 #[cfg(feature = "concurrent")]
186 pub fn concurrent(self) -> concurrent::IoUring {
187 concurrent::IoUring::new(self)
188 }
189}
190
191impl Drop for IoUring {
192 fn drop(&mut self) {
193 unsafe {
194 ManuallyDrop::drop(&mut self.memory);
195 }
196 }
197}
198
199impl Builder {
200 pub fn feature_single_mmap(&mut self) -> &mut Self {
201 self.0.features |= sys::IORING_FEAT_SINGLE_MMAP;
202 self
203 }
204
205 #[cfg(feature = "unstable")]
206 pub fn feature_nodrop(&mut self) -> &mut Self {
207 self.0.features |= sys::IORING_FEAT_NODROP;
208 self
209 }
210
211 #[cfg(feature = "unstable")]
212 pub fn feature_submit_stable(&mut self) -> &mut Self {
213 self.0.features |= sys::IORING_FEAT_SUBMIT_STABLE;
214 self
215 }
216
217 pub fn setup_iopoll(&mut self) -> &mut Self {
220 self.0.flags |= sys::IORING_SETUP_IOPOLL;
221 self
222 }
223
224 pub fn setup_sqpoll(&mut self, idle: impl Into<Option<u32>>) -> &mut Self {
228 self.0.flags |= sys::IORING_SETUP_SQPOLL;
229
230 if let Some(n) = idle.into() {
231 self.0.sq_thread_idle = n;
232 }
233
234 self
235 }
236
237 pub fn setup_sqpoll_cpu(&mut self, n: u32) -> &mut Self {
241 self.0.flags |= sys::IORING_SETUP_SQ_AFF;
242 self.0.sq_thread_cpu = n;
243 self
244 }
245
246 #[cfg(feature = "unstable")]
249 pub fn setup_cqsize(&mut self, n: u32) -> &mut Self {
250 self.0.flags |= sys::IORING_SETUP_CQSIZE;
251 self.0.cq_entries = n;
252 self
253 }
254
255 #[inline]
257 pub fn build(self, entries: u32) -> io::Result<IoUring> {
258 IoUring::with_params(entries, self.0)
259 }
260}
261
262impl Parameters {
263 pub fn is_setup_sqpoll(&self) -> bool {
264 self.0.flags & sys::IORING_SETUP_SQPOLL != 0
265 }
266
267 #[cfg(feature = "unstable")]
268 pub fn is_feature_nodrop(&self) -> bool {
269 self.0.features & sys::IORING_FEAT_NODROP != 0
270 }
271
272 #[cfg(feature = "unstable")]
273 pub fn is_feature_submit_stable(&self) -> bool {
274 self.0.features & sys::IORING_FEAT_SUBMIT_STABLE != 0
275 }
276
277 pub fn sq_entries(&self) -> u32 {
278 self.0.sq_entries
279 }
280
281 pub fn cq_entries(&self) -> u32 {
282 self.0.cq_entries
283 }
284}
285
286impl AsRawFd for IoUring {
287 fn as_raw_fd(&self) -> RawFd {
288 self.fd.as_raw_fd()
289 }
290}