Skip to content

Commit f201eed

Browse files
committed
std::thread::LocalKeyState: Update compile and run tests
1 parent 4998b23 commit f201eed

File tree

4 files changed

+111
-72
lines changed

4 files changed

+111
-72
lines changed

src/libstd/thread/local.rs

+50-64
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ macro_rules! __thread_local_inner {
192192
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
193193
$crate::thread::__OsLocalKeyInner::new();
194194

195-
unsafe fn __getit() -> &'static Option<$t> { __KEY.get() }
195+
unsafe fn __getit() -> &'static $crate::option::Option<$t> { __KEY.get() }
196196

197197
unsafe fn __get_state() -> $crate::thread::LocalKeyState { __KEY.get_state() }
198198

@@ -504,39 +504,33 @@ pub mod fast {
504504
}
505505
}
506506

507-
pub fn get(&self) -> &'static Option<T> {
508-
unsafe { &*self.inner.get() }
507+
pub unsafe fn get(&self) -> &'static Option<T> {
508+
&*self.inner.get()
509509
}
510510

511-
pub fn get_state(&self) -> LocalKeyState {
512-
unsafe { *self.state.get() }
511+
pub unsafe fn get_state(&self) -> LocalKeyState {
512+
*self.state.get()
513513
}
514514

515-
pub fn pre_init(&self) {
516-
unsafe {
517-
// It's critical that we set the state to Initializing before
518-
// registering destructors - if registering destructors causes
519-
// allocation, and the global allocator uses TLS, then the
520-
// allocator needs to be able to detect that the TLS is in
521-
// the Initializing state and perform appropriate fallback
522-
// logic rather than recursing infinitely.
523-
*self.state.get() = LocalKeyState::Initializing;
524-
self.register_dtor();
525-
}
515+
pub unsafe fn pre_init(&self) {
516+
// It's critical that we set the state to Initializing before
517+
// registering destructors - if registering destructors causes
518+
// allocation, and the global allocator uses TLS, then the
519+
// allocator needs to be able to detect that the TLS is in
520+
// the Initializing state and perform appropriate fallback
521+
// logic rather than recursing infinitely.
522+
*self.state.get() = LocalKeyState::Initializing;
523+
self.register_dtor();
526524
}
527525

528-
pub fn post_init(&self, val: T) {
529-
unsafe {
530-
*self.inner.get() = Some(val);
531-
*self.state.get() = LocalKeyState::Valid;
532-
}
526+
pub unsafe fn post_init(&self, val: T) {
527+
*self.inner.get() = Some(val);
528+
*self.state.get() = LocalKeyState::Valid;
533529
}
534530

535-
pub fn rollback_init(&self) {
536-
unsafe {
537-
*self.inner.get() = None;
538-
*self.state.get() = LocalKeyState::Uninitialized;
539-
}
531+
pub unsafe fn rollback_init(&self) {
532+
*self.inner.get() = None;
533+
*self.state.get() = LocalKeyState::Uninitialized;
540534
}
541535

542536
unsafe fn register_dtor(&self) {
@@ -605,54 +599,46 @@ pub mod os {
605599
}
606600
}
607601

608-
pub fn get(&self) -> &'static Option<T> {
609-
unsafe {
610-
match *self.state.get() {
611-
LocalKeyState::Valid => {
612-
// Since the state is Valid, we know that os points to
613-
// an allocated Value<T>.
614-
let ptr = self.os.get() as *mut Value<T>;
615-
debug_assert!(!ptr.is_null());
616-
&*(*ptr).value.get()
617-
}
618-
_ => {
619-
// The dummy_value is guaranteed to always be None. This
620-
// allows us to avoid allocating if the state isn't Valid.
621-
// This is critical because it means that an allocator can
622-
// call try_with and detect that the key is in state
623-
// Initializing without recursing infinitely.
624-
&*self.dummy_value.get()
625-
}
602+
pub unsafe fn get(&self) -> &'static Option<T> {
603+
match *self.state.get() {
604+
LocalKeyState::Valid => {
605+
// Since the state is Valid, we know that os points to
606+
// an allocated Value<T>.
607+
let ptr = self.os.get() as *mut Value<T>;
608+
debug_assert!(!ptr.is_null());
609+
&*(*ptr).value.get()
610+
}
611+
_ => {
612+
// The dummy_value is guaranteed to always be None. This
613+
// allows us to avoid allocating if the state isn't Valid.
614+
// This is critical because it means that an allocator can
615+
// call try_with and detect that the key is in state
616+
// Initializing without recursing infinitely.
617+
&*self.dummy_value.get()
626618
}
627619
}
628620
}
629621

630-
pub fn get_state(&self) -> LocalKeyState {
631-
unsafe { *self.state.get() }
622+
pub unsafe fn get_state(&self) -> LocalKeyState {
623+
*self.state.get()
632624
}
633625

634-
pub fn pre_init(&self) {
635-
unsafe {
636-
*self.state.get() = LocalKeyState::Initializing;
637-
}
626+
pub unsafe fn pre_init(&self) {
627+
*self.state.get() = LocalKeyState::Initializing;
638628
}
639629

640-
pub fn rollback_init(&self) {
641-
unsafe {
642-
*self.state.get() = LocalKeyState::Uninitialized;
643-
}
630+
pub unsafe fn rollback_init(&self) {
631+
*self.state.get() = LocalKeyState::Uninitialized;
644632
}
645633

646-
pub fn post_init(&self, val: T) {
647-
unsafe {
648-
let ptr: Box<Value<T>> = box Value {
649-
key: &*(self as *const _),
650-
value: UnsafeCell::new(Some(val)),
651-
};
652-
let ptr = Box::into_raw(ptr);
653-
self.os.set(ptr as *mut u8);
654-
*self.state.get() = LocalKeyState::Valid;
655-
}
634+
pub unsafe fn post_init(&self, val: T) {
635+
let ptr: Box<Value<T>> = box Value {
636+
key: &*(self as *const _),
637+
value: UnsafeCell::new(Some(val)),
638+
};
639+
let ptr = Box::into_raw(ptr);
640+
self.os.set(ptr as *mut u8);
641+
*self.state.get() = LocalKeyState::Valid;
656642
}
657643
}
658644

src/test/compile-fail/issue-43733-2.rs

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#[cfg(not(target_thread_local))]
1717
struct Key<T> {
1818
_data: std::cell::UnsafeCell<Option<T>>,
19+
_state: std::cell::UnsafeCell<std::thread::LocalKeyState>,
1920
_flag: std::cell::Cell<bool>,
2021
}
2122

@@ -34,6 +35,7 @@ use std::thread::__FastLocalKeyInner as Key;
3435

3536
static __KEY: Key<()> = Key::new();
3637
//~^ ERROR `std::cell::UnsafeCell<std::option::Option<()>>: std::marker::Sync` is not satisfied
38+
//~| ERROR `std::cell::UnsafeCell<std::thread::LocalKeyState>: std::marker::Sync` is not satisfied
3739
//~| ERROR `std::cell::Cell<bool>: std::marker::Sync` is not satisfied
3840

3941
fn main() {}

src/test/compile-fail/issue-43733.rs

+24-8
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,44 @@
99
// except according to those terms.
1010

1111
#![feature(const_fn, drop_types_in_const)]
12-
#![feature(cfg_target_thread_local, thread_local_internals)]
12+
#![feature(cfg_target_thread_local, thread_local_internals, thread_local_state)]
1313

1414
type Foo = std::cell::RefCell<String>;
1515

16-
#[cfg(target_thread_local)]
1716
static __KEY: std::thread::__FastLocalKeyInner<Foo> =
1817
std::thread::__FastLocalKeyInner::new();
1918

2019
#[cfg(not(target_thread_local))]
2120
static __KEY: std::thread::__OsLocalKeyInner<Foo> =
2221
std::thread::__OsLocalKeyInner::new();
2322

24-
fn __getit() -> std::option::Option<
25-
&'static std::cell::UnsafeCell<
26-
std::option::Option<Foo>>>
27-
{
23+
fn __getit() -> &'static std::option::Option<Foo> {
2824
__KEY.get() //~ ERROR invocation of unsafe method requires unsafe
2925
}
3026

27+
fn __get_state() -> std::thread::LocalKeyState {
28+
__KEY.get_state() //~ ERROR invocation of unsafe method requires unsafe
29+
}
30+
31+
fn __pre_init() {
32+
__KEY.pre_init() //~ ERROR invocation of unsafe method requires unsafe
33+
}
34+
35+
fn __post_init(val: Foo) {
36+
__KEY.post_init(val) //~ ERROR invocation of unsafe method requires unsafe
37+
}
38+
39+
fn __rollback_init() {
40+
__KEY.rollback_init() //~ ERROR invocation of unsafe method requires unsafe
41+
}
42+
3143
static FOO: std::thread::LocalKey<Foo> =
32-
std::thread::LocalKey::new(__getit, Default::default);
33-
//~^ ERROR call to unsafe function requires unsafe
44+
std::thread::LocalKey::new(__getit, //~ ERROR call to unsafe function requires unsafe
45+
__get_state,
46+
__pre_init,
47+
Default::default,
48+
__post_init,
49+
__rollback_init);
3450

3551
fn main() {
3652
FOO.with(|foo| println!("{}", foo.borrow()));

src/test/run-fail/tls-init-on-init.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ignore-emscripten no threads support
12+
13+
// Can't include entire panic message because it'd exceed tidy's 100-character line length limit.
14+
// error-pattern:cannot access a TLS value while it is being initialized or during or after
15+
16+
#![feature(thread_local_state)]
17+
18+
use std::thread::{self, LocalKeyState};
19+
20+
struct Foo;
21+
22+
thread_local!(static FOO: Foo = Foo::init());
23+
24+
impl Foo {
25+
fn init() -> Foo {
26+
FOO.with(|_| {});
27+
Foo
28+
}
29+
}
30+
31+
fn main() {
32+
thread::spawn(|| {
33+
FOO.with(|_| {});
34+
}).join().unwrap();
35+
}

0 commit comments

Comments
 (0)