/// Bind to the main completion callback
pub unsafe fn complete(cb: CompletionCb) {
- local_data::local_data_set(complete_key, @(cb));
+ local_data::set(complete_key, @(cb));
extern fn callback(line: *c_char, completions: *()) {
unsafe {
- let cb = *local_data::local_data_get(complete_key)
+ let cb = *local_data::get(complete_key)
.get();
do cb(str::raw::from_c_str(line)) |suggestion| {
#[unsafe_destructor]
impl<'self> Drop for LVal<'self> {
fn drop(&self) {
- let x = unsafe { local_data::local_data_get(self.key) };
+ let x = unsafe { local_data::get(self.key) };
match x {
Some(@y) => {
unsafe {
- local_data::local_data_set(self.key, @(y+1));
+ local_data::set(self.key, @(y+1));
}
}
_ => fail!("Expected key to work"),
pub fn with_insn_ctxt(blk: &fn(&[&'static str])) {
unsafe {
- let opt = local_data::local_data_get(task_local_insn_key);
+ let opt = local_data::get(task_local_insn_key);
if opt.is_some() {
blk(*opt.unwrap());
}
pub fn init_insn_ctxt() {
unsafe {
- local_data::local_data_set(task_local_insn_key, @~[]);
+ local_data::set(task_local_insn_key, @~[]);
}
}
impl Drop for _InsnCtxt {
fn drop(&self) {
unsafe {
- do local_data::local_data_modify(task_local_insn_key) |c| {
+ do local_data::modify(task_local_insn_key) |c| {
do c.map_consume |ctx| {
let mut ctx = copy *ctx;
ctx.pop();
pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
debug!("new InsnCtxt: %s", s);
unsafe {
- do local_data::local_data_modify(task_local_insn_key) |c| {
+ do local_data::modify(task_local_insn_key) |c| {
do c.map_consume |ctx| {
let mut ctx = copy *ctx;
ctx.push(s);
fn task_local_llcx_key(_v: @ContextRef) {}
pub fn task_llcx() -> ContextRef {
- let opt = unsafe { local_data::local_data_get(task_local_llcx_key) };
+ let opt = unsafe { local_data::get(task_local_llcx_key) };
*opt.expect("task-local LLVMContextRef wasn't ever set!")
}
unsafe fn set_task_llcx(c: ContextRef) {
- local_data::local_data_set(task_local_llcx_key, @c);
+ local_data::set(task_local_llcx_key, @c);
}
unsafe fn unset_task_llcx() {
- local_data::local_data_pop(task_local_llcx_key);
+ local_data::pop(task_local_llcx_key);
}
let key = ::std::sys::Closure{ code: %? as *(),
env: ::std::ptr::null() };
let key = ::std::cast::transmute(key);
- *::std::local_data::local_data_get(key).unwrap()
+ *::std::local_data::get(key).unwrap()
};\n", key.code as uint));
// Using this __tls_map handle, deserialize each variable binding that
map.insert(copy *name, @copy value.data);
}
unsafe {
- local_data::local_data_set(tls_key, @map);
+ local_data::set(tls_key, @map);
}
}
/// it updates this cache with the new values of each local variable.
pub fn consume_cache(&mut self) {
let map = unsafe {
- local_data::local_data_pop(tls_key).expect("tls is empty")
+ local_data::pop(tls_key).expect("tls is empty")
};
do map.consume |name, value| {
match self.local_vars.find_mut(&name) {
#[allow(missing_doc)];
-use local_data::{local_data_pop, local_data_set};
use local_data;
use prelude::*;
pub struct Condition<'self, T, U> {
name: &'static str,
- key: local_data::LocalDataKey<'self, @Handler<T, U>>
+ key: local_data::Key<'self, @Handler<T, U>>
}
impl<'self, T, U> Condition<'self, T, U> {
pub fn trap(&'self self, h: &'self fn(T) -> U) -> Trap<'self, T, U> {
unsafe {
let p : *RustClosure = ::cast::transmute(&h);
- let prev = local_data::local_data_get(self.key);
+ let prev = local_data::get(self.key);
let h = @Handler { handle: *p, prev: prev };
Trap { cond: self, handler: h }
}
pub fn raise_default(&self, t: T, default: &fn() -> U) -> U {
unsafe {
- match local_data_pop(self.key) {
+ match local_data::pop(self.key) {
None => {
debug!("Condition.raise: found no handler");
default()
debug!("Condition.raise: found handler");
match handler.prev {
None => {}
- Some(hp) => local_data_set(self.key, hp)
+ 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);
+ local_data::set(self.key, handler);
u
}
}
unsafe {
let _g = Guard { cond: self.cond };
debug!("Trap: pushing handler to TLS");
- local_data_set(self.cond.key, self.handler);
+ local_data::set(self.cond.key, self.handler);
inner()
}
}
fn drop(&self) {
unsafe {
debug!("Guard: popping handler from TLS");
- let curr = local_data_pop(self.cond.key);
+ let curr = local_data::pop(self.cond.key);
match curr {
None => {}
Some(h) => match h.prev {
None => {}
- Some(hp) => local_data_set(self.cond.key, hp)
+ Some(hp) => local_data::set(self.cond.key, hp)
}
}
}
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 dynamic variables, singletons, and interfacing
-with foreign code with bad callback interfaces.
+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 dynamic
+variables, singletons, 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.
+To use, declare a monomorphic (no type parameters) global function at the type
+to store, and use it as the 'key' when accessing.
+
+~~~{.rust}
+use std::local_data;
+
+fn key_int(_: @int) {}
+fn key_vector(_: @~[int]) {}
+
+unsafe {
+ local_data::set(key_int, @3);
+ assert!(local_data::get(key_int) == Some(@3));
+
+ local_data::set(key_vector, @~[3]);
+ assert!(local_data::get(key_vector).unwrap()[0] == 3);
+}
+~~~
Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
magic.
*
* These two cases aside, the interface is safe.
*/
-pub type LocalDataKey<'self,T> = &'self fn:Copy(v: T);
+pub type Key<'self,T> = &'self fn:Copy(v: T);
/**
* Remove a task-local data value from the table, returning the
* reference that was originally created to insert it.
*/
-pub unsafe fn local_data_pop<T: 'static>(key: LocalDataKey<T>) -> Option<T> {
+pub unsafe fn pop<T: 'static>(key: Key<T>) -> Option<T> {
local_pop(Handle::new(), key)
}
/**
* Retrieve a task-local data value. It will also be kept alive in the
* table until explicitly removed.
*/
-pub unsafe fn local_data_get<T: 'static>(key: LocalDataKey<@T>) -> Option<@T> {
+pub unsafe fn get<T: 'static>(key: Key<@T>) -> Option<@T> {
local_get(Handle::new(), key, |loc| loc.map(|&x| *x))
}
/**
* Store a value in task-local data. If this key already has a value,
* that value is overwritten (and its destructor is run).
*/
-pub unsafe fn local_data_set<T: 'static>(key: LocalDataKey<@T>, data: @T) {
+pub unsafe fn set<T: 'static>(key: Key<@T>, data: @T) {
local_set(Handle::new(), key, data)
}
/**
* Modify a task-local data value. If the function returns 'None', the
* data is removed (and its reference dropped).
*/
-pub unsafe fn local_data_modify<T: 'static>(
- key: LocalDataKey<@T>,
- modify_fn: &fn(Option<@T>) -> Option<@T>) {
-
- let cur = local_data_pop(key);
- match modify_fn(cur) {
- Some(next) => { local_data_set(key, next); }
+pub unsafe fn modify<T: 'static>(key: Key<@T>,
+ f: &fn(Option<@T>) -> Option<@T>) {
+ match f(pop(key)) {
+ Some(next) => { set(key, next); }
None => {}
}
}
fn test_tls_multitask() {
unsafe {
fn my_key(_x: @~str) { }
- local_data_set(my_key, @~"parent data");
+ set(my_key, @~"parent data");
do task::spawn {
// TLS shouldn't carry over.
- assert!(local_data_get(my_key).is_none());
- local_data_set(my_key, @~"child data");
- assert!(*(local_data_get(my_key).get()) ==
+ assert!(get(my_key).is_none());
+ set(my_key, @~"child data");
+ assert!(*(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");
+ assert!(*(get(my_key).get()) == ~"parent data");
+ assert!(*(get(my_key).get()) == ~"parent data");
+ assert!(*(get(my_key).get()) == ~"parent data");
}
}
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");
+ set(my_key, @~"first data");
+ set(my_key, @~"next data"); // Shouldn't leak.
+ assert!(*(get(my_key).get()) == ~"next data");
}
}
fn test_tls_pop() {
unsafe {
fn my_key(_x: @~str) { }
- local_data_set(my_key, @~"weasel");
- assert!(*(local_data_pop(my_key).get()) == ~"weasel");
+ set(my_key, @~"weasel");
+ assert!(*(pop(my_key).get()) == ~"weasel");
// Pop must remove the data from the map.
- assert!(local_data_pop(my_key).is_none());
+ assert!(pop(my_key).is_none());
}
}
fn test_tls_modify() {
unsafe {
fn my_key(_x: @~str) { }
- local_data_modify(my_key, |data| {
+ modify(my_key, |data| {
match data {
Some(@ref val) => fail!("unwelcome value: %s", *val),
None => Some(@~"first data")
}
});
- local_data_modify(my_key, |data| {
+ modify(my_key, |data| {
match data {
Some(@~"first data") => Some(@~"next data"),
Some(@ref val) => fail!("wrong value: %s", *val),
None => fail!("missing value")
}
});
- assert!(*(local_data_pop(my_key).get()) == ~"next data");
+ assert!(*(pop(my_key).get()) == ~"next data");
}
}
// a stack smaller than 1 MB.
fn my_key(_x: @~str) { }
do task::spawn {
- unsafe { local_data_set(my_key, @~"hax"); }
+ unsafe { set(my_key, @~"hax"); }
}
}
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);
+ set(str_key, @~"string data");
+ set(box_key, @@());
+ set(int_key, @42);
}
}
}
fn int_key(_x: @int) { }
do task::spawn {
unsafe {
- local_data_set(str_key, @~"string data");
- local_data_set(int_key, @42);
+ set(str_key, @~"string 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);
+ set(int_key, @31337);
}
}
}
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, @@());
+ set(str_key, @~"parent data");
+ set(box_key, @@());
do task::spawn {
// spawn_linked
- local_data_set(str_key, @~"string data");
- local_data_set(box_key, @@());
- local_data_set(int_key, @42);
+ set(str_key, @~"string data");
+ set(box_key, @@());
+ set(int_key, @42);
fail!();
}
// Not quite nondeterministic.
- local_data_set(int_key, @31337);
+ set(int_key, @31337);
fail!();
}
}
unsafe {
fn key(_x: @&'static int) { }
static VALUE: int = 0;
- local_data_set(key, @&VALUE);
+ set(key, @&VALUE);
}
}
/// `os::set_args` function.
pub fn args() -> ~[~str] {
unsafe {
- match local_data::local_data_get(overridden_arg_key) {
+ match local_data::get(overridden_arg_key) {
None => real_args(),
Some(args) => copy args.val
}
pub fn set_args(new_args: ~[~str]) {
unsafe {
let overridden_args = @OverriddenArgs { val: copy new_args };
- local_data::local_data_set(overridden_arg_key, overridden_args);
+ local_data::set(overridden_arg_key, overridden_args);
}
}
pub fn task_rng() -> @mut IsaacRng {
let r : Option<@@mut IsaacRng>;
unsafe {
- r = local_data::local_data_get(tls_rng_state);
+ r = local_data::get(tls_rng_state);
}
match r {
None => {
unsafe {
let rng = @@mut IsaacRng::new_seeded(seed());
- local_data::local_data_set(tls_rng_state, rng);
+ local_data::set(tls_rng_state, rng);
*rng
}
}
use cast;
use libc;
-use local_data::LocalDataKey;
+use local_data;
use managed::raw::BoxRepr;
use prelude::*;
use ptr;
}
}
-unsafe fn key_to_key_value<T: 'static>(key: LocalDataKey<T>) -> *libc::c_void {
+unsafe fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void {
let pair: sys::Closure = cast::transmute(key);
return pair.code as *libc::c_void;
}
}
pub unsafe fn local_pop<T: 'static>(handle: Handle,
- key: LocalDataKey<T>) -> Option<T> {
+ key: local_data::Key<T>) -> Option<T> {
// If you've never seen horrendously unsafe code written in rust before,
// just feel free to look a bit farther...
let map = get_local_map(handle);
}
pub unsafe fn local_get<T: 'static, U>(handle: Handle,
- key: LocalDataKey<T>,
+ key: local_data::Key<T>,
f: &fn(Option<&T>) -> U) -> U {
// This does in theory take multiple mutable loans on the tls map, but the
// references returned are never removed because the map is only increasing
// FIXME(#7673): This shouldn't require '@', it should use '~'
pub unsafe fn local_set<T: 'static>(handle: Handle,
- key: LocalDataKey<@T>,
+ key: local_data::Key<@T>,
data: @T) {
let map = get_local_map(handle);
let keyval = key_to_key_value(key);
let sctable_key = (cast::transmute::<(uint, uint),
&fn:Copy(v: @@mut SCTable)>(
(-4 as uint, 0u)));
- match local_data::local_data_get(sctable_key) {
+ match local_data::get(sctable_key) {
None => {
let new_table = @@mut new_sctable_internal();
- local_data::local_data_set(sctable_key,new_table);
+ local_data::set(sctable_key,new_table);
*new_table
},
Some(intr) => *intr
(cast::transmute::<(uint, uint),
&fn:Copy(v: @@::parse::token::ident_interner)>(
(-3 as uint, 0u)));
- match local_data::local_data_get(key) {
+ match local_data::get(key) {
Some(interner) => *interner,
None => {
let interner = mk_fresh_ident_interner();
- local_data::local_data_set(key, @interner);
+ local_data::set(key, @interner);
interner
}
}