1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use std::libc::{c_int, c_void};
15 use super::{Loop, UvHandle};
16 use std::rt::rtio::{Callback, PausableIdleCallback};
18 pub struct IdleWatcher {
19 handle: *uvll::uv_idle_t,
26 pub fn new(loop_: &mut Loop, cb: ~Callback) -> ~IdleWatcher {
27 let handle = UvHandle::alloc(None::<IdleWatcher>, uvll::UV_IDLE);
29 uvll::uv_idle_init(loop_.handle, handle)
31 let me = ~IdleWatcher {
40 pub fn onetime(loop_: &mut Loop, f: proc()) {
41 let handle = UvHandle::alloc(None::<IdleWatcher>, uvll::UV_IDLE);
43 assert_eq!(uvll::uv_idle_init(loop_.handle, handle), 0);
44 let data: *c_void = cast::transmute(~f);
45 uvll::set_data_for_uv_handle(handle, data);
46 assert_eq!(uvll::uv_idle_start(handle, onetime_cb), 0)
49 extern fn onetime_cb(handle: *uvll::uv_idle_t, status: c_int) {
50 assert_eq!(status, 0);
52 let data = uvll::get_data_for_uv_handle(handle);
53 let f: ~proc() = cast::transmute(data);
55 assert_eq!(uvll::uv_idle_stop(handle), 0);
56 uvll::uv_close(handle, close_cb);
60 extern fn close_cb(handle: *uvll::uv_handle_t) {
61 unsafe { uvll::free_handle(handle) }
66 impl PausableIdleCallback for IdleWatcher {
68 if self.idle_flag == true {
69 assert_eq!(unsafe {uvll::uv_idle_stop(self.handle) }, 0);
70 self.idle_flag = false;
73 fn resume(&mut self) {
74 if self.idle_flag == false {
75 assert_eq!(unsafe { uvll::uv_idle_start(self.handle, idle_cb) }, 0)
76 self.idle_flag = true;
81 impl UvHandle<uvll::uv_idle_t> for IdleWatcher {
82 fn uv_handle(&self) -> *uvll::uv_idle_t { self.handle }
85 extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
86 assert_eq!(status, 0);
87 let idle: &mut IdleWatcher = unsafe { UvHandle::from_uv_handle(&handle) };
91 impl Drop for IdleWatcher {
101 use std::cell::RefCell;
103 use std::rt::rtio::{Callback, PausableIdleCallback};
104 use std::rt::task::{BlockedTask, Task};
105 use std::rt::local::Local;
106 use super::IdleWatcher;
107 use super::super::local_loop;
109 type Chan = Rc<RefCell<(Option<BlockedTask>, uint)>>;
111 struct MyCallback(Rc<RefCell<(Option<BlockedTask>, uint)>>, uint);
112 impl Callback for MyCallback {
114 let task = match *self {
115 MyCallback(ref rc, n) => {
116 match *rc.borrow_mut().deref_mut() {
117 (ref mut task, ref mut val) => {
127 let _ = task.wake().map(|t| t.reawaken());
131 fn mk(v: uint) -> (~IdleWatcher, Chan) {
132 let rc = Rc::new(RefCell::new((None, 0)));
133 let cb = ~MyCallback(rc.clone(), v);
134 let cb = cb as ~Callback:;
135 let cb = unsafe { cast::transmute(cb) };
136 (IdleWatcher::new(&mut local_loop().loop_, cb), rc)
139 fn sleep(chan: &Chan) -> uint {
140 let task: ~Task = Local::take();
141 task.deschedule(1, |task| {
142 match *chan.borrow_mut().deref_mut() {
143 (ref mut slot, _) => {
144 assert!(slot.is_none());
151 match *chan.borrow() { (_, n) => n }
156 let (_idle, _chan) = mk(1);
161 let (mut idle, chan) = mk(1);
163 assert_eq!(sleep(&chan), 1);
166 #[test] #[should_fail]
168 // By default, the test harness is capturing our stderr output through a
169 // channel. This means that when we start failing and "print" our error
170 // message, we could be switched to running on another test. The
171 // IdleWatcher assumes that we're already running on the same task, so
172 // it can cause serious problems and internal race conditions.
174 // To fix this bug, we just set our stderr to a null writer which will
175 // never reschedule us, so we're guaranteed to stay on the same
178 drop(io::stdio::set_stderr(~io::util::NullWriter));
180 let (mut idle, _chan) = mk(1);
186 fn fun_combinations_of_methods() {
187 let (mut idle, chan) = mk(1);
189 assert_eq!(sleep(&chan), 1);
193 assert_eq!(sleep(&chan), 1);
197 assert_eq!(sleep(&chan), 1);
202 let (mut idle1, chan1) = mk(1);
203 let (mut idle2, chan2) = mk(2);
205 assert_eq!(sleep(&chan2), 2);
208 assert_eq!(sleep(&chan1), 1);