diff options
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/local_data.rs | 80 | ||||
| -rw-r--r-- | src/libstd/os.rs | 2 | ||||
| -rw-r--r-- | src/libstd/rand.rs | 2 | ||||
| -rw-r--r-- | src/libstd/rt/task.rs | 4 | ||||
| -rw-r--r-- | src/libstd/std.rs | 1 | ||||
| -rw-r--r-- | src/libstd/task/local_data_priv.rs | 3 | ||||
| -rw-r--r-- | src/libstd/task/spawn.rs | 19 |
7 files changed, 58 insertions, 53 deletions
diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index 640bcc757b3..be170cce07e 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -13,18 +13,19 @@ Task local data management Allows storing arbitrary types inside task-local-storage (TLS), to be accessed -anywhere within a task, keyed by a global slice of the appropriate type. -Useful for dynamic variables, singletons, and interfacing with foreign code -with bad callback interfaces. +anywhere within a task, keyed by a global pointer parameterized over the type of +the TLS slot. Useful for dynamic variables, singletons, and interfacing with +foreign code with bad callback interfaces. -To use, declare a static slice of the type you wish to store. The initialization -should be `&[]`. This is then the key to what you wish to store. +To use, declare a static variable of the type you wish to store. The +initialization should be `&local_data::Key`. This is then the key to what you +wish to store. ~~~{.rust} use std::local_data; -static key_int: local_data::Key<int> = &[]; -static key_vector: local_data::Key<~[int]> = &[]; +static key_int: local_data::Key<int> = &local_data::Key; +static key_vector: local_data::Key<~[int]> = &local_data::Key; local_data::set(key_int, 3); 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}; #[cfg(test)] use task; /** - * Indexes a task-local data slot. The function's code pointer is used for - * comparison. Recommended use is to write an empty function for each desired - * task-local data slot (and use class destructors, not code inside the - * function, if specific teardown is needed). DO NOT use multiple - * instantiations of a single polymorphic function to index data of different - * types; arbitrary type coercion is possible this way. + * Indexes a task-local data slot. This pointer is used for comparison to + * differentiate keys from one another. The actual type `T` is not used anywhere + * as a member of this type, except that it is parameterized with it to define + * the type of each key's value. * - * One other exception is that this global state can be used in a destructor - * context to create a circular @-box reference, which will crash during task - * failure (see issue #3039). - * - * These two cases aside, the interface is safe. + * The value of each Key is of the singleton enum KeyValue. These also have the + * same name as `Key` and their purpose is to take up space in the programs data + * sections to ensure that each value of the `Key` type points to a unique + * location. */ #[cfg(not(stage0))] -pub type Key<T> = &'static [T]; +pub type Key<T> = &'static KeyValue<T>; #[cfg(stage0)] pub type Key<'self,T> = &'self fn:Copy(v: T); +pub enum KeyValue<T> { Key } + /** * Remove a task-local data value from the table, returning the * 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>) { #[test] fn test_tls_multitask() { - static my_key: Key<@~str> = &[]; + static my_key: Key<@~str> = &Key; set(my_key, @~"parent data"); do task::spawn { // TLS shouldn't carry over. @@ -154,7 +154,7 @@ fn test_tls_multitask() { #[test] fn test_tls_overwrite() { - static my_key: Key<@~str> = &[]; + static my_key: Key<@~str> = &Key; set(my_key, @~"first data"); set(my_key, @~"next data"); // Shouldn't leak. assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"next data"); @@ -162,7 +162,7 @@ fn test_tls_overwrite() { #[test] fn test_tls_pop() { - static my_key: Key<@~str> = &[]; + static my_key: Key<@~str> = &Key; set(my_key, @~"weasel"); assert!(*(pop(my_key).get()) == ~"weasel"); // Pop must remove the data from the map. @@ -171,7 +171,7 @@ fn test_tls_pop() { #[test] fn test_tls_modify() { - static my_key: Key<@~str> = &[]; + static my_key: Key<@~str> = &Key; modify(my_key, |data| { match data { Some(@ref val) => fail!("unwelcome value: %s", *val), @@ -196,7 +196,7 @@ fn test_tls_crust_automorestack_memorial_bug() { // to get recorded as something within a rust stack segment. Then a // subsequent upcall (esp. for logging, think vsnprintf) would run on // a stack smaller than 1 MB. - static my_key: Key<@~str> = &[]; + static my_key: Key<@~str> = &Key; do task::spawn { set(my_key, @~"hax"); } @@ -204,9 +204,9 @@ fn test_tls_crust_automorestack_memorial_bug() { #[test] fn test_tls_multiple_types() { - static str_key: Key<@~str> = &[]; - static box_key: Key<@@()> = &[]; - static int_key: Key<@int> = &[]; + static str_key: Key<@~str> = &Key; + static box_key: Key<@@()> = &Key; + static int_key: Key<@int> = &Key; do task::spawn { set(str_key, @~"string data"); set(box_key, @@()); @@ -216,9 +216,9 @@ fn test_tls_multiple_types() { #[test] fn test_tls_overwrite_multiple_types() { - static str_key: Key<@~str> = &[]; - static box_key: Key<@@()> = &[]; - static int_key: Key<@int> = &[]; + static str_key: Key<@~str> = &Key; + static box_key: Key<@@()> = &Key; + static int_key: Key<@int> = &Key; do task::spawn { set(str_key, @~"string data"); set(int_key, @42); @@ -233,9 +233,9 @@ fn test_tls_overwrite_multiple_types() { #[should_fail] #[ignore(cfg(windows))] fn test_tls_cleanup_on_failure() { - static str_key: Key<@~str> = &[]; - static box_key: Key<@@()> = &[]; - static int_key: Key<@int> = &[]; + static str_key: Key<@~str> = &Key; + static box_key: Key<@@()> = &Key; + static int_key: Key<@int> = &Key; set(str_key, @~"parent data"); set(box_key, @@()); do task::spawn { @@ -252,7 +252,7 @@ fn test_tls_cleanup_on_failure() { #[test] fn test_static_pointer() { - static key: Key<@&'static int> = &[]; + static key: Key<@&'static int> = &Key; static VALUE: int = 0; let v: @&'static int = @&VALUE; set(key, v); @@ -260,17 +260,17 @@ fn test_static_pointer() { #[test] fn test_owned() { - static key: Key<~int> = &[]; + static key: Key<~int> = &Key; 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> = &[]; + static key1: Key<int> = &Key; + static key2: Key<int> = &Key; + static key3: Key<int> = &Key; + static key4: Key<int> = &Key; + static key5: Key<int> = &Key; set(key1, 1); set(key2, 2); set(key3, 3); diff --git a/src/libstd/os.rs b/src/libstd/os.rs index cbd1e4e7663..58175db1241 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -1242,7 +1242,7 @@ struct OverriddenArgs { #[cfg(stage0)] fn overridden_arg_key(_v: @OverriddenArgs) {} #[cfg(not(stage0))] -static overridden_arg_key: local_data::Key<@OverriddenArgs> = &[]; +static overridden_arg_key: local_data::Key<@OverriddenArgs> = &local_data::Key; /// Returns the arguments which this program was started with (normally passed /// via the command line). diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index 8551012d6d7..6f89e7ffb07 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -854,7 +854,7 @@ pub fn seed() -> ~[u8] { #[cfg(stage0)] fn tls_rng_state(_v: @@mut IsaacRng) {} #[cfg(not(stage0))] -static tls_rng_state: local_data::Key<@@mut IsaacRng> = &[]; +static tls_rng_state: local_data::Key<@@mut IsaacRng> = &local_data::Key; /** * Gives back a lazily initialized task-local random number generator, diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 0fd8c5c03d3..17d0d59660f 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -348,10 +348,10 @@ mod test { fn tls() { use local_data; do run_in_newsched_task() { - static key: local_data::Key<@~str> = &[]; + static key: local_data::Key<@~str> = &local_data::Key; local_data::set(key, @~"data"); assert!(*local_data::get(key, |k| k.map(|&k| *k)).get() == ~"data"); - static key2: local_data::Key<@~str> = &[]; + static key2: local_data::Key<@~str> = &local_data::Key; local_data::set(key2, @~"data"); assert!(*local_data::get(key2, |k| k.map(|&k| *k)).get() == ~"data"); } diff --git a/src/libstd/std.rs b/src/libstd/std.rs index 8f86216d240..03b895b3860 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -222,6 +222,7 @@ mod std { pub use condition; pub use option; pub use kinds; + pub use local_data; pub use sys; pub use pipes; pub use unstable; diff --git a/src/libstd/task/local_data_priv.rs b/src/libstd/task/local_data_priv.rs index 1a2141e996a..d46e5707f14 100644 --- a/src/libstd/task/local_data_priv.rs +++ b/src/libstd/task/local_data_priv.rs @@ -17,7 +17,6 @@ use prelude::*; use ptr; use task::rt; use util; -use vec; use super::rt::rust_task; use rt::task::{Task, LocalStorage}; @@ -143,7 +142,7 @@ unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap { } fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void { - return vec::raw::to_ptr(key) as *libc::c_void; + unsafe { cast::transmute(key) } } pub unsafe fn local_pop<T: 'static>(handle: Handle, diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 27cb1c2c100..206d19e175f 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -80,6 +80,7 @@ use cell::Cell; use container::MutableMap; use comm::{Chan, GenericChan}; use hashmap::HashSet; +use local_data; use task::local_data_priv::{local_get, local_set, OldHandle}; use task::rt::rust_task; use task::rt; @@ -465,10 +466,14 @@ fn kill_taskgroup(state: TaskGroupInner, me: *rust_task, is_main: bool) { // FIXME (#2912): Work around core-vs-coretest function duplication. Can't use // a proper closure because the #[test]s won't understand. Have to fake it. -macro_rules! taskgroup_key ( - // Use a "code pointer" value that will never be a real code pointer. - () => (cast::transmute((-2 as uint, 0u))) -) +#[cfg(not(stage0))] +fn taskgroup_key() -> local_data::Key<@@mut TCB> { + unsafe { cast::transmute(-2) } +} +#[cfg(stage0)] +fn taskgroup_key() -> local_data::Key<@@mut TCB> { + unsafe { cast::transmute((-2, 0)) } +} fn gen_child_taskgroup(linked: bool, supervised: bool) -> (TaskGroupArc, AncestorList, bool) { @@ -478,7 +483,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) * Step 1. Get spawner's taskgroup info. *##################################################################*/ let spawner_group: @@mut TCB = - do local_get(OldHandle(spawner), taskgroup_key!()) |group| { + do local_get(OldHandle(spawner), taskgroup_key()) |group| { match group { None => { // Main task, doing first spawn ever. Lazily initialise @@ -495,7 +500,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) AncestorList(None), true, None); - local_set(OldHandle(spawner), taskgroup_key!(), group); + local_set(OldHandle(spawner), taskgroup_key(), group); group } Some(&group) => group @@ -688,7 +693,7 @@ fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { is_main, notifier); unsafe { - local_set(OldHandle(child), taskgroup_key!(), group); + local_set(OldHandle(child), taskgroup_key(), group); } // Run the child's body. |
