diff --git a/src/librustuv/idle.rs b/src/librustuv/idle.rs index f4072c7c6813..b3527ce9fb42 100644 --- a/src/librustuv/idle.rs +++ b/src/librustuv/idle.rs @@ -19,11 +19,11 @@ pub struct IdleWatcher { handle: *uvll::uv_idle_t, idle_flag: bool, closed: bool, - callback: Option<~Callback>, + callback: ~Callback, } impl IdleWatcher { - pub fn new(loop_: &mut Loop) -> ~IdleWatcher { + pub fn new(loop_: &mut Loop, cb: ~Callback) -> ~IdleWatcher { let handle = UvHandle::alloc(None::, uvll::UV_IDLE); assert_eq!(unsafe { uvll::uv_idle_init(loop_.handle, handle) @@ -32,7 +32,7 @@ impl IdleWatcher { handle: handle, idle_flag: false, closed: false, - callback: None, + callback: cb, }; return me.install(); } @@ -64,12 +64,6 @@ impl IdleWatcher { } impl PausibleIdleCallback for IdleWatcher { - fn start(&mut self, cb: ~Callback) { - assert!(self.callback.is_none()); - self.callback = Some(cb); - assert_eq!(unsafe { uvll::uv_idle_start(self.handle, idle_cb) }, 0) - self.idle_flag = true; - } fn pause(&mut self) { if self.idle_flag == true { assert_eq!(unsafe {uvll::uv_idle_stop(self.handle) }, 0); @@ -82,13 +76,6 @@ impl PausibleIdleCallback for IdleWatcher { self.idle_flag = true; } } - fn close(&mut self) { - self.pause(); - if !self.closed { - self.closed = true; - self.close_async_(); - } - } } impl UvHandle for IdleWatcher { @@ -96,70 +83,86 @@ impl UvHandle for IdleWatcher { } extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) { + if status == uvll::ECANCELED { return } assert_eq!(status, 0); let idle: &mut IdleWatcher = unsafe { UvHandle::from_uv_handle(&handle) }; - assert!(idle.callback.is_some()); - idle.callback.get_mut_ref().call(); + idle.callback.call(); +} + +impl Drop for IdleWatcher { + fn drop(&mut self) { + self.pause(); + self.close_async_(); + } } #[cfg(test)] mod test { - - use Loop; use super::*; - use std::unstable::run_in_bare_thread; + use std::rt::tube::Tube; + use std::rt::rtio::{Callback, PausibleIdleCallback}; + use super::super::run_uv_loop; - #[test] - #[ignore(reason = "valgrind - loop destroyed before watcher?")] - fn idle_new_then_close() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - let idle_watcher = { IdleWatcher::new(&mut loop_) }; - idle_watcher.close(||()); + struct MyCallback(Tube, int); + impl Callback for MyCallback { + fn call(&mut self) { + match *self { + MyCallback(ref mut tube, val) => tube.send(val) + } } } #[test] - fn idle_smoke_test() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - let mut idle_watcher = { IdleWatcher::new(&mut loop_) }; - let mut count = 10; - let count_ptr: *mut int = &mut count; - do idle_watcher.start |idle_watcher, status| { - let mut idle_watcher = idle_watcher; - assert!(status.is_none()); - if unsafe { *count_ptr == 10 } { - idle_watcher.stop(); - idle_watcher.close(||()); - } else { - unsafe { *count_ptr = *count_ptr + 1; } - } - } - loop_.run(); - loop_.close(); - assert_eq!(count, 10); + fn not_used() { + do run_uv_loop |l| { + let cb = ~MyCallback(Tube::new(), 1); + let _idle = IdleWatcher::new(l, cb as ~Callback); } } #[test] - fn idle_start_stop_start() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - let mut idle_watcher = { IdleWatcher::new(&mut loop_) }; - do idle_watcher.start |idle_watcher, status| { - let mut idle_watcher = idle_watcher; - assert!(status.is_none()); - idle_watcher.stop(); - do idle_watcher.start |idle_watcher, status| { - assert!(status.is_none()); - let mut idle_watcher = idle_watcher; - idle_watcher.stop(); - idle_watcher.close(||()); - } - } - loop_.run(); - loop_.close(); + fn smoke_test() { + do run_uv_loop |l| { + let mut tube = Tube::new(); + let cb = ~MyCallback(tube.clone(), 1); + let mut idle = IdleWatcher::new(l, cb as ~Callback); + idle.resume(); + tube.recv(); + } + } + + #[test] + fn fun_combinations_of_methods() { + do run_uv_loop |l| { + let mut tube = Tube::new(); + let cb = ~MyCallback(tube.clone(), 1); + let mut idle = IdleWatcher::new(l, cb as ~Callback); + idle.resume(); + tube.recv(); + idle.pause(); + idle.resume(); + idle.resume(); + tube.recv(); + idle.pause(); + idle.pause(); + idle.resume(); + tube.recv(); + } + } + + #[test] + fn pause_pauses() { + do run_uv_loop |l| { + let mut tube = Tube::new(); + let cb = ~MyCallback(tube.clone(), 1); + let mut idle1 = IdleWatcher::new(l, cb as ~Callback); + let cb = ~MyCallback(tube.clone(), 2); + let mut idle2 = IdleWatcher::new(l, cb as ~Callback); + idle2.resume(); + assert_eq!(tube.recv(), 2); + idle2.pause(); + idle1.resume(); + assert_eq!(tube.recv(), 1); } } } diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index e9d8aab2e8b6..6ae2c174e18b 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -148,8 +148,8 @@ impl EventLoop for UvEventLoop { IdleWatcher::onetime(self.uvio.uv_loop(), f); } - fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback { - IdleWatcher::new(self.uvio.uv_loop()) as ~PausibleIdleCallback + fn pausible_idle_callback(&mut self, cb: ~Callback) -> ~PausibleIdleCallback { + IdleWatcher::new(self.uvio.uv_loop(), cb) as ~PausibleIdleCallback } fn remote_callback(&mut self, f: ~Callback) -> ~RemoteCallback { diff --git a/src/libstd/rt/basic.rs b/src/libstd/rt/basic.rs index 0c8d192d89ac..322c58bc2b80 100644 --- a/src/libstd/rt/basic.rs +++ b/src/libstd/rt/basic.rs @@ -107,7 +107,7 @@ impl BasicLoop { match self.idle { Some(idle) => { if (*idle).active { - (*idle).work.get_mut_ref().call(); + (*idle).work.call(); } } None => {} @@ -150,8 +150,8 @@ impl EventLoop for BasicLoop { } // XXX: Seems like a really weird requirement to have an event loop provide. - fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback { - let callback = ~BasicPausible::new(self); + fn pausible_idle_callback(&mut self, cb: ~Callback) -> ~PausibleIdleCallback { + let callback = ~BasicPausible::new(self, cb); rtassert!(self.idle.is_none()); unsafe { let cb_ptr: &*mut BasicPausible = cast::transmute(&callback); @@ -204,36 +204,27 @@ impl Drop for BasicRemote { struct BasicPausible { eloop: *mut BasicLoop, - work: Option<~Callback>, + work: ~Callback, active: bool, } impl BasicPausible { - fn new(eloop: &mut BasicLoop) -> BasicPausible { + fn new(eloop: &mut BasicLoop, cb: ~Callback) -> BasicPausible { BasicPausible { active: false, - work: None, + work: cb, eloop: eloop, } } } impl PausibleIdleCallback for BasicPausible { - fn start(&mut self, f: ~Callback) { - rtassert!(!self.active && self.work.is_none()); - self.active = true; - self.work = Some(f); - } fn pause(&mut self) { self.active = false; } fn resume(&mut self) { self.active = true; } - fn close(&mut self) { - self.active = false; - self.work = None; - } } impl Drop for BasicPausible { diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 96ba51234561..1e12da8645ce 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -31,7 +31,7 @@ pub trait Callback { pub trait EventLoop { fn run(&mut self); fn callback(&mut self, proc()); - fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback; + 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 @@ -226,10 +226,8 @@ pub trait RtioTTY { } pub trait PausibleIdleCallback { - fn start(&mut self, f: ~Callback); fn pause(&mut self); fn resume(&mut self); - fn close(&mut self); } pub trait RtioSignal {} diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index f84e10fe9894..c2e665f49030 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -169,7 +169,8 @@ impl Scheduler { pub fn bootstrap(mut ~self, task: ~Task) { // Build an Idle callback. - self.idle_callback = Some(self.event_loop.pausible_idle_callback()); + let cb = ~SchedRunner as ~Callback; + self.idle_callback = Some(self.event_loop.pausible_idle_callback(cb)); // Initialize the TLS key. local_ptr::init_tls_key(); @@ -184,7 +185,7 @@ impl Scheduler { // Before starting our first task, make sure the idle callback // is active. As we do not start in the sleep state this is // important. - self.idle_callback.get_mut_ref().start(~SchedRunner as ~Callback); + self.idle_callback.get_mut_ref().resume(); // Now, as far as all the scheduler state is concerned, we are // inside the "scheduler" context. So we can act like the @@ -202,7 +203,7 @@ impl Scheduler { // Close the idle callback. let mut sched: ~Scheduler = Local::take(); - sched.idle_callback.get_mut_ref().close(); + sched.idle_callback.take(); // Make one go through the loop to run the close callback. sched.run();