Skip to content

Commit 769a2d2

Browse files
authored
Merge pull request #224 from tnull/2024-01-async-events
Introduce `next_event_async` allowing to poll event queue
2 parents 741e706 + 77dfa83 commit 769a2d2

File tree

5 files changed

+153
-8
lines changed

5 files changed

+153
-8
lines changed

bindings/kotlin/ldk-node-android/lib/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ android {
4343
dependencies {
4444
implementation("net.java.dev.jna:jna:5.12.0@aar")
4545
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7")
46+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
4647
implementation("androidx.appcompat:appcompat:1.4.0")
4748
implementation("androidx.core:core-ktx:1.7.0")
4849
api("org.slf4j:slf4j-api:1.7.30")

bindings/kotlin/ldk-node-jvm/lib/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ dependencies {
4646

4747
// Use the Kotlin JDK 8 standard library.
4848
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
49+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
4950

5051
implementation("net.java.dev.jna:jna:5.12.0")
5152
}

bindings/ldk_node.udl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ interface LDKNode {
4343
void stop();
4444
Event? next_event();
4545
Event wait_next_event();
46+
[Async]
47+
Event next_event_async();
4648
void event_handled();
4749
PublicKey node_id();
4850
sequence<SocketAddress>? listening_addresses();

src/event.rs

Lines changed: 140 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer};
2626
use bitcoin::blockdata::locktime::absolute::LockTime;
2727
use bitcoin::secp256k1::PublicKey;
2828
use bitcoin::OutPoint;
29+
use core::future::Future;
30+
use core::task::{Poll, Waker};
2931
use rand::{thread_rng, Rng};
3032
use std::collections::VecDeque;
3133
use std::ops::Deref;
@@ -125,7 +127,8 @@ pub struct EventQueue<K: KVStore + Sync + Send, L: Deref>
125127
where
126128
L::Target: Logger,
127129
{
128-
queue: Mutex<VecDeque<Event>>,
130+
queue: Arc<Mutex<VecDeque<Event>>>,
131+
waker: Arc<Mutex<Option<Waker>>>,
129132
notifier: Condvar,
130133
kv_store: Arc<K>,
131134
logger: L,
@@ -136,9 +139,10 @@ where
136139
L::Target: Logger,
137140
{
138141
pub(crate) fn new(kv_store: Arc<K>, logger: L) -> Self {
139-
let queue: Mutex<VecDeque<Event>> = Mutex::new(VecDeque::new());
142+
let queue = Arc::new(Mutex::new(VecDeque::new()));
143+
let waker = Arc::new(Mutex::new(None));
140144
let notifier = Condvar::new();
141-
Self { queue, notifier, kv_store, logger }
145+
Self { queue, waker, notifier, kv_store, logger }
142146
}
143147

144148
pub(crate) fn add_event(&self, event: Event) -> Result<(), Error> {
@@ -149,6 +153,10 @@ where
149153
}
150154

151155
self.notifier.notify_one();
156+
157+
if let Some(waker) = self.waker.lock().unwrap().take() {
158+
waker.wake();
159+
}
152160
Ok(())
153161
}
154162

@@ -157,6 +165,10 @@ where
157165
locked_queue.front().map(|e| e.clone())
158166
}
159167

168+
pub(crate) async fn next_event_async(&self) -> Event {
169+
EventFuture { event_queue: Arc::clone(&self.queue), waker: Arc::clone(&self.waker) }.await
170+
}
171+
160172
pub(crate) fn wait_next_event(&self) -> Event {
161173
let locked_queue =
162174
self.notifier.wait_while(self.queue.lock().unwrap(), |queue| queue.is_empty()).unwrap();
@@ -170,6 +182,10 @@ where
170182
self.persist_queue(&locked_queue)?;
171183
}
172184
self.notifier.notify_one();
185+
186+
if let Some(waker) = self.waker.lock().unwrap().take() {
187+
waker.wake();
188+
}
173189
Ok(())
174190
}
175191

@@ -207,9 +223,10 @@ where
207223
) -> Result<Self, lightning::ln::msgs::DecodeError> {
208224
let (kv_store, logger) = args;
209225
let read_queue: EventQueueDeserWrapper = Readable::read(reader)?;
210-
let queue: Mutex<VecDeque<Event>> = Mutex::new(read_queue.0);
226+
let queue = Arc::new(Mutex::new(read_queue.0));
227+
let waker = Arc::new(Mutex::new(None));
211228
let notifier = Condvar::new();
212-
Ok(Self { queue, notifier, kv_store, logger })
229+
Ok(Self { queue, waker, notifier, kv_store, logger })
213230
}
214231
}
215232

@@ -240,6 +257,26 @@ impl Writeable for EventQueueSerWrapper<'_> {
240257
}
241258
}
242259

260+
struct EventFuture {
261+
event_queue: Arc<Mutex<VecDeque<Event>>>,
262+
waker: Arc<Mutex<Option<Waker>>>,
263+
}
264+
265+
impl Future for EventFuture {
266+
type Output = Event;
267+
268+
fn poll(
269+
self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>,
270+
) -> core::task::Poll<Self::Output> {
271+
if let Some(event) = self.event_queue.lock().unwrap().front() {
272+
Poll::Ready(event.clone())
273+
} else {
274+
*self.waker.lock().unwrap() = Some(cx.waker().clone());
275+
Poll::Pending
276+
}
277+
}
278+
}
279+
243280
pub(crate) struct EventHandler<K: KVStore + Sync + Send, L: Deref>
244281
where
245282
L::Target: Logger,
@@ -796,12 +833,14 @@ where
796833
mod tests {
797834
use super::*;
798835
use lightning::util::test_utils::{TestLogger, TestStore};
836+
use std::sync::atomic::{AtomicU16, Ordering};
837+
use std::time::Duration;
799838

800-
#[test]
801-
fn event_queue_persistence() {
839+
#[tokio::test]
840+
async fn event_queue_persistence() {
802841
let store = Arc::new(TestStore::new(false));
803842
let logger = Arc::new(TestLogger::new());
804-
let event_queue = EventQueue::new(Arc::clone(&store), Arc::clone(&logger));
843+
let event_queue = Arc::new(EventQueue::new(Arc::clone(&store), Arc::clone(&logger)));
805844
assert_eq!(event_queue.next_event(), None);
806845

807846
let expected_event = Event::ChannelReady {
@@ -814,6 +853,7 @@ mod tests {
814853
// Check we get the expected event and that it is returned until we mark it handled.
815854
for _ in 0..5 {
816855
assert_eq!(event_queue.wait_next_event(), expected_event);
856+
assert_eq!(event_queue.next_event_async().await, expected_event);
817857
assert_eq!(event_queue.next_event(), Some(expected_event.clone()));
818858
}
819859

@@ -832,4 +872,96 @@ mod tests {
832872
event_queue.event_handled().unwrap();
833873
assert_eq!(event_queue.next_event(), None);
834874
}
875+
876+
#[tokio::test]
877+
async fn event_queue_concurrency() {
878+
let store = Arc::new(TestStore::new(false));
879+
let logger = Arc::new(TestLogger::new());
880+
let event_queue = Arc::new(EventQueue::new(Arc::clone(&store), Arc::clone(&logger)));
881+
assert_eq!(event_queue.next_event(), None);
882+
883+
let expected_event = Event::ChannelReady {
884+
channel_id: ChannelId([23u8; 32]),
885+
user_channel_id: UserChannelId(2323),
886+
counterparty_node_id: None,
887+
};
888+
889+
// Check `next_event_async` won't return if the queue is empty and always rather timeout.
890+
tokio::select! {
891+
_ = tokio::time::sleep(Duration::from_secs(1)) => {
892+
// Timeout
893+
}
894+
_ = event_queue.next_event_async() => {
895+
panic!();
896+
}
897+
}
898+
899+
assert_eq!(event_queue.next_event(), None);
900+
// Check we get the expected number of events when polling/enqueuing concurrently.
901+
let enqueued_events = AtomicU16::new(0);
902+
let received_events = AtomicU16::new(0);
903+
let mut delayed_enqueue = false;
904+
905+
for _ in 0..25 {
906+
event_queue.add_event(expected_event.clone()).unwrap();
907+
enqueued_events.fetch_add(1, Ordering::SeqCst);
908+
}
909+
910+
loop {
911+
tokio::select! {
912+
_ = tokio::time::sleep(Duration::from_millis(10)), if !delayed_enqueue => {
913+
event_queue.add_event(expected_event.clone()).unwrap();
914+
enqueued_events.fetch_add(1, Ordering::SeqCst);
915+
delayed_enqueue = true;
916+
}
917+
e = event_queue.next_event_async() => {
918+
assert_eq!(e, expected_event);
919+
event_queue.event_handled().unwrap();
920+
received_events.fetch_add(1, Ordering::SeqCst);
921+
922+
event_queue.add_event(expected_event.clone()).unwrap();
923+
enqueued_events.fetch_add(1, Ordering::SeqCst);
924+
}
925+
e = event_queue.next_event_async() => {
926+
assert_eq!(e, expected_event);
927+
event_queue.event_handled().unwrap();
928+
received_events.fetch_add(1, Ordering::SeqCst);
929+
}
930+
}
931+
932+
if delayed_enqueue
933+
&& received_events.load(Ordering::SeqCst) == enqueued_events.load(Ordering::SeqCst)
934+
{
935+
break;
936+
}
937+
}
938+
assert_eq!(event_queue.next_event(), None);
939+
940+
// Check we operate correctly, even when mixing and matching blocking and async API calls.
941+
let (tx, mut rx) = tokio::sync::watch::channel(());
942+
let thread_queue = Arc::clone(&event_queue);
943+
let thread_event = expected_event.clone();
944+
std::thread::spawn(move || {
945+
let e = thread_queue.wait_next_event();
946+
assert_eq!(e, thread_event);
947+
thread_queue.event_handled().unwrap();
948+
tx.send(()).unwrap();
949+
});
950+
951+
let thread_queue = Arc::clone(&event_queue);
952+
let thread_event = expected_event.clone();
953+
std::thread::spawn(move || {
954+
// Sleep a bit before we enqueue the events everybody is waiting for.
955+
std::thread::sleep(Duration::from_millis(20));
956+
thread_queue.add_event(thread_event.clone()).unwrap();
957+
thread_queue.add_event(thread_event.clone()).unwrap();
958+
});
959+
960+
let e = event_queue.next_event_async().await;
961+
assert_eq!(e, expected_event.clone());
962+
event_queue.event_handled().unwrap();
963+
964+
rx.changed().await.unwrap();
965+
assert_eq!(event_queue.next_event(), None);
966+
}
835967
}

src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,15 @@ impl<K: KVStore + Sync + Send + 'static> Node<K> {
811811
self.event_queue.next_event()
812812
}
813813

814+
/// Returns the next event in the event queue.
815+
///
816+
/// Will asynchronously poll the event queue until the next event is ready.
817+
///
818+
/// **Note:** this will always return the same event until handling is confirmed via [`Node::event_handled`].
819+
pub async fn next_event_async(&self) -> Event {
820+
self.event_queue.next_event_async().await
821+
}
822+
814823
/// Returns the next event in the event queue.
815824
///
816825
/// Will block the current thread until the next event is available.

0 commit comments

Comments
 (0)