@@ -72,7 +72,7 @@ use core::{cmp, mem};
72
72
use core:: cell:: RefCell ;
73
73
use crate :: io:: Read ;
74
74
use crate :: sync:: { Arc , Mutex , RwLock , RwLockReadGuard , FairRwLock , LockTestExt , LockHeldState } ;
75
- use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
75
+ use core:: sync:: atomic:: { AtomicUsize , AtomicBool , Ordering } ;
76
76
use core:: time:: Duration ;
77
77
use core:: ops:: Deref ;
78
78
@@ -926,6 +926,8 @@ where
926
926
927
927
/// See `ChannelManager` struct-level documentation for lock order requirements.
928
928
pending_events : Mutex < Vec < events:: Event > > ,
929
+ /// A simple atomic flag to ensure only one task at a time can be processing events asynchronously.
930
+ pending_events_processor : AtomicBool ,
929
931
/// See `ChannelManager` struct-level documentation for lock order requirements.
930
932
pending_background_events : Mutex < Vec < BackgroundEvent > > ,
931
933
/// Used when we have to take a BIG lock to make sure everything is self-consistent.
@@ -1741,6 +1743,7 @@ where
1741
1743
per_peer_state : FairRwLock :: new ( HashMap :: new ( ) ) ,
1742
1744
1743
1745
pending_events : Mutex :: new ( Vec :: new ( ) ) ,
1746
+ pending_events_processor : AtomicBool :: new ( false ) ,
1744
1747
pending_background_events : Mutex :: new ( Vec :: new ( ) ) ,
1745
1748
total_consistency_lock : RwLock :: new ( ( ) ) ,
1746
1749
persistence_notifier : Notifier :: new ( ) ,
@@ -5282,7 +5285,8 @@ where
5282
5285
5283
5286
/// Process pending events from the [`chain::Watch`], returning whether any events were processed.
5284
5287
fn process_pending_monitor_events ( & self ) -> bool {
5285
- debug_assert ! ( self . total_consistency_lock. try_write( ) . is_err( ) ) ; // Caller holds read lock
5288
+ debug_assert ! ( self . total_consistency_lock. try_write( ) . is_err( ) ||
5289
+ self . pending_events_processor. load( Ordering :: Relaxed ) ) ; // Caller holds read lock or processes events asynchronously.
5286
5290
5287
5291
let mut failed_channels = Vec :: new ( ) ;
5288
5292
let mut pending_monitor_events = self . chain_monitor . release_pending_monitor_events ( ) ;
@@ -5775,9 +5779,9 @@ where
5775
5779
pub async fn process_pending_events_async < Future : core:: future:: Future , H : Fn ( Event ) -> Future > (
5776
5780
& self , handler : H
5777
5781
) {
5778
- // We'll acquire our total consistency lock until the returned future completes so that
5779
- // we can be sure no other persists happen while processing events.
5780
- let _read_guard = self . total_consistency_lock . read ( ) . unwrap ( ) ;
5782
+ if self . pending_events_processor . compare_exchange ( false , true , Ordering :: Acquire , Ordering :: Relaxed ) . is_err ( ) {
5783
+ return ;
5784
+ }
5781
5785
5782
5786
let mut result = NotifyOption :: SkipPersist ;
5783
5787
@@ -5787,7 +5791,8 @@ where
5787
5791
result = NotifyOption :: DoPersist ;
5788
5792
}
5789
5793
5790
- let pending_events = mem:: replace ( & mut * self . pending_events . lock ( ) . unwrap ( ) , vec ! [ ] ) ;
5794
+ let pending_events = self . pending_events . lock ( ) . unwrap ( ) . clone ( ) ;
5795
+ let num_events = pending_events. len ( ) ;
5791
5796
if !pending_events. is_empty ( ) {
5792
5797
result = NotifyOption :: DoPersist ;
5793
5798
}
@@ -5796,9 +5801,13 @@ where
5796
5801
handler ( event) . await ;
5797
5802
}
5798
5803
5804
+ self . pending_events . lock ( ) . unwrap ( ) . drain ( ..num_events) ;
5805
+
5799
5806
if result == NotifyOption :: DoPersist {
5800
5807
self . persistence_notifier . notify ( ) ;
5801
5808
}
5809
+
5810
+ self . pending_events_processor . store ( false , Ordering :: Release ) ;
5802
5811
}
5803
5812
}
5804
5813
@@ -7926,6 +7935,7 @@ where
7926
7935
per_peer_state : FairRwLock :: new ( per_peer_state) ,
7927
7936
7928
7937
pending_events : Mutex :: new ( pending_events_read) ,
7938
+ pending_events_processor : AtomicBool :: new ( false ) ,
7929
7939
pending_background_events : Mutex :: new ( pending_background_events) ,
7930
7940
total_consistency_lock : RwLock :: new ( ( ) ) ,
7931
7941
persistence_notifier : Notifier :: new ( ) ,
0 commit comments