Allow unguarded access to an RwLock's inner value using unsafe · Issue #531 · rust-lang/libs-team (original) (raw)

Proposal

Problem statement

I would like to be able to avoid pointer casts for unguarded accesses of the inner value of an RwLock, similar to RefCells try_borrow_unguarded.

Motivating examples or use cases

I am the maintainer of the readlock crate.

About this crate

At its core, this crate provides a a few types that can act as a replacement for Arc<RwLock<T>> if only a single clone of that Arc is ever used for writing. This is done by introducing two wrapper types around Arc<RwLock<T>>, Shared<T> which can be used for writing but cannot be cloned, and ReadLock<T> which can be obtained from Shared<T> and cloned, but only used for reading. Splitting the capabilities into two types like this reduces the potential for deadlock bugs for code that fits this pattern, and can allow downstream crates to expose a handle to some internally-managed state in a read-only way without introducing custom lock types.

Its type Shared<T> has shared ownership of an RwLock<T>, but guarantees that no other reference to that RwLock ever locks it for writing. It also requires &mut self for write-locking the inner value. Due to this, it can implement Deref<Target = T>.

To implement Deref<Target = T>, I currently call .read() on the inner RwLock, then (unless there's a PoisonError) dereference the RwLockReadGuard and unsafely lifetime-extend the resulting reference using two casts (to raw pointer and back).
If I could instead call an unsafe fn on the RwLock with clear safety requirements that gives me &T directly w/o going through RwLockReadGuard, it would be a lot easier for me to prove my code sound - I am pretty certain the concept is sound (but happy to be proven wrong), but less certain about the current implementation being sound.

Further, and this may deserve to be split into its own ACP, but it seems worth pointing out here: It should also be sound here, and benefit performance, if the new API also allowed un_checked_ access to the inner value, i.e. if it did not require any reads the reader / writer count of the RwLock.

Solution sketch

Honestly, I don't know. I guess a direct equivalent of RefCell::try_borrow_unguarded would be possible and solve my bigger problem around soundness, but it would be really nice to get the performance benefits of unchecked access as well.

Alternatives

As described above, I already have an implementation of the sort of thing this would enable, I'm just not sure whether it's sound. See the readlock crate's source if you want to see the details.