mvdnes / spin-rs

Spin-based synchronization primitives
MIT License
485 stars 92 forks source link

Add pinned variants of methods #126

Closed notgull closed 2 years ago

notgull commented 2 years ago

I've wanted to use this crate in futures programming; however, there's no real way to go from a Pin<&Mutex<T>> to a Pin<MutexGuard<T>>. This requires me to use unsafe code when implemented shared futures, e.g:

#[pin_project]
struct Shared<F>(Arc<Mutex<F>>);

impl<F: Future> Future for Shared<F> {
    type Output = Option<F::Output>;

    fn poll(self: Pin<&mut Self>, ...) {
        let project = self.project();

        // What I want to do:
        match project.0.try_lock_pinned() { /* ... */ }

        // What I am currently doing:
        let mtx = unsafe { Pin::into_inner_unchecked(project.0) };
        let lock = mtx.try_lock().map(|lock| unsafe { Pin::new_unchecked(lock) });
        match lock { /* ... */ }
    }
}

This PR aims to make this code possible by adding methods that allow for locking a pinned Mutex<T> and RwLock<T>. I'm not attached to the names of the methods.

zesterer commented 2 years ago

Hello. I think this PR makes sense, but I'm still a little at a loss as to what the use-case is for Pin<MutexGuard<T>>. What situation requires one over simply using the Deref impl of Pin to go from Pin<&Mutex<T>> to MutexGuard<T>?

notgull commented 2 years ago

The issue is that, if T is !Unpin, then it is impossible to go from a MutexGuard<T> to a Pin<&mut T>. For instance, if I have a Future stored in a Mutex and I've pinned that Mutex, then there is no way to get a pinned inner reference so that I can pill it.

zesterer commented 2 years ago

That makes sense. Do you know whether there's a more traditional way to do this, or is this an 'API hole' in std/lock_api/etc. too?

notgull commented 2 years ago

It's an API hole there as well. I'm working on a PR for the latter (Amanieu/parking_lot#357) and an RFC for the former.

notgull commented 2 years ago

Mmm, I think this actually might be unsound. Closing.

zesterer commented 2 years ago

That's a shame, it would be nice to find a safe way to do something of equivalent capability.

notgull commented 2 years ago

The only thing I can think of is another type that doesn't allow locking through an immutable reference without it being pinned. Maybe a PinMutex type that can only be locked through Pin<&PinMutex> and implements From<Mutex<T>>?