(index<- ) ./libstd/rt/uv/idle.rs
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.
4 //
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.
10
11 use libc::c_int;
12 use option::Some;
13 use rt::uv::uvll;
14 use rt::uv::{Watcher, Loop, NativeHandle, IdleCallback, NullCallback};
15 use rt::uv::status_to_maybe_uv_error;
16
17 pub struct IdleWatcher(*uvll::uv_idle_t);
18 impl Watcher for IdleWatcher { }
19
20 impl IdleWatcher {
21 pub fn new(loop_: &mut Loop) -> IdleWatcher {
22 unsafe {
23 let handle = uvll::idle_new();
24 assert!(handle.is_not_null());
25 assert!(0 == uvll::idle_init(loop_.native_handle(), handle));
26 let mut watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
27 watcher.install_watcher_data();
28 return watcher
29 }
30 }
31
32 pub fn start(&mut self, cb: IdleCallback) {
33 {
34 let data = self.get_watcher_data();
35 data.idle_cb = Some(cb);
36 }
37
38 unsafe {
39 assert!(0 == uvll::idle_start(self.native_handle(), idle_cb))
40 };
41
42 extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
43 let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
44 let data = idle_watcher.get_watcher_data();
45 let cb: &IdleCallback = data.idle_cb.get_ref();
46 let status = status_to_maybe_uv_error(status);
47 (*cb)(idle_watcher, status);
48 }
49 }
50
51 pub fn restart(&mut self) {
52 unsafe {
53 assert!(0 == uvll::idle_start(self.native_handle(), idle_cb))
54 };
55
56 extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
57 let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
58 let data = idle_watcher.get_watcher_data();
59 let cb: &IdleCallback = data.idle_cb.get_ref();
60 let status = status_to_maybe_uv_error(status);
61 (*cb)(idle_watcher, status);
62 }
63 }
64
65 pub fn stop(&mut self) {
66 // NB: Not resetting the Rust idle_cb to None here because `stop` is
67 // likely called from *within* the idle callback, causing a use after
68 // free
69
70 unsafe {
71 assert!(0 == uvll::idle_stop(self.native_handle()));
72 }
73 }
74
75 pub fn close(self, cb: NullCallback) {
76 {
77 let mut this = self;
78 let data = this.get_watcher_data();
79 assert!(data.close_cb.is_none());
80 data.close_cb = Some(cb);
81 }
82
83 unsafe { uvll::close(self.native_handle(), close_cb) };
84
85 extern fn close_cb(handle: *uvll::uv_idle_t) {
86 unsafe {
87 let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
88 {
89 let data = idle_watcher.get_watcher_data();
90 data.close_cb.take_unwrap()();
91 }
92 idle_watcher.drop_watcher_data();
93 uvll::idle_delete(handle);
94 }
95 }
96 }
97 }
98
99 impl NativeHandle<*uvll::uv_idle_t> for IdleWatcher {
100 fn from_native_handle(handle: *uvll::uv_idle_t) -> IdleWatcher {
101 IdleWatcher(handle)
102 }
103 fn native_handle(&self) -> *uvll::uv_idle_t {
104 match self { &IdleWatcher(ptr) => ptr }
105 }
106 }
107
108 #[cfg(test)]
109 mod test {
110
111 use rt::uv::Loop;
112 use super::*;
113 use unstable::run_in_bare_thread;
114
115 #[test]
116 #[ignore(reason = "valgrind - loop destroyed before watcher?")]
117 fn idle_new_then_close() {
118 do run_in_bare_thread {
119 let mut loop_ = Loop::new();
120 let idle_watcher = { IdleWatcher::new(&mut loop_) };
121 idle_watcher.close(||());
122 }
123 }
124
125 #[test]
126 fn idle_smoke_test() {
127 do run_in_bare_thread {
128 let mut loop_ = Loop::new();
129 let mut idle_watcher = { IdleWatcher::new(&mut loop_) };
130 let mut count = 10;
131 let count_ptr: *mut int = &mut count;
132 do idle_watcher.start |idle_watcher, status| {
133 let mut idle_watcher = idle_watcher;
134 assert!(status.is_none());
135 if unsafe { *count_ptr == 10 } {
136 idle_watcher.stop();
137 idle_watcher.close(||());
138 } else {
139 unsafe { *count_ptr = *count_ptr + 1; }
140 }
141 }
142 loop_.run();
143 loop_.close();
144 assert_eq!(count, 10);
145 }
146 }
147
148 #[test]
149 fn idle_start_stop_start() {
150 do run_in_bare_thread {
151 let mut loop_ = Loop::new();
152 let mut idle_watcher = { IdleWatcher::new(&mut loop_) };
153 do idle_watcher.start |idle_watcher, status| {
154 let mut idle_watcher = idle_watcher;
155 assert!(status.is_none());
156 idle_watcher.stop();
157 do idle_watcher.start |idle_watcher, status| {
158 assert!(status.is_none());
159 let mut idle_watcher = idle_watcher;
160 idle_watcher.stop();
161 idle_watcher.close(||());
162 }
163 }
164 loop_.run();
165 loop_.close();
166 }
167 }
168 }