1
Fork 0

Purge the last remnants of the old TLS api

Closes #3273
This commit is contained in:
Alex Crichton 2013-07-12 01:38:44 -07:00
parent 242606c793
commit e3211fa1f1
15 changed files with 290 additions and 292 deletions

View file

@ -66,19 +66,22 @@ pub unsafe fn read(prompt: &str) -> Option<~str> {
} }
} }
pub type CompletionCb<'self> = @fn(~str, &'self fn(~str)); pub type CompletionCb = @fn(~str, @fn(~str));
fn complete_key(_v: @CompletionCb) {} #[cfg(not(stage0))]
static complete_key: local_data::Key<@CompletionCb> = &[];
#[cfg(stage0)]
fn complete_key(_: @CompletionCb) {}
/// Bind to the main completion callback /// Bind to the main completion callback
pub unsafe fn complete(cb: CompletionCb) { pub unsafe fn complete(cb: CompletionCb) {
local_data::set(complete_key, @(cb)); local_data::set(complete_key, @cb);
extern fn callback(line: *c_char, completions: *()) { extern fn callback(line: *c_char, completions: *()) {
unsafe { do local_data::get(complete_key) |cb| {
let cb = *local_data::get(complete_key, |k| k.map(|&k| *k)) let cb = **cb.unwrap();
.get();
unsafe {
do cb(str::raw::from_c_str(line)) |suggestion| { do cb(str::raw::from_c_str(line)) |suggestion| {
do str::as_c_str(suggestion) |buf| { do str::as_c_str(suggestion) |buf| {
rustrt::linenoiseAddCompletion(completions, buf); rustrt::linenoiseAddCompletion(completions, buf);
@ -86,6 +89,7 @@ pub unsafe fn complete(cb: CompletionCb) {
} }
} }
} }
}
rustrt::linenoiseSetCompletionCallback(callback); rustrt::linenoiseSetCompletionCallback(callback);
} }

View file

@ -1195,39 +1195,4 @@ mod big_tests {
isSorted(arr); isSorted(arr);
} }
} }
struct LVal<'self> {
val: uint,
key: &'self fn:Copy(@uint),
}
#[unsafe_destructor]
impl<'self> Drop for LVal<'self> {
fn drop(&self) {
let x = unsafe { local_data::get(self.key, |k| k.map(|&k| *k)) };
match x {
Some(@y) => {
unsafe {
local_data::set(self.key, @(y+1));
}
}
_ => fail!("Expected key to work"),
}
}
}
impl<'self> Ord for LVal<'self> {
fn lt<'a>(&self, other: &'a LVal<'self>) -> bool {
(*self).val < other.val
}
fn le<'a>(&self, other: &'a LVal<'self>) -> bool {
(*self).val <= other.val
}
fn gt<'a>(&self, other: &'a LVal<'self>) -> bool {
(*self).val > other.val
}
fn ge<'a>(&self, other: &'a LVal<'self>) -> bool {
(*self).val >= other.val
}
}
} }

View file

@ -87,29 +87,27 @@ use syntax::abi::{X86, X86_64, Arm, Mips};
pub use middle::trans::context::task_llcx; pub use middle::trans::context::task_llcx;
fn task_local_insn_key(_v: @~[&'static str]) {} #[cfg(not(stage0))]
static task_local_insn_key: local_data::Key<@~[&'static str]> = &[];
#[cfg(stage0)]
fn task_local_insn_key(_: @~[&'static str]) {}
pub fn with_insn_ctxt(blk: &fn(&[&'static str])) { pub fn with_insn_ctxt(blk: &fn(&[&'static str])) {
unsafe {
let opt = local_data::get(task_local_insn_key, |k| k.map(|&k| *k)); let opt = local_data::get(task_local_insn_key, |k| k.map(|&k| *k));
if opt.is_some() { if opt.is_some() {
blk(*opt.unwrap()); blk(*opt.unwrap());
} }
} }
}
pub fn init_insn_ctxt() { pub fn init_insn_ctxt() {
unsafe {
local_data::set(task_local_insn_key, @~[]); local_data::set(task_local_insn_key, @~[]);
} }
}
pub struct _InsnCtxt { _x: () } pub struct _InsnCtxt { _x: () }
#[unsafe_destructor] #[unsafe_destructor]
impl Drop for _InsnCtxt { impl Drop for _InsnCtxt {
fn drop(&self) { fn drop(&self) {
unsafe {
do local_data::modify(task_local_insn_key) |c| { do local_data::modify(task_local_insn_key) |c| {
do c.map_consume |ctx| { do c.map_consume |ctx| {
let mut ctx = copy *ctx; let mut ctx = copy *ctx;
@ -119,11 +117,9 @@ impl Drop for _InsnCtxt {
} }
} }
} }
}
pub fn push_ctxt(s: &'static str) -> _InsnCtxt { pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
debug!("new InsnCtxt: %s", s); debug!("new InsnCtxt: %s", s);
unsafe {
do local_data::modify(task_local_insn_key) |c| { do local_data::modify(task_local_insn_key) |c| {
do c.map_consume |ctx| { do c.map_consume |ctx| {
let mut ctx = copy *ctx; let mut ctx = copy *ctx;
@ -131,7 +127,6 @@ pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
@ctx @ctx
} }
} }
}
_InsnCtxt { _x: () } _InsnCtxt { _x: () }
} }

View file

@ -232,22 +232,24 @@ impl CrateContext {
#[unsafe_destructor] #[unsafe_destructor]
impl Drop for CrateContext { impl Drop for CrateContext {
fn drop(&self) { fn drop(&self) {
unsafe {
unset_task_llcx(); unset_task_llcx();
} }
} }
}
#[cfg(stage0)]
fn task_local_llcx_key(_v: @ContextRef) {} fn task_local_llcx_key(_v: @ContextRef) {}
#[cfg(not(stage0))]
static task_local_llcx_key: local_data::Key<@ContextRef> = &[];
pub fn task_llcx() -> ContextRef { pub fn task_llcx() -> ContextRef {
let opt = unsafe { local_data::get(task_local_llcx_key, |k| k.map(|&k| *k)) }; let opt = local_data::get(task_local_llcx_key, |k| k.map(|&k| *k));
*opt.expect("task-local LLVMContextRef wasn't ever set!") *opt.expect("task-local LLVMContextRef wasn't ever set!")
} }
unsafe fn set_task_llcx(c: ContextRef) { fn set_task_llcx(c: ContextRef) {
local_data::set(task_local_llcx_key, @c); local_data::set(task_local_llcx_key, @c);
} }
unsafe fn unset_task_llcx() { fn unset_task_llcx() {
local_data::pop(task_local_llcx_key); local_data::pop(task_local_llcx_key);
} }

View file

@ -8,10 +8,9 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::cast;
use std::hashmap::HashMap; use std::hashmap::HashMap;
use std::local_data; use std::local_data;
use std::sys; use std::vec;
use syntax::ast; use syntax::ast;
use syntax::parse::token; use syntax::parse::token;
@ -58,7 +57,7 @@ struct LocalVariable {
} }
type LocalCache = @mut HashMap<~str, @~[u8]>; type LocalCache = @mut HashMap<~str, @~[u8]>;
fn tls_key(_k: LocalCache) {} static tls_key: local_data::Key<LocalCache> = &[];
impl Program { impl Program {
pub fn new() -> Program { pub fn new() -> Program {
@ -131,21 +130,18 @@ impl Program {
fn main() { fn main() {
"); ");
let key: sys::Closure = unsafe { let key: *LocalCache = vec::raw::to_ptr(tls_key);
let tls_key: &'static fn(LocalCache) = tls_key;
cast::transmute(tls_key)
};
// First, get a handle to the tls map which stores all the local // First, get a handle to the tls map which stores all the local
// variables. This works by totally legitimately using the 'code' // variables. This works by totally legitimately using the 'code'
// pointer of the 'tls_key' function as a uint, and then casting it back // pointer of the 'tls_key' function as a uint, and then casting it back
// up to a function // up to a function
code.push_str(fmt!(" code.push_str(fmt!("
let __tls_map: @mut ::std::hashmap::HashMap<~str, @~[u8]> = unsafe { let __tls_map: @mut ::std::hashmap::HashMap<~str, @~[u8]> = unsafe {
let key = ::std::sys::Closure{ code: %? as *(), let key = ::std::vec::raw::SliceRepr{ data: %? as *u8,
env: ::std::ptr::null() }; len: 0 };
let key = ::std::cast::transmute(key); let key = ::std::cast::transmute(key);
::std::local_data::get(key, |k| k.map(|&x| *x)).unwrap() ::std::local_data::get(key, |k| k.map(|&x| *x)).unwrap()
};\n", key.code as uint)); };\n", key as uint));
// Using this __tls_map handle, deserialize each variable binding that // Using this __tls_map handle, deserialize each variable binding that
// we know about // we know about
@ -226,18 +222,14 @@ impl Program {
for self.local_vars.iter().advance |(name, value)| { for self.local_vars.iter().advance |(name, value)| {
map.insert(copy *name, @copy value.data); map.insert(copy *name, @copy value.data);
} }
unsafe {
local_data::set(tls_key, map); local_data::set(tls_key, map);
} }
}
/// Once the program has finished running, this function will consume the /// Once the program has finished running, this function will consume the
/// task-local cache of local variables. After the program finishes running, /// task-local cache of local variables. After the program finishes running,
/// it updates this cache with the new values of each local variable. /// it updates this cache with the new values of each local variable.
pub fn consume_cache(&mut self) { pub fn consume_cache(&mut self) {
let map = unsafe { let map = local_data::pop(tls_key).expect("tls is empty");
local_data::pop(tls_key).expect("tls is empty")
};
do map.consume |name, value| { do map.consume |name, value| {
match self.local_vars.find_mut(&name) { match self.local_vars.find_mut(&name) {
Some(v) => { v.data = copy *value; } Some(v) => { v.data = copy *value; }

View file

@ -23,13 +23,59 @@ pub struct Handler<T, U> {
prev: Option<@Handler<T, U>>, prev: Option<@Handler<T, U>>,
} }
#[cfg(stage0)]
pub struct Condition<'self, T, U> { pub struct Condition<'self, T, U> {
name: &'static str, name: &'static str,
key: local_data::Key<'self, @Handler<T, U>> key: local_data::Key<'self, @Handler<T, U>>
} }
#[cfg(not(stage0))]
pub struct Condition<T, U> {
name: &'static str,
key: local_data::Key<@Handler<T, U>>
}
#[cfg(not(stage0))]
impl<T, U> Condition<T, U> {
pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> {
unsafe {
let p : *RustClosure = ::cast::transmute(&h);
let prev = local_data::get(self.key, |k| k.map(|&x| *x));
let h = @Handler { handle: *p, prev: prev };
Trap { cond: self, handler: h }
}
}
pub fn raise(&self, t: T) -> U {
let msg = fmt!("Unhandled condition: %s: %?", self.name, t);
self.raise_default(t, || fail!(copy msg))
}
pub fn raise_default(&self, t: T, default: &fn() -> U) -> U {
unsafe {
match local_data::pop(self.key) {
None => {
debug!("Condition.raise: found no handler");
default()
}
Some(handler) => {
debug!("Condition.raise: found handler");
match handler.prev {
None => {}
Some(hp) => local_data::set(self.key, hp)
}
let handle : &fn(T) -> U =
::cast::transmute(handler.handle);
let u = handle(t);
local_data::set(self.key, handler);
u
}
}
}
}
}
#[cfg(stage0)]
impl<'self, T, U> Condition<'self, T, U> { impl<'self, T, U> Condition<'self, T, U> {
pub fn trap(&'self self, h: &'self fn(T) -> U) -> Trap<'self, T, U> { pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> {
unsafe { unsafe {
let p : *RustClosure = ::cast::transmute(&h); let p : *RustClosure = ::cast::transmute(&h);
let prev = local_data::get(self.key, |k| k.map(|&x| *x)); let prev = local_data::get(self.key, |k| k.map(|&x| *x));
@ -67,30 +113,38 @@ impl<'self, T, U> Condition<'self, T, U> {
} }
} }
#[cfg(stage0)]
struct Trap<'self, T, U> { struct Trap<'self, T, U> {
cond: &'self Condition<'self, T, U>, cond: &'self Condition<'self, T, U>,
handler: @Handler<T, U> handler: @Handler<T, U>
} }
#[cfg(not(stage0))]
struct Trap<'self, T, U> {
cond: &'self Condition<T, U>,
handler: @Handler<T, U>
}
impl<'self, T, U> Trap<'self, T, U> { impl<'self, T, U> Trap<'self, T, U> {
pub fn in<V>(&self, inner: &'self fn() -> V) -> V { pub fn in<V>(&self, inner: &'self fn() -> V) -> V {
unsafe {
let _g = Guard { cond: self.cond }; let _g = Guard { cond: self.cond };
debug!("Trap: pushing handler to TLS"); debug!("Trap: pushing handler to TLS");
local_data::set(self.cond.key, self.handler); local_data::set(self.cond.key, self.handler);
inner() inner()
} }
} }
}
#[cfg(stage0)]
struct Guard<'self, T, U> { struct Guard<'self, T, U> {
cond: &'self Condition<'self, T, U> cond: &'self Condition<'self, T, U>
} }
#[cfg(not(stage0))]
struct Guard<'self, T, U> {
cond: &'self Condition<T, U>
}
#[unsafe_destructor] #[unsafe_destructor]
impl<'self, T, U> Drop for Guard<'self, T, U> { impl<'self, T, U> Drop for Guard<'self, T, U> {
fn drop(&self) { fn drop(&self) {
unsafe {
debug!("Guard: popping handler from TLS"); debug!("Guard: popping handler from TLS");
let curr = local_data::pop(self.cond.key); let curr = local_data::pop(self.cond.key);
match curr { match curr {
@ -102,7 +156,6 @@ impl<'self, T, U> Drop for Guard<'self, T, U> {
} }
} }
} }
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {

View file

@ -12,27 +12,25 @@
Task local data management Task local data management
Allows storing boxes with arbitrary types inside, to be accessed anywhere within Allows storing arbitrary types inside task-local-storage (TLS), to be accessed
a task, keyed by a pointer to a global finaliser function. Useful for dynamic anywhere within a task, keyed by a global slice of the appropriate type.
variables, singletons, and interfacing with foreign code with bad callback Useful for dynamic variables, singletons, and interfacing with foreign code
interfaces. with bad callback interfaces.
To use, declare a monomorphic (no type parameters) global function at the type To use, declare a static slice of the type you wish to store. The initialization
to store, and use it as the 'key' when accessing. should be `&[]`. This is then the key to what you wish to store.
~~~{.rust} ~~~{.rust}
use std::local_data; use std::local_data;
fn key_int(_: @int) {} static key_int: local_data::Key<int> = &[];
fn key_vector(_: @~[int]) {} static key_vector: local_data::Key<~[int]> = &[];
unsafe { local_data::set(key_int, 3);
local_data::set(key_int, @3); local_data::get(key_int, |opt| assert_eq!(opt, Some(&3)));
assert!(local_data::get(key_int) == Some(@3));
local_data::set(key_vector, @~[3]); local_data::set(key_vector, ~[4]);
assert!(local_data::get(key_vector).unwrap()[0] == 3); local_data::get(key_int, |opt| assert_eq!(opt, Some(&~[4])));
}
~~~ ~~~
Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
@ -60,6 +58,9 @@ use task::local_data_priv::{local_get, local_pop, local_set, Handle};
* *
* These two cases aside, the interface is safe. * These two cases aside, the interface is safe.
*/ */
#[cfg(not(stage0))]
pub type Key<T> = &'static [T];
#[cfg(stage0)]
pub type Key<'self,T> = &'self fn:Copy(v: T); pub type Key<'self,T> = &'self fn:Copy(v: T);
/** /**
@ -67,56 +68,55 @@ pub type Key<'self,T> = &'self fn:Copy(v: T);
* reference that was originally created to insert it. * reference that was originally created to insert it.
*/ */
#[cfg(stage0)] #[cfg(stage0)]
pub unsafe fn pop<T: 'static>(key: Key<@T>) -> Option<@T> { pub fn pop<T: 'static>(key: Key<@T>) -> Option<@T> {
local_pop(Handle::new(), key) unsafe { local_pop(Handle::new(), key) }
} }
/** /**
* Remove a task-local data value from the table, returning the * Remove a task-local data value from the table, returning the
* reference that was originally created to insert it. * reference that was originally created to insert it.
*/ */
#[cfg(not(stage0))] #[cfg(not(stage0))]
pub unsafe fn pop<T: 'static>(key: Key<T>) -> Option<T> { pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
local_pop(Handle::new(), key) unsafe { local_pop(Handle::new(), key) }
} }
/** /**
* Retrieve a task-local data value. It will also be kept alive in the * Retrieve a task-local data value. It will also be kept alive in the
* table until explicitly removed. * table until explicitly removed.
*/ */
#[cfg(stage0)] #[cfg(stage0)]
pub unsafe fn get<T: 'static, U>(key: Key<@T>, f: &fn(Option<&@T>) -> U) -> U { pub fn get<T: 'static, U>(key: Key<@T>, f: &fn(Option<&@T>) -> U) -> U {
local_get(Handle::new(), key, f) unsafe { local_get(Handle::new(), key, f) }
} }
/** /**
* Retrieve a task-local data value. It will also be kept alive in the * Retrieve a task-local data value. It will also be kept alive in the
* table until explicitly removed. * table until explicitly removed.
*/ */
#[cfg(not(stage0))] #[cfg(not(stage0))]
pub unsafe fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U { pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
local_get(Handle::new(), key, f) unsafe { local_get(Handle::new(), key, f) }
} }
/** /**
* Store a value in task-local data. If this key already has a value, * Store a value in task-local data. If this key already has a value,
* that value is overwritten (and its destructor is run). * that value is overwritten (and its destructor is run).
*/ */
#[cfg(stage0)] #[cfg(stage0)]
pub unsafe fn set<T: 'static>(key: Key<@T>, data: @T) { pub fn set<T: 'static>(key: Key<@T>, data: @T) {
local_set(Handle::new(), key, data) unsafe { local_set(Handle::new(), key, data) }
} }
/** /**
* Store a value in task-local data. If this key already has a value, * Store a value in task-local data. If this key already has a value,
* that value is overwritten (and its destructor is run). * that value is overwritten (and its destructor is run).
*/ */
#[cfg(not(stage0))] #[cfg(not(stage0))]
pub unsafe fn set<T: 'static>(key: Key<T>, data: T) { pub fn set<T: 'static>(key: Key<T>, data: T) {
local_set(Handle::new(), key, data) unsafe { local_set(Handle::new(), key, data) }
} }
/** /**
* Modify a task-local data value. If the function returns 'None', the * Modify a task-local data value. If the function returns 'None', the
* data is removed (and its reference dropped). * data is removed (and its reference dropped).
*/ */
#[cfg(stage0)] #[cfg(stage0)]
pub unsafe fn modify<T: 'static>(key: Key<@T>, pub fn modify<T: 'static>(key: Key<@T>, f: &fn(Option<@T>) -> Option<@T>) {
f: &fn(Option<@T>) -> Option<@T>) {
match f(pop(key)) { match f(pop(key)) {
Some(next) => { set(key, next); } Some(next) => { set(key, next); }
None => {} None => {}
@ -127,8 +127,7 @@ pub unsafe fn modify<T: 'static>(key: Key<@T>,
* data is removed (and its reference dropped). * data is removed (and its reference dropped).
*/ */
#[cfg(not(stage0))] #[cfg(not(stage0))]
pub unsafe fn modify<T: 'static>(key: Key<T>, pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
f: &fn(Option<T>) -> Option<T>) {
match f(pop(key)) { match f(pop(key)) {
Some(next) => { set(key, next); } Some(next) => { set(key, next); }
None => {} None => {}
@ -137,8 +136,7 @@ pub unsafe fn modify<T: 'static>(key: Key<T>,
#[test] #[test]
fn test_tls_multitask() { fn test_tls_multitask() {
unsafe { static my_key: Key<@~str> = &[];
fn my_key(_x: @~str) { }
set(my_key, @~"parent data"); set(my_key, @~"parent data");
do task::spawn { do task::spawn {
// TLS shouldn't carry over. // TLS shouldn't carry over.
@ -153,33 +151,27 @@ fn test_tls_multitask() {
assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data");
assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data");
} }
}
#[test] #[test]
fn test_tls_overwrite() { fn test_tls_overwrite() {
unsafe { static my_key: Key<@~str> = &[];
fn my_key(_x: @~str) { }
set(my_key, @~"first data"); set(my_key, @~"first data");
set(my_key, @~"next data"); // Shouldn't leak. set(my_key, @~"next data"); // Shouldn't leak.
assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"next data"); assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"next data");
} }
}
#[test] #[test]
fn test_tls_pop() { fn test_tls_pop() {
unsafe { static my_key: Key<@~str> = &[];
fn my_key(_x: @~str) { }
set(my_key, @~"weasel"); set(my_key, @~"weasel");
assert!(*(pop(my_key).get()) == ~"weasel"); assert!(*(pop(my_key).get()) == ~"weasel");
// Pop must remove the data from the map. // Pop must remove the data from the map.
assert!(pop(my_key).is_none()); assert!(pop(my_key).is_none());
} }
}
#[test] #[test]
fn test_tls_modify() { fn test_tls_modify() {
unsafe { static my_key: Key<@~str> = &[];
fn my_key(_x: @~str) { }
modify(my_key, |data| { modify(my_key, |data| {
match data { match data {
Some(@ref val) => fail!("unwelcome value: %s", *val), Some(@ref val) => fail!("unwelcome value: %s", *val),
@ -195,7 +187,6 @@ fn test_tls_modify() {
}); });
assert!(*(pop(my_key).get()) == ~"next data"); assert!(*(pop(my_key).get()) == ~"next data");
} }
}
#[test] #[test]
fn test_tls_crust_automorestack_memorial_bug() { fn test_tls_crust_automorestack_memorial_bug() {
@ -205,33 +196,30 @@ fn test_tls_crust_automorestack_memorial_bug() {
// to get recorded as something within a rust stack segment. Then a // to get recorded as something within a rust stack segment. Then a
// subsequent upcall (esp. for logging, think vsnprintf) would run on // subsequent upcall (esp. for logging, think vsnprintf) would run on
// a stack smaller than 1 MB. // a stack smaller than 1 MB.
fn my_key(_x: @~str) { } static my_key: Key<@~str> = &[];
do task::spawn { do task::spawn {
unsafe { set(my_key, @~"hax"); } set(my_key, @~"hax");
} }
} }
#[test] #[test]
fn test_tls_multiple_types() { fn test_tls_multiple_types() {
fn str_key(_x: @~str) { } static str_key: Key<@~str> = &[];
fn box_key(_x: @@()) { } static box_key: Key<@@()> = &[];
fn int_key(_x: @int) { } static int_key: Key<@int> = &[];
do task::spawn { do task::spawn {
unsafe {
set(str_key, @~"string data"); set(str_key, @~"string data");
set(box_key, @@()); set(box_key, @@());
set(int_key, @42); set(int_key, @42);
} }
} }
}
#[test] #[test]
fn test_tls_overwrite_multiple_types() { fn test_tls_overwrite_multiple_types() {
fn str_key(_x: @~str) { } static str_key: Key<@~str> = &[];
fn box_key(_x: @@()) { } static box_key: Key<@@()> = &[];
fn int_key(_x: @int) { } static int_key: Key<@int> = &[];
do task::spawn { do task::spawn {
unsafe {
set(str_key, @~"string data"); set(str_key, @~"string data");
set(int_key, @42); set(int_key, @42);
// This could cause a segfault if overwriting-destruction is done // This could cause a segfault if overwriting-destruction is done
@ -240,16 +228,14 @@ fn test_tls_overwrite_multiple_types() {
set(int_key, @31337); set(int_key, @31337);
} }
} }
}
#[test] #[test]
#[should_fail] #[should_fail]
#[ignore(cfg(windows))] #[ignore(cfg(windows))]
fn test_tls_cleanup_on_failure() { fn test_tls_cleanup_on_failure() {
unsafe { static str_key: Key<@~str> = &[];
fn str_key(_x: @~str) { } static box_key: Key<@@()> = &[];
fn box_key(_x: @@()) { } static int_key: Key<@int> = &[];
fn int_key(_x: @int) { }
set(str_key, @~"parent data"); set(str_key, @~"parent data");
set(box_key, @@()); set(box_key, @@());
do task::spawn { do task::spawn {
@ -263,21 +249,37 @@ fn test_tls_cleanup_on_failure() {
set(int_key, @31337); set(int_key, @31337);
fail!(); fail!();
} }
}
#[test] #[test]
fn test_static_pointer() { fn test_static_pointer() {
unsafe { static key: Key<@&'static int> = &[];
fn key(_x: @&'static int) { }
static VALUE: int = 0; static VALUE: int = 0;
set(key, @&VALUE); let v: @&'static int = @&VALUE;
} set(key, v);
} }
#[test] #[test]
fn test_owned() { fn test_owned() {
unsafe { static key: Key<~int> = &[];
fn key(_x: ~int) { }
set(key, ~1); set(key, ~1);
} }
#[test]
fn test_same_key_type() {
static key1: Key<int> = &[];
static key2: Key<int> = &[];
static key3: Key<int> = &[];
static key4: Key<int> = &[];
static key5: Key<int> = &[];
set(key1, 1);
set(key2, 2);
set(key3, 3);
set(key4, 4);
set(key5, 5);
get(key1, |x| assert_eq!(*x.unwrap(), 1));
get(key2, |x| assert_eq!(*x.unwrap(), 2));
get(key3, |x| assert_eq!(*x.unwrap(), 3));
get(key4, |x| assert_eq!(*x.unwrap(), 4));
get(key5, |x| assert_eq!(*x.unwrap(), 5));
} }

View file

@ -1239,7 +1239,10 @@ struct OverriddenArgs {
val: ~[~str] val: ~[~str]
} }
#[cfg(stage0)]
fn overridden_arg_key(_v: @OverriddenArgs) {} fn overridden_arg_key(_v: @OverriddenArgs) {}
#[cfg(not(stage0))]
static overridden_arg_key: local_data::Key<@OverriddenArgs> = &[];
/// Returns the arguments which this program was started with (normally passed /// Returns the arguments which this program was started with (normally passed
/// via the command line). /// via the command line).
@ -1247,23 +1250,19 @@ fn overridden_arg_key(_v: @OverriddenArgs) {}
/// The return value of the function can be changed by invoking the /// The return value of the function can be changed by invoking the
/// `os::set_args` function. /// `os::set_args` function.
pub fn args() -> ~[~str] { pub fn args() -> ~[~str] {
unsafe {
match local_data::get(overridden_arg_key, |k| k.map(|&k| *k)) { match local_data::get(overridden_arg_key, |k| k.map(|&k| *k)) {
None => real_args(), None => real_args(),
Some(args) => copy args.val Some(args) => copy args.val
} }
} }
}
/// For the current task, overrides the task-local cache of the arguments this /// For the current task, overrides the task-local cache of the arguments this
/// program had when it started. These new arguments are only available to the /// program had when it started. These new arguments are only available to the
/// current task via the `os::args` method. /// current task via the `os::args` method.
pub fn set_args(new_args: ~[~str]) { pub fn set_args(new_args: ~[~str]) {
unsafe {
let overridden_args = @OverriddenArgs { val: copy new_args }; let overridden_args = @OverriddenArgs { val: copy new_args };
local_data::set(overridden_arg_key, overridden_args); local_data::set(overridden_arg_key, overridden_args);
} }
}
// FIXME #6100 we should really use an internal implementation of this - using // FIXME #6100 we should really use an internal implementation of this - using
// the POSIX glob functions isn't portable to windows, probably has slight // the POSIX glob functions isn't portable to windows, probably has slight

View file

@ -851,7 +851,10 @@ pub fn seed() -> ~[u8] {
} }
// used to make space in TLS for a random number generator // used to make space in TLS for a random number generator
#[cfg(stage0)]
fn tls_rng_state(_v: @@mut IsaacRng) {} fn tls_rng_state(_v: @@mut IsaacRng) {}
#[cfg(not(stage0))]
static tls_rng_state: local_data::Key<@@mut IsaacRng> = &[];
/** /**
* Gives back a lazily initialized task-local random number generator, * Gives back a lazily initialized task-local random number generator,
@ -860,18 +863,13 @@ fn tls_rng_state(_v: @@mut IsaacRng) {}
*/ */
#[inline] #[inline]
pub fn task_rng() -> @mut IsaacRng { pub fn task_rng() -> @mut IsaacRng {
let r : Option<@@mut IsaacRng>; let r = local_data::get(tls_rng_state, |k| k.map(|&k| *k));
unsafe {
r = local_data::get(tls_rng_state, |k| k.map(|&k| *k));
}
match r { match r {
None => { None => {
unsafe {
let rng = @@mut IsaacRng::new_seeded(seed()); let rng = @@mut IsaacRng::new_seeded(seed());
local_data::set(tls_rng_state, rng); local_data::set(tls_rng_state, rng);
*rng *rng
} }
}
Some(rng) => *rng Some(rng) => *rng
} }
} }

View file

@ -348,16 +348,14 @@ mod test {
fn tls() { fn tls() {
use local_data; use local_data;
do run_in_newsched_task() { do run_in_newsched_task() {
unsafe { static key: local_data::Key<@~str> = &[];
fn key(_x: @~str) { }
local_data::set(key, @~"data"); local_data::set(key, @~"data");
assert!(*local_data::get(key, |k| k.map(|&k| *k)).get() == ~"data"); assert!(*local_data::get(key, |k| k.map(|&k| *k)).get() == ~"data");
fn key2(_x: @~str) { } static key2: local_data::Key<@~str> = &[];
local_data::set(key2, @~"data"); local_data::set(key2, @~"data");
assert!(*local_data::get(key2, |k| k.map(|&k| *k)).get() == ~"data"); assert!(*local_data::get(key2, |k| k.map(|&k| *k)).get() == ~"data");
} }
} }
}
#[test] #[test]
fn unwind() { fn unwind() {

View file

@ -15,9 +15,9 @@ use libc;
use local_data; use local_data;
use prelude::*; use prelude::*;
use ptr; use ptr;
use sys;
use task::rt; use task::rt;
use util; use util;
use vec;
use super::rt::rust_task; use super::rt::rust_task;
use rt::task::{Task, LocalStorage}; use rt::task::{Task, LocalStorage};
@ -142,9 +142,8 @@ unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap {
} }
} }
unsafe fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void { fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void {
let pair: sys::Closure = cast::transmute(key); return vec::raw::to_ptr(key) as *libc::c_void;
return pair.code as *libc::c_void;
} }
pub unsafe fn local_pop<T: 'static>(handle: Handle, pub unsafe fn local_pop<T: 'static>(handle: Handle,

View file

@ -20,7 +20,6 @@ use std::hashmap::HashMap;
use std::int; use std::int;
use std::num; use std::num;
use std::option; use std::option;
use std::cast;
use std::local_data; use std::local_data;
pub fn path_name_i(idents: &[ident]) -> ~str { pub fn path_name_i(idents: &[ident]) -> ~str {
@ -695,10 +694,10 @@ pub fn new_sctable_internal() -> SCTable {
// fetch the SCTable from TLS, create one if it doesn't yet exist. // fetch the SCTable from TLS, create one if it doesn't yet exist.
pub fn get_sctable() -> @mut SCTable { pub fn get_sctable() -> @mut SCTable {
unsafe { #[cfg(not(stage0))]
let sctable_key = (cast::transmute::<(uint, uint), static sctable_key: local_data::Key<@@mut SCTable> = &[];
&fn:Copy(v: @@mut SCTable)>( #[cfg(stage0)]
(-4 as uint, 0u))); fn sctable_key(_: @@mut SCTable) {}
match local_data::get(sctable_key, |k| k.map(|&k| *k)) { match local_data::get(sctable_key, |k| k.map(|&k| *k)) {
None => { None => {
let new_table = @@mut new_sctable_internal(); let new_table = @@mut new_sctable_internal();
@ -708,7 +707,6 @@ pub fn get_sctable() -> @mut SCTable {
Some(intr) => *intr Some(intr) => *intr
} }
} }
}
/// Add a value to the end of a vec, return its index /// Add a value to the end of a vec, return its index
fn idx_push<T>(vec: &mut ~[T], val: T) -> uint { fn idx_push<T>(vec: &mut ~[T], val: T) -> uint {

View file

@ -579,11 +579,11 @@ pub fn core_macros() -> @str {
{ pub $c:ident: $in:ty -> $out:ty; } => { { pub $c:ident: $in:ty -> $out:ty; } => {
pub mod $c { pub mod $c {
fn key(_x: @::std::condition::Handler<$in,$out>) { } #[allow(non_uppercase_statics)];
static key: &'static [@::std::condition::Handler<$in, $out>] = &[];
#[allow(non_uppercase_statics)]
pub static cond : pub static cond :
::std::condition::Condition<'static,$in,$out> = ::std::condition::Condition<$in,$out> =
::std::condition::Condition { ::std::condition::Condition {
name: stringify!($c), name: stringify!($c),
key: key key: key
@ -595,11 +595,11 @@ pub fn core_macros() -> @str {
// FIXME (#6009): remove mod's `pub` below once variant above lands. // FIXME (#6009): remove mod's `pub` below once variant above lands.
pub mod $c { pub mod $c {
fn key(_x: @::std::condition::Handler<$in,$out>) { } #[allow(non_uppercase_statics)];
static key: &'static [@::std::condition::Handler<$in, $out>] = &[];
#[allow(non_uppercase_statics)]
pub static cond : pub static cond :
::std::condition::Condition<'static,$in,$out> = ::std::condition::Condition<$in,$out> =
::std::condition::Condition { ::std::condition::Condition {
name: stringify!($c), name: stringify!($c),
key: key key: key

View file

@ -15,7 +15,6 @@ use parse::token;
use util::interner::StrInterner; use util::interner::StrInterner;
use util::interner; use util::interner;
use std::cast;
use std::cmp::Equiv; use std::cmp::Equiv;
use std::local_data; use std::local_data;
use std::rand; use std::rand;
@ -485,11 +484,10 @@ fn mk_fresh_ident_interner() -> @ident_interner {
// if an interner exists in TLS, return it. Otherwise, prepare a // if an interner exists in TLS, return it. Otherwise, prepare a
// fresh one. // fresh one.
pub fn get_ident_interner() -> @ident_interner { pub fn get_ident_interner() -> @ident_interner {
unsafe { #[cfg(not(stage0))]
let key = static key: local_data::Key<@@::parse::token::ident_interner> = &[];
(cast::transmute::<(uint, uint), #[cfg(stage0)]
&fn:Copy(v: @@::parse::token::ident_interner)>( fn key(_: @@::parse::token::ident_interner) {}
(-3 as uint, 0u)));
match local_data::get(key, |k| k.map(|&k| *k)) { match local_data::get(key, |k| k.map(|&k| *k)) {
Some(interner) => *interner, Some(interner) => *interner,
None => { None => {
@ -499,7 +497,6 @@ pub fn get_ident_interner() -> @ident_interner {
} }
} }
} }
}
/* for when we don't care about the contents; doesn't interact with TLD or /* for when we don't care about the contents; doesn't interact with TLD or
serialization */ serialization */

View file

@ -12,10 +12,6 @@
use std::local_data; use std::local_data;
fn key(_x: @&int) { } static key: local_data::Key<@&int> = &[]; //~ ERROR only 'static is allowed
fn main() { fn main() {}
unsafe {
local_data::set(key, @&0); //~ ERROR does not fulfill `'static`
}
}