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

Tracking issue for `thread_local_state` stabilization #27716

Closed
aturon opened this Issue Aug 12, 2015 · 18 comments

Comments

Projects
None yet
9 participants
@aturon
Copy link
Member

aturon commented Aug 12, 2015

This feature allows you to query a thread-local variable for its state: http://static.rust-lang.org/doc/master/std/thread/enum.LocalKeyState.html, which will then tell you what may happen if you try to read from the variable.

The functionality is somewhat niche, but occasionally essential. The APIs appear to be in pretty decent shape as-is.

cc @alexcrichton

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 4, 2015

Nominating for stabilization in 1.6.

@aturon aturon added the I-nominated label Nov 4, 2015

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Nov 5, 2015

The libs team decided to not move this into FCP, some worries around this being:

  • Checking the state and then accessing hits TLS twice, which may be too slow for some use cases.
  • This is very similar to RefCell::borrow_state which has also not yet been stabilized. It's likely that the enum here wants to move to boolean accessors so we can add more states in the future.
@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Jan 29, 2016

Although I nominated this for 1.8, libs decided to remove the nomination as I forgot that the reason this is not in FCP yet is because you hit TLS twice when querying the state.

@apasel422

This comment has been minimized.

Copy link
Member

apasel422 commented Aug 17, 2016

I think this would be better expressed like RefCell::try_borrow.

@PlasmaPower

This comment has been minimized.

Copy link
Contributor

PlasmaPower commented Jul 8, 2017

@PlasmaPower

This comment has been minimized.

Copy link
Contributor

PlasmaPower commented Jul 11, 2017

PR for try_with (similar to RefCell::try_borrow) wrapped into this feature: #43158

bors added a commit that referenced this issue Jul 12, 2017

Auto merge of #43158 - PlasmaPower:thread-local-try-with, r=alexcrichton
Thread local try with

rust-lang/rfcs#2030 was turned into this PR (the RFC was closed, but it looks like just a PR should be good).

See also: state stabilization issue: #27716

`try_with` is used in two places in std: stdio and thread_info. In stdio, it would be better if the result was passed to the closure, but in thread_info, it's better as is where the result is returned from the function call. I'm not sure which is better, but I prefer the current way as it better represents the scope.

bors added a commit that referenced this issue Jul 12, 2017

Auto merge of #43158 - PlasmaPower:thread-local-try-with, r=alexcrichton
Thread local try with

rust-lang/rfcs#2030 was turned into this PR (the RFC was closed, but it looks like just a PR should be good).

See also: state stabilization issue: #27716

`try_with` is used in two places in std: stdio and thread_info. In stdio, it would be better if the result was passed to the closure, but in thread_info, it's better as is where the result is returned from the function call. I'm not sure which is better, but I prefer the current way as it better represents the scope.

bors added a commit that referenced this issue Jul 13, 2017

Auto merge of #43158 - PlasmaPower:thread-local-try-with, r=alexcrichton
Thread local try with

rust-lang/rfcs#2030 was turned into this PR (the RFC was closed, but it looks like just a PR should be good).

See also: state stabilization issue: #27716

`try_with` is used in two places in std: stdio and thread_info. In stdio, it would be better if the result was passed to the closure, but in thread_info, it's better as is where the result is returned from the function call. I'm not sure which is better, but I prefer the current way as it better represents the scope.
@stjepang

This comment has been minimized.

Copy link
Contributor

stjepang commented Oct 13, 2017

The documenation for LocalKey::state says:

A key is initially in the Uninitialized state whenever a thread starts. It will remain in this state up until the first call to with within a thread has run the initialization expression successfully. Once the initialization expression succeeds, the key transitions to the Valid state which will guarantee that future calls to with will succeed within the thread.

But then it also mentions:

Keys may remain in the Destroyed state after destruction has completed. Keys without destructors (e.g. with types that are Copy), may never enter the Destroyed state.

Do we really want to make the first guarantee? Is it not reasonable for Copy types to skip the Uninitialized state altogether and start right off in the Valid state?

@joshlf

This comment has been minimized.

Copy link
Contributor

joshlf commented Oct 14, 2017

+1 to that.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Oct 16, 2017

@stjepang sounds reasonable to me!

@stjepang

This comment has been minimized.

Copy link
Contributor

stjepang commented Oct 17, 2017

Checking the state and then accessing hits TLS twice, which may be too slow for some use cases.

This issue should be resolved now that we have LocalKey::try_with.

This is very similar to RefCell::borrow_state which has also not yet been stabilized. It's likely that the enum here wants to move to boolean accessors so we can add more states in the future.

borrow_state was rejected in favor of try_borrow.
Apart from Unitialized, Valid, and Destroyed state, what may the additional states even be? Is this still a concern? If not, are we ready to kick off FCP?

@joshlf

This comment has been minimized.

Copy link
Contributor

joshlf commented Oct 17, 2017

Apart from Unitialized, Valid, and Destroyed state, what may the additional states even be? Is this still a concern?

In #43491, I proposed adding a fourth Initializing state between Uninitialized and Valid. The idea was to allow detection of initialization loops. My particular goal was to support allocators (e.g., elfmalloc relies on crossbeam, which in turn allocates, etc), and I opened PR #43550, but it was eventually closed when we discovered that there was no good way to transition keys into Initializing before performing any allocation on platforms that don't support the #[thread_local] attribute. Instead, I updated the documentation (#44396) to clarify that recursively-dependent initializers are not supported.

kennytm added a commit to kennytm/rust that referenced this issue Oct 18, 2017

Rollup merge of rust-lang#45340 - stjepang:localkey-state-doc-skip-un…
…initialized, r=alexcrichton

Docs: a LocalKey might start in the Valid state

Add a comment to the docs for `LocalKey::state` explaining that some keys might skip the `Uninitialized` state and start in the `Valid` state.

cc rust-lang#27716

r? @alexcrichton
@stjepang

This comment has been minimized.

Copy link
Contributor

stjepang commented Nov 19, 2017

Until we decide what to do with LocalKeyState, could we stabilize the try_with method only?
I don't see any blockers for that.

@Mark-Simulacrum

This comment has been minimized.

Copy link
Member

Mark-Simulacrum commented Jan 15, 2018

Nominating. I propose that we stabilize the LocalKey::try_with method and deprecate the LocalKey::state method and associated enum. I don't see a good usecase for the enum given this method.

cc @rust-lang/libs

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Jan 23, 2018

I agree with @Mark-Simulacrum's assessment and would be ok stabilizing try_with!

@rfcbot fcp merge

@rfcbot

This comment has been minimized.

Copy link

rfcbot commented Jan 23, 2018

Team member @alexcrichton has proposed to merge this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot

This comment has been minimized.

Copy link

rfcbot commented Feb 14, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot

This comment has been minimized.

Copy link

rfcbot commented Feb 24, 2018

The final comment period is now complete.

Manishearth added a commit to Manishearth/rust that referenced this issue Mar 1, 2018

Rollup merge of rust-lang#48585 - stjepang:stabilize-localkey-try_wit…
…h, r=alexcrichton

Stabilize LocalKey::try_with

The `LocalKey::try_with` method is now stabilized.

`LocalKey::state` and `LocalKeyState` marked as deprecated. Although, is there any reason to keep them - should we perhaps remove them completely?

Closes rust-lang#27716

r? @alexcrichton

Manishearth added a commit to Manishearth/rust that referenced this issue Mar 1, 2018

Rollup merge of rust-lang#48585 - stjepang:stabilize-localkey-try_wit…
…h, r=alexcrichton

Stabilize LocalKey::try_with

The `LocalKey::try_with` method is now stabilized.

`LocalKey::state` and `LocalKeyState` marked as deprecated. Although, is there any reason to keep them - should we perhaps remove them completely?

Closes rust-lang#27716

r? @alexcrichton

@bors bors closed this in #48585 Mar 2, 2018

@stjepang

This comment has been minimized.

Copy link
Contributor

stjepang commented Sep 11, 2018

I regret stabilizing LocalKey::try_with with the current signature. :(

So the signature of LocalKey::try_with is:

pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
where
    F: FnOnce(&T) -> R;

We should've gone with the following instead:

pub fn try_with<F, R>(&'static self, f: F) -> R
where
    F: FnOnce(Result<&T, AccessError>) -> R;

Why? I have a situation with this helper function:

pub fn with_context<F, R>(f: F) -> R
where
    F: FnOnce(&Arc<Context>) -> R,
{
    CONTEXT.try_with(|cx| f(cx)).unwrap_or_else(|_| f(&Context::new()))
}

Unfortunately, the helper function doesn't compile:

error[E0382]: capture of moved value: `f`
   --> src/internal/context.rs:162:53
    |
162 |     CONTEXT.try_with(|cx| f(cx)).unwrap_or_else(|_| f(&Context::new()))
    |                      ----                           ^ value captured here after move
    |                      |
    |                      value moved (into closure) here
    |
    = note: move occurs because `f` has type `F`, which does not implement the `Copy` trait

So F has to be FnMut or additionally Copy, which is annoying.

Had we gone with the other signature for LocalKey::with, this would be easy to do:

pub fn with_context<F, R>(f: F) -> R
where
    F: FnOnce(&Arc<Context>) -> R,
{
    CONTEXT.try_with(|cx| {
        match cx {
            Ok(cx) => f(cx),
            Err(..) => f(&Context::new()),
        }
    })
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.