2013-10-22 17:13:18 -05:00
|
|
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-11-04 14:45:05 -06:00
|
|
|
use std::cast;
|
2014-02-26 11:58:41 -06:00
|
|
|
use libc::{c_int, c_void};
|
2013-10-22 17:13:18 -05:00
|
|
|
|
|
|
|
use uvll;
|
2013-11-04 14:45:05 -06:00
|
|
|
use super::{Loop, UvHandle};
|
2013-12-14 23:29:17 -06:00
|
|
|
use std::rt::rtio::{Callback, PausableIdleCallback};
|
2013-10-22 17:13:18 -05:00
|
|
|
|
2013-11-04 14:45:05 -06:00
|
|
|
pub struct IdleWatcher {
|
|
|
|
handle: *uvll::uv_idle_t,
|
|
|
|
idle_flag: bool,
|
|
|
|
closed: bool,
|
2014-03-08 20:21:49 -06:00
|
|
|
callback: ~Callback:Send,
|
2013-11-04 14:45:05 -06:00
|
|
|
}
|
2013-10-22 17:13:18 -05:00
|
|
|
|
|
|
|
impl IdleWatcher {
|
2014-03-08 20:21:49 -06:00
|
|
|
pub fn new(loop_: &mut Loop, cb: ~Callback:Send) -> ~IdleWatcher {
|
2013-11-04 14:45:05 -06:00
|
|
|
let handle = UvHandle::alloc(None::<IdleWatcher>, uvll::UV_IDLE);
|
|
|
|
assert_eq!(unsafe {
|
2013-11-05 13:29:45 -06:00
|
|
|
uvll::uv_idle_init(loop_.handle, handle)
|
2013-11-04 14:45:05 -06:00
|
|
|
}, 0);
|
|
|
|
let me = ~IdleWatcher {
|
|
|
|
handle: handle,
|
|
|
|
idle_flag: false,
|
|
|
|
closed: false,
|
2013-11-06 13:38:53 -06:00
|
|
|
callback: cb,
|
2013-11-04 14:45:05 -06:00
|
|
|
};
|
|
|
|
return me.install();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn onetime(loop_: &mut Loop, f: proc()) {
|
|
|
|
let handle = UvHandle::alloc(None::<IdleWatcher>, uvll::UV_IDLE);
|
2013-10-22 17:13:18 -05:00
|
|
|
unsafe {
|
2013-11-05 13:29:45 -06:00
|
|
|
assert_eq!(uvll::uv_idle_init(loop_.handle, handle), 0);
|
2013-11-04 14:45:05 -06:00
|
|
|
let data: *c_void = cast::transmute(~f);
|
|
|
|
uvll::set_data_for_uv_handle(handle, data);
|
2013-11-04 16:03:32 -06:00
|
|
|
assert_eq!(uvll::uv_idle_start(handle, onetime_cb), 0)
|
2013-10-22 17:13:18 -05:00
|
|
|
}
|
|
|
|
|
2013-11-04 14:45:05 -06:00
|
|
|
extern fn onetime_cb(handle: *uvll::uv_idle_t, status: c_int) {
|
|
|
|
assert_eq!(status, 0);
|
|
|
|
unsafe {
|
|
|
|
let data = uvll::get_data_for_uv_handle(handle);
|
|
|
|
let f: ~proc() = cast::transmute(data);
|
|
|
|
(*f)();
|
2014-01-30 16:28:36 -06:00
|
|
|
assert_eq!(uvll::uv_idle_stop(handle), 0);
|
2013-11-04 16:03:32 -06:00
|
|
|
uvll::uv_close(handle, close_cb);
|
2013-11-04 14:45:05 -06:00
|
|
|
}
|
2013-10-22 17:13:18 -05:00
|
|
|
}
|
|
|
|
|
2013-11-04 14:45:05 -06:00
|
|
|
extern fn close_cb(handle: *uvll::uv_handle_t) {
|
|
|
|
unsafe { uvll::free_handle(handle) }
|
2013-10-22 17:13:18 -05:00
|
|
|
}
|
|
|
|
}
|
2013-11-04 14:45:05 -06:00
|
|
|
}
|
2013-10-22 17:13:18 -05:00
|
|
|
|
2013-12-14 23:29:17 -06:00
|
|
|
impl PausableIdleCallback for IdleWatcher {
|
2013-11-04 14:45:05 -06:00
|
|
|
fn pause(&mut self) {
|
|
|
|
if self.idle_flag == true {
|
2013-11-04 16:03:32 -06:00
|
|
|
assert_eq!(unsafe {uvll::uv_idle_stop(self.handle) }, 0);
|
2013-11-04 14:45:05 -06:00
|
|
|
self.idle_flag = false;
|
2013-10-22 17:13:18 -05:00
|
|
|
}
|
|
|
|
}
|
2013-11-04 14:45:05 -06:00
|
|
|
fn resume(&mut self) {
|
|
|
|
if self.idle_flag == false {
|
2013-11-04 16:03:32 -06:00
|
|
|
assert_eq!(unsafe { uvll::uv_idle_start(self.handle, idle_cb) }, 0)
|
2013-11-04 14:45:05 -06:00
|
|
|
self.idle_flag = true;
|
|
|
|
}
|
|
|
|
}
|
2013-10-22 17:13:18 -05:00
|
|
|
}
|
|
|
|
|
2013-11-04 14:45:05 -06:00
|
|
|
impl UvHandle<uvll::uv_idle_t> for IdleWatcher {
|
|
|
|
fn uv_handle(&self) -> *uvll::uv_idle_t { self.handle }
|
2013-10-22 17:13:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
|
2013-11-04 14:45:05 -06:00
|
|
|
assert_eq!(status, 0);
|
|
|
|
let idle: &mut IdleWatcher = unsafe { UvHandle::from_uv_handle(&handle) };
|
2013-11-06 13:38:53 -06:00
|
|
|
idle.callback.call();
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for IdleWatcher {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.pause();
|
|
|
|
self.close_async_();
|
|
|
|
}
|
2013-10-22 17:13:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2013-12-13 13:30:59 -06:00
|
|
|
use std::cast;
|
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::rc::Rc;
|
2013-12-18 11:57:58 -06:00
|
|
|
use std::rt::rtio::{Callback, PausableIdleCallback};
|
2013-12-13 13:30:59 -06:00
|
|
|
use std::rt::task::{BlockedTask, Task};
|
|
|
|
use std::rt::local::Local;
|
|
|
|
use super::IdleWatcher;
|
2013-11-07 17:13:06 -06:00
|
|
|
use super::super::local_loop;
|
2013-11-06 13:38:53 -06:00
|
|
|
|
2013-12-13 13:30:59 -06:00
|
|
|
type Chan = Rc<RefCell<(Option<BlockedTask>, uint)>>;
|
|
|
|
|
|
|
|
struct MyCallback(Rc<RefCell<(Option<BlockedTask>, uint)>>, uint);
|
2013-11-06 13:38:53 -06:00
|
|
|
impl Callback for MyCallback {
|
|
|
|
fn call(&mut self) {
|
2013-12-13 13:30:59 -06:00
|
|
|
let task = match *self {
|
|
|
|
MyCallback(ref rc, n) => {
|
2014-03-22 10:56:21 -05:00
|
|
|
match *rc.borrow_mut().deref_mut() {
|
2013-12-13 13:30:59 -06:00
|
|
|
(ref mut task, ref mut val) => {
|
|
|
|
*val = n;
|
2014-02-14 10:42:23 -06:00
|
|
|
match task.take() {
|
|
|
|
Some(t) => t,
|
|
|
|
None => return
|
|
|
|
}
|
2013-12-13 13:30:59 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2014-01-16 21:58:42 -06:00
|
|
|
let _ = task.wake().map(|t| t.reawaken());
|
2013-11-06 13:38:53 -06:00
|
|
|
}
|
|
|
|
}
|
2013-10-22 17:13:18 -05:00
|
|
|
|
2013-12-13 13:30:59 -06:00
|
|
|
fn mk(v: uint) -> (~IdleWatcher, Chan) {
|
2014-01-09 14:56:38 -06:00
|
|
|
let rc = Rc::new(RefCell::new((None, 0)));
|
2013-12-13 13:30:59 -06:00
|
|
|
let cb = ~MyCallback(rc.clone(), v);
|
|
|
|
let cb = cb as ~Callback:;
|
|
|
|
let cb = unsafe { cast::transmute(cb) };
|
|
|
|
(IdleWatcher::new(&mut local_loop().loop_, cb), rc)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sleep(chan: &Chan) -> uint {
|
|
|
|
let task: ~Task = Local::take();
|
|
|
|
task.deschedule(1, |task| {
|
2014-03-22 10:56:21 -05:00
|
|
|
match *chan.borrow_mut().deref_mut() {
|
2013-12-13 13:30:59 -06:00
|
|
|
(ref mut slot, _) => {
|
|
|
|
assert!(slot.is_none());
|
|
|
|
*slot = Some(task);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
|
2014-03-22 10:56:21 -05:00
|
|
|
match *chan.borrow() { (_, n) => n }
|
2013-12-13 13:30:59 -06:00
|
|
|
}
|
|
|
|
|
2013-10-22 17:13:18 -05:00
|
|
|
#[test]
|
2013-11-06 13:38:53 -06:00
|
|
|
fn not_used() {
|
2013-12-13 13:30:59 -06:00
|
|
|
let (_idle, _chan) = mk(1);
|
2013-10-22 17:13:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-11-06 13:38:53 -06:00
|
|
|
fn smoke_test() {
|
2013-12-13 13:30:59 -06:00
|
|
|
let (mut idle, chan) = mk(1);
|
2013-11-07 17:13:06 -06:00
|
|
|
idle.resume();
|
2013-12-13 13:30:59 -06:00
|
|
|
assert_eq!(sleep(&chan), 1);
|
2013-10-22 17:13:18 -05:00
|
|
|
}
|
|
|
|
|
2013-11-07 22:13:25 -06:00
|
|
|
#[test] #[should_fail]
|
|
|
|
fn smoke_fail() {
|
2014-02-17 16:41:33 -06:00
|
|
|
// By default, the test harness is capturing our stderr output through a
|
|
|
|
// channel. This means that when we start failing and "print" our error
|
|
|
|
// message, we could be switched to running on another test. The
|
|
|
|
// IdleWatcher assumes that we're already running on the same task, so
|
|
|
|
// it can cause serious problems and internal race conditions.
|
|
|
|
//
|
|
|
|
// To fix this bug, we just set our stderr to a null writer which will
|
|
|
|
// never reschedule us, so we're guaranteed to stay on the same
|
|
|
|
// task/event loop.
|
|
|
|
use std::io;
|
|
|
|
drop(io::stdio::set_stderr(~io::util::NullWriter));
|
|
|
|
|
2013-12-13 13:30:59 -06:00
|
|
|
let (mut idle, _chan) = mk(1);
|
2013-11-07 22:13:25 -06:00
|
|
|
idle.resume();
|
|
|
|
fail!();
|
|
|
|
}
|
|
|
|
|
2013-10-22 17:13:18 -05:00
|
|
|
#[test]
|
2013-11-06 13:38:53 -06:00
|
|
|
fn fun_combinations_of_methods() {
|
2013-12-13 13:30:59 -06:00
|
|
|
let (mut idle, chan) = mk(1);
|
2013-11-07 17:13:06 -06:00
|
|
|
idle.resume();
|
2013-12-13 13:30:59 -06:00
|
|
|
assert_eq!(sleep(&chan), 1);
|
2013-11-07 17:13:06 -06:00
|
|
|
idle.pause();
|
|
|
|
idle.resume();
|
|
|
|
idle.resume();
|
2013-12-13 13:30:59 -06:00
|
|
|
assert_eq!(sleep(&chan), 1);
|
2013-11-07 17:13:06 -06:00
|
|
|
idle.pause();
|
|
|
|
idle.pause();
|
|
|
|
idle.resume();
|
2013-12-13 13:30:59 -06:00
|
|
|
assert_eq!(sleep(&chan), 1);
|
2013-11-06 13:38:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn pause_pauses() {
|
2013-12-13 13:30:59 -06:00
|
|
|
let (mut idle1, chan1) = mk(1);
|
|
|
|
let (mut idle2, chan2) = mk(2);
|
2013-11-07 17:13:06 -06:00
|
|
|
idle2.resume();
|
2013-12-13 13:30:59 -06:00
|
|
|
assert_eq!(sleep(&chan2), 2);
|
2013-11-07 17:13:06 -06:00
|
|
|
idle2.pause();
|
|
|
|
idle1.resume();
|
2013-12-13 13:30:59 -06:00
|
|
|
assert_eq!(sleep(&chan1), 1);
|
2013-10-22 17:13:18 -05:00
|
|
|
}
|
|
|
|
}
|