@@ -146,38 +146,48 @@ impl SingleIssuerRing {
146146 self . sq ( ) . taskrun ( )
147147 }
148148
149- // Will busy loop until `num_to_complete` has been achieved . It is the caller's
149+ // Will busy loop until `num_to_visit` CQE have been visited . It is the caller's
150150 // responsibility to make sure the CQ will see that many completions, otherwise
151151 // this will result in an infinite loop.
152152 pub ( crate ) fn process_cqes (
153153 & mut self ,
154154 slab : & mut RawSqeSlab ,
155- num_to_complete : Option < usize > ,
155+ num_to_visit : Option < usize > ,
156156 ) -> Result < usize > {
157+ // We need to split `num_visited`/`num_completed` counters because if we
158+ // cancel an SQE inflight, the entry might be dropped from the slab while
159+ // still producing a CQE. In that case, the loop would only increment the
160+ // `num_visited` counter.
161+ let mut num_visited = 0 ;
157162 let mut num_completed = 0 ;
158- let mut should_sync = false ;
159163
160- let to_complete = num_to_complete. unwrap_or ( self . cq ( ) . len ( ) ) ;
164+ let mut cq = self . cq ( ) ;
165+ let to_visit = num_to_visit. unwrap_or ( cq. len ( ) ) ;
161166
162- while num_completed < to_complete {
163- let mut cq = self . cq ( ) ;
167+ let mut should_sync = false ;
164168
165- // Avoid syncing on first pass
169+ while num_visited < to_visit {
170+ // Avoid syncing on first pass.
166171 if should_sync {
172+ // If we get here, we are spinning waiting for completions so
173+ // let's give the CPU a tiny breather.
174+ std:: thread:: yield_now ( ) ;
167175 cq. sync ( ) ;
168176 }
169177
170- for cqe in cq {
178+ for cqe in & mut cq {
179+ num_visited += 1 ;
180+
171181 let raw_sqe = match slab. get_mut ( cqe. user_data ( ) as usize ) {
172182 Err ( e) => {
173183 eprintln ! ( "CQE user data not found in RawSqeSlab: {:?}" , e) ;
174184 continue ;
175185 }
176186 Ok ( sqe) => {
177- if !matches ! ( sqe. get_state ( ) , RawSqeState :: Pending | RawSqeState :: Ready ) {
187+ if !matches ! ( sqe. state , RawSqeState :: Pending | RawSqeState :: Ready ) {
178188 // Ignore unknown CQEs which might have valid index in
179189 // the Slab. Can this even happen?
180- eprintln ! ( "SQE in unexpected state: {:?}" , sqe. get_state ( ) ) ;
190+ eprintln ! ( "SQE in unexpected state: {:?}" , sqe. state ) ;
181191 continue ;
182192 }
183193 sqe
@@ -189,7 +199,12 @@ impl SingleIssuerRing {
189199 if let Some ( CompletionEffect :: WakeHead { head } ) =
190200 raw_sqe. on_completion ( cqe. result ( ) , cqe. flags ( ) . into ( ) ) ?
191201 {
192- slab. get_mut ( head) ?. wake ( ) ?;
202+ slab. get_mut ( head) ?. wake_by_ref ( ) ?;
203+ }
204+
205+ // Exit early if user provided an override for `to_visit`.
206+ if num_visited >= to_visit {
207+ break ;
193208 }
194209 }
195210
@@ -273,6 +288,8 @@ mod tests {
273288 let builder = Builder :: new_local ( ) . sq_ring_size ( sq_ring_size) ;
274289 let ( _runtime, _scheduler) = init_local_runtime_and_context ( Some ( builder) ) ?;
275290
291+ let ( waker, _) = mock_waker ( ) ;
292+
276293 context:: with_slab_and_ring_mut ( |slab, ring| -> Result < ( ) > {
277294 {
278295 let sq = ring. sq ( ) ;
@@ -289,7 +306,7 @@ mod tests {
289306
290307 ( 0 ..n) . for_each ( |i| {
291308 nops. push ( nop ( ) . user_data ( indices[ i] as u64 ) ) ;
292- raws. push ( RawSqe :: new ( CompletionHandler :: new_single ( ) ) ) ;
309+ raws. push ( RawSqe :: new ( & waker , CompletionHandler :: new_single ( ) ) ) ;
293310 } ) ;
294311
295312 let _ = batch. commit ( raws) ?;
@@ -342,15 +359,9 @@ mod tests {
342359 ( 0 ..n) . for_each ( |i| {
343360 let nop = nop ( ) . user_data ( indices[ i] as u64 ) ;
344361
345- let mut raw = RawSqe :: new ( CompletionHandler :: new_single ( ) ) ;
346- raw. set_waker ( & waker) ;
347-
362+ let raw = RawSqe :: new ( & waker, CompletionHandler :: new_single ( ) ) ;
348363 nops. push ( nop) ;
349364 raws. push ( raw) ;
350-
351- // We use single SQE even though we use batch API on slab,
352- // anyways a bit messed up but need to count N pending ios.
353- context:: with_core ( |core| core. increment_pending_ios ( ) ) ;
354365 } ) ;
355366
356367 let _ = batch. commit ( raws) ?;
0 commit comments