Skip to content

Commit 9fd2ac7

Browse files
committed
Make TLS keys actually take up space
If the TLS key is 0-sized, then the linux linker is apparently smart enough to put everything at the same pointer. OSX on the other hand, will reserve some space for all of them. To get around this, the TLS key now actuall consumes space to ensure that it gets a unique pointer
1 parent e3211fa commit 9fd2ac7

File tree

16 files changed

+81
-70
lines changed

16 files changed

+81
-70
lines changed

src/libextra/rl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub unsafe fn read(prompt: &str) -> Option<~str> {
6969
pub type CompletionCb = @fn(~str, @fn(~str));
7070

7171
#[cfg(not(stage0))]
72-
static complete_key: local_data::Key<@CompletionCb> = &[];
72+
static complete_key: local_data::Key<@CompletionCb> = &local_data::Key;
7373
#[cfg(stage0)]
7474
fn complete_key(_: @CompletionCb) {}
7575

src/librustc/back/link.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ pub mod jit {
105105
use metadata::cstore;
106106

107107
use std::cast;
108+
#[cfg(not(stage0))]
108109
use std::local_data;
109110
use std::unstable::intrinsics;
110111

@@ -202,18 +203,19 @@ pub mod jit {
202203

203204
// The stage1 compiler won't work, but that doesn't really matter. TLS
204205
// changed only very recently to allow storage of owned values.
205-
fn engine_key(_: ~Engine) {}
206+
#[cfg(not(stage0))]
207+
static engine_key: local_data::Key<~Engine> = &local_data::Key;
206208

207209
#[cfg(not(stage0))]
208210
fn set_engine(engine: ~Engine) {
209-
unsafe { local_data::set(engine_key, engine) }
211+
local_data::set(engine_key, engine)
210212
}
211213
#[cfg(stage0)]
212214
fn set_engine(_: ~Engine) {}
213215

214216
#[cfg(not(stage0))]
215217
pub fn consume_engine() -> Option<~Engine> {
216-
unsafe { local_data::pop(engine_key) }
218+
local_data::pop(engine_key)
217219
}
218220
#[cfg(stage0)]
219221
pub fn consume_engine() -> Option<~Engine> { None }

src/librustc/middle/trans/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ use syntax::abi::{X86, X86_64, Arm, Mips};
8888
pub use middle::trans::context::task_llcx;
8989

9090
#[cfg(not(stage0))]
91-
static task_local_insn_key: local_data::Key<@~[&'static str]> = &[];
91+
static task_local_insn_key: local_data::Key<@~[&'static str]> = &local_data::Key;
9292
#[cfg(stage0)]
9393
fn task_local_insn_key(_: @~[&'static str]) {}
9494

src/librustc/middle/trans/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ impl Drop for CrateContext {
239239
#[cfg(stage0)]
240240
fn task_local_llcx_key(_v: @ContextRef) {}
241241
#[cfg(not(stage0))]
242-
static task_local_llcx_key: local_data::Key<@ContextRef> = &[];
242+
static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key;
243243

244244
pub fn task_llcx() -> ContextRef {
245245
let opt = local_data::get(task_local_llcx_key, |k| k.map(|&k| *k));

src/librusti/program.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use std::cast;
1112
use std::hashmap::HashMap;
1213
use std::local_data;
13-
use std::vec;
1414

1515
use syntax::ast;
1616
use syntax::parse::token;
@@ -57,7 +57,7 @@ struct LocalVariable {
5757
}
5858

5959
type LocalCache = @mut HashMap<~str, @~[u8]>;
60-
static tls_key: local_data::Key<LocalCache> = &[];
60+
static tls_key: local_data::Key<LocalCache> = &local_data::Key;
6161

6262
impl Program {
6363
pub fn new() -> Program {
@@ -130,16 +130,14 @@ impl Program {
130130
fn main() {
131131
");
132132

133-
let key: *LocalCache = vec::raw::to_ptr(tls_key);
133+
let key: uint= unsafe { cast::transmute(tls_key) };
134134
// First, get a handle to the tls map which stores all the local
135135
// variables. This works by totally legitimately using the 'code'
136136
// pointer of the 'tls_key' function as a uint, and then casting it back
137137
// up to a function
138138
code.push_str(fmt!("
139139
let __tls_map: @mut ::std::hashmap::HashMap<~str, @~[u8]> = unsafe {
140-
let key = ::std::vec::raw::SliceRepr{ data: %? as *u8,
141-
len: 0 };
142-
let key = ::std::cast::transmute(key);
140+
let key = ::std::cast::transmute(%u);
143141
::std::local_data::get(key, |k| k.map(|&x| *x)).unwrap()
144142
};\n", key as uint));
145143

src/libstd/local_data.rs

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,19 @@
1313
Task local data management
1414
1515
Allows storing arbitrary types inside task-local-storage (TLS), to be accessed
16-
anywhere within a task, keyed by a global slice of the appropriate type.
17-
Useful for dynamic variables, singletons, and interfacing with foreign code
18-
with bad callback interfaces.
16+
anywhere within a task, keyed by a global pointer parameterized over the type of
17+
the TLS slot. Useful for dynamic variables, singletons, and interfacing with
18+
foreign code with bad callback interfaces.
1919
20-
To use, declare a static slice of the type you wish to store. The initialization
21-
should be `&[]`. This is then the key to what you wish to store.
20+
To use, declare a static variable of the type you wish to store. The
21+
initialization should be `&local_data::Key`. This is then the key to what you
22+
wish to store.
2223
2324
~~~{.rust}
2425
use std::local_data;
2526
26-
static key_int: local_data::Key<int> = &[];
27-
static key_vector: local_data::Key<~[int]> = &[];
27+
static key_int: local_data::Key<int> = &local_data::Key;
28+
static key_vector: local_data::Key<~[int]> = &local_data::Key;
2829
2930
local_data::set(key_int, 3);
3031
local_data::get(key_int, |opt| assert_eq!(opt, Some(&3)));
@@ -45,24 +46,23 @@ use task::local_data_priv::{local_get, local_pop, local_set, Handle};
4546
#[cfg(test)] use task;
4647

4748
/**
48-
* Indexes a task-local data slot. The function's code pointer is used for
49-
* comparison. Recommended use is to write an empty function for each desired
50-
* task-local data slot (and use class destructors, not code inside the
51-
* function, if specific teardown is needed). DO NOT use multiple
52-
* instantiations of a single polymorphic function to index data of different
53-
* types; arbitrary type coercion is possible this way.
49+
* Indexes a task-local data slot. This pointer is used for comparison to
50+
* differentiate keys from one another. The actual type `T` is not used anywhere
51+
* as a member of this type, except that it is parameterized with it to define
52+
* the type of each key's value.
5453
*
55-
* One other exception is that this global state can be used in a destructor
56-
* context to create a circular @-box reference, which will crash during task
57-
* failure (see issue #3039).
58-
*
59-
* These two cases aside, the interface is safe.
54+
* The value of each Key is of the singleton enum KeyValue. These also have the
55+
* same name as `Key` and their purpose is to take up space in the programs data
56+
* sections to ensure that each value of the `Key` type points to a unique
57+
* location.
6058
*/
6159
#[cfg(not(stage0))]
62-
pub type Key<T> = &'static [T];
60+
pub type Key<T> = &'static KeyValue<T>;
6361
#[cfg(stage0)]
6462
pub type Key<'self,T> = &'self fn:Copy(v: T);
6563

64+
pub enum KeyValue<T> { Key }
65+
6666
/**
6767
* Remove a task-local data value from the table, returning the
6868
* reference that was originally created to insert it.
@@ -136,7 +136,7 @@ pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
136136

137137
#[test]
138138
fn test_tls_multitask() {
139-
static my_key: Key<@~str> = &[];
139+
static my_key: Key<@~str> = &Key;
140140
set(my_key, @~"parent data");
141141
do task::spawn {
142142
// TLS shouldn't carry over.
@@ -154,15 +154,15 @@ fn test_tls_multitask() {
154154
155155
#[test]
156156
fn test_tls_overwrite() {
157-
static my_key: Key<@~str> = &[];
157+
static my_key: Key<@~str> = &Key;
158158
set(my_key, @~"first data");
159159
set(my_key, @~"next data"); // Shouldn't leak.
160160
assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"next data");
161161
}
162162
163163
#[test]
164164
fn test_tls_pop() {
165-
static my_key: Key<@~str> = &[];
165+
static my_key: Key<@~str> = &Key;
166166
set(my_key, @~"weasel");
167167
assert!(*(pop(my_key).get()) == ~"weasel");
168168
// Pop must remove the data from the map.
@@ -171,7 +171,7 @@ fn test_tls_pop() {
171171
172172
#[test]
173173
fn test_tls_modify() {
174-
static my_key: Key<@~str> = &[];
174+
static my_key: Key<@~str> = &Key;
175175
modify(my_key, |data| {
176176
match data {
177177
Some(@ref val) => fail!("unwelcome value: %s", *val),
@@ -196,17 +196,17 @@ fn test_tls_crust_automorestack_memorial_bug() {
196196
// to get recorded as something within a rust stack segment. Then a
197197
// subsequent upcall (esp. for logging, think vsnprintf) would run on
198198
// a stack smaller than 1 MB.
199-
static my_key: Key<@~str> = &[];
199+
static my_key: Key<@~str> = &Key;
200200
do task::spawn {
201201
set(my_key, @~"hax");
202202
}
203203
}
204204
205205
#[test]
206206
fn test_tls_multiple_types() {
207-
static str_key: Key<@~str> = &[];
208-
static box_key: Key<@@()> = &[];
209-
static int_key: Key<@int> = &[];
207+
static str_key: Key<@~str> = &Key;
208+
static box_key: Key<@@()> = &Key;
209+
static int_key: Key<@int> = &Key;
210210
do task::spawn {
211211
set(str_key, @~"string data");
212212
set(box_key, @@());
@@ -216,9 +216,9 @@ fn test_tls_multiple_types() {
216216
217217
#[test]
218218
fn test_tls_overwrite_multiple_types() {
219-
static str_key: Key<@~str> = &[];
220-
static box_key: Key<@@()> = &[];
221-
static int_key: Key<@int> = &[];
219+
static str_key: Key<@~str> = &Key;
220+
static box_key: Key<@@()> = &Key;
221+
static int_key: Key<@int> = &Key;
222222
do task::spawn {
223223
set(str_key, @~"string data");
224224
set(int_key, @42);
@@ -233,9 +233,9 @@ fn test_tls_overwrite_multiple_types() {
233233
#[should_fail]
234234
#[ignore(cfg(windows))]
235235
fn test_tls_cleanup_on_failure() {
236-
static str_key: Key<@~str> = &[];
237-
static box_key: Key<@@()> = &[];
238-
static int_key: Key<@int> = &[];
236+
static str_key: Key<@~str> = &Key;
237+
static box_key: Key<@@()> = &Key;
238+
static int_key: Key<@int> = &Key;
239239
set(str_key, @~"parent data");
240240
set(box_key, @@());
241241
do task::spawn {
@@ -252,25 +252,25 @@ fn test_tls_cleanup_on_failure() {
252252

253253
#[test]
254254
fn test_static_pointer() {
255-
static key: Key<@&'static int> = &[];
255+
static key: Key<@&'static int> = &Key;
256256
static VALUE: int = 0;
257257
let v: @&'static int = @&VALUE;
258258
set(key, v);
259259
}
260260

261261
#[test]
262262
fn test_owned() {
263-
static key: Key<~int> = &[];
263+
static key: Key<~int> = &Key;
264264
set(key, ~1);
265265
}
266266

267267
#[test]
268268
fn test_same_key_type() {
269-
static key1: Key<int> = &[];
270-
static key2: Key<int> = &[];
271-
static key3: Key<int> = &[];
272-
static key4: Key<int> = &[];
273-
static key5: Key<int> = &[];
269+
static key1: Key<int> = &Key;
270+
static key2: Key<int> = &Key;
271+
static key3: Key<int> = &Key;
272+
static key4: Key<int> = &Key;
273+
static key5: Key<int> = &Key;
274274
set(key1, 1);
275275
set(key2, 2);
276276
set(key3, 3);

src/libstd/os.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1242,7 +1242,7 @@ struct OverriddenArgs {
12421242
#[cfg(stage0)]
12431243
fn overridden_arg_key(_v: @OverriddenArgs) {}
12441244
#[cfg(not(stage0))]
1245-
static overridden_arg_key: local_data::Key<@OverriddenArgs> = &[];
1245+
static overridden_arg_key: local_data::Key<@OverriddenArgs> = &local_data::Key;
12461246

12471247
/// Returns the arguments which this program was started with (normally passed
12481248
/// via the command line).

src/libstd/rand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ pub fn seed() -> ~[u8] {
854854
#[cfg(stage0)]
855855
fn tls_rng_state(_v: @@mut IsaacRng) {}
856856
#[cfg(not(stage0))]
857-
static tls_rng_state: local_data::Key<@@mut IsaacRng> = &[];
857+
static tls_rng_state: local_data::Key<@@mut IsaacRng> = &local_data::Key;
858858

859859
/**
860860
* Gives back a lazily initialized task-local random number generator,

src/libstd/rt/task.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,10 @@ mod test {
348348
fn tls() {
349349
use local_data;
350350
do run_in_newsched_task() {
351-
static key: local_data::Key<@~str> = &[];
351+
static key: local_data::Key<@~str> = &local_data::Key;
352352
local_data::set(key, @~"data");
353353
assert!(*local_data::get(key, |k| k.map(|&k| *k)).get() == ~"data");
354-
static key2: local_data::Key<@~str> = &[];
354+
static key2: local_data::Key<@~str> = &local_data::Key;
355355
local_data::set(key2, @~"data");
356356
assert!(*local_data::get(key2, |k| k.map(|&k| *k)).get() == ~"data");
357357
}

src/libstd/std.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ mod std {
222222
pub use condition;
223223
pub use option;
224224
pub use kinds;
225+
pub use local_data;
225226
pub use sys;
226227
pub use pipes;
227228
pub use unstable;

src/libstd/task/local_data_priv.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use prelude::*;
1717
use ptr;
1818
use task::rt;
1919
use util;
20-
use vec;
2120

2221
use super::rt::rust_task;
2322
use rt::task::{Task, LocalStorage};
@@ -143,7 +142,7 @@ unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap {
143142
}
144143

145144
fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void {
146-
return vec::raw::to_ptr(key) as *libc::c_void;
145+
unsafe { cast::transmute(key) }
147146
}
148147

149148
pub unsafe fn local_pop<T: 'static>(handle: Handle,

src/libstd/task/spawn.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ use cell::Cell;
8080
use container::MutableMap;
8181
use comm::{Chan, GenericChan};
8282
use hashmap::HashSet;
83+
use local_data;
8384
use task::local_data_priv::{local_get, local_set, OldHandle};
8485
use task::rt::rust_task;
8586
use task::rt;
@@ -465,10 +466,14 @@ fn kill_taskgroup(state: TaskGroupInner, me: *rust_task, is_main: bool) {
465466

466467
// FIXME (#2912): Work around core-vs-coretest function duplication. Can't use
467468
// a proper closure because the #[test]s won't understand. Have to fake it.
468-
macro_rules! taskgroup_key (
469-
// Use a "code pointer" value that will never be a real code pointer.
470-
() => (cast::transmute((-2 as uint, 0u)))
471-
)
469+
#[cfg(not(stage0))]
470+
fn taskgroup_key() -> local_data::Key<@@mut TCB> {
471+
unsafe { cast::transmute(-2) }
472+
}
473+
#[cfg(stage0)]
474+
fn taskgroup_key() -> local_data::Key<@@mut TCB> {
475+
unsafe { cast::transmute((-2, 0)) }
476+
}
472477

473478
fn gen_child_taskgroup(linked: bool, supervised: bool)
474479
-> (TaskGroupArc, AncestorList, bool) {
@@ -478,7 +483,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
478483
* Step 1. Get spawner's taskgroup info.
479484
*##################################################################*/
480485
let spawner_group: @@mut TCB =
481-
do local_get(OldHandle(spawner), taskgroup_key!()) |group| {
486+
do local_get(OldHandle(spawner), taskgroup_key()) |group| {
482487
match group {
483488
None => {
484489
// Main task, doing first spawn ever. Lazily initialise
@@ -495,7 +500,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
495500
AncestorList(None),
496501
true,
497502
None);
498-
local_set(OldHandle(spawner), taskgroup_key!(), group);
503+
local_set(OldHandle(spawner), taskgroup_key(), group);
499504
group
500505
}
501506
Some(&group) => group
@@ -688,7 +693,7 @@ fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) {
688693
is_main,
689694
notifier);
690695
unsafe {
691-
local_set(OldHandle(child), taskgroup_key!(), group);
696+
local_set(OldHandle(child), taskgroup_key(), group);
692697
}
693698

694699
// Run the child's body.

src/libsyntax/ast_util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ pub fn new_sctable_internal() -> SCTable {
695695
// fetch the SCTable from TLS, create one if it doesn't yet exist.
696696
pub fn get_sctable() -> @mut SCTable {
697697
#[cfg(not(stage0))]
698-
static sctable_key: local_data::Key<@@mut SCTable> = &[];
698+
static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key;
699699
#[cfg(stage0)]
700700
fn sctable_key(_: @@mut SCTable) {}
701701
match local_data::get(sctable_key, |k| k.map(|&k| *k)) {

0 commit comments

Comments
 (0)