13
13
//!
14
14
//! [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
15
15
16
+ use alloc:: sync:: Arc ;
16
17
use core:: mem;
17
18
use core:: time:: Duration ;
18
19
use sync:: { Condvar , Mutex } ;
19
20
20
21
#[ cfg( any( test, feature = "std" ) ) ]
21
22
use std:: time:: Instant ;
22
23
24
+ #[ cfg( feature = "std" ) ]
25
+ use std:: future:: Future as StdFuture ;
26
+ #[ cfg( feature = "std" ) ]
27
+ use std:: task:: { Context , Poll } ;
28
+ #[ cfg( feature = "std" ) ]
29
+ use std:: pin:: Pin ;
30
+
23
31
/// Used to signal to the ChannelManager persister that the manager needs to be re-persisted to
24
32
/// disk/backups, through `await_persistable_update_timeout` and `await_persistable_update`.
25
33
pub ( crate ) struct PersistenceNotifier {
26
- /// Users won't access the persistence_lock directly, but rather wait on its bool using
27
- /// `wait_timeout` and `wait`.
28
- persistence_lock : ( Mutex < bool > , Condvar ) ,
34
+ persist_pending : Mutex < ( bool , Option < Arc < Mutex < FutureState > > > ) > ,
35
+ persistence_condvar : Condvar ,
29
36
}
30
37
31
38
impl PersistenceNotifier {
32
39
pub ( crate ) fn new ( ) -> Self {
33
40
Self {
34
- persistence_lock : ( Mutex :: new ( false ) , Condvar :: new ( ) ) ,
41
+ persist_pending : Mutex :: new ( ( false , None ) ) ,
42
+ persistence_condvar : Condvar :: new ( ) ,
35
43
}
36
44
}
37
45
38
46
pub ( crate ) fn wait ( & self ) {
39
47
loop {
40
- let & ( ref mtx, ref cvar) = & self . persistence_lock ;
41
- let mut guard = mtx. lock ( ) . unwrap ( ) ;
42
- if * guard {
43
- * guard = false ;
48
+ let mut guard = self . persist_pending . lock ( ) . unwrap ( ) ;
49
+ if guard. 0 {
50
+ guard. 0 = false ;
44
51
return ;
45
52
}
46
- guard = cvar . wait ( guard) . unwrap ( ) ;
47
- let result = * guard;
53
+ guard = self . persistence_condvar . wait ( guard) . unwrap ( ) ;
54
+ let result = guard. 0 ;
48
55
if result {
49
- * guard = false ;
56
+ guard. 0 = false ;
50
57
return
51
58
}
52
59
}
@@ -56,22 +63,21 @@ impl PersistenceNotifier {
56
63
pub ( crate ) fn wait_timeout ( & self , max_wait : Duration ) -> bool {
57
64
let current_time = Instant :: now ( ) ;
58
65
loop {
59
- let & ( ref mtx, ref cvar) = & self . persistence_lock ;
60
- let mut guard = mtx. lock ( ) . unwrap ( ) ;
61
- if * guard {
62
- * guard = false ;
66
+ let mut guard = self . persist_pending . lock ( ) . unwrap ( ) ;
67
+ if guard. 0 {
68
+ guard. 0 = false ;
63
69
return true ;
64
70
}
65
- guard = cvar . wait_timeout ( guard, max_wait) . unwrap ( ) . 0 ;
71
+ guard = self . persistence_condvar . wait_timeout ( guard, max_wait) . unwrap ( ) . 0 ;
66
72
// Due to spurious wakeups that can happen on `wait_timeout`, here we need to check if the
67
73
// desired wait time has actually passed, and if not then restart the loop with a reduced wait
68
74
// time. Note that this logic can be highly simplified through the use of
69
75
// `Condvar::wait_while` and `Condvar::wait_timeout_while`, if and when our MSRV is raised to
70
76
// 1.42.0.
71
77
let elapsed = current_time. elapsed ( ) ;
72
- let result = * guard;
78
+ let result = guard. 0 ;
73
79
if result || elapsed >= max_wait {
74
- * guard = false ;
80
+ guard. 0 = false ;
75
81
return result;
76
82
}
77
83
match max_wait. checked_sub ( elapsed) {
@@ -83,18 +89,112 @@ impl PersistenceNotifier {
83
89
84
90
/// Wake waiters, tracking that persistence needs to occur.
85
91
pub ( crate ) fn notify ( & self ) {
86
- let & ( ref persist_mtx, ref cnd) = & self . persistence_lock ;
87
- let mut persistence_lock = persist_mtx. lock ( ) . unwrap ( ) ;
88
- * persistence_lock = true ;
92
+ let mut persistence_lock = self . persist_pending . lock ( ) . unwrap ( ) ;
93
+ persistence_lock. 0 = true ;
94
+ if let Some ( future_state) = persistence_lock. 1 . take ( ) {
95
+ future_state. lock ( ) . unwrap ( ) . complete ( ) ;
96
+ }
89
97
mem:: drop ( persistence_lock) ;
90
- cnd. notify_all ( ) ;
98
+ self . persistence_condvar . notify_all ( ) ;
99
+ }
100
+
101
+ /// Gets a [`Future`] that will get woken up with any waiters
102
+ pub ( crate ) fn get_future ( & self ) -> Future {
103
+ let mut persistence_lock = self . persist_pending . lock ( ) . unwrap ( ) ;
104
+ if persistence_lock. 0 {
105
+ Future {
106
+ state : Arc :: new ( Mutex :: new ( FutureState {
107
+ callbacks : Vec :: new ( ) ,
108
+ complete : false ,
109
+ } ) )
110
+ }
111
+ } else if let Some ( existing_state) = & persistence_lock. 1 {
112
+ Future { state : Arc :: clone ( & existing_state) }
113
+ } else {
114
+ let state = Arc :: new ( Mutex :: new ( FutureState {
115
+ callbacks : Vec :: new ( ) ,
116
+ complete : false ,
117
+ } ) ) ;
118
+ persistence_lock. 1 = Some ( Arc :: clone ( & state) ) ;
119
+ Future { state }
120
+ }
91
121
}
92
122
93
123
#[ cfg( any( test, feature = "_test_utils" ) ) ]
94
124
pub fn needs_persist ( & self ) -> bool {
95
- let & ( ref mtx, _) = & self . persistence_lock ;
96
- let guard = mtx. lock ( ) . unwrap ( ) ;
97
- * guard
125
+ self . persist_pending . lock ( ) . unwrap ( ) . 0
126
+ }
127
+ }
128
+
129
+ /// A callback which is called when a [`Future`] completes.
130
+ ///
131
+ /// Note that this MUST NOT call back into LDK directly, it must instead schedule actions to be
132
+ /// taken later. Rust users should use the [`std::future::Future`] implementation for [`Future`]
133
+ /// instead.
134
+ ///
135
+ /// Note that the [`std::future::Future`] implementation may only work for runtimes which schedule
136
+ /// futures when they receive a wake, rather than immediately executing them.
137
+ pub trait FutureCallback : Send {
138
+ /// The method which is called.
139
+ fn call ( & self ) ;
140
+ }
141
+
142
+ pub struct FutureState {
143
+ callbacks : Vec < Box < dyn FutureCallback > > ,
144
+ complete : bool ,
145
+ }
146
+
147
+ impl FutureState {
148
+ fn complete ( & mut self ) {
149
+ for callback in self . callbacks . drain ( ..) {
150
+ callback. call ( ) ;
151
+ }
152
+ self . complete = true ;
153
+ }
154
+ }
155
+
156
+ /// A simple future which can complete once, and calls some callback(s) when it does so.
157
+ pub struct Future {
158
+ state : Arc < Mutex < FutureState > > ,
159
+ }
160
+
161
+ impl Future {
162
+ /// Registers a callback to be called upon completion of this future. If the future has already
163
+ /// completed, the callback will be called immediately.
164
+ pub fn register_callback ( & self , callback : Box < dyn FutureCallback > ) {
165
+ let mut state = self . state . lock ( ) . unwrap ( ) ;
166
+ if state. complete {
167
+ mem:: drop ( state) ;
168
+ callback. call ( ) ;
169
+ } else {
170
+ state. callbacks . push ( callback) ;
171
+ }
172
+ }
173
+ }
174
+
175
+ #[ cfg( feature = "std" ) ]
176
+ mod std_future {
177
+ use std:: task:: Waker ;
178
+ pub struct StdWaker ( pub Waker ) ;
179
+ impl super :: FutureCallback for StdWaker {
180
+ fn call ( & self ) { self . 0 . wake_by_ref ( ) }
181
+ }
182
+ }
183
+
184
+ #[ cfg( feature = "std" ) ]
185
+ /// (C-not exported) as Rust Futures aren't usable in language bindings.
186
+ impl < ' a > StdFuture for Future {
187
+ type Output = ( ) ;
188
+
189
+ fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
190
+ let mut state = self . state . lock ( ) . unwrap ( ) ;
191
+ if state. complete {
192
+ Poll :: Ready ( ( ) )
193
+ } else {
194
+ let waker = cx. waker ( ) . clone ( ) ;
195
+ state. callbacks . push ( Box :: new ( std_future:: StdWaker ( waker) ) ) ;
196
+ Poll :: Pending
197
+ }
98
198
}
99
199
}
100
200
@@ -115,10 +215,9 @@ mod tests {
115
215
let exit_thread_clone = exit_thread. clone ( ) ;
116
216
thread:: spawn ( move || {
117
217
loop {
118
- let & ( ref persist_mtx, ref cnd) = & thread_notifier. persistence_lock ;
119
- let mut persistence_lock = persist_mtx. lock ( ) . unwrap ( ) ;
120
- * persistence_lock = true ;
121
- cnd. notify_all ( ) ;
218
+ let mut persistence_lock = thread_notifier. persist_pending . lock ( ) . unwrap ( ) ;
219
+ persistence_lock. 0 = true ;
220
+ thread_notifier. persistence_condvar . notify_all ( ) ;
122
221
123
222
if exit_thread_clone. load ( Ordering :: SeqCst ) {
124
223
break
0 commit comments