@@ -72,7 +72,7 @@ use core::{cmp, mem};
7272use core:: cell:: RefCell ;
7373use crate :: io:: Read ;
7474use crate :: sync:: { Arc , Mutex , RwLock , RwLockReadGuard , FairRwLock , LockTestExt , LockHeldState } ;
75- use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
75+ use core:: sync:: atomic:: { AtomicUsize , AtomicBool , Ordering } ;
7676use core:: time:: Duration ;
7777use core:: ops:: Deref ;
7878
@@ -934,6 +934,8 @@ where
934934
935935 /// See `ChannelManager` struct-level documentation for lock order requirements.
936936 pending_events : Mutex < Vec < events:: Event > > ,
937+ /// A simple atomic flag to ensure only one task at a time can be processing events asynchronously.
938+ pending_events_processor : AtomicBool ,
937939 /// See `ChannelManager` struct-level documentation for lock order requirements.
938940 pending_background_events : Mutex < Vec < BackgroundEvent > > ,
939941 /// Used when we have to take a BIG lock to make sure everything is self-consistent.
@@ -1696,30 +1698,47 @@ macro_rules! handle_new_monitor_update {
16961698
16971699macro_rules! process_events_body {
16981700 ( $self: expr, $event_to_handle: expr, $handle_event: expr) => {
1699- // We'll acquire our total consistency lock until the returned future completes so that
1700- // we can be sure no other persists happen while processing events.
1701- let _read_guard = $self. total_consistency_lock. read( ) . unwrap( ) ;
1701+ let mut processed_all_events = false ;
1702+ while !processed_all_events {
1703+ if $self. pending_events_processor. compare_exchange( false , true , Ordering :: Acquire , Ordering :: Relaxed ) . is_err( ) {
1704+ return ;
1705+ }
17021706
1703- let mut result = NotifyOption :: SkipPersist ;
1707+ let mut result = NotifyOption :: SkipPersist ;
17041708
1705- // TODO: This behavior should be documented. It's unintuitive that we query
1706- // ChannelMonitors when clearing other events.
1707- if $self. process_pending_monitor_events( ) {
1708- result = NotifyOption :: DoPersist ;
1709- }
1709+ {
1710+ // We'll acquire our total consistency lock so that we can be sure no other
1711+ // persists happen while processing monitor events.
1712+ let _read_guard = $self. total_consistency_lock. read( ) . unwrap( ) ;
1713+
1714+ // TODO: This behavior should be documented. It's unintuitive that we query
1715+ // ChannelMonitors when clearing other events.
1716+ if $self. process_pending_monitor_events( ) {
1717+ result = NotifyOption :: DoPersist ;
1718+ }
1719+ }
17101720
1711- let pending_events = mem:: replace( & mut * $self. pending_events. lock( ) . unwrap( ) , vec![ ] ) ;
1712- if !pending_events. is_empty( ) {
1713- result = NotifyOption :: DoPersist ;
1714- }
1721+ let pending_events = $self. pending_events. lock( ) . unwrap( ) . clone( ) ;
1722+ let num_events = pending_events. len( ) ;
1723+ if !pending_events. is_empty( ) {
1724+ result = NotifyOption :: DoPersist ;
1725+ }
17151726
1716- for event in pending_events {
1717- $event_to_handle = event;
1718- $handle_event;
1719- }
1727+ for event in pending_events {
1728+ $event_to_handle = event;
1729+ $handle_event;
1730+ }
17201731
1721- if result == NotifyOption :: DoPersist {
1722- $self. persistence_notifier. notify( ) ;
1732+ {
1733+ let mut pending_events = $self. pending_events. lock( ) . unwrap( ) ;
1734+ pending_events. drain( ..num_events) ;
1735+ processed_all_events = pending_events. is_empty( ) ;
1736+ $self. pending_events_processor. store( false , Ordering :: Release ) ;
1737+ }
1738+
1739+ if result == NotifyOption :: DoPersist {
1740+ $self. persistence_notifier. notify( ) ;
1741+ }
17231742 }
17241743 }
17251744}
@@ -1787,6 +1806,7 @@ where
17871806 per_peer_state : FairRwLock :: new ( HashMap :: new ( ) ) ,
17881807
17891808 pending_events : Mutex :: new ( Vec :: new ( ) ) ,
1809+ pending_events_processor : AtomicBool :: new ( false ) ,
17901810 pending_background_events : Mutex :: new ( Vec :: new ( ) ) ,
17911811 total_consistency_lock : RwLock :: new ( ( ) ) ,
17921812 persistence_notifier : Notifier :: new ( ) ,
@@ -8026,6 +8046,7 @@ where
80268046 per_peer_state : FairRwLock :: new ( per_peer_state) ,
80278047
80288048 pending_events : Mutex :: new ( pending_events_read) ,
8049+ pending_events_processor : AtomicBool :: new ( false ) ,
80298050 pending_background_events : Mutex :: new ( pending_background_events) ,
80308051 total_consistency_lock : RwLock :: new ( ( ) ) ,
80318052 persistence_notifier : Notifier :: new ( ) ,
@@ -8057,8 +8078,6 @@ mod tests {
80578078 use bitcoin:: hashes:: Hash ;
80588079 use bitcoin:: hashes:: sha256:: Hash as Sha256 ;
80598080 use bitcoin:: secp256k1:: { PublicKey , Secp256k1 , SecretKey } ;
8060- #[ cfg( feature = "std" ) ]
8061- use core:: time:: Duration ;
80628081 use core:: sync:: atomic:: Ordering ;
80638082 use crate :: events:: { Event , HTLCDestination , MessageSendEvent , MessageSendEventsProvider , ClosureReason } ;
80648083 use crate :: ln:: { PaymentPreimage , PaymentHash , PaymentSecret } ;
0 commit comments