about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-12-10 19:16:19 -0800
committerbors <bors@rust-lang.org>2013-12-10 19:16:19 -0800
commitb8b16ae0996074861693f0f76d5d937fafe6a37e (patch)
tree03f3fadcb4558ec1ddda3d61669636c1fcad1264 /src/libstd/rt
parentac4dd9efee9248f4c3235460f3c93acc9932eb5a (diff)
parentfd7a513bef7fe3c6f5128cc53135facca37f23e5 (diff)
downloadrust-b8b16ae0996074861693f0f76d5d937fafe6a37e.tar.gz
rust-b8b16ae0996074861693f0f76d5d937fafe6a37e.zip
auto merge of #10791 : pcwalton/rust/decelling, r=pcwalton
34 uses of `Cell` remain.

r? @alexcrichton
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/basic.rs5
-rw-r--r--src/libstd/rt/borrowck.rs9
-rw-r--r--src/libstd/rt/comm.rs83
-rw-r--r--src/libstd/rt/deque.rs5
-rw-r--r--src/libstd/rt/kill.rs7
-rw-r--r--src/libstd/rt/local.rs88
-rw-r--r--src/libstd/rt/local_heap.rs3
-rw-r--r--src/libstd/rt/local_ptr.rs47
-rw-r--r--src/libstd/rt/mod.rs33
-rw-r--r--src/libstd/rt/rtio.rs78
-rw-r--r--src/libstd/rt/sched.rs76
-rw-r--r--src/libstd/rt/task.rs111
-rw-r--r--src/libstd/rt/test.rs30
-rw-r--r--src/libstd/rt/tube.rs43
14 files changed, 311 insertions, 307 deletions
diff --git a/src/libstd/rt/basic.rs b/src/libstd/rt/basic.rs
index 311138d15a2..fa47ceb1c04 100644
--- a/src/libstd/rt/basic.rs
+++ b/src/libstd/rt/basic.rs
@@ -159,8 +159,9 @@ impl EventLoop for BasicLoop {
         ~BasicRemote::new(self.messages.clone(), id) as ~RemoteCallback
     }
 
-    fn io<'a>(&'a mut self, f: |&'a mut IoFactory|) {
-        f(self.io)
+    fn io<'a>(&'a mut self) -> Option<&'a mut IoFactory> {
+        let factory: &mut IoFactory = self.io;
+        Some(factory)
     }
 }
 
diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs
index 30c2264bd86..82f92bdb803 100644
--- a/src/libstd/rt/borrowck.rs
+++ b/src/libstd/rt/borrowck.rs
@@ -8,7 +8,6 @@
 // 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};
@@ -35,7 +34,8 @@ pub struct 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]) {
@@ -44,8 +44,9 @@ 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() {
diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs
index 06743bce9bf..2b1e7865a73 100644
--- a/src/libstd/rt/comm.rs
+++ b/src/libstd/rt/comm.rs
@@ -25,7 +25,7 @@ use unstable::sync::UnsafeArc;
 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;
 
@@ -169,10 +169,8 @@ impl<T: Send> ChanOne<T> {
                             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);
                     }
                 }
             }
@@ -230,9 +228,8 @@ impl<T: Send> SelectInner for PortOne<T> {
         // 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 {
@@ -568,7 +565,7 @@ impl<'self, T: Send> SelectPortInner<T> for &'self Port<T> {
 impl<'self, T: Send> SelectPort<T> for &'self Port<T> { }
 
 pub struct SharedChan<T> {
-    // Just like Chan, but a shared AtomicOption instead of Cell
+    // Just like Chan, but a shared AtomicOption
     priv next: UnsafeArc<AtomicOption<StreamChanOne<T>>>
 }
 
@@ -719,7 +716,6 @@ mod test {
     use super::*;
     use option::*;
     use rt::test::*;
-    use cell::Cell;
     use num::Times;
     use rt::util;
 
@@ -843,9 +839,8 @@ mod test {
     fn oneshot_multi_task_recv_then_send() {
         do run_in_newsched_task {
             let (port, chan) = oneshot::<~int>();
-            let port_cell = Cell::new(port);
             do spawntask {
-                assert!(port_cell.take().recv() == ~10);
+                assert!(port.recv() == ~10);
             }
 
             chan.send(~10);
@@ -856,13 +851,11 @@ mod test {
     fn oneshot_multi_task_recv_then_close() {
         do run_in_newsched_task {
             let (port, chan) = oneshot::<~int>();
-            let port_cell = Cell::new(port);
-            let chan_cell = Cell::new(chan);
             do spawntask_later {
-                let _cell = chan_cell.take();
+                let _ = chan;
             }
             let res = do spawntask_try {
-                assert!(port_cell.take().recv() == ~10);
+                assert!(port.recv() == ~10);
             };
             assert!(res.is_err());
         }
@@ -874,9 +867,8 @@ mod test {
         stress_factor().times(|| {
             do run_in_newsched_task {
                 let (port, chan) = oneshot::<int>();
-                let port_cell = Cell::new(port);
                 let thread = do spawntask_thread {
-                    let _p = port_cell.take();
+                    let _ = port;
                 };
                 let _chan = chan;
                 thread.join();
@@ -890,14 +882,11 @@ mod test {
         stress_factor().times(|| {
             do run_in_newsched_task {
                 let (port, chan) = oneshot::<int>();
-                let chan_cell = Cell::new(chan);
-                let port_cell = Cell::new(port);
                 let thread1 = do spawntask_thread {
-                    let _p = port_cell.take();
+                    let _ = port;
                 };
                 let thread2 = do spawntask_thread {
-                    let c = chan_cell.take();
-                    c.send(1);
+                    chan.send(1);
                 };
                 thread1.join();
                 thread2.join();
@@ -911,19 +900,17 @@ mod test {
         stress_factor().times(|| {
             do run_in_newsched_task {
                 let (port, chan) = oneshot::<int>();
-                let chan_cell = Cell::new(chan);
-                let port_cell = Cell::new(port);
                 let thread1 = do spawntask_thread {
-                    let port_cell = Cell::new(port_cell.take());
+                    let port = port;
                     let res = do spawntask_try {
-                        port_cell.take().recv();
+                        port.recv();
                     };
                     assert!(res.is_err());
                 };
                 let thread2 = do spawntask_thread {
-                    let chan_cell = Cell::new(chan_cell.take());
+                    let chan = chan;
                     do spawntask {
-                        chan_cell.take();
+                        let _ = chan;
                     }
                 };
                 thread1.join();
@@ -938,13 +925,11 @@ mod test {
         stress_factor().times(|| {
             do run_in_newsched_task {
                 let (port, chan) = oneshot::<~int>();
-                let chan_cell = Cell::new(chan);
-                let port_cell = Cell::new(port);
                 let thread1 = do spawntask_thread {
-                    chan_cell.take().send(~10);
+                    chan.send(~10);
                 };
                 let thread2 = do spawntask_thread {
-                    assert!(port_cell.take().recv() == ~10);
+                    assert!(port.recv() == ~10);
                 };
                 thread1.join();
                 thread2.join();
@@ -965,9 +950,7 @@ mod test {
                 fn send(chan: Chan<~int>, i: int) {
                     if i == 10 { return }
 
-                    let chan_cell = Cell::new(chan);
                     do spawntask_random {
-                        let chan = chan_cell.take();
                         chan.send(~i);
                         send(chan, i + 1);
                     }
@@ -976,9 +959,7 @@ mod test {
                 fn recv(port: Port<~int>, i: int) {
                     if i == 10 { return }
 
-                    let port_cell = Cell::new(port);
                     do spawntask_random {
-                        let port = port_cell.take();
                         assert!(port.recv() == ~i);
                         recv(port, i + 1);
                     };
@@ -1131,7 +1112,7 @@ mod test {
 
     #[test]
     fn send_deferred() {
-        use unstable::sync::atomically;
+        use unstable::sync::atomic;
 
         // Tests no-rescheduling of send_deferred on all types of channels.
         do run_in_newsched_task {
@@ -1141,24 +1122,18 @@ mod test {
             let cshared = SharedChan::new(cshared);
             let mp = megapipe();
 
-            let pone = Cell::new(pone);
-            do spawntask { pone.take().recv(); }
-            let pstream = Cell::new(pstream);
-            do spawntask { pstream.take().recv(); }
-            let pshared = Cell::new(pshared);
-            do spawntask { pshared.take().recv(); }
-            let p_mp = Cell::new(mp.clone());
-            do spawntask { p_mp.take().recv(); }
+            do spawntask { pone.recv(); }
+            do spawntask { pstream.recv(); }
+            do spawntask { pshared.recv(); }
+            let p_mp = mp.clone();
+            do spawntask { p_mp.recv(); }
 
-            let cs = Cell::new((cone, cstream, cshared, mp));
             unsafe {
-                atomically(|| {
-                    let (cone, cstream, cshared, mp) = cs.take();
-                    cone.send_deferred(());
-                    cstream.send_deferred(());
-                    cshared.send_deferred(());
-                    mp.send_deferred(());
-                })
+                let _guard = atomic();
+                cone.send_deferred(());
+                cstream.send_deferred(());
+                cshared.send_deferred(());
+                mp.send_deferred(());
             }
         }
     }
diff --git a/src/libstd/rt/deque.rs b/src/libstd/rt/deque.rs
index 3595587f342..44672984b64 100644
--- a/src/libstd/rt/deque.rs
+++ b/src/libstd/rt/deque.rs
@@ -163,10 +163,9 @@ impl<T: Send> BufferPool<T> {
 
     fn free(&mut self, buf: ~Buffer<T>) {
         unsafe {
-            use cell::Cell;
-            let buf = Cell::new(buf);
+            let mut buf = Some(buf);
             self.pool.with(|pool| {
-                let buf = buf.take();
+                let buf = buf.take_unwrap();
                 match pool.iter().position(|v| v.size() > buf.size()) {
                     Some(i) => pool.insert(i, buf),
                     None => pool.push(buf),
diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs
index 56c77ffaa0d..e3f9cd09632 100644
--- a/src/libstd/rt/kill.rs
+++ b/src/libstd/rt/kill.rs
@@ -151,7 +151,6 @@ There are two known issues with the current scheme for exit code propagation.
 */
 
 use cast;
-use cell::Cell;
 use option::{Option, Some, None};
 use prelude::*;
 use rt::task::Task;
@@ -256,8 +255,10 @@ impl Death {
 
     /// Collect failure exit codes from children and propagate them to a parent.
     pub fn collect_failure(&mut self, result: UnwindResult) {
-        let result = Cell::new(result);
-        self.on_exit.take().map(|on_exit| on_exit(result.take()));
+        match self.on_exit.take() {
+            None => {}
+            Some(on_exit) => on_exit(result),
+        }
     }
 
     /// Enter a possibly-nested "atomic" section of code. Just for assertions.
diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs
index 2375ce55766..d73ad98a25b 100644
--- a/src/libstd/rt/local.rs
+++ b/src/libstd/rt/local.rs
@@ -12,36 +12,28 @@ use option::{Option, Some, None};
 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]
@@ -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) {
-        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 {
@@ -71,24 +85,12 @@ impl Local for 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 {
@@ -182,11 +184,11 @@ mod test {
             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);
         }
     }
diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs
index 2386a261bdf..e364137de45 100644
--- a/src/libstd/rt/local_heap.rs
+++ b/src/libstd/rt/local_heap.rs
@@ -304,7 +304,8 @@ pub unsafe fn local_free(ptr: *libc::c_char) {
 }
 
 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)]
diff --git a/src/libstd/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs
index be3b5f951eb..66fe9742121 100644
--- a/src/libstd/rt/local_ptr.rs
+++ b/src/libstd/rt/local_ptr.rs
@@ -18,8 +18,7 @@
 #[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
@@ -28,20 +27,48 @@ pub use self::native::*;
 #[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
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 3d0222cefae..ce8d1ab1983 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -57,7 +57,6 @@ Several modules in `core` are clients of `rt`:
 // XXX: this should not be here.
 #[allow(missing_doc)];
 
-use cell::Cell;
 use clone::Clone;
 use container::Container;
 use iter::Iterator;
@@ -274,7 +273,7 @@ fn run_(main: proc(), use_main_sched: bool) -> int {
 
     let nscheds = util::default_sched_threads();
 
-    let main = Cell::new(main);
+    let mut main = Some(main);
 
     // The shared list of sleeping schedulers.
     let sleepers = SleeperList::new();
@@ -376,24 +375,24 @@ fn run_(main: proc(), use_main_sched: bool) -> int {
     };
 
     let mut threads = ~[];
-
-    let on_exit = Cell::new(on_exit);
+    let mut on_exit = Some(on_exit);
 
     if !use_main_sched {
 
         // In the case where we do not use a main_thread scheduler we
         // run the main task in one of our threads.
 
-        let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, main.take());
+        let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
+                                            None,
+                                            ::util::replace(&mut main,
+                                                            None).unwrap());
         main_task.name = Some(SendStrStatic("<main>"));
-        main_task.death.on_exit = Some(on_exit.take());
-        let main_task_cell = Cell::new(main_task);
+        main_task.death.on_exit = ::util::replace(&mut on_exit, None);
 
         let sched = scheds.pop();
-        let sched_cell = Cell::new(sched);
+        let main_task = main_task;
         let thread = do Thread::start {
-            let sched = sched_cell.take();
-            sched.bootstrap(main_task_cell.take());
+            sched.bootstrap(main_task);
         };
         threads.push(thread);
     }
@@ -401,9 +400,8 @@ fn run_(main: proc(), use_main_sched: bool) -> int {
     // Run each remaining scheduler in a thread.
     for sched in scheds.move_rev_iter() {
         rtdebug!("creating regular schedulers");
-        let sched_cell = Cell::new(sched);
         let thread = do Thread::start {
-            let mut sched = sched_cell.take();
+            let mut sched = sched;
             let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || {
                 rtdebug!("boostraping a non-primary scheduler");
             };
@@ -415,16 +413,19 @@ fn run_(main: proc(), use_main_sched: bool) -> int {
     // If we do have a main thread scheduler, run it now.
 
     if use_main_sched {
-
         rtdebug!("about to create the main scheduler task");
 
         let mut main_sched = main_sched.unwrap();
 
         let home = Sched(main_sched.make_handle());
-        let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None,
-                                                  home, main.take());
+        let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool,
+                                                  None,
+                                                  home,
+                                                  ::util::replace(&mut main,
+                                                                  None).
+                                                                  unwrap());
         main_task.name = Some(SendStrStatic("<main>"));
-        main_task.death.on_exit = Some(on_exit.take());
+        main_task.death.on_exit = ::util::replace(&mut on_exit, None);
         rtdebug!("bootstrapping main_task");
 
         main_sched.bootstrap(main_task);
diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs
index f83932f9ffa..05cc051a23e 100644
--- a/src/libstd/rt/rtio.rs
+++ b/src/libstd/rt/rtio.rs
@@ -9,15 +9,19 @@
 // except according to those terms.
 
 use c_str::CString;
+use cast;
 use comm::{SharedChan, PortOne, Port};
 use libc::c_int;
 use libc;
+use ops::Drop;
 use option::*;
 use path::Path;
 use result::*;
 
 use ai = io::net::addrinfo;
 use io::IoError;
+use io::native::NATIVE_IO_FACTORY;
+use io::native;
 use io::net::ip::{IpAddr, SocketAddr};
 use io::process::{ProcessConfig, ProcessExit};
 use io::signal::Signum;
@@ -34,9 +38,8 @@ pub trait EventLoop {
     fn pausible_idle_callback(&mut self, ~Callback) -> ~PausibleIdleCallback;
     fn remote_callback(&mut self, ~Callback) -> ~RemoteCallback;
 
-    /// The asynchronous I/O services. Not all event loops may provide one
-    // FIXME(#9382) this is an awful interface
-    fn io<'a>(&'a mut self, f: |&'a mut IoFactory|);
+    /// The asynchronous I/O services. Not all event loops may provide one.
+    fn io<'a>(&'a mut self) -> Option<&'a mut IoFactory>;
 }
 
 pub trait RemoteCallback {
@@ -75,31 +78,60 @@ pub enum CloseBehavior {
     CloseAsynchronously,
 }
 
-pub fn with_local_io<T>(f: |&mut IoFactory| -> Option<T>) -> Option<T> {
-    use rt::sched::Scheduler;
-    use rt::local::Local;
-    use io::native;
-
-    unsafe {
-        // First, attempt to use the local scheduler's I/O services
-        let sched: Option<*mut Scheduler> = Local::try_unsafe_borrow();
-        match sched {
-            Some(sched) => {
-                let mut io = None;
-                (*sched).event_loop.io(|i| io = Some(i));
-                match io {
-                    Some(io) => return f(io),
-                    None => {}
+pub struct LocalIo<'a> {
+    priv factory: &'a mut IoFactory,
+}
+
+#[unsafe_destructor]
+impl<'a> Drop for LocalIo<'a> {
+    fn drop(&mut self) {
+        // XXX(pcwalton): Do nothing here for now, but eventually we may want
+        // something. For now this serves to make `LocalIo` noncopyable.
+    }
+}
+
+impl<'a> LocalIo<'a> {
+    /// Returns the local I/O: either the local scheduler's I/O services or
+    /// the native I/O services.
+    pub fn borrow() -> LocalIo {
+        use rt::sched::Scheduler;
+        use rt::local::Local;
+
+        unsafe {
+            // First, attempt to use the local scheduler's I/O services
+            let sched: Option<*mut Scheduler> = Local::try_unsafe_borrow();
+            match sched {
+                Some(sched) => {
+                    match (*sched).event_loop.io() {
+                        Some(factory) => {
+                            return LocalIo {
+                                factory: factory,
+                            }
+                        }
+                        None => {}
+                    }
                 }
+                None => {}
+            }
+            // If we don't have a scheduler or the scheduler doesn't have I/O
+            // services, then fall back to the native I/O services.
+            let native_io: &'static mut native::IoFactory =
+                &mut NATIVE_IO_FACTORY;
+            LocalIo {
+                factory: native_io as &mut IoFactory:'static
             }
-            None => {}
         }
     }
 
-    // If we don't have a scheduler or the scheduler doesn't have I/O services,
-    // then fall back to the native I/O services.
-    let mut io = native::IoFactory;
-    f(&mut io as &mut IoFactory)
+    /// Returns the underlying I/O factory as a trait reference.
+    #[inline]
+    pub fn get<'a>(&'a mut self) -> &'a mut IoFactory {
+        // XXX(pcwalton): I think this is actually sound? Could borrow check
+        // allow this safely?
+        unsafe {
+            cast::transmute_copy(&self.factory)
+        }
+    }
 }
 
 pub trait IoFactory {
diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs
index eb5b2df4ed9..eefed412466 100644
--- a/src/libstd/rt/sched.rs
+++ b/src/libstd/rt/sched.rs
@@ -24,7 +24,6 @@ use rt::local_ptr;
 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;
@@ -235,12 +234,12 @@ impl Scheduler {
         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();
         }
@@ -751,10 +750,8 @@ impl Scheduler {
     }
 
     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
@@ -922,7 +919,6 @@ mod test {
     use unstable::run_in_bare_thread;
     use borrow::to_uint;
     use rt::sched::{Scheduler};
-    use cell::Cell;
     use rt::deque::BufferPool;
     use rt::thread::Thread;
     use rt::task::{Task, Sched};
@@ -1048,7 +1044,7 @@ mod test {
                 queues.clone(),
                 sleepers.clone());
 
-            let normal_handle = Cell::new(normal_sched.make_handle());
+            let normal_handle = normal_sched.make_handle();
 
             let friend_handle = normal_sched.make_handle();
 
@@ -1061,7 +1057,7 @@ mod test {
                 false,
                 Some(friend_handle));
 
-            let special_handle = Cell::new(special_sched.make_handle());
+            let special_handle = special_sched.make_handle();
 
             let t1_handle = special_sched.make_handle();
             let t4_handle = special_sched.make_handle();
@@ -1092,26 +1088,19 @@ mod test {
             };
             rtdebug!("task4 id: **{}**", borrow::to_uint(task4));
 
-            let task1 = Cell::new(task1);
-            let task2 = Cell::new(task2);
-            let task3 = Cell::new(task3);
-            let task4 = Cell::new(task4);
-
             // Signal from the special task that we are done.
             let (port, chan) = oneshot::<()>();
-            let port = Cell::new(port);
-            let chan = Cell::new(chan);
 
             let normal_task = ~do Task::new_root(&mut normal_sched.stack_pool, None) {
                 rtdebug!("*about to submit task2*");
-                Scheduler::run_task(task2.take());
+                Scheduler::run_task(task2);
                 rtdebug!("*about to submit task4*");
-                Scheduler::run_task(task4.take());
+                Scheduler::run_task(task4);
                 rtdebug!("*normal_task done*");
-                port.take().recv();
-                let mut nh = normal_handle.take();
+                port.recv();
+                let mut nh = normal_handle;
                 nh.send(Shutdown);
-                let mut sh = special_handle.take();
+                let mut sh = special_handle;
                 sh.send(Shutdown);
             };
 
@@ -1119,27 +1108,24 @@ mod test {
 
             let special_task = ~do Task::new_root(&mut special_sched.stack_pool, None) {
                 rtdebug!("*about to submit task1*");
-                Scheduler::run_task(task1.take());
+                Scheduler::run_task(task1);
                 rtdebug!("*about to submit task3*");
-                Scheduler::run_task(task3.take());
+                Scheduler::run_task(task3);
                 rtdebug!("*done with special_task*");
-                chan.take().send(());
+                chan.send(());
             };
 
             rtdebug!("special task: {}", borrow::to_uint(special_task));
 
-            let special_sched = Cell::new(special_sched);
-            let normal_sched = Cell::new(normal_sched);
-            let special_task = Cell::new(special_task);
-            let normal_task = Cell::new(normal_task);
-
+            let normal_sched = normal_sched;
             let normal_thread = do Thread::start {
-                normal_sched.take().bootstrap(normal_task.take());
+                normal_sched.bootstrap(normal_task);
                 rtdebug!("finished with normal_thread");
             };
 
+            let special_sched = special_sched;
             let special_thread = do Thread::start {
-                special_sched.take().bootstrap(special_task.take());
+                special_sched.bootstrap(special_task);
                 rtdebug!("finished with special_sched");
             };
 
@@ -1178,20 +1164,18 @@ mod test {
 
         do run_in_bare_thread {
             let (port, chan) = oneshot::<()>();
-            let port = Cell::new(port);
-            let chan = Cell::new(chan);
 
             let thread_one = do Thread::start {
-                let chan = Cell::new(chan.take());
+                let chan = chan;
                 do run_in_newsched_task_core {
-                    chan.take().send(());
+                    chan.send(());
                 }
             };
 
             let thread_two = do Thread::start {
-                let port = Cell::new(port.take());
+                let port = port;
                 do run_in_newsched_task_core {
-                    port.take().recv();
+                    port.recv();
                 }
             };
 
@@ -1222,10 +1206,9 @@ mod test {
 
                 let mut handle = sched.make_handle();
 
-                let sched = Cell::new(sched);
-
+                let sched = sched;
                 let thread = do Thread::start {
-                    let mut sched = sched.take();
+                    let mut sched = sched;
                     let bootstrap_task =
                         ~Task::new_root(&mut sched.stack_pool,
                                         None,
@@ -1256,9 +1239,8 @@ mod test {
             let mut ports = ~[];
             10.times(|| {
                 let (port, chan) = oneshot();
-                let chan_cell = Cell::new(chan);
                 do spawntask_later {
-                    chan_cell.take().send(());
+                    chan.send(());
                 }
                 ports.push(port);
             });
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
index 63cc397e8d7..86cc895eb27 100644
--- a/src/libstd/rt/task.rs
+++ b/src/libstd/rt/task.rs
@@ -19,7 +19,6 @@ use prelude::*;
 
 use borrow;
 use cast::transmute;
-use cell::Cell;
 use cleanup;
 use libc::{c_void, uintptr_t, c_char, size_t};
 use local_data;
@@ -144,17 +143,15 @@ impl 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 = ~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 {
@@ -165,17 +162,14 @@ impl 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 {
@@ -371,26 +365,25 @@ impl 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");
+            }
+        }
     }
 }
 
@@ -433,16 +426,16 @@ impl Coroutine {
     }
 
     fn build_start_wrapper(start: proc()) -> proc() {
-        let start_cell = Cell::new(start);
         let wrapper: proc() = proc() {
             // First code after swap to this new context. Run our
             // cleanup job.
             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
@@ -451,6 +444,7 @@ impl Coroutine {
                 // need to unsafe_borrow.
                 let task: *mut Task = Local::unsafe_borrow();
 
+                let mut start_cell = Some(start);
                 (*task).run(|| {
                     // N.B. Removing `start` from the start wrapper
                     // closure by emptying a cell is critical for
@@ -462,7 +456,7 @@ impl Coroutine {
                     // be in task context. By moving `start` out of
                     // the closure, all the user code goes our of
                     // scope while the task is still running.
-                    let start = start_cell.take();
+                    let start = start_cell.take_unwrap();
                     start();
                 });
             }
@@ -594,16 +588,19 @@ pub extern "C" fn rust_stack_exhausted() {
         //  #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");
         }
diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs
index 2ab543a4c36..96b80d11129 100644
--- a/src/libstd/rt/test.rs
+++ b/src/libstd/rt/test.rs
@@ -10,7 +10,6 @@
 
 use io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
 
-use cell::Cell;
 use clone::Clone;
 use container::Container;
 use iter::{Iterator, range};
@@ -65,16 +64,14 @@ pub fn new_test_sched() -> Scheduler {
 }
 
 pub fn run_in_uv_task(f: proc()) {
-    let f = Cell::new(f);
     do run_in_bare_thread {
-        run_in_uv_task_core(f.take());
+        run_in_uv_task_core(f);
     }
 }
 
 pub fn run_in_newsched_task(f: proc()) {
-    let f = Cell::new(f);
     do run_in_bare_thread {
-        run_in_newsched_task_core(f.take());
+        run_in_newsched_task_core(f);
     }
 }
 
@@ -206,8 +203,6 @@ pub fn run_in_mt_newsched_task(f: proc()) {
     // see comment in other function (raising fd limits)
     prepare_for_lots_of_tests();
 
-    let f = Cell::new(f);
-
     do run_in_bare_thread {
         let nthreads = match os::getenv("RUST_RT_TEST_THREADS") {
             Some(nstr) => FromStr::from_str(nstr).unwrap(),
@@ -254,18 +249,18 @@ pub fn run_in_mt_newsched_task(f: proc()) {
 
             rtassert!(exit_status.is_success());
         };
-        let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, f.take());
+        let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
+                                            None,
+                                            f);
         main_task.death.on_exit = Some(on_exit);
 
         let mut threads = ~[];
-        let main_task = Cell::new(main_task);
 
         let main_thread = {
             let sched = scheds.pop();
-            let sched_cell = Cell::new(sched);
+            let main_task = main_task;
             do Thread::start {
-                let sched = sched_cell.take();
-                sched.bootstrap(main_task.take());
+                sched.bootstrap(main_task);
             }
         };
         threads.push(main_thread);
@@ -275,11 +270,9 @@ pub fn run_in_mt_newsched_task(f: proc()) {
             let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || {
                 rtdebug!("bootstrapping non-primary scheduler");
             };
-            let bootstrap_task_cell = Cell::new(bootstrap_task);
-            let sched_cell = Cell::new(sched);
+            let sched = sched;
             let thread = do Thread::start {
-                let sched = sched_cell.take();
-                sched.bootstrap(bootstrap_task_cell.take());
+                sched.bootstrap(bootstrap_task);
             };
 
             threads.push(thread);
@@ -335,11 +328,8 @@ pub fn spawntask_try(f: proc()) -> Result<(),()> {
 
 /// Spawn a new task in a new scheduler and return a thread handle.
 pub fn spawntask_thread(f: proc()) -> Thread<()> {
-
-    let f = Cell::new(f);
-
     let thread = do Thread::start {
-        run_in_newsched_task_core(f.take());
+        run_in_newsched_task_core(f);
     };
 
     return thread;
diff --git a/src/libstd/rt/tube.rs b/src/libstd/rt/tube.rs
index 0d4171d5a64..5e867bcdfba 100644
--- a/src/libstd/rt/tube.rs
+++ b/src/libstd/rt/tube.rs
@@ -88,7 +88,6 @@ impl<T> Clone for Tube<T> {
 
 #[cfg(test)]
 mod test {
-    use cell::Cell;
     use rt::test::*;
     use rt::rtio::EventLoop;
     use rt::sched::Scheduler;
@@ -100,11 +99,10 @@ mod test {
     fn simple_test() {
         do run_in_newsched_task {
             let mut tube: Tube<int> = Tube::new();
-            let tube_clone = tube.clone();
-            let tube_clone_cell = Cell::new(tube_clone);
+            let mut tube_clone = Some(tube.clone());
             let sched: ~Scheduler = Local::take();
             sched.deschedule_running_task_and_then(|sched, task| {
-                let mut tube_clone = tube_clone_cell.take();
+                let mut tube_clone = tube_clone.take_unwrap();
                 tube_clone.send(1);
                 sched.enqueue_blocked_task(task);
             });
@@ -117,13 +115,12 @@ mod test {
     fn blocking_test() {
         do run_in_newsched_task {
             let mut tube: Tube<int> = Tube::new();
-            let tube_clone = tube.clone();
-            let tube_clone = Cell::new(tube_clone);
+            let mut tube_clone = Some(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_unwrap();
                 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);
@@ -141,26 +138,24 @@ mod test {
 
         do run_in_newsched_task {
             let mut tube: Tube<int> = Tube::new();
-            let tube_clone = tube.clone();
-            let tube_clone = Cell::new(tube_clone);
+            let mut tube_clone = Some(tube.clone());
             let sched: ~Scheduler = Local::take();
             sched.deschedule_running_task_and_then(|sched, task| {
-                callback_send(tube_clone.take(), 0);
+                callback_send(tube_clone.take_unwrap(), 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);