sync: preserve permit state in notify_waiters (#3660)

This commit is contained in:
Simon Lindholm 2021-05-05 15:20:24 +02:00 committed by GitHub
parent 8ef39dfb22
commit 6845a93cbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 7 deletions

View File

@ -192,6 +192,10 @@ fn inc_num_notify_waiters_calls(data: usize) -> usize {
data + (1 << NOTIFY_WAITERS_SHIFT)
}
fn atomic_inc_num_notify_waiters_calls(data: &AtomicUsize) {
data.fetch_add(1 << NOTIFY_WAITERS_SHIFT, SeqCst);
}
impl Notify {
/// Create a new `Notify`, initialized without a permit.
///
@ -394,11 +398,9 @@ impl Notify {
let curr = self.state.load(SeqCst);
if let EMPTY | NOTIFIED = get_state(curr) {
// There are no waiting tasks. In this case, no synchronization is
// established between `notify` and `notified().await`.
// All we need to do is increment the number of times this
// method was called.
self.state.store(inc_num_notify_waiters_calls(curr), SeqCst);
// There are no waiting tasks. All we need to do is increment the
// number of times this method was called.
atomic_inc_num_notify_waiters_calls(&self.state);
return;
}

View File

@ -33,12 +33,41 @@ fn notify_waiters() {
tx.notify_waiters();
});
th.join().unwrap();
block_on(async {
notified1.await;
notified2.await;
});
th.join().unwrap();
});
}
#[test]
fn notify_waiters_and_one() {
loom::model(|| {
let notify = Arc::new(Notify::new());
let tx1 = notify.clone();
let tx2 = notify.clone();
let th1 = thread::spawn(move || {
tx1.notify_waiters();
});
let th2 = thread::spawn(move || {
tx2.notify_one();
});
let th3 = thread::spawn(move || {
let notified = notify.notified();
block_on(async {
notified.await;
});
});
th1.join().unwrap();
th2.join().unwrap();
th3.join().unwrap();
});
}