A low level library to interact with the io-uring api with Rust 🦀.
This is an attempt to reduce boilerplate. This library does not provide special safety guards.
Checkout this very basic example.
- RTFM¹
- ¹ Read The Fabulous Manpage
- Implement the
RingOperation
trait for your ring operation.#[derive(Debug)] pub struct MyRingOp; impl RingOperation for MyRingOp { // Data passed with an io_uring request (io_urings user data) // Example: this may hold connection specific data for a TCP connection type RingData = (); // Error type that may occur during setup type SetupError = (); // Error type that may occur during tear down type TeardownError = (); // Error type indicate a warning during `on_completion` type ControlFlowWarn = (); // Error type indicate an error during `on_completion` type ControlFlowError = (); fn setup<W: Fn(&mut Entry, Self::RingData)>(&mut self, submitter: SubmissionQueueSubmitter<Self::RingData, W>) -> Result<(), Self::SetupError> { // This function is called once before the ring enters its "normal" operation loop. // Example: here you may setup a TCP socket and submit a sqe to accept clients Ok(()) } fn on_completion<W: Fn(&mut Entry, Self::RingData)>(&mut self, completion_entry: io_uring::cqueue::Entry, ring_data: Self::RingData, submitter: SubmissionQueueSubmitter<Self::RingData, W>) -> (ControlFlow<Self::ControlFlowWarn, Self::ControlFlowError>, Option<Self::RingData>) { // This function is called whenever we got a cqe for `MyRingOp`. // The *magic* should happen here. // Example: here you may process any cqe // depending on your operation you can set the control flow of this ring // V (ControlFlow::Continue, None) // /\ // There are multi-shot operations. Whenever you expect to receive `ring_data` again in the future you have // to give it back after mutating it. } fn on_teardown_completion<W: Fn(&mut Entry, Self::RingData)>(&mut self, _completion_entry: io_uring::cqueue::Entry, _ring_data: Self::RingData, _submitter: SubmissionQueueSubmitter<Self::RingData, W>) -> Result<(), Self::TeardownError> { // When the ring is shutting down all requests are canceled. // This function is basically the same as `on_completion` except it is only called once for a specific request. // Example: here you may release/free/drop your resources Ok(()) } }
- Create an IoUring with your RingOperation
rummelplatz::ring! { my_ring, my_ring_op: super::MyRingOp, my_other_op: super::MyOtherRingOp }
- Run it
// create your operations let my_op = MyRingOp; // create the ring let mut ring = my_ring::Ring::new( my_ring::Ring::new_raw_ring(NonZeroU32::new(128).unwrap())?, None, my_op, ); // run it ring.run();
opcode::MsgRingData
cqe flags should always containIORING_CQE_F_MORE
Rummelplatz is keeping track of requests currently in flight. To preventlet msg = opcode::MsgRingData::new( Fd, 0, user_data, Some(IORING_CQE_F_MORE), ) .build() .user_data(0); if let Err(e) = unsafe { submitter.push_raw(msg) } { //... }
MsgRingData
cqes to affect that internal counter they have to be flagged as if they were coming from a multi-shot request.- There are probably more :))
- everyone creating and maintaining io-uring and the Linux kernel
- tokio-rs/io-uring