auto merge of #7751 : alexcrichton/rust/finish-tls, r=pcwalton
This changes the interface to `get`, and it also changes the keys to be static slices instead of static functions. This allows the removal of the `unsafe` interface because while functions can monomorphize from different types to the same actual function, static slices cannot do this. From at least what I can tell, we don't need to worry about LLVM coalescing these addresses. If we ever use the `unnamed_addr` it looks like there's cause for worry, but there doesn't appear to be any coalescing atm.
This commit is contained in:
commit
1c35ab322f
26 changed files with 358 additions and 350 deletions
|
@ -66,24 +66,28 @@ 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> = &local_data::Key;
|
||||
#[cfg(stage0)]
|
||||
fn complete_key(_: @CompletionCb) {}
|
||||
|
||||
/// Bind to the main completion callback
|
||||
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: *()) {
|
||||
unsafe {
|
||||
let cb = *local_data::get(complete_key, |k| k.map(|&k| *k))
|
||||
.get();
|
||||
do local_data::get(complete_key) |cb| {
|
||||
let cb = **cb.unwrap();
|
||||
|
||||
do cb(str::raw::from_c_str(line)) |suggestion| {
|
||||
do str::as_c_str(suggestion) |buf| {
|
||||
rustrt::linenoiseAddCompletion(completions, buf);
|
||||
unsafe {
|
||||
do cb(str::raw::from_c_str(line)) |suggestion| {
|
||||
do str::as_c_str(suggestion) |buf| {
|
||||
rustrt::linenoiseAddCompletion(completions, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1195,39 +1195,4 @@ mod big_tests {
|
|||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,6 +105,7 @@ pub mod jit {
|
|||
use metadata::cstore;
|
||||
|
||||
use std::cast;
|
||||
#[cfg(not(stage0))]
|
||||
use std::local_data;
|
||||
use std::unstable::intrinsics;
|
||||
|
||||
|
@ -202,18 +203,19 @@ pub mod jit {
|
|||
|
||||
// The stage1 compiler won't work, but that doesn't really matter. TLS
|
||||
// changed only very recently to allow storage of owned values.
|
||||
fn engine_key(_: ~Engine) {}
|
||||
#[cfg(not(stage0))]
|
||||
static engine_key: local_data::Key<~Engine> = &local_data::Key;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
fn set_engine(engine: ~Engine) {
|
||||
unsafe { local_data::set(engine_key, engine) }
|
||||
local_data::set(engine_key, engine)
|
||||
}
|
||||
#[cfg(stage0)]
|
||||
fn set_engine(_: ~Engine) {}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub fn consume_engine() -> Option<~Engine> {
|
||||
unsafe { local_data::pop(engine_key) }
|
||||
local_data::pop(engine_key)
|
||||
}
|
||||
#[cfg(stage0)]
|
||||
pub fn consume_engine() -> Option<~Engine> { None }
|
||||
|
|
|
@ -209,7 +209,7 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
|
|||
LintSpec {
|
||||
lint: non_uppercase_statics,
|
||||
desc: "static constants should have uppercase identifiers",
|
||||
default: warn
|
||||
default: allow
|
||||
}),
|
||||
|
||||
("managed_heap_memory",
|
||||
|
|
|
@ -87,21 +87,20 @@ use syntax::abi::{X86, X86_64, Arm, Mips};
|
|||
|
||||
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]> = &local_data::Key;
|
||||
#[cfg(stage0)]
|
||||
fn task_local_insn_key(_: @~[&'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));
|
||||
if opt.is_some() {
|
||||
blk(*opt.unwrap());
|
||||
}
|
||||
let opt = local_data::get(task_local_insn_key, |k| k.map(|&k| *k));
|
||||
if opt.is_some() {
|
||||
blk(*opt.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_insn_ctxt() {
|
||||
unsafe {
|
||||
local_data::set(task_local_insn_key, @~[]);
|
||||
}
|
||||
local_data::set(task_local_insn_key, @~[]);
|
||||
}
|
||||
|
||||
pub struct _InsnCtxt { _x: () }
|
||||
|
@ -109,13 +108,11 @@ pub struct _InsnCtxt { _x: () }
|
|||
#[unsafe_destructor]
|
||||
impl Drop for _InsnCtxt {
|
||||
fn drop(&self) {
|
||||
unsafe {
|
||||
do local_data::modify(task_local_insn_key) |c| {
|
||||
do c.map_consume |ctx| {
|
||||
let mut ctx = copy *ctx;
|
||||
ctx.pop();
|
||||
@ctx
|
||||
}
|
||||
do local_data::modify(task_local_insn_key) |c| {
|
||||
do c.map_consume |ctx| {
|
||||
let mut ctx = copy *ctx;
|
||||
ctx.pop();
|
||||
@ctx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,13 +120,11 @@ impl Drop for _InsnCtxt {
|
|||
|
||||
pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
|
||||
debug!("new InsnCtxt: %s", s);
|
||||
unsafe {
|
||||
do local_data::modify(task_local_insn_key) |c| {
|
||||
do c.map_consume |ctx| {
|
||||
let mut ctx = copy *ctx;
|
||||
ctx.push(s);
|
||||
@ctx
|
||||
}
|
||||
do local_data::modify(task_local_insn_key) |c| {
|
||||
do c.map_consume |ctx| {
|
||||
let mut ctx = copy *ctx;
|
||||
ctx.push(s);
|
||||
@ctx
|
||||
}
|
||||
}
|
||||
_InsnCtxt { _x: () }
|
||||
|
@ -1428,7 +1423,7 @@ pub fn with_scope(bcx: block,
|
|||
|
||||
pub fn with_scope_result(bcx: block,
|
||||
opt_node_info: Option<NodeInfo>,
|
||||
name: &str,
|
||||
_name: &str,
|
||||
f: &fn(block) -> Result) -> Result {
|
||||
let _icx = push_ctxt("with_scope_result");
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ fn get_impl_resolutions(bcx: block,
|
|||
impl_id: ast::def_id)
|
||||
-> typeck::vtable_res {
|
||||
if impl_id.crate == ast::local_crate {
|
||||
*bcx.ccx().maps.vtable_map.get(&impl_id.node)
|
||||
bcx.ccx().maps.vtable_map.get_copy(&impl_id.node)
|
||||
} else {
|
||||
// XXX: This is a temporary hack to work around not properly
|
||||
// exporting information about resolutions for impls.
|
||||
|
@ -670,15 +670,13 @@ pub fn trans_call_inner(in_cx: block,
|
|||
None => { assert!(ty::type_is_immediate(bcx.tcx(), ret_ty)) }
|
||||
Some(expr::Ignore) => {
|
||||
// drop the value if it is not being saved.
|
||||
unsafe {
|
||||
if ty::type_needs_drop(bcx.tcx(), ret_ty) {
|
||||
if ty::type_is_immediate(bcx.tcx(), ret_ty) {
|
||||
let llscratchptr = alloc_ty(bcx, ret_ty, "__ret");
|
||||
Store(bcx, llresult, llscratchptr);
|
||||
bcx = glue::drop_ty(bcx, llscratchptr, ret_ty);
|
||||
} else {
|
||||
bcx = glue::drop_ty(bcx, llretslot, ret_ty);
|
||||
}
|
||||
if ty::type_needs_drop(bcx.tcx(), ret_ty) {
|
||||
if ty::type_is_immediate(bcx.tcx(), ret_ty) {
|
||||
let llscratchptr = alloc_ty(bcx, ret_ty, "__ret");
|
||||
Store(bcx, llresult, llscratchptr);
|
||||
bcx = glue::drop_ty(bcx, llscratchptr, ret_ty);
|
||||
} else {
|
||||
bcx = glue::drop_ty(bcx, llretslot, ret_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -232,22 +232,24 @@ impl CrateContext {
|
|||
#[unsafe_destructor]
|
||||
impl Drop for CrateContext {
|
||||
fn drop(&self) {
|
||||
unsafe {
|
||||
unset_task_llcx();
|
||||
}
|
||||
unset_task_llcx();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
fn task_local_llcx_key(_v: @ContextRef) {}
|
||||
#[cfg(not(stage0))]
|
||||
static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key;
|
||||
|
||||
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!")
|
||||
}
|
||||
|
||||
unsafe fn set_task_llcx(c: ContextRef) {
|
||||
fn set_task_llcx(c: ContextRef) {
|
||||
local_data::set(task_local_llcx_key, @c);
|
||||
}
|
||||
|
||||
unsafe fn unset_task_llcx() {
|
||||
fn unset_task_llcx() {
|
||||
local_data::pop(task_local_llcx_key);
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@ pub fn trans_break_cont(bcx: block,
|
|||
// Locate closest loop block, outputting cleanup as we go.
|
||||
let mut unwind = bcx;
|
||||
let mut cur_scope = unwind.scope;
|
||||
let mut target = unwind;
|
||||
let mut target;
|
||||
loop {
|
||||
cur_scope = match cur_scope {
|
||||
Some(@scope_info {
|
||||
|
|
|
@ -3621,25 +3621,29 @@ pub fn trait_method_def_ids(cx: ctxt, id: ast::def_id) -> @~[def_id] {
|
|||
}
|
||||
|
||||
pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> {
|
||||
*do cx.impl_trait_cache.find_or_insert_with(id) |_| {
|
||||
if id.crate == ast::local_crate {
|
||||
debug!("(impl_trait_ref) searching for trait impl %?", id);
|
||||
match cx.items.find(&id.node) {
|
||||
Some(&ast_map::node_item(@ast::item {
|
||||
node: ast::item_impl(_, ref opt_trait, _, _),
|
||||
_},
|
||||
_)) => {
|
||||
match opt_trait {
|
||||
&Some(ref t) => Some(ty::node_id_to_trait_ref(cx, t.ref_id)),
|
||||
&None => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
csearch::get_impl_trait(cx, id)
|
||||
}
|
||||
match cx.impl_trait_cache.find(&id) {
|
||||
Some(&ret) => { return ret; }
|
||||
None => {}
|
||||
}
|
||||
let ret = if id.crate == ast::local_crate {
|
||||
debug!("(impl_trait_ref) searching for trait impl %?", id);
|
||||
match cx.items.find(&id.node) {
|
||||
Some(&ast_map::node_item(@ast::item {
|
||||
node: ast::item_impl(_, ref opt_trait, _, _),
|
||||
_},
|
||||
_)) => {
|
||||
match opt_trait {
|
||||
&Some(ref t) => Some(ty::node_id_to_trait_ref(cx, t.ref_id)),
|
||||
&None => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
csearch::get_impl_trait(cx, id)
|
||||
};
|
||||
cx.impl_trait_cache.insert(id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pub fn ty_to_def_id(ty: t) -> Option<ast::def_id> {
|
||||
|
|
|
@ -303,7 +303,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
|
|||
let tcx = ccx.tcx;
|
||||
let main_t = ty::node_id_to_type(tcx, main_id);
|
||||
match ty::get(main_t).sty {
|
||||
ty::ty_bare_fn(ref fn_ty) => {
|
||||
ty::ty_bare_fn(*) => {
|
||||
match tcx.items.find(&main_id) {
|
||||
Some(&ast_map::node_item(it,_)) => {
|
||||
match it.node {
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
#[crate_type = "lib"];
|
||||
|
||||
#[allow(non_implicitly_copyable_typarams)];
|
||||
#[allow(non_camel_case_types)];
|
||||
#[allow(non_uppercase_statics)];
|
||||
#[deny(deprecated_pattern)];
|
||||
|
||||
extern mod extra;
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
use std::cast;
|
||||
use std::hashmap::HashMap;
|
||||
use std::local_data;
|
||||
use std::sys;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::parse::token;
|
||||
|
@ -58,7 +57,7 @@ struct LocalVariable {
|
|||
}
|
||||
|
||||
type LocalCache = @mut HashMap<~str, @~[u8]>;
|
||||
fn tls_key(_k: LocalCache) {}
|
||||
static tls_key: local_data::Key<LocalCache> = &local_data::Key;
|
||||
|
||||
impl Program {
|
||||
pub fn new() -> Program {
|
||||
|
@ -131,21 +130,16 @@ impl Program {
|
|||
fn main() {
|
||||
");
|
||||
|
||||
let key: sys::Closure = unsafe {
|
||||
let tls_key: &'static fn(LocalCache) = tls_key;
|
||||
cast::transmute(tls_key)
|
||||
};
|
||||
let key: uint= unsafe { cast::transmute(tls_key) };
|
||||
// First, get a handle to the tls map which stores all the local
|
||||
// variables. This works by totally legitimately using the 'code'
|
||||
// pointer of the 'tls_key' function as a uint, and then casting it back
|
||||
// up to a function
|
||||
code.push_str(fmt!("
|
||||
let __tls_map: @mut ::std::hashmap::HashMap<~str, @~[u8]> = unsafe {
|
||||
let key = ::std::sys::Closure{ code: %? as *(),
|
||||
env: ::std::ptr::null() };
|
||||
let key = ::std::cast::transmute(key);
|
||||
let key = ::std::cast::transmute(%u);
|
||||
::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
|
||||
// we know about
|
||||
|
@ -226,18 +220,14 @@ impl Program {
|
|||
for self.local_vars.iter().advance |(name, value)| {
|
||||
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
|
||||
/// task-local cache of local variables. After the program finishes running,
|
||||
/// it updates this cache with the new values of each local variable.
|
||||
pub fn consume_cache(&mut self) {
|
||||
let map = unsafe {
|
||||
local_data::pop(tls_key).expect("tls is empty")
|
||||
};
|
||||
let map = local_data::pop(tls_key).expect("tls is empty");
|
||||
do map.consume |name, value| {
|
||||
match self.local_vars.find_mut(&name) {
|
||||
Some(v) => { v.data = copy *value; }
|
||||
|
|
|
@ -23,13 +23,59 @@ pub struct Handler<T, U> {
|
|||
prev: Option<@Handler<T, U>>,
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub struct Condition<'self, T, U> {
|
||||
name: &'static str,
|
||||
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> {
|
||||
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 {
|
||||
let p : *RustClosure = ::cast::transmute(&h);
|
||||
let prev = local_data::get(self.key, |k| k.map(|&x| *x));
|
||||
|
@ -67,38 +113,45 @@ impl<'self, T, U> Condition<'self, T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
struct Trap<'self, T, U> {
|
||||
cond: &'self Condition<'self, 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> {
|
||||
pub fn in<V>(&self, inner: &'self fn() -> V) -> V {
|
||||
unsafe {
|
||||
let _g = Guard { cond: self.cond };
|
||||
debug!("Trap: pushing handler to TLS");
|
||||
local_data::set(self.cond.key, self.handler);
|
||||
inner()
|
||||
}
|
||||
let _g = Guard { cond: self.cond };
|
||||
debug!("Trap: pushing handler to TLS");
|
||||
local_data::set(self.cond.key, self.handler);
|
||||
inner()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
struct Guard<'self, T, U> {
|
||||
cond: &'self Condition<'self, T, U>
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
struct Guard<'self, T, U> {
|
||||
cond: &'self Condition<T, U>
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<'self, T, U> Drop for Guard<'self, T, U> {
|
||||
fn drop(&self) {
|
||||
unsafe {
|
||||
debug!("Guard: popping handler from TLS");
|
||||
let curr = local_data::pop(self.cond.key);
|
||||
match curr {
|
||||
debug!("Guard: popping handler from TLS");
|
||||
let curr = local_data::pop(self.cond.key);
|
||||
match curr {
|
||||
None => {}
|
||||
Some(h) => match h.prev {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,27 +12,26 @@
|
|||
|
||||
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 arbitrary types inside task-local-storage (TLS), to be accessed
|
||||
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 monomorphic (no type parameters) global function at the type
|
||||
to store, and use it as the 'key' when accessing.
|
||||
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;
|
||||
|
||||
fn key_int(_: @int) {}
|
||||
fn key_vector(_: @~[int]) {}
|
||||
static key_int: local_data::Key<int> = &local_data::Key;
|
||||
static key_vector: local_data::Key<~[int]> = &local_data::Key;
|
||||
|
||||
unsafe {
|
||||
local_data::set(key_int, @3);
|
||||
assert!(local_data::get(key_int) == Some(@3));
|
||||
local_data::set(key_int, 3);
|
||||
local_data::get(key_int, |opt| assert_eq!(opt, Some(&3)));
|
||||
|
||||
local_data::set(key_vector, @~[3]);
|
||||
assert!(local_data::get(key_vector).unwrap()[0] == 3);
|
||||
}
|
||||
local_data::set(key_vector, ~[4]);
|
||||
local_data::get(key_int, |opt| assert_eq!(opt, Some(&~[4])));
|
||||
~~~
|
||||
|
||||
Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
|
||||
|
@ -47,76 +46,77 @@ 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 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.
|
||||
*/
|
||||
#[cfg(stage0)]
|
||||
pub unsafe fn pop<T: 'static>(key: Key<@T>) -> Option<@T> {
|
||||
local_pop(Handle::new(), key)
|
||||
pub fn pop<T: 'static>(key: Key<@T>) -> Option<@T> {
|
||||
unsafe { local_pop(Handle::new(), key) }
|
||||
}
|
||||
/**
|
||||
* Remove a task-local data value from the table, returning the
|
||||
* reference that was originally created to insert it.
|
||||
*/
|
||||
#[cfg(not(stage0))]
|
||||
pub unsafe fn pop<T: 'static>(key: Key<T>) -> Option<T> {
|
||||
local_pop(Handle::new(), key)
|
||||
pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
|
||||
unsafe { local_pop(Handle::new(), key) }
|
||||
}
|
||||
/**
|
||||
* Retrieve a task-local data value. It will also be kept alive in the
|
||||
* table until explicitly removed.
|
||||
*/
|
||||
#[cfg(stage0)]
|
||||
pub unsafe fn get<T: 'static, U>(key: Key<@T>, f: &fn(Option<&@T>) -> U) -> U {
|
||||
local_get(Handle::new(), key, f)
|
||||
pub fn get<T: 'static, U>(key: Key<@T>, f: &fn(Option<&@T>) -> U) -> U {
|
||||
unsafe { local_get(Handle::new(), key, f) }
|
||||
}
|
||||
/**
|
||||
* Retrieve a task-local data value. It will also be kept alive in the
|
||||
* table until explicitly removed.
|
||||
*/
|
||||
#[cfg(not(stage0))]
|
||||
pub unsafe fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
|
||||
local_get(Handle::new(), key, f)
|
||||
pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
|
||||
unsafe { local_get(Handle::new(), key, f) }
|
||||
}
|
||||
/**
|
||||
* Store a value in task-local data. If this key already has a value,
|
||||
* that value is overwritten (and its destructor is run).
|
||||
*/
|
||||
#[cfg(stage0)]
|
||||
pub unsafe fn set<T: 'static>(key: Key<@T>, data: @T) {
|
||||
local_set(Handle::new(), key, data)
|
||||
pub fn set<T: 'static>(key: Key<@T>, data: @T) {
|
||||
unsafe { local_set(Handle::new(), key, data) }
|
||||
}
|
||||
/**
|
||||
* Store a value in task-local data. If this key already has a value,
|
||||
* that value is overwritten (and its destructor is run).
|
||||
*/
|
||||
#[cfg(not(stage0))]
|
||||
pub unsafe fn set<T: 'static>(key: Key<T>, data: T) {
|
||||
local_set(Handle::new(), key, data)
|
||||
pub fn set<T: 'static>(key: Key<T>, data: T) {
|
||||
unsafe { 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).
|
||||
*/
|
||||
#[cfg(stage0)]
|
||||
pub unsafe fn modify<T: 'static>(key: Key<@T>,
|
||||
f: &fn(Option<@T>) -> Option<@T>) {
|
||||
pub fn modify<T: 'static>(key: Key<@T>, f: &fn(Option<@T>) -> Option<@T>) {
|
||||
match f(pop(key)) {
|
||||
Some(next) => { set(key, next); }
|
||||
None => {}
|
||||
|
@ -127,8 +127,7 @@ pub unsafe fn modify<T: 'static>(key: Key<@T>,
|
|||
* data is removed (and its reference dropped).
|
||||
*/
|
||||
#[cfg(not(stage0))]
|
||||
pub unsafe fn modify<T: 'static>(key: Key<T>,
|
||||
f: &fn(Option<T>) -> Option<T>) {
|
||||
pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
|
||||
match f(pop(key)) {
|
||||
Some(next) => { set(key, next); }
|
||||
None => {}
|
||||
|
@ -137,64 +136,56 @@ pub unsafe fn modify<T: 'static>(key: Key<T>,
|
|||
|
||||
#[test]
|
||||
fn test_tls_multitask() {
|
||||
unsafe {
|
||||
fn my_key(_x: @~str) { }
|
||||
set(my_key, @~"parent data");
|
||||
do task::spawn {
|
||||
// TLS shouldn't carry over.
|
||||
assert!(get(my_key, |k| k.map(|&k| *k)).is_none());
|
||||
set(my_key, @~"child data");
|
||||
assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) ==
|
||||
~"child data");
|
||||
// should be cleaned up for us
|
||||
}
|
||||
// Must work multiple times
|
||||
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");
|
||||
static my_key: Key<@~str> = &Key;
|
||||
set(my_key, @~"parent data");
|
||||
do task::spawn {
|
||||
// TLS shouldn't carry over.
|
||||
assert!(get(my_key, |k| k.map(|&k| *k)).is_none());
|
||||
set(my_key, @~"child data");
|
||||
assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) ==
|
||||
~"child data");
|
||||
// should be cleaned up for us
|
||||
}
|
||||
// Must work multiple times
|
||||
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]
|
||||
fn test_tls_overwrite() {
|
||||
unsafe {
|
||||
fn my_key(_x: @~str) { }
|
||||
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");
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tls_pop() {
|
||||
unsafe {
|
||||
fn my_key(_x: @~str) { }
|
||||
set(my_key, @~"weasel");
|
||||
assert!(*(pop(my_key).get()) == ~"weasel");
|
||||
// Pop must remove the data from the map.
|
||||
assert!(pop(my_key).is_none());
|
||||
}
|
||||
static my_key: Key<@~str> = &Key;
|
||||
set(my_key, @~"weasel");
|
||||
assert!(*(pop(my_key).get()) == ~"weasel");
|
||||
// Pop must remove the data from the map.
|
||||
assert!(pop(my_key).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tls_modify() {
|
||||
unsafe {
|
||||
fn my_key(_x: @~str) { }
|
||||
modify(my_key, |data| {
|
||||
match data {
|
||||
Some(@ref val) => fail!("unwelcome value: %s", *val),
|
||||
None => Some(@~"first 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!(*(pop(my_key).get()) == ~"next data");
|
||||
}
|
||||
static my_key: Key<@~str> = &Key;
|
||||
modify(my_key, |data| {
|
||||
match data {
|
||||
Some(@ref val) => fail!("unwelcome value: %s", *val),
|
||||
None => Some(@~"first 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!(*(pop(my_key).get()) == ~"next data");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -205,40 +196,36 @@ 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.
|
||||
fn my_key(_x: @~str) { }
|
||||
static my_key: Key<@~str> = &Key;
|
||||
do task::spawn {
|
||||
unsafe { set(my_key, @~"hax"); }
|
||||
set(my_key, @~"hax");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tls_multiple_types() {
|
||||
fn str_key(_x: @~str) { }
|
||||
fn box_key(_x: @@()) { }
|
||||
fn int_key(_x: @int) { }
|
||||
static str_key: Key<@~str> = &Key;
|
||||
static box_key: Key<@@()> = &Key;
|
||||
static int_key: Key<@int> = &Key;
|
||||
do task::spawn {
|
||||
unsafe {
|
||||
set(str_key, @~"string data");
|
||||
set(box_key, @@());
|
||||
set(int_key, @42);
|
||||
}
|
||||
set(str_key, @~"string data");
|
||||
set(box_key, @@());
|
||||
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) { }
|
||||
static str_key: Key<@~str> = &Key;
|
||||
static box_key: Key<@@()> = &Key;
|
||||
static int_key: Key<@int> = &Key;
|
||||
do task::spawn {
|
||||
unsafe {
|
||||
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.
|
||||
set(int_key, @31337);
|
||||
}
|
||||
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.
|
||||
set(int_key, @31337);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,38 +233,53 @@ fn test_tls_overwrite_multiple_types() {
|
|||
#[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) { }
|
||||
set(str_key, @~"parent data");
|
||||
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 {
|
||||
// spawn_linked
|
||||
set(str_key, @~"string data");
|
||||
set(box_key, @@());
|
||||
do task::spawn {
|
||||
// spawn_linked
|
||||
set(str_key, @~"string data");
|
||||
set(box_key, @@());
|
||||
set(int_key, @42);
|
||||
fail!();
|
||||
}
|
||||
// Not quite nondeterministic.
|
||||
set(int_key, @31337);
|
||||
set(int_key, @42);
|
||||
fail!();
|
||||
}
|
||||
// Not quite nondeterministic.
|
||||
set(int_key, @31337);
|
||||
fail!();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_static_pointer() {
|
||||
unsafe {
|
||||
fn key(_x: @&'static int) { }
|
||||
static VALUE: int = 0;
|
||||
set(key, @&VALUE);
|
||||
}
|
||||
static key: Key<@&'static int> = &Key;
|
||||
static VALUE: int = 0;
|
||||
let v: @&'static int = @&VALUE;
|
||||
set(key, v);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_owned() {
|
||||
unsafe {
|
||||
fn key(_x: ~int) { }
|
||||
set(key, ~1);
|
||||
}
|
||||
static key: Key<~int> = &Key;
|
||||
set(key, ~1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_same_key_type() {
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -1239,7 +1239,10 @@ struct OverriddenArgs {
|
|||
val: ~[~str]
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
fn overridden_arg_key(_v: @OverriddenArgs) {}
|
||||
#[cfg(not(stage0))]
|
||||
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).
|
||||
|
@ -1247,11 +1250,9 @@ fn overridden_arg_key(_v: @OverriddenArgs) {}
|
|||
/// The return value of the function can be changed by invoking the
|
||||
/// `os::set_args` function.
|
||||
pub fn args() -> ~[~str] {
|
||||
unsafe {
|
||||
match local_data::get(overridden_arg_key, |k| k.map(|&k| *k)) {
|
||||
None => real_args(),
|
||||
Some(args) => copy args.val
|
||||
}
|
||||
match local_data::get(overridden_arg_key, |k| k.map(|&k| *k)) {
|
||||
None => real_args(),
|
||||
Some(args) => copy args.val
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1259,10 +1260,8 @@ pub fn args() -> ~[~str] {
|
|||
/// program had when it started. These new arguments are only available to the
|
||||
/// current task via the `os::args` method.
|
||||
pub fn set_args(new_args: ~[~str]) {
|
||||
unsafe {
|
||||
let overridden_args = @OverriddenArgs { val: copy new_args };
|
||||
local_data::set(overridden_arg_key, overridden_args);
|
||||
}
|
||||
let overridden_args = @OverriddenArgs { val: copy new_args };
|
||||
local_data::set(overridden_arg_key, overridden_args);
|
||||
}
|
||||
|
||||
// FIXME #6100 we should really use an internal implementation of this - using
|
||||
|
|
|
@ -851,7 +851,10 @@ pub fn seed() -> ~[u8] {
|
|||
}
|
||||
|
||||
// used to make space in TLS for a random number generator
|
||||
#[cfg(stage0)]
|
||||
fn tls_rng_state(_v: @@mut IsaacRng) {}
|
||||
#[cfg(not(stage0))]
|
||||
static tls_rng_state: local_data::Key<@@mut IsaacRng> = &local_data::Key;
|
||||
|
||||
/**
|
||||
* Gives back a lazily initialized task-local random number generator,
|
||||
|
@ -860,17 +863,12 @@ fn tls_rng_state(_v: @@mut IsaacRng) {}
|
|||
*/
|
||||
#[inline]
|
||||
pub fn task_rng() -> @mut IsaacRng {
|
||||
let r : Option<@@mut IsaacRng>;
|
||||
unsafe {
|
||||
r = local_data::get(tls_rng_state, |k| k.map(|&k| *k));
|
||||
}
|
||||
let r = local_data::get(tls_rng_state, |k| k.map(|&k| *k));
|
||||
match r {
|
||||
None => {
|
||||
unsafe {
|
||||
let rng = @@mut IsaacRng::new_seeded(seed());
|
||||
local_data::set(tls_rng_state, rng);
|
||||
*rng
|
||||
}
|
||||
let rng = @@mut IsaacRng::new_seeded(seed());
|
||||
local_data::set(tls_rng_state, rng);
|
||||
*rng
|
||||
}
|
||||
Some(rng) => *rng
|
||||
}
|
||||
|
|
|
@ -348,14 +348,12 @@ mod test {
|
|||
fn tls() {
|
||||
use local_data;
|
||||
do run_in_newsched_task() {
|
||||
unsafe {
|
||||
fn key(_x: @~str) { }
|
||||
local_data::set(key, @~"data");
|
||||
assert!(*local_data::get(key, |k| k.map(|&k| *k)).get() == ~"data");
|
||||
fn key2(_x: @~str) { }
|
||||
local_data::set(key2, @~"data");
|
||||
assert!(*local_data::get(key2, |k| k.map(|&k| *k)).get() == ~"data");
|
||||
}
|
||||
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> = &local_data::Key;
|
||||
local_data::set(key2, @~"data");
|
||||
assert!(*local_data::get(key2, |k| k.map(|&k| *k)).get() == ~"data");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -15,7 +15,6 @@ use libc;
|
|||
use local_data;
|
||||
use prelude::*;
|
||||
use ptr;
|
||||
use sys;
|
||||
use task::rt;
|
||||
use util;
|
||||
|
||||
|
@ -142,9 +141,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 {
|
||||
let pair: sys::Closure = cast::transmute(key);
|
||||
return pair.code as *libc::c_void;
|
||||
fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void {
|
||||
unsafe { cast::transmute(key) }
|
||||
}
|
||||
|
||||
pub unsafe fn local_pop<T: 'static>(handle: Handle,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -20,7 +20,6 @@ use std::hashmap::HashMap;
|
|||
use std::int;
|
||||
use std::num;
|
||||
use std::option;
|
||||
use std::cast;
|
||||
use std::local_data;
|
||||
|
||||
pub fn path_name_i(idents: &[ident]) -> ~str {
|
||||
|
@ -695,18 +694,17 @@ pub fn new_sctable_internal() -> SCTable {
|
|||
|
||||
// fetch the SCTable from TLS, create one if it doesn't yet exist.
|
||||
pub fn get_sctable() -> @mut SCTable {
|
||||
unsafe {
|
||||
let sctable_key = (cast::transmute::<(uint, uint),
|
||||
&fn:Copy(v: @@mut SCTable)>(
|
||||
(-4 as uint, 0u)));
|
||||
match local_data::get(sctable_key, |k| k.map(|&k| *k)) {
|
||||
None => {
|
||||
let new_table = @@mut new_sctable_internal();
|
||||
local_data::set(sctable_key,new_table);
|
||||
*new_table
|
||||
},
|
||||
Some(intr) => *intr
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key;
|
||||
#[cfg(stage0)]
|
||||
fn sctable_key(_: @@mut SCTable) {}
|
||||
match local_data::get(sctable_key, |k| k.map(|&k| *k)) {
|
||||
None => {
|
||||
let new_table = @@mut new_sctable_internal();
|
||||
local_data::set(sctable_key,new_table);
|
||||
*new_table
|
||||
},
|
||||
Some(intr) => *intr
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -579,11 +579,13 @@ pub fn core_macros() -> @str {
|
|||
{ pub $c:ident: $in:ty -> $out:ty; } => {
|
||||
|
||||
pub mod $c {
|
||||
fn key(_x: @::std::condition::Handler<$in,$out>) { }
|
||||
#[allow(non_uppercase_statics)];
|
||||
static key: ::std::local_data::Key<
|
||||
@::std::condition::Handler<$in, $out>> =
|
||||
&::std::local_data::Key;
|
||||
|
||||
#[allow(non_uppercase_statics)]
|
||||
pub static cond :
|
||||
::std::condition::Condition<'static,$in,$out> =
|
||||
::std::condition::Condition<$in,$out> =
|
||||
::std::condition::Condition {
|
||||
name: stringify!($c),
|
||||
key: key
|
||||
|
@ -595,11 +597,13 @@ pub fn core_macros() -> @str {
|
|||
|
||||
// FIXME (#6009): remove mod's `pub` below once variant above lands.
|
||||
pub mod $c {
|
||||
fn key(_x: @::std::condition::Handler<$in,$out>) { }
|
||||
#[allow(non_uppercase_statics)];
|
||||
static key: ::std::local_data::Key<
|
||||
@::std::condition::Handler<$in, $out>> =
|
||||
&::std::local_data::Key;
|
||||
|
||||
#[allow(non_uppercase_statics)]
|
||||
pub static cond :
|
||||
::std::condition::Condition<'static,$in,$out> =
|
||||
::std::condition::Condition<$in,$out> =
|
||||
::std::condition::Condition {
|
||||
name: stringify!($c),
|
||||
key: key
|
||||
|
|
|
@ -144,7 +144,8 @@ pub struct protocol_ {
|
|||
impl protocol_ {
|
||||
/// Get a state.
|
||||
pub fn get_state(&self, name: &str) -> state {
|
||||
*self.states.iter().find_(|i| name == i.name).get()
|
||||
let mut i = self.states.iter();
|
||||
*i.find_(|i| name == i.name).get()
|
||||
}
|
||||
|
||||
pub fn get_state_by_id(&self, id: uint) -> state { self.states[id] }
|
||||
|
|
|
@ -15,7 +15,6 @@ use parse::token;
|
|||
use util::interner::StrInterner;
|
||||
use util::interner;
|
||||
|
||||
use std::cast;
|
||||
use std::cmp::Equiv;
|
||||
use std::local_data;
|
||||
use std::rand;
|
||||
|
@ -485,18 +484,17 @@ fn mk_fresh_ident_interner() -> @ident_interner {
|
|||
// if an interner exists in TLS, return it. Otherwise, prepare a
|
||||
// fresh one.
|
||||
pub fn get_ident_interner() -> @ident_interner {
|
||||
unsafe {
|
||||
let key =
|
||||
(cast::transmute::<(uint, uint),
|
||||
&fn:Copy(v: @@::parse::token::ident_interner)>(
|
||||
(-3 as uint, 0u)));
|
||||
match local_data::get(key, |k| k.map(|&k| *k)) {
|
||||
Some(interner) => *interner,
|
||||
None => {
|
||||
let interner = mk_fresh_ident_interner();
|
||||
local_data::set(key, @interner);
|
||||
interner
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
static key: local_data::Key<@@::parse::token::ident_interner> =
|
||||
&local_data::Key;
|
||||
#[cfg(stage0)]
|
||||
fn key(_: @@::parse::token::ident_interner) {}
|
||||
match local_data::get(key, |k| k.map(|&k| *k)) {
|
||||
Some(interner) => *interner,
|
||||
None => {
|
||||
let interner = mk_fresh_ident_interner();
|
||||
local_data::set(key, @interner);
|
||||
interner
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#[license = "MIT/ASL2"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[allow(non_camel_case_types)];
|
||||
#[allow(non_uppercase_statics)];
|
||||
#[deny(deprecated_pattern)];
|
||||
|
||||
extern mod extra;
|
||||
|
|
|
@ -12,10 +12,7 @@
|
|||
|
||||
use std::local_data;
|
||||
|
||||
fn key(_x: @&int) { }
|
||||
static key: local_data::Key<@&int> = &local_data::Key;
|
||||
//~^ ERROR only 'static is allowed
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
local_data::set(key, @&0); //~ ERROR does not fulfill `'static`
|
||||
}
|
||||
}
|
||||
fn main() {}
|
||||
|
|
Loading…
Reference in a new issue