99 std:: { io, os:: fd:: RawFd , time:: Duration } ,
1010} ;
1111
12+ /// Trait for accessing the context and pushing operations to the [Ring].
13+ ///
14+ /// Enables generic operations on [Ring] or [Completion].
15+ pub trait RingAccess {
16+ type Context ;
17+ type Operation ;
18+
19+ /// Returns a reference to the context value stored in a [Ring].
20+ fn context ( & self ) -> & Self :: Context ;
21+
22+ /// Returns a mutable reference to the context value stored in a [Ring].
23+ fn context_mut ( & mut self ) -> & mut Self :: Context ;
24+
25+ /// Pushes an operation for execution in io_uring.
26+ ///
27+ /// Once completed, [RingOp::complete] will be called with the result.
28+ ///
29+ /// Note that the exact moment the operation is submitted to the kernel is implementation
30+ /// specific.
31+ fn push ( & mut self , op : Self :: Operation ) -> io:: Result < ( ) > ;
32+ }
33+
1234/// An io_uring instance.
1335pub struct Ring < T , E : RingOp < T > > {
1436 ring : IoUring ,
@@ -30,16 +52,6 @@ impl<T, E: RingOp<T>> Ring<T, E> {
3052 }
3153 }
3254
33- /// Returns a reference to the context value.
34- pub fn context ( & self ) -> & T {
35- & self . context
36- }
37-
38- /// Returns a mutable reference to the context value.
39- pub fn context_mut ( & mut self ) -> & mut T {
40- & mut self . context
41- }
42-
4355 /// Registers in-memory fixed buffers for I/O with the kernel.
4456 ///
4557 /// # Safety
@@ -64,40 +76,6 @@ impl<T, E: RingOp<T>> Ring<T, E> {
6476 self . ring . submitter ( ) . register_files ( fds)
6577 }
6678
67- /// Pushes an operation to the submission queue.
68- ///
69- /// Once completed, [RingOp::complete] will be called with the result.
70- ///
71- /// Note that the operation is not submitted to the kernel until [Ring::submit] is called. If
72- /// the submission queue is full, submit will be called internally to make room for the new
73- /// operation.
74- ///
75- /// See also [Ring::submit].
76- pub fn push ( & mut self , op : E ) -> io:: Result < ( ) > {
77- loop {
78- self . process_completions ( ) ?;
79-
80- if !self . entries . is_full ( ) {
81- break ;
82- }
83- // if the entries slab is full, we need to submit and poll
84- // completions to make room
85- self . submit_and_wait ( 1 , None ) ?;
86- }
87- let key = self . entries . insert ( op) ;
88- let entry = self . entries . get_mut ( key) . unwrap ( ) . entry ( ) ;
89- let entry = entry. user_data ( key as u64 ) ;
90- // Safety: the entry is stored in self.entries and guaranteed to be valid for the lifetime
91- // of the operation. E implementations must still ensure that the entry
92- // remains valid until the last E::complete call.
93- while unsafe { self . ring . submission ( ) . push ( & entry) } . is_err ( ) {
94- self . submit ( ) ?;
95- self . process_completions ( ) ?;
96- }
97-
98- Ok ( ( ) )
99- }
100-
10179 /// Submits all pending operations to the kernel.
10280 ///
10381 /// If the ring can't accept any more submissions because the completion
@@ -226,23 +204,69 @@ pub struct Completion<'a, T, E: RingOp<T>> {
226204 context : & ' a mut T ,
227205}
228206
229- impl < T , E : RingOp < T > > Completion < ' _ , T , E > {
230- /// Returns a reference to the context value stored in a [Ring].
231- pub fn context ( & self ) -> & T {
232- self . context
207+ impl < T , E : RingOp < T > > RingAccess for Ring < T , E > {
208+ type Context = T ;
209+ type Operation = E ;
210+
211+ fn context ( & self ) -> & T {
212+ & self . context
233213 }
234214
235- /// Returns a mutable reference to the context value stored in a [Ring].
236- pub fn context_mut ( & mut self ) -> & mut T {
237- self . context
215+ fn context_mut ( & mut self ) -> & mut T {
216+ & mut self . context
238217 }
239218
240219 /// Pushes an operation to the submission queue.
241220 ///
221+ /// Note that the operation is not submitted to the kernel until [Ring::submit] is called. If
222+ /// the submission queue is full, submit will be called internally to make room for the new
223+ /// operation.
224+ ///
225+ /// See also [Ring::submit].
226+ fn push ( & mut self , op : E ) -> io:: Result < ( ) > {
227+ loop {
228+ self . process_completions ( ) ?;
229+
230+ if !self . entries . is_full ( ) {
231+ break ;
232+ }
233+ // if the entries slab is full, we need to submit and poll
234+ // completions to make room
235+ self . submit_and_wait ( 1 , None ) ?;
236+ }
237+ let key = self . entries . insert ( op) ;
238+ let entry = self . entries . get_mut ( key) . unwrap ( ) . entry ( ) ;
239+ let entry = entry. user_data ( key as u64 ) ;
240+ // Safety: the entry is stored in self.entries and guaranteed to be valid for the lifetime
241+ // of the operation. E implementations must still ensure that the entry
242+ // remains valid until the last E::complete call.
243+ while unsafe { self . ring . submission ( ) . push ( & entry) } . is_err ( ) {
244+ self . submit ( ) ?;
245+ self . process_completions ( ) ?;
246+ }
247+
248+ Ok ( ( ) )
249+ }
250+ }
251+
252+ impl < T , E : RingOp < T > > RingAccess for Completion < ' _ , T , E > {
253+ type Context = T ;
254+ type Operation = E ;
255+
256+ fn context ( & self ) -> & T {
257+ self . context
258+ }
259+
260+ fn context_mut ( & mut self ) -> & mut T {
261+ self . context
262+ }
263+
242264 /// This can be used to push new operations from within [RingOp::complete].
243265 ///
244- /// See also [Ring::push].
245- pub fn push ( & mut self , op : E ) {
266+ /// Note that the operations are buffered until completion is finished and then pushed
267+ /// to the parent [Ring].
268+ fn push ( & mut self , op : E ) -> io:: Result < ( ) > {
246269 self . new_entries . push ( op) ;
270+ Ok ( ( ) )
247271 }
248272}
0 commit comments