librustuv: RAII-ify Local::borrow, and remove some 12 Cells.

This commit is contained in:
Patrick Walton 2013-12-03 19:18:58 -08:00
parent 786dea207d
commit 7cac9fe763
14 changed files with 208 additions and 176 deletions

View File

@ -162,16 +162,20 @@ pub struct ForbidSwitch {
impl ForbidSwitch { impl ForbidSwitch {
fn new(s: &'static str) -> ForbidSwitch { fn new(s: &'static str) -> ForbidSwitch {
let mut sched = Local::borrow(None::<Scheduler>);
ForbidSwitch { ForbidSwitch {
msg: s, sched: Local::borrow(|s: &mut Scheduler| s.sched_id()) msg: s,
sched: sched.get().sched_id(),
} }
} }
} }
impl Drop for ForbidSwitch { impl Drop for ForbidSwitch {
fn drop(&mut self) { fn drop(&mut self) {
assert!(self.sched == Local::borrow(|s: &mut Scheduler| s.sched_id()), let mut sched = Local::borrow(None::<Scheduler>);
"didnt want a scheduler switch: {}", self.msg); assert!(self.sched == sched.get().sched_id(),
"didnt want a scheduler switch: {}",
self.msg);
} }
} }
@ -389,15 +393,16 @@ pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
#[cfg(test)] #[cfg(test)]
fn local_loop() -> &'static mut Loop { fn local_loop() -> &'static mut Loop {
unsafe { unsafe {
cast::transmute(Local::borrow(|sched: &mut Scheduler| { cast::transmute({
let mut sched = Local::borrow(None::<Scheduler>);
let mut io = None; let mut io = None;
sched.event_loop.io(|i| { sched.get().event_loop.io(|i| {
let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) = let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
cast::transmute(i); cast::transmute(i);
io = Some(uvio); io = Some(uvio);
}); });
io.unwrap() io.unwrap()
}).uv_loop()) }.uv_loop())
} }
} }

View File

@ -29,7 +29,10 @@ macro_rules! uvdebug (
// get a handle for the current scheduler // get a handle for the current scheduler
macro_rules! get_handle_to_current_scheduler( macro_rules! get_handle_to_current_scheduler(
() => (Local::borrow(|sched: &mut Scheduler| sched.make_handle())) () => ({
let mut sched = Local::borrow(None::<Scheduler>);
sched.get().make_handle()
})
) )
pub fn dumb_println(args: &fmt::Arguments) { pub fn dumb_println(args: &fmt::Arguments) {

View File

@ -1080,11 +1080,10 @@ mod test {
}; };
unsafe fn local_io() -> &'static mut IoFactory { unsafe fn local_io() -> &'static mut IoFactory {
Local::borrow(|sched: &mut Scheduler| { let mut sched = Local::borrow(None::<Scheduler>);
let mut io = None; let mut io = None;
sched.event_loop.io(|i| io = Some(i)); sched.get().event_loop.io(|i| io = Some(i));
cast::transmute(io.unwrap()) cast::transmute(io.unwrap())
})
} }
let test_function: proc() = proc() { let test_function: proc() = proc() {

View File

@ -45,9 +45,10 @@ pub trait HomingIO {
let _f = ForbidUnwind::new("going home"); let _f = ForbidUnwind::new("going home");
let current_sched_id = Local::borrow(|sched: &mut Scheduler| { let current_sched_id = {
sched.sched_id() let mut sched = Local::borrow(None::<Scheduler>);
}); sched.get().sched_id()
};
// Only need to invoke a context switch if we're not on the right // Only need to invoke a context switch if we're not on the right
// scheduler. // scheduler.
@ -59,9 +60,10 @@ pub trait HomingIO {
}); });
}) })
} }
let current_sched_id = Local::borrow(|sched: &mut Scheduler| { let current_sched_id = {
sched.sched_id() let mut sched = Local::borrow(None::<Scheduler>);
}); sched.get().sched_id()
};
assert!(current_sched_id == self.home().sched_id); assert!(current_sched_id == self.home().sched_id);
self.home().sched_id self.home().sched_id
@ -96,7 +98,8 @@ struct HomingMissile {
impl HomingMissile { impl HomingMissile {
pub fn check(&self, msg: &'static str) { pub fn check(&self, msg: &'static str) {
let local_id = Local::borrow(|sched: &mut Scheduler| sched.sched_id()); let mut sched = Local::borrow(None::<Scheduler>);
let local_id = sched.get().sched_id();
assert!(local_id == self.io_home, "{}", msg); assert!(local_id == self.io_home, "{}", msg);
} }
} }

View File

@ -169,6 +169,7 @@ pub mod raw {
use at_vec::capacity; use at_vec::capacity;
use cast; use cast;
use cast::{transmute, transmute_copy}; use cast::{transmute, transmute_copy};
use option::None;
use ptr; use ptr;
use mem; use mem;
use uint; use uint;
@ -259,9 +260,8 @@ pub mod raw {
use rt::local::Local; use rt::local::Local;
use rt::task::Task; use rt::task::Task;
Local::borrow(|task: &mut Task| { let mut task = Local::borrow(None::<Task>);
task.heap.realloc(ptr as *mut Box<()>, size) as *() task.get().heap.realloc(ptr as *mut Box<()>, size) as *()
})
} }
} }

View File

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use cell::Cell;
use c_str::{ToCStr, CString}; use c_str::{ToCStr, CString};
use libc::{c_char, size_t}; use libc::{c_char, size_t};
use option::{Option, None, Some}; use option::{Option, None, Some};
@ -35,7 +34,8 @@ pub struct BorrowRecord {
} }
fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> { fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> {
Local::borrow(|task: &mut Task| task.borrow_list.take()) let mut task = Local::borrow(None::<Task>);
task.get().borrow_list.take()
} }
fn swap_task_borrow_list(f: |~[BorrowRecord]| -> ~[BorrowRecord]) { fn swap_task_borrow_list(f: |~[BorrowRecord]| -> ~[BorrowRecord]) {
@ -44,8 +44,9 @@ fn swap_task_borrow_list(f: |~[BorrowRecord]| -> ~[BorrowRecord]) {
None => ~[] None => ~[]
}; };
let borrows = f(borrows); let borrows = f(borrows);
let borrows = Cell::new(borrows);
Local::borrow(|task: &mut Task| task.borrow_list = Some(borrows.take())) let mut task = Local::borrow(None::<Task>);
task.get().borrow_list = Some(borrows)
} }
pub fn clear_task_borrow_list() { pub fn clear_task_borrow_list() {

View File

@ -25,7 +25,7 @@ use unstable::sync::UnsafeArc;
use util; use util;
use util::Void; use util::Void;
use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable, SendDeferred}; use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable, SendDeferred};
use cell::{Cell, RefCell}; use cell::RefCell;
use clone::Clone; use clone::Clone;
use tuple::ImmutableTuple; use tuple::ImmutableTuple;
@ -169,10 +169,8 @@ impl<T: Send> ChanOne<T> {
Scheduler::run_task(woken_task); Scheduler::run_task(woken_task);
}); });
} else { } else {
let recvr = Cell::new(recvr); let mut sched = Local::borrow(None::<Scheduler>);
Local::borrow(|sched: &mut Scheduler| { sched.get().enqueue_blocked_task(recvr);
sched.enqueue_blocked_task(recvr.take());
})
} }
} }
} }
@ -230,9 +228,8 @@ impl<T: Send> SelectInner for PortOne<T> {
// The optimistic check is never necessary for correctness. For testing // The optimistic check is never necessary for correctness. For testing
// purposes, making it randomly return false simulates a racing sender. // purposes, making it randomly return false simulates a racing sender.
use rand::{Rand}; use rand::{Rand};
let actually_check = Local::borrow(|sched: &mut Scheduler| { let mut sched = Local::borrow(None::<Scheduler>);
Rand::rand(&mut sched.rng) let actually_check = Rand::rand(&mut sched.get().rng);
});
if actually_check { if actually_check {
unsafe { (*self.packet()).state.load(Acquire) == STATE_ONE } unsafe { (*self.packet()).state.load(Acquire) == STATE_ONE }
} else { } else {

View File

@ -12,36 +12,28 @@ use option::{Option, Some, None};
use rt::sched::Scheduler; use rt::sched::Scheduler;
use rt::task::Task; use rt::task::Task;
use rt::local_ptr; use rt::local_ptr;
use cell::Cell;
pub trait Local { /// Encapsulates some task-local data.
pub trait Local<Borrowed> {
fn put(value: ~Self); fn put(value: ~Self);
fn take() -> ~Self; fn take() -> ~Self;
fn exists(unused_value: Option<Self>) -> bool; fn exists(unused_value: Option<Self>) -> bool;
fn borrow<T>(f: |&mut Self| -> T) -> T; fn borrow(unused_value: Option<Self>) -> Borrowed;
unsafe fn unsafe_take() -> ~Self; unsafe fn unsafe_take() -> ~Self;
unsafe fn unsafe_borrow() -> *mut Self; unsafe fn unsafe_borrow() -> *mut Self;
unsafe fn try_unsafe_borrow() -> Option<*mut Self>; unsafe fn try_unsafe_borrow() -> Option<*mut Self>;
} }
impl Local for Task { impl Local<local_ptr::Borrowed<Task>> for Task {
#[inline] #[inline]
fn put(value: ~Task) { unsafe { local_ptr::put(value) } } fn put(value: ~Task) { unsafe { local_ptr::put(value) } }
#[inline] #[inline]
fn take() -> ~Task { unsafe { local_ptr::take() } } fn take() -> ~Task { unsafe { local_ptr::take() } }
fn exists(_: Option<Task>) -> bool { local_ptr::exists() } fn exists(_: Option<Task>) -> bool { local_ptr::exists() }
fn borrow<T>(f: |&mut Task| -> T) -> T { #[inline]
let mut res: Option<T> = None; fn borrow(_: Option<Task>) -> local_ptr::Borrowed<Task> {
let res_ptr: *mut Option<T> = &mut res;
unsafe { unsafe {
local_ptr::borrow(|task| { local_ptr::borrow::<Task>()
let result = f(task);
*res_ptr = Some(result);
})
}
match res {
Some(r) => { r }
None => { rtabort!("function failed in local_borrow") }
} }
} }
#[inline] #[inline]
@ -54,13 +46,35 @@ impl Local for Task {
} }
} }
impl Local for Scheduler { /// Encapsulates a temporarily-borrowed scheduler.
pub struct BorrowedScheduler {
priv task: local_ptr::Borrowed<Task>,
}
impl BorrowedScheduler {
fn new(mut task: local_ptr::Borrowed<Task>) -> BorrowedScheduler {
if task.get().sched.is_none() {
rtabort!("no scheduler")
} else {
BorrowedScheduler {
task: task,
}
}
}
#[inline]
pub fn get<'a>(&'a mut self) -> &'a mut ~Scheduler {
match self.task.get().sched {
None => rtabort!("no scheduler"),
Some(ref mut sched) => sched,
}
}
}
impl Local<BorrowedScheduler> for Scheduler {
fn put(value: ~Scheduler) { fn put(value: ~Scheduler) {
let value = Cell::new(value); let mut task = Local::borrow(None::<Task>);
Local::borrow(|task: &mut Task| { task.get().sched = Some(value);
let task = task;
task.sched = Some(value.take());
});
} }
#[inline] #[inline]
fn take() -> ~Scheduler { fn take() -> ~Scheduler {
@ -71,24 +85,12 @@ impl Local for Scheduler {
} }
} }
fn exists(_: Option<Scheduler>) -> bool { fn exists(_: Option<Scheduler>) -> bool {
Local::borrow(|task: &mut Task| { let mut task = Local::borrow(None::<Task>);
match task.sched { task.get().sched.is_some()
Some(ref _task) => true,
None => false
} }
}) #[inline]
} fn borrow(_: Option<Scheduler>) -> BorrowedScheduler {
fn borrow<T>(f: |&mut Scheduler| -> T) -> T { BorrowedScheduler::new(Local::borrow(None::<Task>))
Local::borrow(|task: &mut Task| {
match task.sched {
Some(~ref mut task) => {
f(task)
}
None => {
rtabort!("no scheduler")
}
}
})
} }
unsafe fn unsafe_take() -> ~Scheduler { rtabort!("unimpl") } unsafe fn unsafe_take() -> ~Scheduler { rtabort!("unimpl") }
unsafe fn unsafe_borrow() -> *mut Scheduler { unsafe fn unsafe_borrow() -> *mut Scheduler {
@ -182,10 +184,10 @@ mod test {
let task = ~Task::new_root(&mut sched.stack_pool, None, proc(){}); let task = ~Task::new_root(&mut sched.stack_pool, None, proc(){});
Local::put(task); Local::put(task);
let res = Local::borrow(|_task: &mut Task| { {
true let _ = Local::borrow(None::<Task>);
}); }
assert!(res)
let task: ~Task = Local::take(); let task: ~Task = Local::take();
cleanup_task(task); cleanup_task(task);
} }

View File

@ -304,7 +304,8 @@ pub unsafe fn local_free(ptr: *libc::c_char) {
} }
pub fn live_allocs() -> *mut Box { pub fn live_allocs() -> *mut Box {
Local::borrow(|task: &mut Task| task.heap.live_allocs) let mut task = Local::borrow(None::<Task>);
task.get().heap.live_allocs
} }
#[cfg(test)] #[cfg(test)]

View File

@ -18,8 +18,7 @@
#[allow(dead_code)]; #[allow(dead_code)];
use cast; use cast;
use cell::Cell; use ops::Drop;
use unstable::finally::Finally;
#[cfg(windows)] // mingw-w32 doesn't like thread_local things #[cfg(windows)] // mingw-w32 doesn't like thread_local things
#[cfg(target_os = "android")] // see #10686 #[cfg(target_os = "android")] // see #10686
@ -28,20 +27,48 @@ pub use self::native::*;
#[cfg(not(windows), not(target_os = "android"))] #[cfg(not(windows), not(target_os = "android"))]
pub use self::compiled::*; pub use self::compiled::*;
/// Encapsulates a borrowed value. When this value goes out of scope, the
/// pointer is returned.
pub struct Borrowed<T> {
priv val: *(),
}
#[unsafe_destructor]
impl<T> Drop for Borrowed<T> {
fn drop(&mut self) {
unsafe {
if self.val.is_null() {
rtabort!("Aiee, returning null borrowed object!");
}
let val: ~T = cast::transmute(self.val);
put::<T>(val);
assert!(exists());
}
}
}
impl<T> Borrowed<T> {
pub fn get<'a>(&'a mut self) -> &'a mut T {
unsafe {
let val_ptr: &mut ~T = cast::transmute(&mut self.val);
let val_ptr: &'a mut T = *val_ptr;
val_ptr
}
}
}
/// Borrow the thread-local value from thread-local storage. /// Borrow the thread-local value from thread-local storage.
/// While the value is borrowed it is not available in TLS. /// While the value is borrowed it is not available in TLS.
/// ///
/// # Safety note /// # Safety note
/// ///
/// Does not validate the pointer type. /// Does not validate the pointer type.
pub unsafe fn borrow<T>(f: |&mut T|) { #[inline]
let mut value = take(); pub unsafe fn borrow<T>() -> Borrowed<T> {
let val: *() = cast::transmute(take::<T>());
// XXX: Need a different abstraction from 'finally' here to avoid unsafety Borrowed {
let unsafe_ptr = cast::transmute_mut_region(&mut *value); val: val,
let value_cell = Cell::new(value); }
(|| f(unsafe_ptr)).finally(|| put(value_cell.take()));
} }
/// Compiled implementation of accessing the runtime local pointer. This is /// Compiled implementation of accessing the runtime local pointer. This is

View File

@ -24,7 +24,6 @@ use rt::local_ptr;
use rt::local::Local; use rt::local::Local;
use rt::rtio::{RemoteCallback, PausibleIdleCallback, Callback}; use rt::rtio::{RemoteCallback, PausibleIdleCallback, Callback};
use borrow::{to_uint}; use borrow::{to_uint};
use cell::Cell;
use rand::{XorShiftRng, Rng, Rand}; use rand::{XorShiftRng, Rng, Rand};
use iter::range; use iter::range;
use unstable::mutex::Mutex; use unstable::mutex::Mutex;
@ -235,12 +234,12 @@ impl Scheduler {
unsafe { unsafe {
let event_loop: *mut ~EventLoop = &mut self.event_loop; let event_loop: *mut ~EventLoop = &mut self.event_loop;
{
// Our scheduler must be in the task before the event loop // Our scheduler must be in the task before the event loop
// is started. // is started.
let self_sched = Cell::new(self); let mut stask = Local::borrow(None::<Task>);
Local::borrow(|stask: &mut Task| { stask.get().sched = Some(self);
stask.sched = Some(self_sched.take()); }
});
(*event_loop).run(); (*event_loop).run();
} }
@ -751,10 +750,8 @@ impl Scheduler {
} }
pub fn run_task_later(next_task: ~Task) { pub fn run_task_later(next_task: ~Task) {
let next_task = Cell::new(next_task); let mut sched = Local::borrow(None::<Scheduler>);
Local::borrow(|sched: &mut Scheduler| { sched.get().enqueue_task(next_task);
sched.enqueue_task(next_task.take());
});
} }
/// Yield control to the scheduler, executing another task. This is guaranteed /// Yield control to the scheduler, executing another task. This is guaranteed

View File

@ -144,17 +144,15 @@ impl Task {
f: proc(), f: proc(),
home: SchedHome) home: SchedHome)
-> ~Task { -> ~Task {
let f = Cell::new(f); let mut running_task = Local::borrow(None::<Task>);
let home = Cell::new(home); let mut sched = running_task.get().sched.take_unwrap();
Local::borrow(|running_task: &mut Task| { let new_task = ~running_task.get()
let mut sched = running_task.sched.take_unwrap(); .new_child_homed(&mut sched.stack_pool,
let new_task = ~running_task.new_child_homed(&mut sched.stack_pool,
stack_size, stack_size,
home.take(), home,
f.take()); f);
running_task.sched = Some(sched); running_task.get().sched = Some(sched);
new_task new_task
})
} }
pub fn build_child(stack_size: Option<uint>, f: proc()) -> ~Task { pub fn build_child(stack_size: Option<uint>, f: proc()) -> ~Task {
@ -165,17 +163,14 @@ impl Task {
f: proc(), f: proc(),
home: SchedHome) home: SchedHome)
-> ~Task { -> ~Task {
let f = Cell::new(f); let mut running_task = Local::borrow(None::<Task>);
let home = Cell::new(home); let mut sched = running_task.get().sched.take_unwrap();
Local::borrow(|running_task: &mut Task| {
let mut sched = running_task.sched.take_unwrap();
let new_task = ~Task::new_root_homed(&mut sched.stack_pool, let new_task = ~Task::new_root_homed(&mut sched.stack_pool,
stack_size, stack_size,
home.take(), home,
f.take()); f);
running_task.sched = Some(sched); running_task.get().sched = Some(sched);
new_task new_task
})
} }
pub fn build_root(stack_size: Option<uint>, f: proc()) -> ~Task { pub fn build_root(stack_size: Option<uint>, f: proc()) -> ~Task {
@ -371,10 +366,10 @@ impl Task {
// Grab both the scheduler and the task from TLS and check if the // Grab both the scheduler and the task from TLS and check if the
// task is executing on an appropriate scheduler. // task is executing on an appropriate scheduler.
pub fn on_appropriate_sched() -> bool { pub fn on_appropriate_sched() -> bool {
Local::borrow(|task: &mut Task| { let mut task = Local::borrow(None::<Task>);
let sched_id = task.sched.get_ref().sched_id(); let sched_id = task.get().sched.get_ref().sched_id();
let sched_run_anything = task.sched.get_ref().run_anything; let sched_run_anything = task.get().sched.get_ref().run_anything;
match task.task_type { match task.get().task_type {
GreenTask(Some(AnySched)) => { GreenTask(Some(AnySched)) => {
rtdebug!("anysched task in sched check ****"); rtdebug!("anysched task in sched check ****");
sched_run_anything sched_run_anything
@ -390,7 +385,6 @@ impl Task {
rtabort!("type error: expected: GreenTask, found: SchedTask"); rtabort!("type error: expected: GreenTask, found: SchedTask");
} }
} }
})
} }
} }
@ -440,9 +434,10 @@ impl Coroutine {
unsafe { unsafe {
// Again - might work while safe, or it might not. // Again - might work while safe, or it might not.
Local::borrow(|sched: &mut Scheduler| { {
sched.run_cleanup_job(); let mut sched = Local::borrow(None::<Scheduler>);
}); sched.get().run_cleanup_job();
}
// To call the run method on a task we need a direct // To call the run method on a task we need a direct
// reference to it. The task is in TLS, so we can // reference to it. The task is in TLS, so we can
@ -594,8 +589,12 @@ pub extern "C" fn rust_stack_exhausted() {
// #2361 - possible implementation of not using landing pads // #2361 - possible implementation of not using landing pads
if in_green_task_context() { if in_green_task_context() {
Local::borrow(|task: &mut Task| { let mut task = Local::borrow(None::<Task>);
let n = task.name.as_ref().map(|n| n.as_slice()).unwrap_or("<unnamed>"); let n = task.get()
.name
.as_ref()
.map(|n| n.as_slice())
.unwrap_or("<unnamed>");
// See the message below for why this is not emitted to the // See the message below for why this is not emitted to the
// task's logger. This has the additional conundrum of the // task's logger. This has the additional conundrum of the
@ -603,7 +602,6 @@ pub extern "C" fn rust_stack_exhausted() {
// call would happen to initialized it (calling out to libuv), // call would happen to initialized it (calling out to libuv),
// and the FFI call needs 2MB of stack when we just ran out. // and the FFI call needs 2MB of stack when we just ran out.
rterrln!("task '{}' has overflowed its stack", n); rterrln!("task '{}' has overflowed its stack", n);
})
} else { } else {
rterrln!("stack overflow in non-task context"); rterrln!("stack overflow in non-task context");
} }

View File

@ -121,9 +121,9 @@ mod test {
let tube_clone = Cell::new(tube_clone); let tube_clone = Cell::new(tube_clone);
let sched: ~Scheduler = Local::take(); let sched: ~Scheduler = Local::take();
sched.deschedule_running_task_and_then(|sched, task| { sched.deschedule_running_task_and_then(|sched, task| {
let tube_clone = Cell::new(tube_clone.take()); let tube_clone = tube_clone.take();
do sched.event_loop.callback { do sched.event_loop.callback {
let mut tube_clone = tube_clone.take(); let mut tube_clone = tube_clone;
// The task should be blocked on this now and // The task should be blocked on this now and
// sending will wake it up. // sending will wake it up.
tube_clone.send(1); tube_clone.send(1);
@ -148,19 +148,18 @@ mod test {
callback_send(tube_clone.take(), 0); callback_send(tube_clone.take(), 0);
fn callback_send(tube: Tube<int>, i: int) { fn callback_send(tube: Tube<int>, i: int) {
if i == 100 { return; } if i == 100 {
return
}
let tube = Cell::new(Cell::new(tube)); let mut sched = Local::borrow(None::<Scheduler>);
Local::borrow(|sched: &mut Scheduler| { do sched.get().event_loop.callback {
let tube = tube.take(); let mut tube = tube;
do sched.event_loop.callback {
let mut tube = tube.take();
// The task should be blocked on this now and // The task should be blocked on this now and
// sending will wake it up. // sending will wake it up.
tube.send(i); tube.send(i);
callback_send(tube, i + 1); callback_send(tube, i + 1);
} }
})
} }
sched.enqueue_blocked_task(task); sched.enqueue_blocked_task(task);

View File

@ -429,12 +429,11 @@ pub fn with_task_name<U>(blk: |Option<&str>| -> U) -> U {
use rt::task::Task; use rt::task::Task;
if in_green_task_context() { if in_green_task_context() {
Local::borrow(|task: &mut Task| { let mut task = Local::borrow(None::<Task>);
match task.name { match task.get().name {
Some(ref name) => blk(Some(name.as_slice())), Some(ref name) => blk(Some(name.as_slice())),
None => blk(None) None => blk(None)
} }
})
} else { } else {
fail!("no task name exists in non-green task context") fail!("no task name exists in non-green task context")
} }
@ -456,7 +455,8 @@ pub fn failing() -> bool {
use rt::task::Task; use rt::task::Task;
Local::borrow(|local: &mut Task| local.unwinder.unwinding) let mut local = Local::borrow(None::<Task>);
local.get().unwinder.unwinding
} }
// The following 8 tests test the following 2^3 combinations: // The following 8 tests test the following 2^3 combinations:
@ -601,9 +601,9 @@ fn test_try_fail() {
#[cfg(test)] #[cfg(test)]
fn get_sched_id() -> int { fn get_sched_id() -> int {
Local::borrow(|sched: &mut ::rt::sched::Scheduler| { use rt::sched::Scheduler;
sched.sched_id() as int let mut sched = Local::borrow(None::<Scheduler>);
}) sched.get().sched_id() as int
} }
#[test] #[test]