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

std: Rewrite Once with poisoning #32325

Merged
merged 1 commit into from
Mar 27, 2016
Merged

Conversation

alexcrichton
Copy link
Member

This commit rewrites the std::sync::Once primitive with poisoning in mind in
light of #31688. Currently a panic in the initialization closure will cause
future initialization closures to run, but the purpose of a Once is usually to
initialize some global state so it's highly likely that the global state is
corrupt if a panic happened. The same strategy of a mutex is taken where a panic
is propagated by default.

A new API, call_once_force, was added to subvert panics like is available on
Mutex as well (for when panicking is handled internally).

Adding this support was a significant enough change to the implementation that
it was just completely rewritten from scratch, primarily to avoid using a
StaticMutex which needs to have destroy() called on it at some point (a pain
to do).

Closes #31688

@alexcrichton
Copy link
Member Author

r? @aturon

cc @rust-lang/libs

@sfackler
Copy link
Member

Oooh, is this the first use of thread::park?

@alexcrichton
Copy link
Member Author

Nah unfortunately that trophy went to channels long ago :)

/// this function will continue to attempt to call initialization functions
/// until one of them doesn't panic.
///
/// The closure `f` is yielded a boolean indicating whether this `Once` is
Copy link
Member

Choose a reason for hiding this comment

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

Is true "I am poisoned", or "I am valid"?

Copy link
Member Author

Choose a reason for hiding this comment

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

Probably an indicator that this should be an enum or an opaque struct! Currently it means "I'm poisoned"

Copy link
Member

Choose a reason for hiding this comment

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

Agreed.

@Stebalien
Copy link
Contributor

There is actually a use case for panicking in the Once initializer: it's the only way to abort initialization. This could be useful for, e.g., caching result of an expensive RPC call that is expected to succeed but may fail on occasion.

@alexcrichton
Copy link
Member Author

@Stebalien that's an interesting data point! When we discussed this at the libs triage meeting we didn't reach a firm conclusion about whether we were comfortable to move forward with this or not, so it's good to have this data!

// primitive works now!
//
// So to recap, the guarantees of a Once are that it will call the
// initialization closure exactly once, and it will never return until the one
Copy link
Member

Choose a reason for hiding this comment

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

s/exactly/at most/

}

// Run the initialization routine, letting it know if we're
// poisoned or not, and then just return immediately after
Copy link
Member

Choose a reason for hiding this comment

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

Would be helpful for this comment to mention that Finish does the wakeups.

@aturon
Copy link
Member

aturon commented Mar 25, 2016

Beautiful -- this is pretty much exactly what I imagined when we discussed the algorithm the other day.

Just a couple minor nits -- would be good to introduce an enum/struct before landing, rather than having to do that adjustment later. With that, r=me.

mutex: StaticMutex,
cnt: AtomicIsize,
lock_cnt: AtomicIsize,
state: AtomicUsize,
Copy link
Member

Choose a reason for hiding this comment

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

This struct should have some PhantomData describing the kind of data state can point to. (Basically this should be done any time a pointer is hidden in a usize, so that auto traits etc work correctly.)

@alexcrichton alexcrichton added the relnotes Marks issues that should be documented in the release notes of the next release. label Mar 25, 2016
@alexcrichton alexcrichton force-pushed the panic-once branch 2 times, most recently from 316c24e to a755a67 Compare March 25, 2016 23:28
@alexcrichton
Copy link
Member Author

@bors: r=aturon a755a67

Manishearth added a commit to Manishearth/rust that referenced this pull request Mar 26, 2016
std: Rewrite Once with poisoning

This commit rewrites the `std::sync::Once` primitive with poisoning in mind in
light of rust-lang#31688. Currently a panic in the initialization closure will cause
future initialization closures to run, but the purpose of a Once is usually to
initialize some global state so it's highly likely that the global state is
corrupt if a panic happened. The same strategy of a mutex is taken where a panic
is propagated by default.

A new API, `call_once_force`, was added to subvert panics like is available on
Mutex as well (for when panicking is handled internally).

Adding this support was a significant enough change to the implementation that
it was just completely rewritten from scratch, primarily to avoid using a
`StaticMutex` which needs to have `destroy()` called on it at some point (a pain
to do).

Closes rust-lang#31688
bors added a commit that referenced this pull request Mar 26, 2016
@Manishearth
Copy link
Member

@bors r-

<core macros>:2:4: 2:12 error: cannot apply unary operator `!` to type `&sync::once::OnceState`
<core macros>:2 if ! $ cond {
                   ^~~~~~~~
../src/libstd/sync/once.rs:443:13: 443:30 note: in this expansion of assert! (defined in <core macros>)
<core macros>:2:4: 2:12 error: cannot apply unary operator `!` to type `&sync::once::OnceState`
<core macros>:2 if ! $ cond {
                   ^~~~~~~~
../src/libstd/sync/once.rs:466:17: 466:28 note: in this expansion of assert! (defined in <core macros>)
error: aborting due to 2 previous errors
make: *** [x86_64-unknown-linux-gnu/stage2/test/stdtest-x86_64-unknown-linux-gnu] Error 101

http://buildbot.rust-lang.org/builders/auto-linux-64-nopt-t/builds/8503/steps/test/logs/stdio

bors added a commit that referenced this pull request Mar 26, 2016
Rollup of 11 pull requests

- Successful merges: #32131, #32199, #32257, #32325, #32435, #32447, #32448, #32456, #32469, #32476, #32482
- Failed merges: #32240
This commit rewrites the `std::sync::Once` primitive with poisoning in mind in
light of rust-lang#31688. Currently a panic in the initialization closure will cause
future initialization closures to run, but the purpose of a Once is usually to
initialize some global state so it's highly likely that the global state is
corrupt if a panic happened. The same strategy of a mutex is taken where a panic
is propagated by default.

A new API, `call_once_force`, was added to subvert panics like is available on
Mutex as well (for when panicking is handled internally).

Adding this support was a significant enough change to the implementation that
it was just completely rewritten from scratch, primarily to avoid using a
`StaticMutex` which needs to have `destroy()` called on it at some point (a pain
to do).

Closes rust-lang#31688
@alexcrichton
Copy link
Member Author

@bors: r=aturon c966c33

@bors
Copy link
Contributor

bors commented Mar 26, 2016

⌛ Testing commit c966c33 with merge 97ec69f...

bors added a commit that referenced this pull request Mar 26, 2016
std: Rewrite Once with poisoning

This commit rewrites the `std::sync::Once` primitive with poisoning in mind in
light of #31688. Currently a panic in the initialization closure will cause
future initialization closures to run, but the purpose of a Once is usually to
initialize some global state so it's highly likely that the global state is
corrupt if a panic happened. The same strategy of a mutex is taken where a panic
is propagated by default.

A new API, `call_once_force`, was added to subvert panics like is available on
Mutex as well (for when panicking is handled internally).

Adding this support was a significant enough change to the implementation that
it was just completely rewritten from scratch, primarily to avoid using a
`StaticMutex` which needs to have `destroy()` called on it at some point (a pain
to do).

Closes #31688
@bors bors merged commit c966c33 into rust-lang:master Mar 27, 2016
@alexcrichton alexcrichton deleted the panic-once branch March 27, 2016 17:49
@huonw
Copy link
Member

huonw commented Apr 21, 2016

There is actually a use case for panicking in the Once initializer: it's the only way to abort initialization. This could be useful for, e.g., caching result of an expensive RPC call that is expected to succeed but may fail on occasion.

Was this discussed further? (I've unfortunately missed quite a few libs meetings recently.)

It seems like it might be worth providing a separate function something like try_call_once<F: FnOnce() -> Status>(...) enum Status { Succeeded, Retry } that handles this case in a non-hacky way.

@aturon
Copy link
Member

aturon commented Apr 21, 2016

@huonw IIRC, we decided that functionality like this can be easily added in the future if desired.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
relnotes Marks issues that should be documented in the release notes of the next release.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants