Skip to content

Rollup of 8 pull requests #140378

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Apr 28, 2025
Merged
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8808d5a
std(docs): clarify how std::fs::set_permisions works with symlinks
lolbinarycat Apr 8, 2025
37c4a37
clarify std::fs::set_permissions symlink behavior
lolbinarycat Apr 8, 2025
11f7290
refactor(test): Decouple parsing from help generation
epage Jan 27, 2025
aa8670f
fix(test): Expose '--no-capture', deprecating '--nocapture'
epage Jan 27, 2025
3d29e84
Fix `download-ci-gcc key` in `bootstrap.example.toml`
Kobzol Apr 23, 2025
d4011ae
Download GCC from CI on test builders
Kobzol Apr 23, 2025
59b6cf5
uefi: Update r-efi
Ayush1325 Mar 20, 2025
6f5698c
Avoid re-interning in `LateContext::get_def_path`
DaniPopes Apr 26, 2025
9fed91f
docs: fix incorrect stability markers on `std::{todo, matches}`
notriddle Apr 26, 2025
d40d424
CI: docker: host-x86_64: test-various: uefi_qemu_test: Update r-efi
Ayush1325 Apr 27, 2025
0795b2d
specify explicit safety guidance for from_utf8_unchecked
DiuDiu777 Apr 27, 2025
2ab4034
Add `Arc::is_unique`
SabrinaJewson Mar 25, 2025
009a84f
Rollup merge of #138395 - Kobzol:ci-download-gcc, r=Mark-Simulacrum
ChrisDenton Apr 28, 2025
52b846d
Rollup merge of #138737 - Ayush1325:r-efi-update, r=tgross35
ChrisDenton Apr 28, 2025
55f9326
Rollup merge of #138939 - SabrinaJewson:arc-is-unique, r=tgross35
ChrisDenton Apr 28, 2025
8ee9029
Rollup merge of #139224 - epage:nocapture, r=thomcc
ChrisDenton Apr 28, 2025
c439543
Rollup merge of #139546 - lolbinarycat:std-set_permissions-75942, r=t…
ChrisDenton Apr 28, 2025
5633102
Rollup merge of #140345 - DaniPopes:get-def-path, r=Urgau
ChrisDenton Apr 28, 2025
bd36f25
Rollup merge of #140351 - rust-lang:notriddle/stability-use, r=thomcc
ChrisDenton Apr 28, 2025
0ae362b
Rollup merge of #140359 - DiuDiu777:str-fix, r=Noratrieb
ChrisDenton Apr 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add Arc::is_unique
  • Loading branch information
SabrinaJewson committed Apr 27, 2025
commit 2ab403441f9740cb371cd1d5121daffb88f08a2d
69 changes: 61 additions & 8 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2446,7 +2446,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
#[inline]
#[stable(feature = "arc_unique", since = "1.4.0")]
pub fn get_mut(this: &mut Self) -> Option<&mut T> {
if this.is_unique() {
if Self::is_unique(this) {
// This unsafety is ok because we're guaranteed that the pointer
// returned is the *only* pointer that will ever be returned to T. Our
// reference count is guaranteed to be 1 at this point, and we required
Expand Down Expand Up @@ -2526,28 +2526,81 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
unsafe { &mut (*this.ptr.as_ptr()).data }
}

/// Determine whether this is the unique reference (including weak refs) to
/// the underlying data.
/// Determine whether this is the unique reference to the underlying data.
///
/// Note that this requires locking the weak ref count.
fn is_unique(&mut self) -> bool {
/// Returns `true` if there are no other `Arc` or [`Weak`] pointers to the same allocation;
/// returns `false` otherwise.
///
/// If this function returns `true`, then is guaranteed to be safe to call [`get_mut_unchecked`]
/// on this `Arc`, so long as no clones occur in between.
///
/// # Examples
///
/// ```
/// #![feature(arc_is_unique)]
///
/// use std::sync::Arc;
///
/// let x = Arc::new(3);
/// assert!(Arc::is_unique(&x));
///
/// let y = Arc::clone(&x);
/// assert!(!Arc::is_unique(&x));
/// drop(y);
///
/// // Weak references also count, because they could be upgraded at any time.
/// let z = Arc::downgrade(&x);
/// assert!(!Arc::is_unique(&x));
/// ```
///
/// # Pointer invalidation
///
/// This function will always return the same value as `Arc::get_mut(arc).is_some()`. However,
/// unlike that operation it does not produce any mutable references to the underlying data,
/// meaning no pointers to the data inside the `Arc` are invalidated by the call. Thus, the
/// following code is valid, even though it would be UB if it used `Arc::get_mut`:
///
/// ```
/// #![feature(arc_is_unique)]
///
/// use std::sync::Arc;
///
/// let arc = Arc::new(5);
/// let pointer: *const i32 = &*arc;
/// assert!(Arc::is_unique(&arc));
/// assert_eq!(unsafe { *pointer }, 5);
/// ```
///
/// # Atomic orderings
///
/// Concurrent drops to other `Arc` pointers to the same allocation will synchronize with this
/// call - that is, this call performs an `Acquire` operation on the underlying strong and weak
/// ref counts. This ensures that calling `get_mut_unchecked` is safe.
///
/// Note that this operation requires locking the weak ref count, so concurrent calls to
/// `downgrade` may spin-loop for a short period of time.
///
/// [`get_mut_unchecked`]: Self::get_mut_unchecked
#[inline]
#[unstable(feature = "arc_is_unique", issue = "138938")]
pub fn is_unique(this: &Self) -> bool {
// lock the weak pointer count if we appear to be the sole weak pointer
// holder.
//
// The acquire label here ensures a happens-before relationship with any
// writes to `strong` (in particular in `Weak::upgrade`) prior to decrements
// of the `weak` count (via `Weak::drop`, which uses release). If the upgraded
// weak ref was never dropped, the CAS here will fail so we do not care to synchronize.
if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
if this.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
// This needs to be an `Acquire` to synchronize with the decrement of the `strong`
// counter in `drop` -- the only access that happens when any but the last reference
// is being dropped.
let unique = self.inner().strong.load(Acquire) == 1;
let unique = this.inner().strong.load(Acquire) == 1;

// The release write here synchronizes with a read in `downgrade`,
// effectively preventing the above read of `strong` from happening
// after the write.
self.inner().weak.store(1, Release); // release the lock
this.inner().weak.store(1, Release); // release the lock
unique
} else {
false
Expand Down
Loading