Skip to content

Commit 4b0e084

Browse files
committed
rollup merge of #20354: alexcrichton/second-pass-thread_local
Conflicts: src/libstd/sys/common/thread_info.rs
2 parents 009ec5d + be11aa6 commit 4b0e084

File tree

3 files changed

+145
-44
lines changed

3 files changed

+145
-44
lines changed

src/libstd/sys/common/thread_info.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010

1111
use core::prelude::*;
1212

13-
use thread::Thread;
1413
use cell::RefCell;
1514
use string::String;
15+
use thread::Thread;
16+
use thread_local::State;
1617

1718
struct ThreadInfo {
1819
// This field holds the known bounds of the stack in (lo, hi)
@@ -27,7 +28,7 @@ thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(N
2728

2829
impl ThreadInfo {
2930
fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R {
30-
if THREAD_INFO.destroyed() {
31+
if THREAD_INFO.state() == State::Destroyed {
3132
panic!("Use of std::thread::Thread::current() is not possible after \
3233
the thread's local data has been destroyed");
3334
}

src/libstd/thread_local/mod.rs

Lines changed: 127 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,23 @@
3535
//! `Cell` or `RefCell` types.
3636
3737
#![macro_escape]
38-
#![experimental]
38+
#![stable]
3939

4040
use prelude::v1::*;
4141

4242
use cell::UnsafeCell;
4343

44-
// Sure wish we had macro hygiene, no?
45-
#[doc(hidden)] pub use self::imp::Key as KeyInner;
46-
#[doc(hidden)] pub use self::imp::destroy_value;
47-
#[doc(hidden)] pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER;
48-
#[doc(hidden)] pub use sys_common::thread_local::StaticKey as OsStaticKey;
49-
5044
pub mod scoped;
5145

46+
// Sure wish we had macro hygiene, no?
47+
#[doc(hidden)]
48+
pub mod __impl {
49+
pub use super::imp::Key as KeyInner;
50+
pub use super::imp::destroy_value;
51+
pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER;
52+
pub use sys_common::thread_local::StaticKey as OsStaticKey;
53+
}
54+
5255
/// A thread local storage key which owns its contents.
5356
///
5457
/// This key uses the fastest possible implementation available to it for the
@@ -90,6 +93,7 @@ pub mod scoped;
9093
/// assert_eq!(*f.borrow(), 2);
9194
/// });
9295
/// ```
96+
#[stable]
9397
pub struct Key<T> {
9498
// The key itself may be tagged with #[thread_local], and this `Key` is
9599
// stored as a `static`, and it's not valid for a static to reference the
@@ -100,7 +104,7 @@ pub struct Key<T> {
100104
// This is trivially devirtualizable by LLVM because we never store anything
101105
// to this field and rustc can declare the `static` as constant as well.
102106
#[doc(hidden)]
103-
pub inner: fn() -> &'static KeyInner<UnsafeCell<Option<T>>>,
107+
pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
104108

105109
// initialization routine to invoke to create a value
106110
#[doc(hidden)]
@@ -109,12 +113,12 @@ pub struct Key<T> {
109113

110114
/// Declare a new thread local storage key of type `std::thread_local::Key`.
111115
#[macro_export]
112-
#[doc(hidden)]
116+
#[stable]
113117
macro_rules! thread_local {
114118
(static $name:ident: $t:ty = $init:expr) => (
115119
static $name: ::std::thread_local::Key<$t> = {
116120
use std::cell::UnsafeCell as __UnsafeCell;
117-
use std::thread_local::KeyInner as __KeyInner;
121+
use std::thread_local::__impl::KeyInner as __KeyInner;
118122
use std::option::Option as __Option;
119123
use std::option::Option::None as __None;
120124

@@ -131,7 +135,7 @@ macro_rules! thread_local {
131135
(pub static $name:ident: $t:ty = $init:expr) => (
132136
pub static $name: ::std::thread_local::Key<$t> = {
133137
use std::cell::UnsafeCell as __UnsafeCell;
134-
use std::thread_local::KeyInner as __KeyInner;
138+
use std::thread_local::__impl::KeyInner as __KeyInner;
135139
use std::option::Option as __Option;
136140
use std::option::Option::None as __None;
137141

@@ -168,46 +172,77 @@ macro_rules! thread_local {
168172
// itself. Woohoo.
169173

170174
#[macro_export]
175+
#[doc(hidden)]
171176
macro_rules! __thread_local_inner {
172177
(static $name:ident: $t:ty = $init:expr) => (
173178
#[cfg_attr(any(target_os = "macos", target_os = "linux"), thread_local)]
174-
static $name: ::std::thread_local::KeyInner<$t> =
179+
static $name: ::std::thread_local::__impl::KeyInner<$t> =
175180
__thread_local_inner!($init, $t);
176181
);
177182
(pub static $name:ident: $t:ty = $init:expr) => (
178183
#[cfg_attr(any(target_os = "macos", target_os = "linux"), thread_local)]
179-
pub static $name: ::std::thread_local::KeyInner<$t> =
184+
pub static $name: ::std::thread_local::__impl::KeyInner<$t> =
180185
__thread_local_inner!($init, $t);
181186
);
182187
($init:expr, $t:ty) => ({
183188
#[cfg(any(target_os = "macos", target_os = "linux"))]
184-
const INIT: ::std::thread_local::KeyInner<$t> = {
185-
::std::thread_local::KeyInner {
189+
const _INIT: ::std::thread_local::__impl::KeyInner<$t> = {
190+
::std::thread_local::__impl::KeyInner {
186191
inner: ::std::cell::UnsafeCell { value: $init },
187192
dtor_registered: ::std::cell::UnsafeCell { value: false },
188193
dtor_running: ::std::cell::UnsafeCell { value: false },
189194
}
190195
};
191196

192197
#[cfg(all(not(any(target_os = "macos", target_os = "linux"))))]
193-
const INIT: ::std::thread_local::KeyInner<$t> = {
198+
const _INIT: ::std::thread_local::__impl::KeyInner<$t> = {
194199
unsafe extern fn __destroy(ptr: *mut u8) {
195-
::std::thread_local::destroy_value::<$t>(ptr);
200+
::std::thread_local::__impl::destroy_value::<$t>(ptr);
196201
}
197202

198-
::std::thread_local::KeyInner {
203+
::std::thread_local::__impl::KeyInner {
199204
inner: ::std::cell::UnsafeCell { value: $init },
200-
os: ::std::thread_local::OsStaticKey {
201-
inner: ::std::thread_local::OS_INIT_INNER,
205+
os: ::std::thread_local::__impl::OsStaticKey {
206+
inner: ::std::thread_local::__impl::OS_INIT_INNER,
202207
dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)),
203208
},
204209
}
205210
};
206211

207-
INIT
212+
_INIT
208213
});
209214
}
210215

216+
/// Indicator of the state of a thread local storage key.
217+
#[unstable = "state querying was recently added"]
218+
#[deriving(Eq, PartialEq, Copy)]
219+
pub enum State {
220+
/// All keys are in this state whenever a thread starts. Keys will
221+
/// transition to the `Valid` state once the first call to `with` happens
222+
/// and the initialization expression succeeds.
223+
///
224+
/// Keys in the `Uninitialized` state will yield a reference to the closure
225+
/// passed to `with` so long as the initialization routine does not panic.
226+
Uninitialized,
227+
228+
/// Once a key has been accessed successfully, it will enter the `Valid`
229+
/// state. Keys in the `Valid` state will remain so until the thread exits,
230+
/// at which point the destructor will be run and the key will enter the
231+
/// `Destroyed` state.
232+
///
233+
/// Keys in the `Valid` state will be guaranteed to yield a reference to the
234+
/// closure passed to `with`.
235+
Valid,
236+
237+
/// When a thread exits, the destructors for keys will be run (if
238+
/// necessary). While a destructor is running, and possibly after a
239+
/// destructor has run, a key is in the `Destroyed` state.
240+
///
241+
/// Keys in the `Destroyed` states will trigger a panic when accessed via
242+
/// `with`.
243+
Destroyed,
244+
}
245+
211246
impl<T: 'static> Key<T> {
212247
/// Acquire a reference to the value in this TLS key.
213248
///
@@ -219,6 +254,7 @@ impl<T: 'static> Key<T> {
219254
/// This function will `panic!()` if the key currently has its
220255
/// destructor running, and it **may** panic if the destructor has
221256
/// previously been run for this thread.
257+
#[stable]
222258
pub fn with<F, R>(&'static self, f: F) -> R
223259
where F: FnOnce(&T) -> R {
224260
let slot = (self.inner)();
@@ -233,17 +269,52 @@ impl<T: 'static> Key<T> {
233269
}
234270

235271
unsafe fn init(&self, slot: &UnsafeCell<Option<T>>) -> &T {
236-
*slot.get() = Some((self.init)());
237-
(*slot.get()).as_ref().unwrap()
272+
// Execute the initialization up front, *then* move it into our slot,
273+
// just in case initialization fails.
274+
let value = (self.init)();
275+
let ptr = slot.get();
276+
*ptr = Some(value);
277+
(*ptr).as_ref().unwrap()
238278
}
239279

240-
/// Test this TLS key to determine whether its value has been destroyed for
241-
/// the current thread or not.
280+
/// Query the current state of this key.
281+
///
282+
/// A key is initially in the `Uninitialized` state whenever a thread
283+
/// starts. It will remain in this state up until the first call to `with`
284+
/// within a thread has run the initialization expression successfully.
285+
///
286+
/// Once the initialization expression succeeds, the key transitions to the
287+
/// `Valid` state which will guarantee that future calls to `with` will
288+
/// succeed within the thread.
289+
///
290+
/// When a thread exits, each key will be destroyed in turn, and as keys are
291+
/// destroyed they will enter the `Destroyed` state just before the
292+
/// destructor starts to run. Keys may remain in the `Destroyed` state after
293+
/// destruction has completed. Keys without destructors (e.g. with types
294+
/// that are `Copy`), may never enter the `Destroyed` state.
242295
///
243-
/// This will not initialize the key if it is not already initialized.
244-
pub fn destroyed(&'static self) -> bool {
245-
unsafe { (self.inner)().get().is_none() }
296+
/// Keys in the `Uninitialized` can be accessed so long as the
297+
/// initialization does not panic. Keys in the `Valid` state are guaranteed
298+
/// to be able to be accessed. Keys in the `Destroyed` state will panic on
299+
/// any call to `with`.
300+
#[unstable = "state querying was recently added"]
301+
pub fn state(&'static self) -> State {
302+
unsafe {
303+
match (self.inner)().get() {
304+
Some(cell) => {
305+
match *cell.get() {
306+
Some(..) => State::Valid,
307+
None => State::Uninitialized,
308+
}
309+
}
310+
None => State::Destroyed,
311+
}
312+
}
246313
}
314+
315+
/// Deprecated
316+
#[deprecated = "function renamed to state() and returns more info"]
317+
pub fn destroyed(&'static self) -> bool { self.state() == State::Destroyed }
247318
}
248319

249320
#[cfg(any(target_os = "macos", target_os = "linux"))]
@@ -457,6 +528,7 @@ mod tests {
457528

458529
use sync::mpsc::{channel, Sender};
459530
use cell::UnsafeCell;
531+
use super::State;
460532
use thread::Thread;
461533

462534
struct Foo(Sender<()>);
@@ -490,6 +562,29 @@ mod tests {
490562
});
491563
}
492564

565+
#[test]
566+
fn states() {
567+
struct Foo;
568+
impl Drop for Foo {
569+
fn drop(&mut self) {
570+
assert!(FOO.state() == State::Destroyed);
571+
}
572+
}
573+
fn foo() -> Foo {
574+
assert!(FOO.state() == State::Uninitialized);
575+
Foo
576+
}
577+
thread_local!(static FOO: Foo = foo());
578+
579+
Thread::spawn(|| {
580+
assert!(FOO.state() == State::Uninitialized);
581+
FOO.with(|_| {
582+
assert!(FOO.state() == State::Valid);
583+
});
584+
assert!(FOO.state() == State::Valid);
585+
}).join().ok().unwrap();
586+
}
587+
493588
#[test]
494589
fn smoke_dtor() {
495590
thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell {
@@ -522,7 +617,7 @@ mod tests {
522617
fn drop(&mut self) {
523618
unsafe {
524619
HITS += 1;
525-
if K2.destroyed() {
620+
if K2.state() == State::Destroyed {
526621
assert_eq!(HITS, 3);
527622
} else {
528623
if HITS == 1 {
@@ -538,7 +633,7 @@ mod tests {
538633
fn drop(&mut self) {
539634
unsafe {
540635
HITS += 1;
541-
assert!(!K1.destroyed());
636+
assert!(K1.state() != State::Destroyed);
542637
assert_eq!(HITS, 2);
543638
K1.with(|s| *s.get() = Some(S1));
544639
}
@@ -559,7 +654,7 @@ mod tests {
559654

560655
impl Drop for S1 {
561656
fn drop(&mut self) {
562-
assert!(K1.destroyed());
657+
assert!(K1.state() == State::Destroyed);
563658
}
564659
}
565660

@@ -582,7 +677,7 @@ mod tests {
582677
fn drop(&mut self) {
583678
let S1(ref tx) = *self;
584679
unsafe {
585-
if !K2.destroyed() {
680+
if K2.state() != State::Destroyed {
586681
K2.with(|s| *s.get() = Some(Foo(tx.clone())));
587682
}
588683
}

src/libstd/thread_local/scoped.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,17 @@
3939
//! ```
4040
4141
#![macro_escape]
42+
#![unstable = "scoped TLS has yet to have wide enough use to fully consider \
43+
stabilizing its interface"]
4244

4345
use prelude::v1::*;
4446

4547
// macro hygiene sure would be nice, wouldn't it?
46-
#[doc(hidden)] pub use self::imp::KeyInner;
47-
#[doc(hidden)] pub use sys_common::thread_local::INIT as OS_INIT;
48+
#[doc(hidden)]
49+
pub mod __impl {
50+
pub use super::imp::KeyInner;
51+
pub use sys_common::thread_local::INIT as OS_INIT;
52+
}
4853

4954
/// Type representing a thread local storage key corresponding to a reference
5055
/// to the type parameter `T`.
@@ -53,7 +58,7 @@ use prelude::v1::*;
5358
/// type `T` scoped to a particular lifetime. Keys provides two methods, `set`
5459
/// and `with`, both of which currently use closures to control the scope of
5560
/// their contents.
56-
pub struct Key<T> { #[doc(hidden)] pub inner: KeyInner<T> }
61+
pub struct Key<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
5762

5863
/// Declare a new scoped thread local storage key.
5964
///
@@ -88,21 +93,21 @@ macro_rules! __scoped_thread_local_inner {
8893
use std::thread_local::scoped::Key as __Key;
8994

9095
#[cfg(not(any(windows, target_os = "android", target_os = "ios")))]
91-
const INIT: __Key<$t> = __Key {
92-
inner: ::std::thread_local::scoped::KeyInner {
96+
const _INIT: __Key<$t> = __Key {
97+
inner: ::std::thread_local::scoped::__impl::KeyInner {
9398
inner: ::std::cell::UnsafeCell { value: 0 as *mut _ },
9499
}
95100
};
96101

97102
#[cfg(any(windows, target_os = "android", target_os = "ios"))]
98-
const INIT: __Key<$t> = __Key {
99-
inner: ::std::thread_local::scoped::KeyInner {
100-
inner: ::std::thread_local::scoped::OS_INIT,
103+
const _INIT: __Key<$t> = __Key {
104+
inner: ::std::thread_local::scoped::__impl::KeyInner {
105+
inner: ::std::thread_local::scoped::__impl::OS_INIT,
101106
marker: ::std::kinds::marker::InvariantType,
102107
}
103108
};
104109

105-
INIT
110+
_INIT
106111
})
107112
}
108113

@@ -139,7 +144,7 @@ impl<T> Key<T> {
139144
F: FnOnce() -> R,
140145
{
141146
struct Reset<'a, T: 'a> {
142-
key: &'a KeyInner<T>,
147+
key: &'a __impl::KeyInner<T>,
143148
val: *mut T,
144149
}
145150
#[unsafe_destructor]

0 commit comments

Comments
 (0)