]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/uv/idle.rs
a21146620ca823ec8643adfdb84c00f31a391b38
[rust.git] / src / 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(idle_watcher, 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(idle_watcher, 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 }