Skip to content

Commit

Permalink
Fix race condition due to incorrect use of Notify
Browse files Browse the repository at this point in the history
madadam committed Aug 14, 2024
1 parent 9c1f5f6 commit bc6facf
Showing 2 changed files with 24 additions and 12 deletions.
30 changes: 19 additions & 11 deletions lib/tests/common/wait_map.rs
Original file line number Diff line number Diff line change
@@ -52,19 +52,27 @@ where
Q: ToOwned<Owned = K> + ?Sized,
{
loop {
let notify = match self.inner.lock().unwrap().entry(key.to_owned()) {
Entry::Occupied(entry) => match entry.get() {
Slot::Occupied(value) => return value.clone(),
Slot::Waiting(notify) => notify.clone(),
},
Entry::Vacant(entry) => {
let notify = Arc::new(Notify::new());
entry.insert(Slot::Waiting(notify.clone()));
notify
}
// We need to call `Notify::notified` while the mutex is still locked but then await it
// only after it's been unlocked. This is so we don't miss any notifications.
let mut notify = None;
let notified = {
let mut inner = self.inner.lock().unwrap();
let new_notify = match inner.entry(key.to_owned()) {
Entry::Occupied(entry) => match entry.get() {
Slot::Occupied(value) => return value.clone(),
Slot::Waiting(notify) => notify.clone(),
},
Entry::Vacant(entry) => {
let notify = Arc::new(Notify::new());
entry.insert(Slot::Waiting(notify.clone()));
notify
}
};

notify.get_or_insert(new_notify).notified()
};

notify.notified().await;
notified.await;
}
}

6 changes: 5 additions & 1 deletion net/src/stun.rs
Original file line number Diff line number Diff line change
@@ -191,6 +191,10 @@ impl<T: DatagramSocket> StunClient<T> {

let result = time::timeout(TIMEOUT, async move {
loop {
// Need to obtain the `notified` future before removing the response but await it
// after. This is so we don't miss any notifications.
let notified = self.responses_notify.notified();

if let Some(response) = self.remove_response(transaction_id) {
return Ok(response);
}
@@ -205,7 +209,7 @@ impl<T: DatagramSocket> StunClient<T> {
self.insert_response(response);
}
},
_ = self.responses_notify.notified() => (),
_ = notified => (),
}
}
})

0 comments on commit bc6facf

Please sign in to comment.