@@ -5,6 +5,8 @@ use alloc::collections::VecDeque;
5
5
use alloc:: vec:: Vec ;
6
6
7
7
use core:: future:: Future ;
8
+ #[ cfg( debug_assertions) ]
9
+ use core:: sync:: atomic:: { AtomicU8 , Ordering } ;
8
10
use core:: task:: { Poll , Waker } ;
9
11
10
12
/// The maximum queue size we allow before starting to drop events.
@@ -14,37 +16,40 @@ pub(crate) struct EventQueue {
14
16
queue : Arc < Mutex < VecDeque < LiquidityEvent > > > ,
15
17
waker : Arc < Mutex < Option < Waker > > > ,
16
18
#[ cfg( feature = "std" ) ]
17
- condvar : crate :: sync:: Condvar ,
19
+ condvar : Arc < crate :: sync:: Condvar > ,
20
+ #[ cfg( debug_assertions) ]
21
+ num_held_notifier_guards : Arc < AtomicU8 > ,
18
22
}
19
23
20
24
impl EventQueue {
21
25
pub fn new ( ) -> Self {
22
26
let queue = Arc :: new ( Mutex :: new ( VecDeque :: new ( ) ) ) ;
23
27
let waker = Arc :: new ( Mutex :: new ( None ) ) ;
24
- #[ cfg( feature = "std" ) ]
25
- {
26
- let condvar = crate :: sync:: Condvar :: new ( ) ;
27
- Self { queue, waker, condvar }
28
+ Self {
29
+ queue,
30
+ waker,
31
+ #[ cfg( feature = "std" ) ]
32
+ condvar : Arc :: new ( crate :: sync:: Condvar :: new ( ) ) ,
33
+ #[ cfg( debug_assertions) ]
34
+ num_held_notifier_guards : Arc :: new ( AtomicU8 :: new ( 0 ) ) ,
28
35
}
29
- #[ cfg( not( feature = "std" ) ) ]
30
- Self { queue, waker }
31
36
}
32
37
33
38
pub fn enqueue < E : Into < LiquidityEvent > > ( & self , event : E ) {
39
+ #[ cfg( debug_assertions) ]
34
40
{
35
- let mut queue = self . queue . lock ( ) . unwrap ( ) ;
36
- if queue. len ( ) < MAX_EVENT_QUEUE_SIZE {
37
- queue. push_back ( event. into ( ) ) ;
38
- } else {
39
- return ;
40
- }
41
+ let num_held_notifier_guards = self . num_held_notifier_guards . load ( Ordering :: Relaxed ) ;
42
+ debug_assert ! (
43
+ num_held_notifier_guards > 0 ,
44
+ "We should be holding at least one notifier guard whenever enqueuing new events"
45
+ ) ;
41
46
}
42
-
43
- if let Some ( waker) = self . waker . lock ( ) . unwrap ( ) . take ( ) {
44
- waker. wake ( ) ;
47
+ let mut queue = self . queue . lock ( ) . unwrap ( ) ;
48
+ if queue. len ( ) < MAX_EVENT_QUEUE_SIZE {
49
+ queue. push_back ( event. into ( ) ) ;
50
+ } else {
51
+ return ;
45
52
}
46
- #[ cfg( feature = "std" ) ]
47
- self . condvar . notify_one ( ) ;
48
53
}
49
54
50
55
pub fn next_event ( & self ) -> Option < LiquidityEvent > {
@@ -83,6 +88,81 @@ impl EventQueue {
83
88
pub fn get_and_clear_pending_events ( & self ) -> Vec < LiquidityEvent > {
84
89
self . queue . lock ( ) . unwrap ( ) . split_off ( 0 ) . into ( )
85
90
}
91
+
92
+ // Returns an [`EventQueueNotifierGuard`] that will notify about new event when dropped.
93
+ pub fn notifier ( & self ) -> EventQueueNotifierGuard {
94
+ #[ cfg( debug_assertions) ]
95
+ {
96
+ self . num_held_notifier_guards . fetch_add ( 1 , Ordering :: Relaxed ) ;
97
+ }
98
+ EventQueueNotifierGuard {
99
+ queue : Arc :: clone ( & self . queue ) ,
100
+ waker : Arc :: clone ( & self . waker ) ,
101
+ #[ cfg( feature = "std" ) ]
102
+ condvar : Arc :: clone ( & self . condvar ) ,
103
+ #[ cfg( debug_assertions) ]
104
+ num_held_notifier_guards : Arc :: clone ( & self . num_held_notifier_guards ) ,
105
+ }
106
+ }
107
+ }
108
+
109
+ impl Drop for EventQueue {
110
+ fn drop ( & mut self ) {
111
+ #[ cfg( debug_assertions) ]
112
+ {
113
+ let num_held_notifier_guards = self . num_held_notifier_guards . load ( Ordering :: Relaxed ) ;
114
+ debug_assert ! (
115
+ num_held_notifier_guards == 0 ,
116
+ "We should not be holding any notifier guards when the event queue is dropped"
117
+ ) ;
118
+ }
119
+ }
120
+ }
121
+
122
+ // A guard type that will notify about new events when dropped.
123
+ #[ must_use]
124
+ pub ( crate ) struct EventQueueNotifierGuard {
125
+ queue : Arc < Mutex < VecDeque < LiquidityEvent > > > ,
126
+ waker : Arc < Mutex < Option < Waker > > > ,
127
+ #[ cfg( feature = "std" ) ]
128
+ condvar : Arc < crate :: sync:: Condvar > ,
129
+ #[ cfg( debug_assertions) ]
130
+ num_held_notifier_guards : Arc < AtomicU8 > ,
131
+ }
132
+
133
+ impl Drop for EventQueueNotifierGuard {
134
+ fn drop ( & mut self ) {
135
+ let should_notify = !self . queue . lock ( ) . unwrap ( ) . is_empty ( ) ;
136
+
137
+ if should_notify {
138
+ if let Some ( waker) = self . waker . lock ( ) . unwrap ( ) . take ( ) {
139
+ waker. wake ( ) ;
140
+ }
141
+
142
+ #[ cfg( feature = "std" ) ]
143
+ self . condvar . notify_one ( ) ;
144
+ }
145
+
146
+ #[ cfg( debug_assertions) ]
147
+ {
148
+ let res = self . num_held_notifier_guards . fetch_update (
149
+ Ordering :: Relaxed ,
150
+ Ordering :: Relaxed ,
151
+ |x| Some ( x. saturating_sub ( 1 ) ) ,
152
+ ) ;
153
+ match res {
154
+ Ok ( previous_value) if previous_value == 0 => debug_assert ! (
155
+ false ,
156
+ "num_held_notifier_guards counter out-of-sync! This should never happen!"
157
+ ) ,
158
+ Err ( _) => debug_assert ! (
159
+ false ,
160
+ "num_held_notifier_guards counter out-of-sync! This should never happen!"
161
+ ) ,
162
+ _ => { } ,
163
+ }
164
+ }
165
+ }
86
166
}
87
167
88
168
struct EventFuture {
@@ -129,6 +209,7 @@ mod tests {
129
209
} ) ;
130
210
131
211
for _ in 0 ..3 {
212
+ let _guard = event_queue. notifier ( ) ;
132
213
event_queue. enqueue ( expected_event. clone ( ) ) ;
133
214
}
134
215
@@ -154,13 +235,15 @@ mod tests {
154
235
let mut delayed_enqueue = false ;
155
236
156
237
for _ in 0 ..25 {
238
+ let _guard = event_queue. notifier ( ) ;
157
239
event_queue. enqueue ( expected_event. clone ( ) ) ;
158
240
enqueued_events. fetch_add ( 1 , Ordering :: SeqCst ) ;
159
241
}
160
242
161
243
loop {
162
244
tokio:: select! {
163
245
_ = tokio:: time:: sleep( Duration :: from_millis( 10 ) ) , if !delayed_enqueue => {
246
+ let _guard = event_queue. notifier( ) ;
164
247
event_queue. enqueue( expected_event. clone( ) ) ;
165
248
enqueued_events. fetch_add( 1 , Ordering :: SeqCst ) ;
166
249
delayed_enqueue = true ;
@@ -169,6 +252,7 @@ mod tests {
169
252
assert_eq!( e, expected_event) ;
170
253
received_events. fetch_add( 1 , Ordering :: SeqCst ) ;
171
254
255
+ let _guard = event_queue. notifier( ) ;
172
256
event_queue. enqueue( expected_event. clone( ) ) ;
173
257
enqueued_events. fetch_add( 1 , Ordering :: SeqCst ) ;
174
258
}
@@ -201,6 +285,7 @@ mod tests {
201
285
std:: thread:: spawn ( move || {
202
286
// Sleep a bit before we enqueue the events everybody is waiting for.
203
287
std:: thread:: sleep ( Duration :: from_millis ( 20 ) ) ;
288
+ let _guard = thread_queue. notifier ( ) ;
204
289
thread_queue. enqueue ( thread_event. clone ( ) ) ;
205
290
thread_queue. enqueue ( thread_event. clone ( ) ) ;
206
291
} ) ;
0 commit comments