@@ -284,6 +284,10 @@ mod submodule_status {
284
284
/// It's a crutch that is just there to make single-threaded applications possible at all, as it's not really an iterator
285
285
/// anymore. If this matters, better run [Repository::index_worktree_status()] by hand as it provides all control one would need,
286
286
/// just not as an iterator.
287
+ ///
288
+ /// Also, even with `parallel` set, the first call to `next()` will block until there is an item available, without a chance
289
+ /// to interrupt unless [`status::Platform::should_interrupt_*()`](crate::status::Platform::should_interrupt_shared()) was
290
+ /// configured.
287
291
pub struct Iter {
288
292
#[ cfg( feature = "parallel" ) ]
289
293
#[ allow( clippy:: type_complexity) ]
@@ -292,7 +296,7 @@ pub struct Iter {
292
296
std:: thread:: JoinHandle < Result < iter:: Outcome , crate :: status:: index_worktree:: Error > > ,
293
297
) > ,
294
298
#[ cfg( feature = "parallel" ) ]
295
- should_interrupt : std :: sync :: Arc < AtomicBool > ,
299
+ should_interrupt : crate :: status :: OwnedOrStaticAtomic ,
296
300
/// Without parallelization, the iterator has to buffer all changes in advance.
297
301
#[ cfg( not( feature = "parallel" ) ) ]
298
302
items : std:: vec:: IntoIter < iter:: Item > ,
@@ -309,8 +313,6 @@ pub mod iter {
309
313
use crate :: status:: index_worktree:: { iter, BuiltinSubmoduleStatus } ;
310
314
use crate :: status:: { index_worktree, Platform } ;
311
315
use crate :: worktree:: IndexPersistedOrInMemory ;
312
- use std:: sync:: atomic:: AtomicBool ;
313
- use std:: sync:: Arc ;
314
316
315
317
pub ( super ) enum ApplyChange {
316
318
SetSizeToZero ,
@@ -564,7 +566,6 @@ pub mod iter {
564
566
Some ( index) => index,
565
567
} ;
566
568
567
- let should_interrupt = Arc :: new ( AtomicBool :: default ( ) ) ;
568
569
let skip_hash = self
569
570
. repo
570
571
. config
@@ -574,6 +575,7 @@ pub mod iter {
574
575
. transpose ( )
575
576
. with_lenient_default ( self . repo . config . lenient_config ) ?
576
577
. unwrap_or_default ( ) ;
578
+ let should_interrupt = self . should_interrupt . clone ( ) . unwrap_or_default ( ) ;
577
579
let submodule = BuiltinSubmoduleStatus :: new ( self . repo . clone ( ) . into_sync ( ) , self . submodules ) ?;
578
580
#[ cfg( feature = "parallel" ) ]
579
581
{
@@ -726,10 +728,28 @@ pub mod iter {
726
728
#[ cfg( feature = "parallel" ) ]
727
729
impl Drop for super :: Iter {
728
730
fn drop ( & mut self ) {
729
- self . should_interrupt . store ( true , std:: sync:: atomic:: Ordering :: Relaxed ) ;
730
- // Allow to temporarily 'leak' the producer to not block on drop, nobody
731
- // is interested in the result of the thread anymore.
732
- drop ( self . rx_and_join . take ( ) ) ;
731
+ use crate :: status:: OwnedOrStaticAtomic ;
732
+ let Some ( ( rx, handle) ) = self . rx_and_join . take ( ) else {
733
+ return ;
734
+ } ;
735
+ let prev = self . should_interrupt . swap ( true , std:: sync:: atomic:: Ordering :: Relaxed ) ;
736
+ let undo = match & self . should_interrupt {
737
+ OwnedOrStaticAtomic :: Shared ( flag) => * flag,
738
+ OwnedOrStaticAtomic :: Owned { flag, private : false } => flag. as_ref ( ) ,
739
+ OwnedOrStaticAtomic :: Owned { private : true , .. } => {
740
+ // Leak the handle to let it shut down in the background, so drop returns more quickly.
741
+ drop ( ( rx, handle) ) ;
742
+ return ;
743
+ }
744
+ } ;
745
+ // Wait until there is time to respond before we undo the change.
746
+ handle. join ( ) . ok ( ) ;
747
+ undo. fetch_update (
748
+ std:: sync:: atomic:: Ordering :: SeqCst ,
749
+ std:: sync:: atomic:: Ordering :: SeqCst ,
750
+ |current| current. then_some ( prev) ,
751
+ )
752
+ . ok ( ) ;
733
753
}
734
754
}
735
755
0 commit comments