diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 096770842573..9bb13af5a822 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -219,7 +219,9 @@ mod send_map; // Concurrency mod comm; -mod task; +mod task { + mod local_data; +} mod future; mod pipes; diff --git a/src/libcore/task.rs b/src/libcore/task.rs index fbac23289647..788802a5fe9e 100644 --- a/src/libcore/task.rs +++ b/src/libcore/task.rs @@ -66,11 +66,7 @@ export get_task; export unkillable, rekillable; export atomically; -export local_data_key; -export local_data_pop; -export local_data_get; -export local_data_set; -export local_data_modify; +export local_data; export SingleThreaded; export ThreadPerCore; @@ -1213,7 +1209,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) /*######################################################################* * Step 1. Get spawner's taskgroup info. *######################################################################*/ - let spawner_group = match unsafe { local_get(spawner, + let spawner_group = match unsafe { local_data::local_get(spawner, taskgroup_key!()) } { None => { // Main task, doing first spawn ever. Lazily initialise here. @@ -1225,7 +1221,9 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) // Main task/group has no ancestors, no notifier, etc. let group = @TCB(spawner, move tasks, AncestorList(None), true, None); - unsafe { local_set(spawner, taskgroup_key!(), group); } + unsafe { + local_data::local_set(spawner, taskgroup_key!(), group); + } group } Some(group) => group @@ -1352,7 +1350,9 @@ fn spawn_raw(+opts: TaskOpts, +f: fn~()) { if enlist_many(child, &child_arc, &mut ancestors) { let group = @TCB(child, move child_arc, move ancestors, is_main, move notifier); - unsafe { local_set(child, taskgroup_key!(), group); } + unsafe { + local_data::local_set(child, taskgroup_key!(), group); + } // Run the child's body. f(); @@ -1429,230 +1429,6 @@ fn spawn_raw(+opts: TaskOpts, +f: fn~()) { } } -/* ************************************************************************** - * Task local data management - * - * Allows storing boxes with arbitrary types inside, to be accessed anywhere - * within a task, keyed by a pointer to a global finaliser function. Useful - * for task-spawning metadata (tracking linked failure state), dynamic - * variables, and interfacing with foreign code with bad callback interfaces. - * - * To use, declare a monomorphic global function at the type to store, and use - * it as the 'key' when accessing. See the 'tls' tests below for examples. - * - * Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation magic. - ****************************************************************************/ - -/** - * 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. - * - * 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. - */ -type LocalDataKey = &fn(+@T); - -trait LocalData { } -impl @T: LocalData { } - -impl LocalData: Eq { - pure fn eq(&&other: LocalData) -> bool unsafe { - let ptr_a: (uint, uint) = cast::reinterpret_cast(&self); - let ptr_b: (uint, uint) = cast::reinterpret_cast(&other); - return ptr_a == ptr_b; - } - pure fn ne(&&other: LocalData) -> bool { !self.eq(other) } -} - -// We use dvec because it's the best data structure in core. If TLS is used -// heavily in future, this could be made more efficient with a proper map. -type TaskLocalElement = (*libc::c_void, *libc::c_void, LocalData); -// Has to be a pointer at outermost layer; the foreign call returns void *. -type TaskLocalMap = @dvec::DVec>; - -extern fn cleanup_task_local_map(map_ptr: *libc::c_void) unsafe { - assert !map_ptr.is_null(); - // Get and keep the single reference that was created at the beginning. - let _map: TaskLocalMap = cast::reinterpret_cast(&map_ptr); - // All local_data will be destroyed along with the map. -} - -// Gets the map from the runtime. Lazily initialises if not done so already. -unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { - - // Relies on the runtime initialising the pointer to null. - // NOTE: The map's box lives in TLS invisibly referenced once. Each time - // we retrieve it for get/set, we make another reference, which get/set - // drop when they finish. No "re-storing after modifying" is needed. - let map_ptr = rustrt::rust_get_task_local_data(task); - if map_ptr.is_null() { - let map: TaskLocalMap = @dvec::DVec(); - // Use reinterpret_cast -- transmute would take map away from us also. - rustrt::rust_set_task_local_data( - task, cast::reinterpret_cast(&map)); - rustrt::rust_task_local_data_atexit(task, cleanup_task_local_map); - // Also need to reference it an extra time to keep it for now. - cast::bump_box_refcount(map); - map - } else { - let map = cast::transmute(move map_ptr); - cast::bump_box_refcount(map); - map - } -} - -unsafe fn key_to_key_value( - key: LocalDataKey) -> *libc::c_void { - - // Keys are closures, which are (fnptr,envptr) pairs. Use fnptr. - // Use reintepret_cast -- transmute would leak (forget) the closure. - let pair: (*libc::c_void, *libc::c_void) = cast::reinterpret_cast(&key); - pair.first() -} - -// If returning Some(..), returns with @T with the map's reference. Careful! -unsafe fn local_data_lookup( - map: TaskLocalMap, key: LocalDataKey) - -> Option<(uint, *libc::c_void)> { - - let key_value = key_to_key_value(key); - let map_pos = (*map).position(|entry| - match entry { - Some((k,_,_)) => k == key_value, - None => false - } - ); - do map_pos.map |index| { - // .get() is guaranteed because of "None { false }" above. - let (_, data_ptr, _) = (*map)[index].get(); - (index, data_ptr) - } -} - -unsafe fn local_get_helper( - task: *rust_task, key: LocalDataKey, - do_pop: bool) -> Option<@T> { - - let map = get_task_local_map(task); - // Interpreturn our findings from the map - do local_data_lookup(map, key).map |result| { - // A reference count magically appears on 'data' out of thin air. It - // was referenced in the local_data box, though, not here, so before - // overwriting the local_data_box we need to give an extra reference. - // We must also give an extra reference when not removing. - let (index, data_ptr) = result; - let data: @T = cast::transmute(move data_ptr); - cast::bump_box_refcount(data); - if do_pop { - (*map).set_elt(index, None); - } - data - } -} - -unsafe fn local_pop( - task: *rust_task, - key: LocalDataKey) -> Option<@T> { - - local_get_helper(task, key, true) -} - -unsafe fn local_get( - task: *rust_task, - key: LocalDataKey) -> Option<@T> { - - local_get_helper(task, key, false) -} - -unsafe fn local_set( - task: *rust_task, key: LocalDataKey, +data: @T) { - - let map = get_task_local_map(task); - // Store key+data as *voids. Data is invisibly referenced once; key isn't. - let keyval = key_to_key_value(key); - // We keep the data in two forms: one as an unsafe pointer, so we can get - // it back by casting; another in an existential box, so the reference we - // own on it can be dropped when the box is destroyed. The unsafe pointer - // does not have a reference associated with it, so it may become invalid - // when the box is destroyed. - let data_ptr = cast::reinterpret_cast(&data); - let data_box = data as LocalData; - // Construct new entry to store in the map. - let new_entry = Some((keyval, data_ptr, data_box)); - // Find a place to put it. - match local_data_lookup(map, key) { - Some((index, _old_data_ptr)) => { - // Key already had a value set, _old_data_ptr, whose reference - // will get dropped when the local_data box is overwritten. - (*map).set_elt(index, new_entry); - } - None => { - // Find an empty slot. If not, grow the vector. - match (*map).position(|x| x.is_none()) { - Some(empty_index) => (*map).set_elt(empty_index, new_entry), - None => (*map).push(new_entry) - } - } - } -} - -unsafe fn local_modify( - task: *rust_task, key: LocalDataKey, - modify_fn: fn(Option<@T>) -> Option<@T>) { - - // Could be more efficient by doing the lookup work, but this is easy. - let newdata = modify_fn(local_pop(task, key)); - if newdata.is_some() { - local_set(task, key, option::unwrap(move newdata)); - } -} - -/* Exported interface for task-local data (plus local_data_key above). */ -/** - * Remove a task-local data value from the table, returning the - * reference that was originally created to insert it. - */ -unsafe fn local_data_pop( - key: LocalDataKey) -> Option<@T> { - - local_pop(rustrt::rust_get_task(), key) -} -/** - * Retrieve a task-local data value. It will also be kept alive in the - * table until explicitly removed. - */ -unsafe fn local_data_get( - key: LocalDataKey) -> Option<@T> { - - local_get(rustrt::rust_get_task(), key) -} -/** - * Store a value in task-local data. If this key already has a value, - * that value is overwritten (and its destructor is run). - */ -unsafe fn local_data_set( - key: LocalDataKey, +data: @T) { - - local_set(rustrt::rust_get_task(), key, data) -} -/** - * Modify a task-local data value. If the function returns 'None', the - * data is removed (and its reference dropped). - */ -unsafe fn local_data_modify( - key: LocalDataKey, - modify_fn: fn(Option<@T>) -> Option<@T>) { - - local_modify(rustrt::rust_get_task(), key, modify_fn) -} - extern mod rustrt { #[rust_stack] fn rust_task_yield(task: *rust_task) -> bool; @@ -2317,117 +2093,6 @@ fn test_child_doesnt_ref_parent() { task::spawn(child_no(0)); } -#[test] -fn test_tls_multitask() unsafe { - fn my_key(+_x: @~str) { } - local_data_set(my_key, @~"parent data"); - do task::spawn unsafe { - assert local_data_get(my_key).is_none(); // TLS shouldn't carry over. - local_data_set(my_key, @~"child data"); - assert *(local_data_get(my_key).get()) == ~"child data"; - // should be cleaned up for us - } - // Must work multiple times - assert *(local_data_get(my_key).get()) == ~"parent data"; - assert *(local_data_get(my_key).get()) == ~"parent data"; - assert *(local_data_get(my_key).get()) == ~"parent data"; -} - -#[test] -fn test_tls_overwrite() unsafe { - fn my_key(+_x: @~str) { } - local_data_set(my_key, @~"first data"); - local_data_set(my_key, @~"next data"); // Shouldn't leak. - assert *(local_data_get(my_key).get()) == ~"next data"; -} - -#[test] -fn test_tls_pop() unsafe { - fn my_key(+_x: @~str) { } - local_data_set(my_key, @~"weasel"); - assert *(local_data_pop(my_key).get()) == ~"weasel"; - // Pop must remove the data from the map. - assert local_data_pop(my_key).is_none(); -} - -#[test] -fn test_tls_modify() unsafe { - fn my_key(+_x: @~str) { } - local_data_modify(my_key, |data| { - match data { - Some(@val) => fail ~"unwelcome value: " + val, - None => Some(@~"first data") - } - }); - local_data_modify(my_key, |data| { - match data { - Some(@~"first data") => Some(@~"next data"), - Some(@val) => fail ~"wrong value: " + val, - None => fail ~"missing value" - } - }); - assert *(local_data_pop(my_key).get()) == ~"next data"; -} - -#[test] -fn test_tls_crust_automorestack_memorial_bug() unsafe { - // This might result in a stack-canary clobber if the runtime fails to set - // sp_limit to 0 when calling the cleanup extern - it might automatically - // jump over to the rust stack, which causes next_c_sp 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. - fn my_key(+_x: @~str) { } - do task::spawn { - unsafe { local_data_set(my_key, @~"hax"); } - } -} - -#[test] -fn test_tls_multiple_types() unsafe { - fn str_key(+_x: @~str) { } - fn box_key(+_x: @@()) { } - fn int_key(+_x: @int) { } - do task::spawn unsafe { - local_data_set(str_key, @~"string data"); - local_data_set(box_key, @@()); - local_data_set(int_key, @42); - } -} - -#[test] -fn test_tls_overwrite_multiple_types() { - fn str_key(+_x: @~str) { } - fn box_key(+_x: @@()) { } - fn int_key(+_x: @int) { } - do task::spawn unsafe { - local_data_set(str_key, @~"string data"); - local_data_set(int_key, @42); - // This could cause a segfault if overwriting-destruction is done with - // the crazy polymorphic transmute rather than the provided finaliser. - local_data_set(int_key, @31337); - } -} - -#[test] -#[should_fail] -#[ignore(cfg(windows))] -fn test_tls_cleanup_on_failure() unsafe { - fn str_key(+_x: @~str) { } - fn box_key(+_x: @@()) { } - fn int_key(+_x: @int) { } - local_data_set(str_key, @~"parent data"); - local_data_set(box_key, @@()); - do task::spawn unsafe { // spawn_linked - local_data_set(str_key, @~"string data"); - local_data_set(box_key, @@()); - local_data_set(int_key, @42); - fail; - } - // Not quite nondeterministic. - local_data_set(int_key, @31337); - fail; -} - #[test] fn test_sched_thread_per_core() { let (chan, port) = pipes::stream(); diff --git a/src/libcore/task/local_data.rs b/src/libcore/task/local_data.rs new file mode 100644 index 000000000000..4fbf0475c0a5 --- /dev/null +++ b/src/libcore/task/local_data.rs @@ -0,0 +1,346 @@ +/*! + +Task local data management + +Allows storing boxes with arbitrary types inside, to be accessed anywhere +within a task, keyed by a pointer to a global finaliser function. Useful +for task-spawning metadata (tracking linked failure state), dynamic +variables, and interfacing with foreign code with bad callback interfaces. + +To use, declare a monomorphic global function at the type to store, and use +it as the 'key' when accessing. See the 'tls' tests below for examples. + +Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation magic. + +*/ + +export local_data_key; +export local_data_pop; +export local_data_get; +export local_data_set; +export local_data_modify; + +// XXX: These shouldn't be exported but they are used by task.rs +export local_get; +export local_set; + +/** + * 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. + * + * 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. + */ +type LocalDataKey = &fn(+@T); + +trait LocalData { } +impl @T: LocalData { } + +impl LocalData: Eq { + pure fn eq(&&other: LocalData) -> bool unsafe { + let ptr_a: (uint, uint) = cast::reinterpret_cast(&self); + let ptr_b: (uint, uint) = cast::reinterpret_cast(&other); + return ptr_a == ptr_b; + } + pure fn ne(&&other: LocalData) -> bool { !self.eq(other) } +} + +// We use dvec because it's the best data structure in core. If TLS is used +// heavily in future, this could be made more efficient with a proper map. +type TaskLocalElement = (*libc::c_void, *libc::c_void, LocalData); +// Has to be a pointer at outermost layer; the foreign call returns void *. +type TaskLocalMap = @dvec::DVec>; + +extern fn cleanup_task_local_map(map_ptr: *libc::c_void) unsafe { + assert !map_ptr.is_null(); + // Get and keep the single reference that was created at the beginning. + let _map: TaskLocalMap = cast::reinterpret_cast(&map_ptr); + // All local_data will be destroyed along with the map. +} + +// Gets the map from the runtime. Lazily initialises if not done so already. +unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { + + // Relies on the runtime initialising the pointer to null. + // NOTE: The map's box lives in TLS invisibly referenced once. Each time + // we retrieve it for get/set, we make another reference, which get/set + // drop when they finish. No "re-storing after modifying" is needed. + let map_ptr = rustrt::rust_get_task_local_data(task); + if map_ptr.is_null() { + let map: TaskLocalMap = @dvec::DVec(); + // Use reinterpret_cast -- transmute would take map away from us also. + rustrt::rust_set_task_local_data( + task, cast::reinterpret_cast(&map)); + rustrt::rust_task_local_data_atexit(task, cleanup_task_local_map); + // Also need to reference it an extra time to keep it for now. + cast::bump_box_refcount(map); + map + } else { + let map = cast::transmute(move map_ptr); + cast::bump_box_refcount(map); + map + } +} + +unsafe fn key_to_key_value( + key: LocalDataKey) -> *libc::c_void { + + // Keys are closures, which are (fnptr,envptr) pairs. Use fnptr. + // Use reintepret_cast -- transmute would leak (forget) the closure. + let pair: (*libc::c_void, *libc::c_void) = cast::reinterpret_cast(&key); + pair.first() +} + +// If returning Some(..), returns with @T with the map's reference. Careful! +unsafe fn local_data_lookup( + map: TaskLocalMap, key: LocalDataKey) + -> Option<(uint, *libc::c_void)> { + + let key_value = key_to_key_value(key); + let map_pos = (*map).position(|entry| + match entry { + Some((k,_,_)) => k == key_value, + None => false + } + ); + do map_pos.map |index| { + // .get() is guaranteed because of "None { false }" above. + let (_, data_ptr, _) = (*map)[index].get(); + (index, data_ptr) + } +} + +unsafe fn local_get_helper( + task: *rust_task, key: LocalDataKey, + do_pop: bool) -> Option<@T> { + + let map = get_task_local_map(task); + // Interpreturn our findings from the map + do local_data_lookup(map, key).map |result| { + // A reference count magically appears on 'data' out of thin air. It + // was referenced in the local_data box, though, not here, so before + // overwriting the local_data_box we need to give an extra reference. + // We must also give an extra reference when not removing. + let (index, data_ptr) = result; + let data: @T = cast::transmute(move data_ptr); + cast::bump_box_refcount(data); + if do_pop { + (*map).set_elt(index, None); + } + data + } +} + +unsafe fn local_pop( + task: *rust_task, + key: LocalDataKey) -> Option<@T> { + + local_get_helper(task, key, true) +} + +unsafe fn local_get( + task: *rust_task, + key: LocalDataKey) -> Option<@T> { + + local_get_helper(task, key, false) +} + +unsafe fn local_set( + task: *rust_task, key: LocalDataKey, +data: @T) { + + let map = get_task_local_map(task); + // Store key+data as *voids. Data is invisibly referenced once; key isn't. + let keyval = key_to_key_value(key); + // We keep the data in two forms: one as an unsafe pointer, so we can get + // it back by casting; another in an existential box, so the reference we + // own on it can be dropped when the box is destroyed. The unsafe pointer + // does not have a reference associated with it, so it may become invalid + // when the box is destroyed. + let data_ptr = cast::reinterpret_cast(&data); + let data_box = data as LocalData; + // Construct new entry to store in the map. + let new_entry = Some((keyval, data_ptr, data_box)); + // Find a place to put it. + match local_data_lookup(map, key) { + Some((index, _old_data_ptr)) => { + // Key already had a value set, _old_data_ptr, whose reference + // will get dropped when the local_data box is overwritten. + (*map).set_elt(index, new_entry); + } + None => { + // Find an empty slot. If not, grow the vector. + match (*map).position(|x| x.is_none()) { + Some(empty_index) => (*map).set_elt(empty_index, new_entry), + None => (*map).push(new_entry) + } + } + } +} + +unsafe fn local_modify( + task: *rust_task, key: LocalDataKey, + modify_fn: fn(Option<@T>) -> Option<@T>) { + + // Could be more efficient by doing the lookup work, but this is easy. + let newdata = modify_fn(local_pop(task, key)); + if newdata.is_some() { + local_set(task, key, option::unwrap(move newdata)); + } +} + +/* Exported interface for task-local data (plus local_data_key above). */ +/** + * Remove a task-local data value from the table, returning the + * reference that was originally created to insert it. + */ +unsafe fn local_data_pop( + key: LocalDataKey) -> Option<@T> { + + local_pop(rustrt::rust_get_task(), key) +} +/** + * Retrieve a task-local data value. It will also be kept alive in the + * table until explicitly removed. + */ +unsafe fn local_data_get( + key: LocalDataKey) -> Option<@T> { + + local_get(rustrt::rust_get_task(), key) +} +/** + * Store a value in task-local data. If this key already has a value, + * that value is overwritten (and its destructor is run). + */ +unsafe fn local_data_set( + key: LocalDataKey, +data: @T) { + + local_set(rustrt::rust_get_task(), key, data) +} +/** + * Modify a task-local data value. If the function returns 'None', the + * data is removed (and its reference dropped). + */ +unsafe fn local_data_modify( + key: LocalDataKey, + modify_fn: fn(Option<@T>) -> Option<@T>) { + + local_modify(rustrt::rust_get_task(), key, modify_fn) +} + +#[test] +fn test_tls_multitask() unsafe { + fn my_key(+_x: @~str) { } + local_data_set(my_key, @~"parent data"); + do task::spawn unsafe { + assert local_data_get(my_key).is_none(); // TLS shouldn't carry over. + local_data_set(my_key, @~"child data"); + assert *(local_data_get(my_key).get()) == ~"child data"; + // should be cleaned up for us + } + // Must work multiple times + assert *(local_data_get(my_key).get()) == ~"parent data"; + assert *(local_data_get(my_key).get()) == ~"parent data"; + assert *(local_data_get(my_key).get()) == ~"parent data"; +} + +#[test] +fn test_tls_overwrite() unsafe { + fn my_key(+_x: @~str) { } + local_data_set(my_key, @~"first data"); + local_data_set(my_key, @~"next data"); // Shouldn't leak. + assert *(local_data_get(my_key).get()) == ~"next data"; +} + +#[test] +fn test_tls_pop() unsafe { + fn my_key(+_x: @~str) { } + local_data_set(my_key, @~"weasel"); + assert *(local_data_pop(my_key).get()) == ~"weasel"; + // Pop must remove the data from the map. + assert local_data_pop(my_key).is_none(); +} + +#[test] +fn test_tls_modify() unsafe { + fn my_key(+_x: @~str) { } + local_data_modify(my_key, |data| { + match data { + Some(@val) => fail ~"unwelcome value: " + val, + None => Some(@~"first data") + } + }); + local_data_modify(my_key, |data| { + match data { + Some(@~"first data") => Some(@~"next data"), + Some(@val) => fail ~"wrong value: " + val, + None => fail ~"missing value" + } + }); + assert *(local_data_pop(my_key).get()) == ~"next data"; +} + +#[test] +fn test_tls_crust_automorestack_memorial_bug() unsafe { + // This might result in a stack-canary clobber if the runtime fails to set + // sp_limit to 0 when calling the cleanup extern - it might automatically + // jump over to the rust stack, which causes next_c_sp 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. + fn my_key(+_x: @~str) { } + do task::spawn { + unsafe { local_data_set(my_key, @~"hax"); } + } +} + +#[test] +fn test_tls_multiple_types() unsafe { + fn str_key(+_x: @~str) { } + fn box_key(+_x: @@()) { } + fn int_key(+_x: @int) { } + do task::spawn unsafe { + local_data_set(str_key, @~"string data"); + local_data_set(box_key, @@()); + local_data_set(int_key, @42); + } +} + +#[test] +fn test_tls_overwrite_multiple_types() { + fn str_key(+_x: @~str) { } + fn box_key(+_x: @@()) { } + fn int_key(+_x: @int) { } + do task::spawn unsafe { + local_data_set(str_key, @~"string data"); + local_data_set(int_key, @42); + // This could cause a segfault if overwriting-destruction is done with + // the crazy polymorphic transmute rather than the provided finaliser. + local_data_set(int_key, @31337); + } +} + +#[test] +#[should_fail] +#[ignore(cfg(windows))] +fn test_tls_cleanup_on_failure() unsafe { + fn str_key(+_x: @~str) { } + fn box_key(+_x: @@()) { } + fn int_key(+_x: @int) { } + local_data_set(str_key, @~"parent data"); + local_data_set(box_key, @@()); + do task::spawn unsafe { // spawn_linked + local_data_set(str_key, @~"string data"); + local_data_set(box_key, @@()); + local_data_set(int_key, @42); + fail; + } + // Not quite nondeterministic. + local_data_set(int_key, @31337); + fail; +} diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 15b025420db3..f7aa0f7555ee 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -39,7 +39,9 @@ macro_rules! interner_key ( ) fn serialize_ident(s: S, i: ident) { - let intr = match unsafe{task::local_data_get(interner_key!())}{ + let intr = match unsafe{ + task::local_data::local_data_get(interner_key!()) + } { None => fail ~"serialization: TLS interner not set up", Some(intr) => intr }; @@ -47,7 +49,9 @@ fn serialize_ident(s: S, i: ident) { s.emit_str(*(*intr).get(i)); } fn deserialize_ident(d: D) -> ident { - let intr = match unsafe{task::local_data_get(interner_key!())}{ + let intr = match unsafe{ + task::local_data::local_data_get(interner_key!()) + } { None => fail ~"deserialization: TLS interner not set up", Some(intr) => intr }; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 570915e657fb..5629907ff144 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -348,8 +348,12 @@ fn mk_ident_interner() -> ident_interner { let rv = interner::mk_prefill::<@~str>(init_vec); /* having multiple interners will just confuse the serializer */ - unsafe{ assert task::local_data_get(interner_key!()).is_none() }; - unsafe{ task::local_data_set(interner_key!(), @rv) }; + unsafe { + assert task::local_data::local_data_get(interner_key!()).is_none() + }; + unsafe { + task::local_data::local_data_set(interner_key!(), @rv) + }; rv } diff --git a/src/rustdoc/extract.rs b/src/rustdoc/extract.rs index c35f59864f6d..ba617b7cce61 100644 --- a/src/rustdoc/extract.rs +++ b/src/rustdoc/extract.rs @@ -2,10 +2,10 @@ use syntax::ast; use doc::ItemUtils; +use task::local_data::local_data_get; export from_srv, extract, to_str, interner; - /* can't import macros yet, so this is copied from token.rs. See its comment * there. */ macro_rules! interner_key ( @@ -16,13 +16,13 @@ macro_rules! interner_key ( // Hack; rather than thread an interner through everywhere, rely on // thread-local data fn to_str(id: ast::ident) -> ~str { - let intr = unsafe{ task::local_data_get(interner_key!()) }; + let intr = unsafe{ local_data_get(interner_key!()) }; return *(*intr.get()).get(id); } fn interner() -> syntax::parse::token::ident_interner { - return *(unsafe{ task::local_data_get(interner_key!()) }).get(); + return *(unsafe{ local_data_get(interner_key!()) }).get(); } fn from_srv(