@@ -2,68 +2,87 @@ use crate::cbus::{LCPipe, RecvError, SendError};
2
2
use crate :: fiber:: Cond ;
3
3
use std:: cell:: RefCell ;
4
4
use std:: num:: NonZeroUsize ;
5
- use std:: sync;
6
5
use std:: sync:: atomic:: { AtomicBool , Ordering } ;
7
- use std:: sync:: Condvar as StdCondvar ;
8
- use std:: sync :: { Arc , Mutex , Weak } ;
6
+ use std:: sync:: { self , Arc , Mutex , Weak } ;
7
+ use std:: thread ;
9
8
10
9
type CordWaker = crate :: cbus:: unbounded:: Waker ;
11
10
11
+ /// Current thread process handler.
12
+ #[ derive( Clone ) ]
13
+ struct Thread {
14
+ inner : thread:: Thread ,
15
+ flag : Arc < AtomicBool > ,
16
+ }
17
+
18
+ impl Thread {
19
+ fn current ( ) -> Self {
20
+ Self {
21
+ inner : thread:: current ( ) ,
22
+ flag : Arc :: new ( AtomicBool :: new ( true ) ) ,
23
+ }
24
+ }
25
+
26
+ fn park ( & self ) {
27
+ if self
28
+ . flag
29
+ . compare_exchange ( true , false , Ordering :: AcqRel , Ordering :: Acquire )
30
+ . is_ok ( )
31
+ {
32
+ thread:: park ( ) ;
33
+ } ;
34
+ }
35
+
36
+ fn unpark ( & self ) {
37
+ if self
38
+ . flag
39
+ . compare_exchange ( false , true , Ordering :: AcqRel , Ordering :: Acquire )
40
+ . is_ok ( )
41
+ {
42
+ self . inner . unpark ( ) ;
43
+ } ;
44
+ }
45
+ }
46
+
12
47
/// A synchronization component between producers (an OS thread) and a consumer (a cord).
13
48
/// The responsibility of this component is to wake up a producer when it's blocked because
14
49
/// channel internal buffer is full.
15
50
struct ThreadWaker {
16
- lock : Mutex < bool > ,
17
- cond : StdCondvar ,
51
+ /// A queue of threads that are waiting to send data.
52
+ list : crossbeam_queue :: SegQueue < Thread > ,
18
53
}
19
54
20
55
impl ThreadWaker {
21
56
fn new ( ) -> Self {
22
57
Self {
23
- lock : Mutex :: new ( false ) ,
24
- cond : StdCondvar :: new ( ) ,
58
+ list : crossbeam_queue:: SegQueue :: new ( ) ,
25
59
}
26
60
}
27
61
28
62
/// Lock until waker is woken up.
29
63
/// In context of sync-channels, return from this function mean that there's some free
30
64
/// space in message buffer, or receiver is disconnected.
31
65
fn wait ( & self , disconnected : & AtomicBool ) {
32
- let mut started = self
33
- . lock
34
- . lock ( )
35
- . expect ( "unexpected panic in consumer thread" ) ;
36
-
37
66
if disconnected. load ( Ordering :: Acquire ) {
38
67
return ;
39
68
}
40
-
41
- while !* started {
42
- started = self
43
- . cond
44
- . wait ( started)
45
- . expect ( "unexpected panic in consumer thread" ) ;
46
- }
69
+ let t = Thread :: current ( ) ;
70
+ self . list . push ( t. clone ( ) ) ;
71
+ t. park ( ) ;
47
72
}
48
73
49
74
/// Send wakeup signal to a single [`ThreadWaker::wait`] caller.
50
75
fn wakeup_one ( & self ) {
51
- let mut started = self
52
- . lock
53
- . lock ( )
54
- . expect ( "unexpected panic in producer thread" ) ;
55
- * started = true ;
56
- self . cond . notify_one ( ) ;
76
+ if let Some ( thread) = self . list . pop ( ) {
77
+ thread. unpark ( ) ;
78
+ }
57
79
}
58
80
59
81
/// Send wakeup signal to all [`ThreadWaker::wait`] callers.
60
82
fn wakeup_all ( & self ) {
61
- let mut started = self
62
- . lock
63
- . lock ( )
64
- . expect ( "unexpected panic in producer thread" ) ;
65
- * started = true ;
66
- self . cond . notify_all ( ) ;
83
+ while let Some ( thread) = self . list . pop ( ) {
84
+ thread. unpark ( ) ;
85
+ }
67
86
}
68
87
}
69
88
@@ -215,29 +234,21 @@ impl<T> Sender<T> {
215
234
/// * `message`: message to send
216
235
pub fn send ( & self , msg : T ) -> Result < ( ) , SendError < T > > {
217
236
let mut msg = msg;
218
- // We assume that this lock has a minimal impact on performance, in most of situations
219
- // lock of mutex will take the fast path.
220
- let _crit_section = self . arc_guard . lock ( ) . unwrap ( ) ;
221
-
222
- // wake up a sleeping receiver
223
- if let Some ( waker) = self . cord_waker . upgrade ( ) {
224
- loop {
225
- let push_result = self . inner . chan . list . push ( msg) ;
226
- if let Err ( not_accepted_msg) = push_result {
227
- self . thread_waker . wait ( & self . inner . chan . disconnected ) ;
228
- if self . inner . chan . disconnected . load ( Ordering :: Acquire ) {
229
- return Err ( SendError ( not_accepted_msg) ) ;
230
- }
231
- msg = not_accepted_msg;
232
- } else {
233
- break ;
234
- }
237
+ loop {
238
+ if self . inner . chan . disconnected . load ( Ordering :: Acquire ) {
239
+ return Err ( SendError ( msg) ) ;
235
240
}
236
-
237
- waker. wakeup ( & mut self . lcpipe . borrow_mut ( ) ) ;
238
- Ok ( ( ) )
239
- } else {
240
- Err ( SendError ( msg) )
241
+ let crit_section = self . arc_guard . lock ( ) . unwrap ( ) ;
242
+ let Some ( waker) = self . cord_waker . upgrade ( ) else {
243
+ return Err ( SendError ( msg) ) ;
244
+ } ;
245
+ let Err ( not_accepted_msg) = self . inner . chan . list . push ( msg) else {
246
+ waker. wakeup ( & mut self . lcpipe . borrow_mut ( ) ) ;
247
+ return Ok ( ( ) ) ;
248
+ } ;
249
+ msg = not_accepted_msg;
250
+ drop ( crit_section) ;
251
+ self . thread_waker . wait ( & self . inner . chan . disconnected ) ;
241
252
}
242
253
}
243
254
}
@@ -277,6 +288,9 @@ impl<T> EndpointReceiver<T> {
277
288
return Err ( RecvError :: Disconnected ) ;
278
289
}
279
290
291
+ // Need to wake thread so it can push message
292
+ // FIXME: why cord waker waits it's cond for 1ms ?
293
+ self . thread_waker . wakeup_one ( ) ;
280
294
self . cord_waker
281
295
. as_ref ( )
282
296
. expect ( "unreachable: waker must exists" )
0 commit comments