Skip to content

Commit 35ebf03

Browse files
committed
auto merge of #10312 : thestinger/rust/thread_local, r=alexcritchton
This provides a building block for fast thread-local storage. It does not change the safety semantics of `static mut`. Closes #10310
2 parents e9a1869 + a5af479 commit 35ebf03

File tree

7 files changed

+132
-7
lines changed

7 files changed

+132
-7
lines changed

doc/rust.md

+2
Original file line numberDiff line numberDiff line change
@@ -1754,6 +1754,8 @@ names are effectively reserved. Some significant attributes include:
17541754
* The `deriving` attribute, for automatically generating
17551755
implementations of certain traits.
17561756
* The `static_assert` attribute, for asserting that a static bool is true at compiletime
1757+
* The `thread_local` attribute, for defining a `static mut` as a thread-local. Note that this is
1758+
only a low-level building block, and is not local to a *task*, nor does it provide safety.
17571759

17581760
Other attributes may be added or removed during development of the language.
17591761

src/librustc/front/feature_gate.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
3838
("asm", Active),
3939
("managed_boxes", Active),
4040
("non_ascii_idents", Active),
41+
("thread_local", Active),
4142

4243
// These are used to test this portion of the compiler, they don't actually
4344
// mean anything
@@ -107,6 +108,17 @@ impl Visitor<()> for Context {
107108
}
108109

109110
fn visit_item(&mut self, i: @ast::item, _:()) {
111+
// NOTE: uncomment after snapshot
112+
/*
113+
for attr in i.attrs.iter() {
114+
if "thread_local" == attr.name() {
115+
self.gate_feature("thread_local", i.span,
116+
"`#[thread_local]` is an experimental feature, and does not \
117+
currently handle destructors. There is no corresponding \
118+
`#[task_local]` mapping to the task model");
119+
}
120+
}
121+
*/
110122
match i.node {
111123
ast::item_enum(ref def, _) => {
112124
for variant in def.variants.iter() {
@@ -152,8 +164,8 @@ impl Visitor<()> for Context {
152164
},
153165
ast::ty_box(_) => {
154166
self.gate_feature("managed_boxes", t.span,
155-
"The managed box syntax is being replaced by the `std::gc::Gc`
156-
and `std::rc::Rc` types. Equivalent functionality to managed
167+
"The managed box syntax is being replaced by the `std::gc::Gc` \
168+
and `std::rc::Rc` types. Equivalent functionality to managed \
157169
trait objects will be implemented but is currently missing.");
158170
}
159171
_ => {}

src/librustc/lib/llvm.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1749,6 +1749,12 @@ pub fn SetUnnamedAddr(Global: ValueRef, Unnamed: bool) {
17491749
}
17501750
}
17511751

1752+
pub fn set_thread_local(global: ValueRef, is_thread_local: bool) {
1753+
unsafe {
1754+
llvm::LLVMSetThreadLocal(global, is_thread_local as Bool);
1755+
}
1756+
}
1757+
17521758
pub fn ConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef {
17531759
unsafe {
17541760
llvm::LLVMConstICmp(Pred as c_ushort, V1, V2)

src/librustc/middle/lint.rs

+1
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,7 @@ static obsolete_attrs: &'static [(&'static str, &'static str)] = &[
816816
static other_attrs: &'static [&'static str] = &[
817817
// item-level
818818
"address_insignificant", // can be crate-level too
819+
"thread_local", // for statics
819820
"allow", "deny", "forbid", "warn", // lint options
820821
"deprecated", "experimental", "unstable", "stable", "locked", "frozen", //item stability
821822
"crate_map", "cfg", "doc", "export_name", "link_section", "no_freeze",

src/librustc/middle/trans/base.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2544,6 +2544,10 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
25442544
inlineable = true;
25452545
}
25462546

2547+
if attr::contains_name(i.attrs, "thread_local") {
2548+
lib::llvm::set_thread_local(g, true);
2549+
}
2550+
25472551
if !inlineable {
25482552
debug!("{} not inlined", sym);
25492553
ccx.non_inlineable_statics.insert(id);

src/libstd/rt/local_ptr.rs

+101-5
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,35 @@
1717
1818
use libc::c_void;
1919
use cast;
20+
#[cfg(stage0)]
21+
#[cfg(windows)]
2022
use ptr;
2123
use cell::Cell;
2224
use option::{Option, Some, None};
2325
use unstable::finally::Finally;
26+
#[cfg(stage0)]
27+
#[cfg(windows)]
2428
use unstable::mutex::{Mutex, MUTEX_INIT};
29+
#[cfg(stage0)]
30+
#[cfg(windows)]
2531
use tls = rt::thread_local_storage;
2632

33+
#[cfg(not(stage0), not(windows), test)]
34+
#[thread_local]
35+
pub use realstd::rt::shouldnt_be_public::RT_TLS_PTR;
36+
37+
#[cfg(not(stage0), not(windows), not(test))]
38+
#[thread_local]
39+
pub static mut RT_TLS_PTR: *mut c_void = 0 as *mut c_void;
40+
41+
#[cfg(stage0)]
42+
#[cfg(windows)]
2743
static mut RT_TLS_KEY: tls::Key = -1;
2844

2945
/// Initialize the TLS key. Other ops will fail if this isn't executed first.
46+
#[inline(never)]
47+
#[cfg(stage0)]
48+
#[cfg(windows)]
3049
pub fn init_tls_key() {
3150
static mut lock: Mutex = MUTEX_INIT;
3251
static mut initialized: bool = false;
@@ -41,24 +60,42 @@ pub fn init_tls_key() {
4160
}
4261
}
4362

63+
#[cfg(not(stage0), not(windows))]
64+
pub fn init_tls_key() {}
65+
4466
/// Give a pointer to thread-local storage.
4567
///
4668
/// # Safety note
4769
///
4870
/// Does not validate the pointer type.
4971
#[inline]
72+
#[cfg(stage0)]
73+
#[cfg(windows)]
5074
pub unsafe fn put<T>(sched: ~T) {
5175
let key = tls_key();
5276
let void_ptr: *mut c_void = cast::transmute(sched);
5377
tls::set(key, void_ptr);
5478
}
5579

80+
/// Give a pointer to thread-local storage.
81+
///
82+
/// # Safety note
83+
///
84+
/// Does not validate the pointer type.
85+
#[inline]
86+
#[cfg(not(stage0), not(windows))]
87+
pub unsafe fn put<T>(sched: ~T) {
88+
RT_TLS_PTR = cast::transmute(sched)
89+
}
90+
5691
/// Take ownership of a pointer from thread-local storage.
5792
///
5893
/// # Safety note
5994
///
6095
/// Does not validate the pointer type.
6196
#[inline]
97+
#[cfg(stage0)]
98+
#[cfg(windows)]
6299
pub unsafe fn take<T>() -> ~T {
63100
let key = tls_key();
64101
let void_ptr: *mut c_void = tls::get(key);
@@ -70,13 +107,28 @@ pub unsafe fn take<T>() -> ~T {
70107
return ptr;
71108
}
72109

110+
/// Take ownership of a pointer from thread-local storage.
111+
///
112+
/// # Safety note
113+
///
114+
/// Does not validate the pointer type.
115+
#[inline]
116+
#[cfg(not(stage0), not(windows))]
117+
pub unsafe fn take<T>() -> ~T {
118+
let ptr: ~T = cast::transmute(RT_TLS_PTR);
119+
RT_TLS_PTR = cast::transmute(0); // can't use `as`, due to type not matching with `cfg(test)`
120+
ptr
121+
}
122+
73123
/// Take ownership of a pointer from thread-local storage.
74124
///
75125
/// # Safety note
76126
///
77127
/// Does not validate the pointer type.
78128
/// Leaves the old pointer in TLS for speed.
79129
#[inline]
130+
#[cfg(stage0)]
131+
#[cfg(windows)]
80132
pub unsafe fn unsafe_take<T>() -> ~T {
81133
let key = tls_key();
82134
let void_ptr: *mut c_void = tls::get(key);
@@ -87,7 +139,21 @@ pub unsafe fn unsafe_take<T>() -> ~T {
87139
return ptr;
88140
}
89141

142+
/// Take ownership of a pointer from thread-local storage.
143+
///
144+
/// # Safety note
145+
///
146+
/// Does not validate the pointer type.
147+
/// Leaves the old pointer in TLS for speed.
148+
#[inline]
149+
#[cfg(not(stage0), not(windows))]
150+
pub unsafe fn unsafe_take<T>() -> ~T {
151+
cast::transmute(RT_TLS_PTR)
152+
}
153+
90154
/// Check whether there is a thread-local pointer installed.
155+
#[cfg(stage0)]
156+
#[cfg(windows)]
91157
pub fn exists() -> bool {
92158
unsafe {
93159
match maybe_tls_key() {
@@ -97,6 +163,14 @@ pub fn exists() -> bool {
97163
}
98164
}
99165

166+
/// Check whether there is a thread-local pointer installed.
167+
#[cfg(not(stage0), not(windows))]
168+
pub fn exists() -> bool {
169+
unsafe {
170+
RT_TLS_PTR.is_not_null()
171+
}
172+
}
173+
100174
/// Borrow the thread-local value from thread-local storage.
101175
/// While the value is borrowed it is not available in TLS.
102176
///
@@ -119,6 +193,8 @@ pub unsafe fn borrow<T>(f: |&mut T|) {
119193
///
120194
/// Because this leaves the value in thread-local storage it is possible
121195
/// For the Scheduler pointer to be aliased
196+
#[cfg(stage0)]
197+
#[cfg(windows)]
122198
pub unsafe fn unsafe_borrow<T>() -> *mut T {
123199
let key = tls_key();
124200
let void_ptr = tls::get(key);
@@ -128,6 +204,16 @@ pub unsafe fn unsafe_borrow<T>() -> *mut T {
128204
void_ptr as *mut T
129205
}
130206

207+
#[cfg(not(stage0), not(windows))]
208+
pub unsafe fn unsafe_borrow<T>() -> *mut T {
209+
if RT_TLS_PTR.is_null() {
210+
rtabort!("thread-local pointer is null. bogus!");
211+
}
212+
RT_TLS_PTR as *mut T
213+
}
214+
215+
#[cfg(stage0)]
216+
#[cfg(windows)]
131217
pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
132218
match maybe_tls_key() {
133219
Some(key) => {
@@ -142,7 +228,18 @@ pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
142228
}
143229
}
144230

231+
#[cfg(not(stage0), not(windows))]
232+
pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
233+
if RT_TLS_PTR.is_null() {
234+
None
235+
} else {
236+
Some(RT_TLS_PTR as *mut T)
237+
}
238+
}
239+
145240
#[inline]
241+
#[cfg(stage0)]
242+
#[cfg(windows)]
146243
fn tls_key() -> tls::Key {
147244
match maybe_tls_key() {
148245
Some(key) => key,
@@ -151,7 +248,8 @@ fn tls_key() -> tls::Key {
151248
}
152249

153250
#[inline]
154-
#[cfg(not(test))]
251+
#[cfg(not(test), stage0)]
252+
#[cfg(not(test), windows)]
155253
pub fn maybe_tls_key() -> Option<tls::Key> {
156254
unsafe {
157255
// NB: This is a little racy because, while the key is
@@ -172,11 +270,9 @@ pub fn maybe_tls_key() -> Option<tls::Key> {
172270
}
173271
}
174272

175-
// XXX: The boundary between the running runtime and the testing runtime
176-
// seems to be fuzzy at the moment, and trying to use two different keys
177-
// results in disaster. This should not be necessary.
178273
#[inline]
179-
#[cfg(test)]
274+
#[cfg(test, stage0)]
275+
#[cfg(test, windows)]
180276
pub fn maybe_tls_key() -> Option<tls::Key> {
181277
unsafe { ::cast::transmute(::realstd::rt::shouldnt_be_public::maybe_tls_key()) }
182278
}

src/libstd/rt/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ pub use self::kill::BlockedTask;
9595
pub mod shouldnt_be_public {
9696
pub use super::select::SelectInner;
9797
pub use super::select::{SelectInner, SelectPortInner};
98+
#[cfg(stage0)]
99+
#[cfg(windows)]
98100
pub use super::local_ptr::maybe_tls_key;
101+
#[cfg(not(stage0), not(windows))]
102+
pub use super::local_ptr::RT_TLS_PTR;
99103
}
100104

101105
// Internal macros used by the runtime.

0 commit comments

Comments
 (0)