Arc locking#88112
Conversation
|
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Mark-Simulacrum (or someone else) soon. Please see the contribution instructions for more information. |
This comment has been minimized.
This comment has been minimized.
|
This does not interact correctly with |
This comment has been minimized.
This comment has been minimized.
|
@Aaron1011 This does interact correctly with |
|
It does not. rust/library/alloc/src/sync.rs Lines 1572 to 1574 in aa8f27b A 'locked' |
|
@Aaron1011 And, as it turns out, that's safe. Read the PR description again. |
|
I didn't say anything about this being unsafe - using this API can cause a memory leak, which is not documented anywhere. |
|
Ahh. So we should have something like "Note that failing to unlock the |
| // Check if we're locked. Relaxed is fine here because if this branch | ||
| // is taken, we're the only possible strong reference. | ||
| if self.inner().strong.load(Relaxed) == 0 { | ||
| panic!("Not allowed to clone a locked Arc"); | ||
| } |
There was a problem hiding this comment.
This doesn't need to be here since there's no way you can access an Arc while it is locked:
- the
Arcyou locked is mutably borrowed - there was no other
Arcbecauselock_strong_countrequired the strong count to be 1, meaning theArcthat locked it was the only one Weaks can't be upgrade in the meantime because the strong count being 0 will make them fail
@Aaron1011 for this same reason Drop is still sound, because it will never run while an Arc is locked
There was a problem hiding this comment.
We don't return a guard. We return a bool.
There was a problem hiding this comment.
Oh, I didn't see the methods were public. I was expecting them to be encapsulated in a public API like the one shown in the first post.
If this is the case then Drop is indeed leaky
There was a problem hiding this comment.
The guards aren't necessarily useful, since you still can't do anything with the guard (safely) you couldn't already do with the Arc (due to variance). However, these primitives would be useful to writing higher level guard types that, through a wrapper such as Static (or with a T: 'static bound) could provide safe, statically checked, mutable access to an Arc.
There was a problem hiding this comment.
The guards aren't necessarily useful, since you still can't do anything with the guard (safely) you couldn't already do with the Arc (due to variance).
The fundamental idea behind this being able to provide an API akin to Arc::get_mut but that doesn't fail when Weaks still exists, instead temporarely prevents them from up upgrading. This is not possible with the current Arc.
There was a problem hiding this comment.
This check must be here no matter what, because, assuming a hypothetical borrow_mut that returns a guard, without this, you could cause UB in safe code by leaking the guard.
(Granted, the with_mut variant doesn't have this issue.)
|
Anyway how do you benchmark changes to alloc/Arc...? |
|
Currently there don't seem to be any benchmarks for Arc. You can write new ones and add them under |
|
I am not personally convinced these merit being in std; there's a whole host of things you could do with the counters in an Arc, but if we're to start exposing functions like this I'm not convinced it's better than giving unsafe access to the counters directly (e.g., by exposing ArcInner). r? @m-ou-se for T-libs-api consideration (potentially to say 'no') |
|
(turned out |
These are low-level primitives, which means this doesn't do anything on its own, but may enable third-party crates to provide safe wrappers around
get_mut_unchecked. For example:Another possible wrapper would be:this one is unsound, see https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=a70acf048225b351d6620c226661e8d3 (found by @SkiFire13 )These can be compared to
new_cyclicand are arguably just an extension of existingget_mutsemantics. In particular, they allow safely mutating an owningArcwhile there areWeaks around, by preventing them from beingupgraded. Note that this condition alone is necessary, but not sufficient:Arcis covariant by default, so these wrappers are in fact necessary, because the following example would blow up otherwise:This is trivially a compile-time error when using
Arc<Static<T>>orArc<Invariant<T>>.Anyway, mostly throwing this here to hopefully get a perf run on it more than anything. This adds an extra atomic load on clone.
Also note that dropping a locked
Arcwould lead to an abort when upgrading a Weak, or a leak otherwise, andmake_mutwould also make it leak. These are all safe so there's no reason to make locking/unlocking unsafe.get_mutalso fails, by design.strong_countwill return 0 on lockedArcs and the documentation should be updated to reflect that, or otherwise massaged, if this feature is decided to be added. (We'd prefer it to return 0, similar to howWeak::strong_countreturns 0 whenArc::new_cyclicis used.)