1
1
use std:: pin:: Pin ;
2
- use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
3
- use std:: sync:: Arc ;
4
2
use std:: time:: Duration ;
5
3
6
4
use futures_timer:: Delay ;
@@ -61,19 +59,7 @@ impl WaitTimeoutResult {
61
59
/// ```
62
60
#[ derive( Debug ) ]
63
61
pub struct Condvar {
64
- blocked : std:: sync:: Mutex < Slab < WaitEntry > > ,
65
- }
66
-
67
- /// Flag to mark if the task was notified
68
- const NOTIFIED : usize = 1 ;
69
- /// State if the task was notified with `notify_once`
70
- /// so it should notify another task if the future is dropped without waking.
71
- const NOTIFIED_ONCE : usize = 0b11 ;
72
-
73
- #[ derive( Debug ) ]
74
- struct WaitEntry {
75
- state : Arc < AtomicUsize > ,
76
- waker : Option < Waker > ,
62
+ blocked : std:: sync:: Mutex < Slab < Option < Waker > > > ,
77
63
}
78
64
79
65
impl Condvar {
@@ -137,8 +123,8 @@ impl Condvar {
137
123
AwaitNotify {
138
124
cond : self ,
139
125
guard : Some ( guard) ,
140
- state : Arc :: new ( AtomicUsize :: new ( 0 ) ) ,
141
126
key : None ,
127
+ notified : false ,
142
128
}
143
129
}
144
130
@@ -316,11 +302,9 @@ impl Condvar {
316
302
}
317
303
318
304
#[ inline]
319
- fn notify ( mut blocked : std:: sync:: MutexGuard < ' _ , Slab < WaitEntry > > , all : bool ) {
320
- let state = if all { NOTIFIED } else { NOTIFIED_ONCE } ;
305
+ fn notify ( mut blocked : std:: sync:: MutexGuard < ' _ , Slab < Option < Waker > > > , all : bool ) {
321
306
for ( _, entry) in blocked. iter_mut ( ) {
322
- if let Some ( w) = entry. waker . take ( ) {
323
- entry. state . store ( state, Ordering :: Release ) ;
307
+ if let Some ( w) = entry. take ( ) {
324
308
w. wake ( ) ;
325
309
if !all {
326
310
return ;
@@ -332,8 +316,8 @@ fn notify(mut blocked: std::sync::MutexGuard<'_, Slab<WaitEntry>>, all: bool) {
332
316
struct AwaitNotify < ' a , ' b , T > {
333
317
cond : & ' a Condvar ,
334
318
guard : Option < MutexGuard < ' b , T > > ,
335
- state : Arc < AtomicUsize > ,
336
319
key : Option < usize > ,
320
+ notified : bool ,
337
321
}
338
322
339
323
impl < ' a , ' b , T > Future for AwaitNotify < ' a , ' b , T > {
@@ -344,20 +328,14 @@ impl<'a, 'b, T> Future for AwaitNotify<'a, 'b, T> {
344
328
Some ( _) => {
345
329
let mut blocked = self . cond . blocked . lock ( ) . unwrap ( ) ;
346
330
let w = cx. waker ( ) . clone ( ) ;
347
- self . key = Some ( blocked. insert ( WaitEntry {
348
- state : self . state . clone ( ) ,
349
- waker : Some ( w) ,
350
- } ) ) ;
331
+ self . key = Some ( blocked. insert ( Some ( w) ) ) ;
351
332
352
333
// the guard is dropped when we return, which frees the lock
353
334
Poll :: Pending
354
335
}
355
336
None => {
356
- if self . state . fetch_and ( !NOTIFIED , Ordering :: AcqRel ) & NOTIFIED != 0 {
357
- Poll :: Ready ( ( ) )
358
- } else {
359
- Poll :: Pending
360
- }
337
+ self . notified = true ;
338
+ Poll :: Ready ( ( ) )
361
339
}
362
340
}
363
341
}
@@ -367,12 +345,14 @@ impl<'a, 'b, T> Drop for AwaitNotify<'a, 'b, T> {
367
345
fn drop ( & mut self ) {
368
346
if let Some ( key) = self . key {
369
347
let mut blocked = self . cond . blocked . lock ( ) . unwrap ( ) ;
370
- blocked. remove ( key) ;
348
+ let opt_waker = blocked. remove ( key) ;
371
349
372
- if !blocked. is_empty ( ) && self . state . load ( Ordering :: Acquire ) == NOTIFIED_ONCE {
373
- // we got a notification form notify_once but didn't handle it,
374
- // so send it to a different task
350
+ if opt_waker. is_none ( ) && !self . notified {
351
+ // wake up the next task, because this task was notified, but
352
+ // we are dropping it before it can finished.
353
+ // This may result in a spurious wake-up, but that's ok.
375
354
notify ( blocked, false ) ;
355
+
376
356
}
377
357
}
378
358
}
0 commit comments