1
1
use crate :: bstr:: { BStr , BString } ;
2
+ use crate :: status:: OwnedOrStaticAtomic ;
2
3
use crate :: { config, Repository } ;
3
4
use gix_status:: index_as_worktree:: traits:: { CompareBlobs , SubmoduleStatus } ;
4
5
use std:: sync:: atomic:: AtomicBool ;
@@ -284,6 +285,10 @@ mod submodule_status {
284
285
/// It's a crutch that is just there to make single-threaded applications possible at all, as it's not really an iterator
285
286
/// anymore. If this matters, better run [Repository::index_worktree_status()] by hand as it provides all control one would need,
286
287
/// just not as an iterator.
288
+ ///
289
+ /// Also, even with `parallel` set, the first call to `next()` will block until there is an item available, without a chance
290
+ /// to interrupt unless [`status::Platform::should_interrupt_*()`](crate::status::Platform::should_interrupt_shared()) was
291
+ /// configured.
287
292
pub struct Iter {
288
293
#[ cfg( feature = "parallel" ) ]
289
294
#[ allow( clippy:: type_complexity) ]
@@ -292,7 +297,7 @@ pub struct Iter {
292
297
std:: thread:: JoinHandle < Result < iter:: Outcome , crate :: status:: index_worktree:: Error > > ,
293
298
) > ,
294
299
#[ cfg( feature = "parallel" ) ]
295
- should_interrupt : std :: sync :: Arc < AtomicBool > ,
300
+ should_interrupt : OwnedOrStaticAtomic ,
296
301
/// Without parallelization, the iterator has to buffer all changes in advance.
297
302
#[ cfg( not( feature = "parallel" ) ) ]
298
303
items : std:: vec:: IntoIter < iter:: Item > ,
@@ -307,10 +312,8 @@ pub mod iter {
307
312
use crate :: bstr:: BString ;
308
313
use crate :: config:: cache:: util:: ApplyLeniencyDefault ;
309
314
use crate :: status:: index_worktree:: { iter, BuiltinSubmoduleStatus } ;
310
- use crate :: status:: { index_worktree, Platform } ;
315
+ use crate :: status:: { index_worktree, OwnedOrStaticAtomic , Platform } ;
311
316
use crate :: worktree:: IndexPersistedOrInMemory ;
312
- use std:: sync:: atomic:: AtomicBool ;
313
- use std:: sync:: Arc ;
314
317
315
318
pub ( super ) enum ApplyChange {
316
319
SetSizeToZero ,
@@ -564,7 +567,6 @@ pub mod iter {
564
567
Some ( index) => index,
565
568
} ;
566
569
567
- let should_interrupt = Arc :: new ( AtomicBool :: default ( ) ) ;
568
570
let skip_hash = self
569
571
. repo
570
572
. config
@@ -574,6 +576,7 @@ pub mod iter {
574
576
. transpose ( )
575
577
. with_lenient_default ( self . repo . config . lenient_config ) ?
576
578
. unwrap_or_default ( ) ;
579
+ let should_interrupt = self . should_interrupt . clone ( ) . unwrap_or_default ( ) ;
577
580
let submodule = BuiltinSubmoduleStatus :: new ( self . repo . clone ( ) . into_sync ( ) , self . submodules ) ?;
578
581
#[ cfg( feature = "parallel" ) ]
579
582
{
@@ -726,10 +729,27 @@ pub mod iter {
726
729
#[ cfg( feature = "parallel" ) ]
727
730
impl Drop for super :: Iter {
728
731
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 ( ) ) ;
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