impl ForbidSwitch {
fn new(s: &'static str) -> ForbidSwitch {
+ let mut sched = Local::borrow(None::<Scheduler>);
ForbidSwitch {
- msg: s, sched: Local::borrow(|s: &mut Scheduler| s.sched_id())
+ msg: s,
+ sched: sched.get().sched_id(),
}
}
}
impl Drop for ForbidSwitch {
fn drop(&mut self) {
- assert!(self.sched == Local::borrow(|s: &mut Scheduler| s.sched_id()),
- "didnt want a scheduler switch: {}", self.msg);
+ let mut sched = Local::borrow(None::<Scheduler>);
+ assert!(self.sched == sched.get().sched_id(),
+ "didnt want a scheduler switch: {}",
+ self.msg);
}
}
#[cfg(test)]
fn local_loop() -> &'static mut Loop {
unsafe {
- cast::transmute(Local::borrow(|sched: &mut Scheduler| {
+ cast::transmute({
+ let mut sched = Local::borrow(None::<Scheduler>);
let mut io = None;
- sched.event_loop.io(|i| {
+ sched.get().event_loop.io(|i| {
let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
cast::transmute(i);
io = Some(uvio);
});
io.unwrap()
- }).uv_loop())
+ }.uv_loop())
}
}
// get a handle for the 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) {
};
unsafe fn local_io() -> &'static mut IoFactory {
- Local::borrow(|sched: &mut Scheduler| {
- let mut io = None;
- sched.event_loop.io(|i| io = Some(i));
- cast::transmute(io.unwrap())
- })
+ let mut sched = Local::borrow(None::<Scheduler>);
+ let mut io = None;
+ sched.get().event_loop.io(|i| io = Some(i));
+ cast::transmute(io.unwrap())
}
let test_function: proc() = proc() {
let _f = ForbidUnwind::new("going home");
- let current_sched_id = Local::borrow(|sched: &mut Scheduler| {
- sched.sched_id()
- });
+ let current_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
// scheduler.
});
})
}
- let current_sched_id = Local::borrow(|sched: &mut Scheduler| {
- sched.sched_id()
- });
+ let current_sched_id = {
+ let mut sched = Local::borrow(None::<Scheduler>);
+ sched.get().sched_id()
+ };
assert!(current_sched_id == self.home().sched_id);
self.home().sched_id
impl HomingMissile {
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);
}
}
use at_vec::capacity;
use cast;
use cast::{transmute, transmute_copy};
+ use option::None;
use ptr;
use mem;
use uint;
use rt::local::Local;
use rt::task::Task;
- Local::borrow(|task: &mut Task| {
- task.heap.realloc(ptr as *mut Box<()>, size) as *()
- })
+ let mut task = Local::borrow(None::<Task>);
+ task.get().heap.realloc(ptr as *mut Box<()>, size) as *()
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use cell::Cell;
use c_str::{ToCStr, CString};
use libc::{c_char, size_t};
use option::{Option, None, Some};
}
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]) {
None => ~[]
};
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() {
use util;
use util::Void;
use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable, SendDeferred};
-use cell::{Cell, RefCell};
+use cell::RefCell;
use clone::Clone;
use tuple::ImmutableTuple;
Scheduler::run_task(woken_task);
});
} else {
- let recvr = Cell::new(recvr);
- Local::borrow(|sched: &mut Scheduler| {
- sched.enqueue_blocked_task(recvr.take());
- })
+ let mut sched = Local::borrow(None::<Scheduler>);
+ sched.get().enqueue_blocked_task(recvr);
}
}
}
// The optimistic check is never necessary for correctness. For testing
// purposes, making it randomly return false simulates a racing sender.
use rand::{Rand};
- let actually_check = Local::borrow(|sched: &mut Scheduler| {
- Rand::rand(&mut sched.rng)
- });
+ let mut sched = Local::borrow(None::<Scheduler>);
+ let actually_check = Rand::rand(&mut sched.get().rng);
if actually_check {
unsafe { (*self.packet()).state.load(Acquire) == STATE_ONE }
} else {
use rt::sched::Scheduler;
use rt::task::Task;
use rt::local_ptr;
-use cell::Cell;
-pub trait Local {
+/// Encapsulates some task-local data.
+pub trait Local<Borrowed> {
fn put(value: ~Self);
fn take() -> ~Self;
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_borrow() -> *mut Self;
unsafe fn try_unsafe_borrow() -> Option<*mut Self>;
}
-impl Local for Task {
+impl Local<local_ptr::Borrowed<Task>> for Task {
#[inline]
fn put(value: ~Task) { unsafe { local_ptr::put(value) } }
#[inline]
fn take() -> ~Task { unsafe { local_ptr::take() } }
fn exists(_: Option<Task>) -> bool { local_ptr::exists() }
- fn borrow<T>(f: |&mut Task| -> T) -> T {
- let mut res: Option<T> = None;
- let res_ptr: *mut Option<T> = &mut res;
+ #[inline]
+ fn borrow(_: Option<Task>) -> local_ptr::Borrowed<Task> {
unsafe {
- local_ptr::borrow(|task| {
- let result = f(task);
- *res_ptr = Some(result);
- })
- }
- match res {
- Some(r) => { r }
- None => { rtabort!("function failed in local_borrow") }
+ local_ptr::borrow::<Task>()
}
}
#[inline]
}
}
-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) {
- let value = Cell::new(value);
- Local::borrow(|task: &mut Task| {
- let task = task;
- task.sched = Some(value.take());
- });
+ let mut task = Local::borrow(None::<Task>);
+ task.get().sched = Some(value);
}
#[inline]
fn take() -> ~Scheduler {
}
}
fn exists(_: Option<Scheduler>) -> bool {
- Local::borrow(|task: &mut Task| {
- match task.sched {
- Some(ref _task) => true,
- None => false
- }
- })
+ let mut task = Local::borrow(None::<Task>);
+ task.get().sched.is_some()
}
- fn borrow<T>(f: |&mut Scheduler| -> T) -> T {
- Local::borrow(|task: &mut Task| {
- match task.sched {
- Some(~ref mut task) => {
- f(task)
- }
- None => {
- rtabort!("no scheduler")
- }
- }
- })
+ #[inline]
+ fn borrow(_: Option<Scheduler>) -> BorrowedScheduler {
+ BorrowedScheduler::new(Local::borrow(None::<Task>))
}
unsafe fn unsafe_take() -> ~Scheduler { rtabort!("unimpl") }
unsafe fn unsafe_borrow() -> *mut Scheduler {
let task = ~Task::new_root(&mut sched.stack_pool, None, proc(){});
Local::put(task);
- let res = Local::borrow(|_task: &mut Task| {
- true
- });
- assert!(res)
- let task: ~Task = Local::take();
+ {
+ let _ = Local::borrow(None::<Task>);
+ }
+
+ let task: ~Task = Local::take();
cleanup_task(task);
}
}
}
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)]
#[allow(dead_code)];
use cast;
-use cell::Cell;
-use unstable::finally::Finally;
+use ops::Drop;
#[cfg(windows)] // mingw-w32 doesn't like thread_local things
#[cfg(target_os = "android")] // see #10686
#[cfg(not(windows), not(target_os = "android"))]
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.
/// While the value is borrowed it is not available in TLS.
///
/// # Safety note
///
/// Does not validate the pointer type.
-pub unsafe fn borrow<T>(f: |&mut T|) {
- let mut value = take();
-
- // XXX: Need a different abstraction from 'finally' here to avoid unsafety
- let unsafe_ptr = cast::transmute_mut_region(&mut *value);
- let value_cell = Cell::new(value);
-
- (|| f(unsafe_ptr)).finally(|| put(value_cell.take()));
+#[inline]
+pub unsafe fn borrow<T>() -> Borrowed<T> {
+ let val: *() = cast::transmute(take::<T>());
+ Borrowed {
+ val: val,
+ }
}
/// Compiled implementation of accessing the runtime local pointer. This is
use rt::local::Local;
use rt::rtio::{RemoteCallback, PausibleIdleCallback, Callback};
use borrow::{to_uint};
-use cell::Cell;
use rand::{XorShiftRng, Rng, Rand};
use iter::range;
use unstable::mutex::Mutex;
unsafe {
let event_loop: *mut ~EventLoop = &mut self.event_loop;
- // Our scheduler must be in the task before the event loop
- // is started.
- let self_sched = Cell::new(self);
- Local::borrow(|stask: &mut Task| {
- stask.sched = Some(self_sched.take());
- });
+ {
+ // Our scheduler must be in the task before the event loop
+ // is started.
+ let mut stask = Local::borrow(None::<Task>);
+ stask.get().sched = Some(self);
+ }
(*event_loop).run();
}
}
pub fn run_task_later(next_task: ~Task) {
- let next_task = Cell::new(next_task);
- Local::borrow(|sched: &mut Scheduler| {
- sched.enqueue_task(next_task.take());
- });
+ let mut sched = Local::borrow(None::<Scheduler>);
+ sched.get().enqueue_task(next_task);
}
/// Yield control to the scheduler, executing another task. This is guaranteed
f: proc(),
home: SchedHome)
-> ~Task {
- let f = Cell::new(f);
- let home = Cell::new(home);
- Local::borrow(|running_task: &mut Task| {
- let mut sched = running_task.sched.take_unwrap();
- let new_task = ~running_task.new_child_homed(&mut sched.stack_pool,
- stack_size,
- home.take(),
- f.take());
- running_task.sched = Some(sched);
- new_task
- })
+ let mut running_task = Local::borrow(None::<Task>);
+ let mut sched = running_task.get().sched.take_unwrap();
+ let new_task = ~running_task.get()
+ .new_child_homed(&mut sched.stack_pool,
+ stack_size,
+ home,
+ f);
+ running_task.get().sched = Some(sched);
+ new_task
}
pub fn build_child(stack_size: Option<uint>, f: proc()) -> ~Task {
f: proc(),
home: SchedHome)
-> ~Task {
- let f = Cell::new(f);
- let home = Cell::new(home);
- 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,
- stack_size,
- home.take(),
- f.take());
- running_task.sched = Some(sched);
- new_task
- })
+ let mut running_task = Local::borrow(None::<Task>);
+ let mut sched = running_task.get().sched.take_unwrap();
+ let new_task = ~Task::new_root_homed(&mut sched.stack_pool,
+ stack_size,
+ home,
+ f);
+ running_task.get().sched = Some(sched);
+ new_task
}
pub fn build_root(stack_size: Option<uint>, f: proc()) -> ~Task {
// Grab both the scheduler and the task from TLS and check if the
// task is executing on an appropriate scheduler.
pub fn on_appropriate_sched() -> bool {
- Local::borrow(|task: &mut Task| {
- let sched_id = task.sched.get_ref().sched_id();
- let sched_run_anything = task.sched.get_ref().run_anything;
- match task.task_type {
- GreenTask(Some(AnySched)) => {
- rtdebug!("anysched task in sched check ****");
- sched_run_anything
- }
- GreenTask(Some(Sched(SchedHandle { sched_id: ref id, ..}))) => {
- rtdebug!("homed task in sched check ****");
- *id == sched_id
- }
- GreenTask(None) => {
- rtabort!("task without home");
- }
- SchedTask => {
- rtabort!("type error: expected: GreenTask, found: SchedTask");
- }
+ let mut task = Local::borrow(None::<Task>);
+ let sched_id = task.get().sched.get_ref().sched_id();
+ let sched_run_anything = task.get().sched.get_ref().run_anything;
+ match task.get().task_type {
+ GreenTask(Some(AnySched)) => {
+ rtdebug!("anysched task in sched check ****");
+ sched_run_anything
+ }
+ GreenTask(Some(Sched(SchedHandle { sched_id: ref id, ..}))) => {
+ rtdebug!("homed task in sched check ****");
+ *id == sched_id
+ }
+ GreenTask(None) => {
+ rtabort!("task without home");
}
- })
+ SchedTask => {
+ rtabort!("type error: expected: GreenTask, found: SchedTask");
+ }
+ }
}
}
unsafe {
// 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
// reference to it. The task is in TLS, so we can
// #2361 - possible implementation of not using landing pads
if in_green_task_context() {
- Local::borrow(|task: &mut Task| {
- let n = task.name.as_ref().map(|n| n.as_slice()).unwrap_or("<unnamed>");
-
- // See the message below for why this is not emitted to the
- // task's logger. This has the additional conundrum of the
- // logger may not be initialized just yet, meaning that an FFI
- // call would happen to initialized it (calling out to libuv),
- // and the FFI call needs 2MB of stack when we just ran out.
- rterrln!("task '{}' has overflowed its stack", n);
- })
+ let mut task = Local::borrow(None::<Task>);
+ 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
+ // task's logger. This has the additional conundrum of the
+ // logger may not be initialized just yet, meaning that an FFI
+ // call would happen to initialized it (calling out to libuv),
+ // and the FFI call needs 2MB of stack when we just ran out.
+ rterrln!("task '{}' has overflowed its stack", n);
} else {
rterrln!("stack overflow in non-task context");
}
let tube_clone = Cell::new(tube_clone);
let sched: ~Scheduler = Local::take();
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 {
- let mut tube_clone = tube_clone.take();
+ let mut tube_clone = tube_clone;
// The task should be blocked on this now and
// sending will wake it up.
tube_clone.send(1);
callback_send(tube_clone.take(), 0);
fn callback_send(tube: Tube<int>, i: int) {
- if i == 100 { return; }
-
- let tube = Cell::new(Cell::new(tube));
- Local::borrow(|sched: &mut Scheduler| {
- let tube = tube.take();
- do sched.event_loop.callback {
- let mut tube = tube.take();
- // The task should be blocked on this now and
- // sending will wake it up.
- tube.send(i);
- callback_send(tube, i + 1);
- }
- })
+ if i == 100 {
+ return
+ }
+
+ let mut sched = Local::borrow(None::<Scheduler>);
+ do sched.get().event_loop.callback {
+ let mut tube = tube;
+ // The task should be blocked on this now and
+ // sending will wake it up.
+ tube.send(i);
+ callback_send(tube, i + 1);
+ }
}
sched.enqueue_blocked_task(task);
use rt::task::Task;
if in_green_task_context() {
- Local::borrow(|task: &mut Task| {
- match task.name {
- Some(ref name) => blk(Some(name.as_slice())),
- None => blk(None)
- }
- })
+ let mut task = Local::borrow(None::<Task>);
+ match task.get().name {
+ Some(ref name) => blk(Some(name.as_slice())),
+ None => blk(None)
+ }
} else {
fail!("no task name exists in non-green task context")
}
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:
#[cfg(test)]
fn get_sched_id() -> int {
- Local::borrow(|sched: &mut ::rt::sched::Scheduler| {
- sched.sched_id() as int
- })
+ use rt::sched::Scheduler;
+ let mut sched = Local::borrow(None::<Scheduler>);
+ sched.get().sched_id() as int
}
#[test]