-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Open
Labels
A-tokioArea: The main tokio crateArea: The main tokio crateM-syncModule: tokio/syncModule: tokio/syncT-docsTopic: documentationTopic: documentation
Description
In eclipse-zenoh/zenoh#2409 I have a scenario roughly equivalent to to the following Future implementation:
/// A [`Future`] that polls a single mutex in two branches.
///
/// On the first poll, we poll a [`Mutex::lock_owned`] (i.e. [`Self::lock_fut`]) on the mutex while
/// it is held (see [`main`]). Thus we return [`Poll::Pending`].
///
/// On the second poll we use [`task::block_in_place`] and [`Handle::block_on`] to await
/// [`Mutex::lock`] on the mutex.
///
/// Because [`Self::lock_fut`] is assigned the only available permit by Tokio's semaphore logic, we
/// are unable to acquire the mutex on the second poll.
struct BlockOnSecondPoll {
polled: AtomicBool,
mutex: Arc<Mutex<()>>,
lock_fut: Pin<Box<dyn Future<Output = tokio::sync::OwnedMutexGuard<()>>>>,
}
impl Future for BlockOnSecondPoll {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let was_polled = self.polled.fetch_or(true, atomic::Ordering::SeqCst);
if was_polled {
tracing::info!("will block forever");
let () = *task::block_in_place(|| Handle::current().block_on(self.mutex.lock()));
unreachable!()
} else {
match self.lock_fut.as_mut().poll(cx) {
Poll::Ready(_) => unreachable!(),
Poll::Pending => {
tracing::info!("pending");
Poll::Pending
}
}
}
}
}(see https://github.com/fuzzypixelz/tokio-inaccessible-permit for the full code)
BlockOnSecondPoll reliably deadlocks the process. Tokio's behavior is perfectly correct here. But I believe that the warning section of the block_in_place documentation:
Be aware that although this function avoids starving other independently spawned tasks, any other code running concurrently in the same task will be suspended during the call to block_in_place. This can happen e.g. when using the join! macro. To avoid this issue, use spawn_blocking instead of block_in_place.
Could be a bit more strongly worded ;)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
A-tokioArea: The main tokio crateArea: The main tokio crateM-syncModule: tokio/syncModule: tokio/syncT-docsTopic: documentationTopic: documentation