Skip to content

Commit f2453b7

Browse files
committed
Allow events processing without holding total_consistency_lock
Unfortunately, the RAII types used by `RwLock` are not `Send`, which is why they can't be held over `await` boundaries. In order to allow asynchronous events processing in multi-threaded environments, we here allow to process events without holding the `total_consistency_lock`.
1 parent b546822 commit f2453b7

File tree

2 files changed

+53
-30
lines changed

2 files changed

+53
-30
lines changed

lightning-background-processor/src/lib.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -1485,10 +1485,9 @@ mod tests {
14851485
})
14861486
}, false,
14871487
);
1488-
// TODO: Drop _local and simply spawn after #2003
1489-
let local_set = tokio::task::LocalSet::new();
1490-
local_set.spawn_local(bp_future);
1491-
local_set.spawn_local(async move {
1488+
1489+
let t1 = tokio::spawn(bp_future);
1490+
let t2 = tokio::spawn(async move {
14921491
do_test_not_pruning_network_graph_until_graph_sync_completion!(nodes, {
14931492
let mut i = 0;
14941493
loop {
@@ -1500,7 +1499,9 @@ mod tests {
15001499
}, tokio::time::sleep(Duration::from_millis(1)).await);
15011500
exit_sender.send(()).unwrap();
15021501
});
1503-
local_set.await;
1502+
let (r1, r2) = tokio::join!(t1, t2);
1503+
r1.unwrap().unwrap();
1504+
r2.unwrap()
15041505
}
15051506

15061507
macro_rules! do_test_payment_path_scoring {
@@ -1654,13 +1655,14 @@ mod tests {
16541655
})
16551656
}, false,
16561657
);
1657-
// TODO: Drop _local and simply spawn after #2003
1658-
let local_set = tokio::task::LocalSet::new();
1659-
local_set.spawn_local(bp_future);
1660-
local_set.spawn_local(async move {
1658+
let t1 = tokio::spawn(bp_future);
1659+
let t2 = tokio::spawn(async move {
16611660
do_test_payment_path_scoring!(nodes, receiver.recv().await);
16621661
exit_sender.send(()).unwrap();
16631662
});
1664-
local_set.await;
1663+
1664+
let (r1, r2) = tokio::join!(t1, t2);
1665+
r1.unwrap().unwrap();
1666+
r2.unwrap()
16651667
}
16661668
}

lightning/src/ln/channelmanager.rs

+41-20
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ use core::{cmp, mem};
7272
use core::cell::RefCell;
7373
use crate::io::Read;
7474
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};
7676
use core::time::Duration;
7777
use core::ops::Deref;
7878

@@ -926,6 +926,8 @@ where
926926

927927
/// See `ChannelManager` struct-level documentation for lock order requirements.
928928
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,
929931
/// See `ChannelManager` struct-level documentation for lock order requirements.
930932
pending_background_events: Mutex<Vec<BackgroundEvent>>,
931933
/// Used when we have to take a BIG lock to make sure everything is self-consistent.
@@ -1680,30 +1682,47 @@ macro_rules! handle_new_monitor_update {
16801682

16811683
macro_rules! process_events_body {
16821684
($self: expr, $event_to_handle: expr, $handle_event: expr) => {
1683-
// We'll acquire our total consistency lock until the returned future completes so that
1684-
// we can be sure no other persists happen while processing events.
1685-
let _read_guard = $self.total_consistency_lock.read().unwrap();
1685+
let mut processed_all_events = false;
1686+
while !processed_all_events {
1687+
if $self.pending_events_processor.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() {
1688+
return;
1689+
}
16861690

1687-
let mut result = NotifyOption::SkipPersist;
1691+
let mut result = NotifyOption::SkipPersist;
16881692

1689-
// TODO: This behavior should be documented. It's unintuitive that we query
1690-
// ChannelMonitors when clearing other events.
1691-
if $self.process_pending_monitor_events() {
1692-
result = NotifyOption::DoPersist;
1693-
}
1693+
{
1694+
// We'll acquire our total consistency lock so that we can be sure no other
1695+
// persists happen while processing monitor events.
1696+
let _read_guard = $self.total_consistency_lock.read().unwrap();
1697+
1698+
// TODO: This behavior should be documented. It's unintuitive that we query
1699+
// ChannelMonitors when clearing other events.
1700+
if $self.process_pending_monitor_events() {
1701+
result = NotifyOption::DoPersist;
1702+
}
1703+
}
16941704

1695-
let pending_events = mem::replace(&mut *$self.pending_events.lock().unwrap(), vec![]);
1696-
if !pending_events.is_empty() {
1697-
result = NotifyOption::DoPersist;
1698-
}
1705+
let pending_events = $self.pending_events.lock().unwrap().clone();
1706+
let num_events = pending_events.len();
1707+
if !pending_events.is_empty() {
1708+
result = NotifyOption::DoPersist;
1709+
}
16991710

1700-
for event in pending_events {
1701-
$event_to_handle = event;
1702-
$handle_event;
1703-
}
1711+
for event in pending_events {
1712+
$event_to_handle = event;
1713+
$handle_event;
1714+
}
17041715

1705-
if result == NotifyOption::DoPersist {
1706-
$self.persistence_notifier.notify();
1716+
{
1717+
let mut pending_events = $self.pending_events.lock().unwrap();
1718+
pending_events.drain(..num_events);
1719+
processed_all_events = pending_events.is_empty();
1720+
$self.pending_events_processor.store(false, Ordering::Release);
1721+
}
1722+
1723+
if result == NotifyOption::DoPersist {
1724+
$self.persistence_notifier.notify();
1725+
}
17071726
}
17081727
}
17091728
}
@@ -1771,6 +1790,7 @@ where
17711790
per_peer_state: FairRwLock::new(HashMap::new()),
17721791

17731792
pending_events: Mutex::new(Vec::new()),
1793+
pending_events_processor: AtomicBool::new(false),
17741794
pending_background_events: Mutex::new(Vec::new()),
17751795
total_consistency_lock: RwLock::new(()),
17761796
persistence_notifier: Notifier::new(),
@@ -7916,6 +7936,7 @@ where
79167936
per_peer_state: FairRwLock::new(per_peer_state),
79177937

79187938
pending_events: Mutex::new(pending_events_read),
7939+
pending_events_processor: AtomicBool::new(false),
79197940
pending_background_events: Mutex::new(pending_background_events),
79207941
total_consistency_lock: RwLock::new(()),
79217942
persistence_notifier: Notifier::new(),

0 commit comments

Comments
 (0)