Skip to content

Commit c354912

Browse files
committed
Add SubmissionQueue::push_opcode()/push_multiple_opcode()
Add SubmissionQueue::push_opcode()/push_multiple_opcode() to generate SQE in place. Signed-off-by: Liu Jiang <[email protected]>
1 parent 8f8f609 commit c354912

File tree

2 files changed

+132
-22
lines changed

2 files changed

+132
-22
lines changed

src/opcode.rs

+28-22
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
use std::mem;
66
use std::os::unix::io::RawFd;
77

8-
use crate::squeue::Entry;
8+
use crate::squeue::{Entry, OptionValues};
99
use crate::sys;
1010
use crate::types::{self, sealed};
1111

1212
/// Trait to prepare an SQE from an opcode object.
1313
pub trait PrepareSQE {
1414
/// Prepare an SQE from an opcode object.
15-
fn prepare(&self, sqe: &mut sys::io_uring_sqe);
15+
fn prepare(&self, sqe: &mut sys::io_uring_sqe, options: &OptionValues);
1616
}
1717

1818
macro_rules! assign_fd {
@@ -58,9 +58,11 @@ macro_rules! opcode {
5858

5959
pub const CODE = $opcode:expr;
6060

61-
fn set_used_fields(&$self:ident, $sqe1:ident : &mut sys::io_uring_sqe) $set_used_fields:block
61+
fn set_used_fields(&$self:ident, $sqe1:ident : &mut sys::io_uring_sqe)
62+
$set_used_fields:block
6263

63-
fn zero_unused_fields($sqe2:ident : &mut sys::io_uring_sqe) $zero_unused_fields:block
64+
fn zero_unused_fields($sqe2:ident : &mut sys::io_uring_sqe, $options:ident : &OptionValues)
65+
$zero_unused_fields:block
6466
) => {
6567
$( #[$outer] )*
6668
pub struct $name {
@@ -100,15 +102,16 @@ macro_rules! opcode {
100102
}
101103

102104
#[inline]
103-
fn set_used_fields(&$self, $sqe1: &mut sys::io_uring_sqe) $set_used_fields
105+
fn set_used_fields(&$self, $sqe1 : &mut sys::io_uring_sqe) $set_used_fields
104106

105107
#[inline]
106-
fn zero_unused_fields($sqe2: &mut sys::io_uring_sqe) $zero_unused_fields
108+
fn zero_unused_fields($sqe2 : &mut sys::io_uring_sqe, $options : &OptionValues)
109+
$zero_unused_fields
107110
}
108111

109112
impl PrepareSQE for $name {
110-
fn prepare(&self, sqe: &mut sys::io_uring_sqe) {
111-
Self::zero_unused_fields(sqe);
113+
fn prepare(&self, sqe: &mut sys::io_uring_sqe, options: &OptionValues) {
114+
Self::zero_unused_fields(sqe, options);
112115
self.set_used_fields(sqe);
113116
}
114117
}
@@ -121,6 +124,13 @@ fn sqe_zeroed() -> sys::io_uring_sqe {
121124
unsafe { std::mem::zeroed() }
122125
}
123126

127+
#[inline(always)]
128+
fn set_options(sqe: &mut sys::io_uring_sqe, options: &OptionValues) {
129+
sqe.flags = options.flags;
130+
sqe.personality = options.personality;
131+
sqe.user_data = options.user_data;
132+
}
133+
124134
opcode!(
125135
/// Do not perform any I/O.
126136
///
@@ -135,8 +145,9 @@ opcode!(
135145
sqe.fd = -1;
136146
}
137147

138-
fn zero_unused_fields(sqe: &mut sys::io_uring_sqe) {
148+
fn zero_unused_fields(sqe: &mut sys::io_uring_sqe, options: &OptionValues) {
139149
*sqe = unsafe { std::mem::zeroed() };
150+
set_options(sqe, options);
140151
}
141152
);
142153

@@ -167,13 +178,11 @@ opcode!(
167178
sqe.__bindgen_anon_3.rw_flags = self.rw_flags;
168179
}
169180

170-
fn zero_unused_fields(sqe: &mut sys::io_uring_sqe) {
171-
sqe.flags = 0;
172-
sqe.user_data = 0;
181+
fn zero_unused_fields(sqe: &mut sys::io_uring_sqe, options: &OptionValues) {
173182
sqe.__bindgen_anon_4.buf_index = 0;
174-
sqe.personality = 0;
175183
sqe.splice_fd_in = 0;
176184
sqe.__pad2 = [0, 0];
185+
set_options(sqe, options);
177186
}
178187
);
179188

@@ -204,13 +213,11 @@ opcode!(
204213
sqe.__bindgen_anon_3.rw_flags = self.rw_flags;
205214
}
206215

207-
fn zero_unused_fields(sqe: &mut sys::io_uring_sqe) {
208-
sqe.flags = 0;
209-
sqe.user_data = 0;
216+
fn zero_unused_fields(sqe: &mut sys::io_uring_sqe, options: &OptionValues) {
210217
sqe.__bindgen_anon_4.buf_index = 0;
211-
sqe.personality = 0;
212218
sqe.splice_fd_in = 0;
213219
sqe.__pad2 = [0, 0];
220+
set_options(sqe, options);
214221
}
215222
);
216223

@@ -241,8 +248,9 @@ opcode!(
241248
sqe.__bindgen_anon_3.fsync_flags = self.flags.bits();
242249
}
243250

244-
fn zero_unused_fields(sqe: &mut sys::io_uring_sqe) {
251+
fn zero_unused_fields(sqe: &mut sys::io_uring_sqe, options: &OptionValues) {
245252
*sqe = unsafe { std::mem::zeroed() };
253+
set_options(sqe, options);
246254
}
247255
);
248256

@@ -279,12 +287,10 @@ opcode!(
279287
sqe.__bindgen_anon_3.rw_flags = self.rw_flags;
280288
}
281289

282-
fn zero_unused_fields(sqe: &mut sys::io_uring_sqe) {
283-
sqe.flags = 0;
284-
sqe.user_data = 0;
285-
sqe.personality = 0;
290+
fn zero_unused_fields(sqe: &mut sys::io_uring_sqe, options: &OptionValues) {
286291
sqe.splice_fd_in = 0;
287292
sqe.__pad2 = [0, 0];
293+
set_options(sqe, options);
288294
}
289295
);
290296

src/squeue.rs

+104
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::error::Error;
55
use std::fmt::{self, Display, Formatter};
66
use std::sync::atomic;
77

8+
use crate::opcode::PrepareSQE;
89
use crate::sys;
910
use crate::util::{unsync_load, Mmap};
1011

@@ -43,6 +44,20 @@ pub struct SubmissionQueue<'a> {
4344
#[derive(Clone)]
4445
pub struct Entry(pub(crate) sys::io_uring_sqe);
4546

47+
/// Common options for Submission Queue Entry.
48+
#[derive(Clone, Copy, Default, Debug)]
49+
pub struct OptionValues {
50+
pub(crate) user_data: u64,
51+
pub(crate) personality: u16,
52+
pub(crate) flags: u8,
53+
}
54+
55+
const OPTION_VALUES: OptionValues = OptionValues {
56+
user_data: 0,
57+
personality: 0,
58+
flags: 0,
59+
};
60+
4661
bitflags! {
4762
/// Submission flags
4863
pub struct Flags: u8 {
@@ -269,6 +284,57 @@ impl SubmissionQueue<'_> {
269284
Ok(())
270285
}
271286

287+
/// Attempts to push an opcode into the submission queue.
288+
/// If the queue is full, an error is returned.
289+
///
290+
/// # Safety
291+
///
292+
/// Developers must ensure that parameters of the opcode (such as buffer) are valid and will
293+
/// be valid for the entire duration of the operation, otherwise it may cause memory problems.
294+
#[inline]
295+
pub unsafe fn push_opcode<'a, T: PrepareSQE>(
296+
&'a mut self,
297+
opcode: &T,
298+
options: Option<&OptionValues>,
299+
) -> Result<(), PushError> {
300+
if !self.is_full() {
301+
let sqe = self.next_sqe();
302+
let options = options.unwrap_or(&OPTION_VALUES);
303+
opcode.prepare(sqe, options);
304+
Ok(())
305+
} else {
306+
Err(PushError)
307+
}
308+
}
309+
310+
/// Attempts to push several opcodes into the queue.
311+
/// If the queue does not have space for all of the entries, an error is returned.
312+
///
313+
/// # Safety
314+
///
315+
/// Developers must ensure that parameters of all the entries (such as buffer) are valid and
316+
/// will be valid for the entire duration of the operation, otherwise it may cause memory
317+
/// problems.
318+
#[cfg(feature = "unstable")]
319+
#[inline]
320+
pub unsafe fn push_multiple_opcode<'a, T: PrepareSQE>(
321+
&'a mut self,
322+
ops: &[(T, Option<&OptionValues>)],
323+
) -> Result<(), PushError> {
324+
if self.capacity() - self.len() < ops.len() {
325+
return Err(PushError);
326+
}
327+
328+
for (opcode, options) in ops {
329+
let sqe = self.next_sqe();
330+
let options = options.unwrap_or(&OPTION_VALUES);
331+
opcode.prepare(sqe, options);
332+
self.move_forward();
333+
}
334+
335+
Ok(())
336+
}
337+
272338
#[inline]
273339
fn next_sqe(&mut self) -> &mut sys::io_uring_sqe {
274340
// Safe because we are accessing an entry in the allocated submission queue.
@@ -320,6 +386,44 @@ impl Entry {
320386
}
321387
}
322388

389+
impl OptionValues {
390+
/// Create a new instance of `OptionValues`.
391+
pub fn new(user_data: u64, personality: u16, flags: Flags) -> Self {
392+
OptionValues {
393+
user_data,
394+
personality,
395+
flags: flags.bits(),
396+
}
397+
}
398+
399+
/// Set the user data.
400+
///
401+
/// This is an application-supplied value that will be passed straight through into the
402+
/// [completion queue entry](crate::cqueue::Entry::user_data).
403+
#[inline]
404+
pub fn user_data(mut self, user_data: u64) -> Self {
405+
self.user_data = user_data;
406+
self
407+
}
408+
409+
/// Set the personality of this event.
410+
///
411+
/// You can obtain a personality using
412+
/// [`Submitter::register_personality`](crate::Submitter::register_personality).
413+
#[inline]
414+
pub fn personality(mut self, personality: u16) -> Self {
415+
self.personality = personality;
416+
self
417+
}
418+
419+
/// Set the submission event's [flags](Flags).
420+
#[inline]
421+
pub fn flags(mut self, flags: Flags) -> Self {
422+
self.flags |= flags.bits();
423+
self
424+
}
425+
}
426+
323427
/// An error pushing to the submission queue due to it being full.
324428
#[derive(Debug, Clone, PartialEq, Eq)]
325429
#[non_exhaustive]

0 commit comments

Comments
 (0)