Skip to content
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

Stabilize weak pointers on Rc and Arc, as well as the meaty uniqueness methods #27760

Closed
wants to merge 4 commits into from

Conversation

Gankra
Copy link
Contributor

@Gankra Gankra commented Aug 12, 2015

The community has spoken: weak pointers are highly desirable!

Also Rc and Arc are kinda busted for recursive datastructures without these uniqueness methods!

The "read only" uniqueness introspection is punted on as neither critical nor obviously super useful (particularly for Arc, where such methods are inherently racy). Though they are harmless from a maintenance perspective.

Note that make_unique has been renamed to make_mut for symmery with get_mut.

This addresses the bulk of #27718

r? @aturon on the implementation of Arc::try_unwrap which I had to add since it was accidentally omitted in the past. Largely just derived from drop on the assumption that try_unwrap is "basically" just Drop.

@Gankra Gankra added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Aug 12, 2015
@Gankra
Copy link
Contributor Author

Gankra commented Aug 12, 2015

One thing that's a bit questionable: downgrade as a method. However since clone is also a method it basically makes sense.

@Diggsey
Copy link
Contributor

Diggsey commented Aug 12, 2015

try_unwrap seems broken: you're decrementing the strong count and then returning Err(self). I don't know if it's possible to fix: even if you increment it again before returning, there's a race condition because in that time another Arc could have been dropped and the data freed.

Isn't the reason this method was omitted, the fact that it cannot be implemented safely?

@Gankra
Copy link
Contributor Author

Gankra commented Aug 12, 2015

@Diggsey Aha, good point! (I wasn't thinking about it too much, just did a quick hackjob)

@Gankra Gankra force-pushed the weaknique branch 2 times, most recently from 8acbe27 to 58a51dd Compare August 12, 2015 22:33
@Diggsey
Copy link
Contributor

Diggsey commented Aug 12, 2015

Oh, another minor issue that was present even before, and probably applies to Rc too: it's still possible to overflow both refcounts. The strong refcount can be overflowed by repeatedly cloning a Weak, and then upgrading it, forgetting the Arc it returns. The weak refcount can be overflowed by repeatedly downgrading and Arc and forgetting the Weak it returns. The fix should be straightforward.

@Gankra Gankra force-pushed the weaknique branch 2 times, most recently from 5cb8da8 to ecec02e Compare August 12, 2015 22:43
@Gankra
Copy link
Contributor Author

Gankra commented Aug 12, 2015

Rc is protected because everything correctly calls inc_strong and inc_weak -- but Arc is more adhoc and definitely still has holes as you describe.

@Gankra
Copy link
Contributor Author

Gankra commented Aug 12, 2015

I think those holes should be addressed in another PR, though -- its quite orthogonal.

@eefriedman
Copy link
Contributor

It's definitely possible to implement try_unwrap correctly... if self.inner().strong.compare_and_swap(1, 0, Acquire) != 1 { return self } etc. Not sure about instantly stabilizing it, though.

@Gankra
Copy link
Contributor Author

Gankra commented Aug 12, 2015

@eefriedman Ah yes, that seems like the right code (weak is prevented from racily bypassing this via its CAS loop in upgrade).

impl fixed.

I think it should be stabilized with the rest of these methods -- there's no fundamental reason to keep it separately unstable.

#[stable(feature = "rc_unique", since="1.4.0")]
pub fn try_unwrap(self) -> Result<T, Arc<T>> {
// See `drop` for impl details
self.inner().strong.compare_and_swap(1, 0, Acquire) != 1 { return Err(self) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing "if"?

Also, the atomic::fence call is redundant... or did you mean to use a Relaxed compare_and_swap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eefriedman I was mimicking drop -- but now I'm not sure the Acquire is right for this CAS. iirc it's Release in drop because of some specific clause in the C11 memory model. I'm just going to punt on getting this right until @aturon chimes in.

@Gankra Gankra force-pushed the weaknique branch 2 times, most recently from 0db83d4 to 354be75 Compare August 13, 2015 01:44
#[stable(feature = "rc_unique", since="1.4.0")]
pub fn try_unwrap(self) -> Result<T, Arc<T>> {
// See `drop` for impl details
if self.inner().strong.compare_and_swap(1, 0, Acquire) != 1 { return Err(self) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To match drop, shouldn't this be Release?

Also, can you expand on the "magic" comment below? This code is super tricky already and I'd hate to make it more difficult to understand...

@SimonSapin
Copy link
Contributor

This fixes #24789. (The PR message should include that so that it's auto-closed.)

@alexcrichton
Copy link
Member

Also #27718 now that you mention it!

@SimonSapin
Copy link
Contributor

Although this is a big step for #27718, I don’t think it should completely close it as there are unstable items left. I think stabilization tracking issues should only be closed when all relevant items are either stabilized or deprecated.

@bors
Copy link
Contributor

bors commented Aug 14, 2015

☔ The latest upstream changes (presumably #27684) made this pull request unmergeable. Please resolve the merge conflicts.

/// ```
#[inline]
#[stable(feature = "rc_unique", since="1.4.0")]
pub fn try_unwrap(self) -> Result<T, Arc<T>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not take self, yes?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should. When this is the only strong reference T is moved out of Arc<T> so this needs to take ownership of the reference. (Err(Arc<T>) is given "back" untouched if there are other strong references.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant that it should have the signature pub fn try_unwrap(this: Arc<T>) -> Result<T, Arc<T>> rather than pub fn try_unwrap(self) -> Result<T, Arc<T>>.

@Gankra
Copy link
Contributor Author

Gankra commented Aug 14, 2015

Closing pending rework for FCP. Will post new PR soon.

@Gankra Gankra closed this Aug 14, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants