Skip to content

Conversation

@00xc
Copy link

@00xc 00xc commented Dec 2, 2025

Implement map_split() for AtomicRef and AtomicRefMut, equivalent to Ref::map_split() and RefMut::map_split() in the standard library. This method allows splitting the reference types into 2 by borrowing different parts of the data protected by the cell.

In order to do this, change the internal implementation so that mutable and immutable borrows are tracked in the higher and lower halves of the internal AtomicUsize respectively. Before, only the highest bit was dedicated to track a mutable borrow, and the rest was dedicated to immutable ones.

NOTE: The changes I introduce here do not alter the performance of the already existing functionality, with one exception: dropping an AtomicRefMut involves a CAS loop, where it used to be a single atomic swap.

The reason for this change is that the atomic operation on drop needs to do 2 things: clear the current mutable borrow and all immutable borrows that failed (since these are left as benign side effects). With a single mutable borrow, this was done by simply setting the variable to zero. With several mutable borrows, the operation needs to decrement by 1 the higher half of the AtomicUsize, and set to zero the lowest half. This can only be done in a single atomic step with a CAS.

00xc added 2 commits December 2, 2025 23:13
Use higher half of AtomicUsize to track mutable borrows, instead of just
the highest bit. This is in preparation to implement map_split() for
AtomicRef and AtomicRefMut, the latter of which will require having more
than one mutable borrow.

Unfortunately, this means that dropping an AtomicBorrowRefMut cannot
unconditionally set the borrow count to zero anymore, as in the future
there may be more than one mutable borrow. We need to drop the reference
count by one, and also clear the lower bits for failed attempts to
acquire an immutable borrow, which can only be done in a single step
with a CAS loop.
Add a new method to split an AtomicRef / AtomicRefMut into two, by
borrowing from distinct parts of the backing data, just like
Ref{,Mut}::map_split() in the standard library.

Unfortunately, the mutable borrow increment during the split must be
peformed with a CAS loop, as we cannot afford to overflow the borrow
count without potentially triggering undefined behavior.

Add as well some basic tests to verify the functionality of the new
methods.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant