diff options
| author | bors <bors@rust-lang.org> | 2013-12-10 19:16:19 -0800 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-12-10 19:16:19 -0800 |
| commit | b8b16ae0996074861693f0f76d5d937fafe6a37e (patch) | |
| tree | 03f3fadcb4558ec1ddda3d61669636c1fcad1264 /src/libstd/rt | |
| parent | ac4dd9efee9248f4c3235460f3c93acc9932eb5a (diff) | |
| parent | fd7a513bef7fe3c6f5128cc53135facca37f23e5 (diff) | |
| download | rust-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.rs | 5 | ||||
| -rw-r--r-- | src/libstd/rt/borrowck.rs | 9 | ||||
| -rw-r--r-- | src/libstd/rt/comm.rs | 83 | ||||
| -rw-r--r-- | src/libstd/rt/deque.rs | 5 | ||||
| -rw-r--r-- | src/libstd/rt/kill.rs | 7 | ||||
| -rw-r--r-- | src/libstd/rt/local.rs | 88 | ||||
| -rw-r--r-- | src/libstd/rt/local_heap.rs | 3 | ||||
| -rw-r--r-- | src/libstd/rt/local_ptr.rs | 47 | ||||
| -rw-r--r-- | src/libstd/rt/mod.rs | 33 | ||||
| -rw-r--r-- | src/libstd/rt/rtio.rs | 78 | ||||
| -rw-r--r-- | src/libstd/rt/sched.rs | 76 | ||||
| -rw-r--r-- | src/libstd/rt/task.rs | 111 | ||||
| -rw-r--r-- | src/libstd/rt/test.rs | 30 | ||||
| -rw-r--r-- | src/libstd/rt/tube.rs | 43 |
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); |
