From 4c70dbfc71e7536acf6dfcacb7fcfbc03aaedce5 Mon Sep 17 00:00:00 2001 From: Janis Date: Sat, 5 Jul 2025 14:21:31 +0200 Subject: [PATCH] Parker: park with callback before waiting --- src/sync.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/sync.rs b/src/sync.rs index b75f4a4..9d23b70 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -214,11 +214,38 @@ impl Parker { } pub fn park(&self) { + self.park_inner(|| ()); + } + + pub fn park_with_callback(&self, before_sleep: F) + where + F: FnOnce(), + { + // This function is called when the thread is about to park. + self.park_inner(before_sleep); + } + + // If the caller wants to park the thread on a mutex'd condition, it is + // possible for a deadlock to occur when the mutex is dropped just before + // this parker atomically changes it's state to `PARKED`. For that reason, + // we use a callback to allow the caller to perform any necessary actions + // before parking, but after the parker is set to `PARKED`. If another + // thread then checks the condition and checks if this thread should be + // woken, we will be immediately notified. + // Thusly, it is important that any caller synchronise any conditionals with + // a mutex externally, and then unlock that mutex in `before_sleep`. + fn park_inner(&self, before_sleep: F) + where + F: FnOnce(), + { if self.mutex.fetch_sub(1, Ordering::Acquire) == Self::NOTIFIED { + before_sleep(); // The thread was notified, so we can return immediately. return; } + before_sleep(); + loop { atomic_wait::wait(&self.mutex, Self::PARKED);