]> git.lizzy.rs Git - rust.git/blob - src/librustuv/lib.rs
ad1c53e97397fd1844bef5d96a399d1ae37ac411
[rust.git] / src / librustuv / lib.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 /*!
12
13 Bindings to libuv, along with the default implementation of `std::rt::rtio`.
14
15 UV types consist of the event loop (Loop), Watchers, Requests and
16 Callbacks.
17
18 Watchers and Requests encapsulate pointers to uv *handles*, which have
19 subtyping relationships with each other.  This subtyping is reflected
20 in the bindings with explicit or implicit coercions. For example, an
21 upcast from TcpWatcher to StreamWatcher is done with
22 `tcp_watcher.as_stream()`. In other cases a callback on a specific
23 type of watcher will be passed a watcher of a supertype.
24
25 Currently all use of Request types (connect/write requests) are
26 encapsulated in the bindings and don't need to be dealt with by the
27 caller.
28
29 # Safety note
30
31 Due to the complex lifecycle of uv handles, as well as compiler bugs,
32 this module is not memory safe and requires explicit memory management,
33 via `close` and `delete` methods.
34
35 */
36
37 #[link(name = "rustuv",
38        package_id = "rustuv",
39        vers = "0.9-pre",
40        uuid = "f3719011-0459-9b86-b11c-29265c0d0864",
41        url = "https://github.com/mozilla/rust/tree/master/src/librustuv")];
42
43 #[license = "MIT/ASL2"];
44 #[crate_type = "rlib"];
45 #[crate_type = "dylib"];
46
47 #[feature(macro_rules, globs)];
48
49 use std::cast::transmute;
50 use std::cast;
51 use std::libc::{c_int, malloc};
52 use std::ptr::null;
53 use std::ptr;
54 use std::rt::BlockedTask;
55 use std::rt::local::Local;
56 use std::rt::sched::Scheduler;
57 use std::str::raw::from_c_str;
58 use std::str;
59 use std::task;
60 use std::unstable::finally::Finally;
61 use std::vec;
62
63 use std::io::IoError;
64
65 pub use self::async::AsyncWatcher;
66 pub use self::file::{FsRequest, FileWatcher};
67 pub use self::idle::IdleWatcher;
68 pub use self::net::{TcpWatcher, TcpListener, TcpAcceptor, UdpWatcher};
69 pub use self::pipe::{PipeWatcher, PipeListener, PipeAcceptor};
70 pub use self::process::Process;
71 pub use self::signal::SignalWatcher;
72 pub use self::timer::TimerWatcher;
73 pub use self::tty::TtyWatcher;
74
75 mod macros;
76
77 /// The implementation of `rtio` for libuv
78 pub mod uvio;
79
80 /// C bindings to libuv
81 pub mod uvll;
82
83 pub mod file;
84 pub mod net;
85 pub mod idle;
86 pub mod timer;
87 pub mod async;
88 pub mod addrinfo;
89 pub mod process;
90 pub mod pipe;
91 pub mod tty;
92 pub mod signal;
93 pub mod stream;
94
95 /// A type that wraps a uv handle
96 pub trait UvHandle<T> {
97     fn uv_handle(&self) -> *T;
98
99     // FIXME(#8888) dummy self
100     fn alloc(_: Option<Self>, ty: uvll::uv_handle_type) -> *T {
101         unsafe {
102             let handle = uvll::malloc_handle(ty);
103             assert!(!handle.is_null());
104             handle as *T
105         }
106     }
107
108     unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut Self {
109         cast::transmute(uvll::get_data_for_uv_handle(*h))
110     }
111
112     fn install(~self) -> ~Self {
113         unsafe {
114             let myptr = cast::transmute::<&~Self, &*u8>(&self);
115             uvll::set_data_for_uv_handle(self.uv_handle(), *myptr);
116         }
117         self
118     }
119
120     fn close_async_(&mut self) {
121         // we used malloc to allocate all handles, so we must always have at
122         // least a callback to free all the handles we allocated.
123         extern fn close_cb(handle: *uvll::uv_handle_t) {
124             unsafe { uvll::free_handle(handle) }
125         }
126
127         unsafe {
128             uvll::set_data_for_uv_handle(self.uv_handle(), null::<()>());
129             uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb)
130         }
131     }
132
133     fn close(&mut self) {
134         let mut slot = None;
135
136         unsafe {
137             uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb);
138             uvll::set_data_for_uv_handle(self.uv_handle(), ptr::null::<()>());
139
140             wait_until_woken_after(&mut slot, || {
141                 uvll::set_data_for_uv_handle(self.uv_handle(), &slot);
142             })
143         }
144
145         extern fn close_cb(handle: *uvll::uv_handle_t) {
146             unsafe {
147                 let data = uvll::get_data_for_uv_handle(handle);
148                 uvll::free_handle(handle);
149                 if data == ptr::null() { return }
150                 let slot: &mut Option<BlockedTask> = cast::transmute(data);
151                 let sched: ~Scheduler = Local::take();
152                 sched.resume_blocked_task_immediately(slot.take_unwrap());
153             }
154         }
155     }
156 }
157
158 pub struct ForbidSwitch {
159     msg: &'static str,
160     sched: uint,
161 }
162
163 impl ForbidSwitch {
164     fn new(s: &'static str) -> ForbidSwitch {
165         ForbidSwitch {
166             msg: s, sched: Local::borrow(|s: &mut Scheduler| s.sched_id())
167         }
168     }
169 }
170
171 impl Drop for ForbidSwitch {
172     fn drop(&mut self) {
173         assert!(self.sched == Local::borrow(|s: &mut Scheduler| s.sched_id()),
174                 "didnt want a scheduler switch: {}", self.msg);
175     }
176 }
177
178 pub struct ForbidUnwind {
179     msg: &'static str,
180     failing_before: bool,
181 }
182
183 impl ForbidUnwind {
184     fn new(s: &'static str) -> ForbidUnwind {
185         ForbidUnwind {
186             msg: s, failing_before: task::failing(),
187         }
188     }
189 }
190
191 impl Drop for ForbidUnwind {
192     fn drop(&mut self) {
193         assert!(self.failing_before == task::failing(),
194                 "didnt want an unwind during: {}", self.msg);
195     }
196 }
197
198 fn wait_until_woken_after(slot: *mut Option<BlockedTask>, f: ||) {
199     let _f = ForbidUnwind::new("wait_until_woken_after");
200     unsafe {
201         assert!((*slot).is_none());
202         let sched: ~Scheduler = Local::take();
203         sched.deschedule_running_task_and_then(|_, task| {
204             f();
205             *slot = Some(task);
206         })
207     }
208 }
209
210 pub struct Request {
211     handle: *uvll::uv_req_t,
212     priv defused: bool,
213 }
214
215 impl Request {
216     pub fn new(ty: uvll::uv_req_type) -> Request {
217         unsafe {
218             let handle = uvll::malloc_req(ty);
219             uvll::set_data_for_req(handle, null::<()>());
220             Request::wrap(handle)
221         }
222     }
223
224     pub fn wrap(handle: *uvll::uv_req_t) -> Request {
225         Request { handle: handle, defused: false }
226     }
227
228     pub fn set_data<T>(&self, t: *T) {
229         unsafe { uvll::set_data_for_req(self.handle, t) }
230     }
231
232     pub unsafe fn get_data<T>(&self) -> &'static mut T {
233         let data = uvll::get_data_for_req(self.handle);
234         assert!(data != null());
235         cast::transmute(data)
236     }
237
238     // This function should be used when the request handle has been given to an
239     // underlying uv function, and the uv function has succeeded. This means
240     // that uv will at some point invoke the callback, and in the meantime we
241     // can't deallocate the handle because libuv could be using it.
242     //
243     // This is still a problem in blocking situations due to linked failure. In
244     // the connection callback the handle should be re-wrapped with the `wrap`
245     // function to ensure its destruction.
246     pub fn defuse(&mut self) {
247         self.defused = true;
248     }
249 }
250
251 impl Drop for Request {
252     fn drop(&mut self) {
253         if !self.defused {
254             unsafe { uvll::free_req(self.handle) }
255         }
256     }
257 }
258
259 /// XXX: Loop(*handle) is buggy with destructors. Normal structs
260 /// with dtors may not be destructured, but tuple structs can,
261 /// but the results are not correct.
262 pub struct Loop {
263     priv handle: *uvll::uv_loop_t
264 }
265
266 impl Loop {
267     pub fn new() -> Loop {
268         let handle = unsafe { uvll::loop_new() };
269         assert!(handle.is_not_null());
270         Loop::wrap(handle)
271     }
272
273     pub fn wrap(handle: *uvll::uv_loop_t) -> Loop { Loop { handle: handle } }
274
275     pub fn run(&mut self) {
276         unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) };
277     }
278
279     pub fn close(&mut self) {
280         unsafe { uvll::uv_loop_delete(self.handle) };
281     }
282 }
283
284 // XXX: Need to define the error constants like EOF so they can be
285 // compared to the UvError type
286
287 pub struct UvError(c_int);
288
289 impl UvError {
290     pub fn name(&self) -> ~str {
291         unsafe {
292             let inner = match self { &UvError(a) => a };
293             let name_str = uvll::uv_err_name(inner);
294             assert!(name_str.is_not_null());
295             from_c_str(name_str)
296         }
297     }
298
299     pub fn desc(&self) -> ~str {
300         unsafe {
301             let inner = match self { &UvError(a) => a };
302             let desc_str = uvll::uv_strerror(inner);
303             assert!(desc_str.is_not_null());
304             from_c_str(desc_str)
305         }
306     }
307
308     pub fn is_eof(&self) -> bool {
309         **self == uvll::EOF
310     }
311 }
312
313 impl ToStr for UvError {
314     fn to_str(&self) -> ~str {
315         format!("{}: {}", self.name(), self.desc())
316     }
317 }
318
319 #[test]
320 fn error_smoke_test() {
321     let err: UvError = UvError(uvll::EOF);
322     assert_eq!(err.to_str(), ~"EOF: end of file");
323 }
324
325 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
326     unsafe {
327         // Importing error constants
328         use uvll::*;
329         use std::io::*;
330
331         // uv error descriptions are static
332         let c_desc = uvll::uv_strerror(*uverr);
333         let desc = str::raw::c_str_to_static_slice(c_desc);
334
335         let kind = match *uverr {
336             UNKNOWN => OtherIoError,
337             OK => OtherIoError,
338             EOF => EndOfFile,
339             EACCES => PermissionDenied,
340             ECONNREFUSED => ConnectionRefused,
341             ECONNRESET => ConnectionReset,
342             ENOTCONN => NotConnected,
343             EPIPE => BrokenPipe,
344             ECONNABORTED => ConnectionAborted,
345             err => {
346                 uvdebug!("uverr.code {}", err as int);
347                 // XXX: Need to map remaining uv error types
348                 OtherIoError
349             }
350         };
351
352         IoError {
353             kind: kind,
354             desc: desc,
355             detail: None
356         }
357     }
358 }
359
360 /// Given a uv error code, convert a callback status to a UvError
361 pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
362     if status >= 0 {
363         None
364     } else {
365         Some(UvError(status))
366     }
367 }
368
369 pub fn status_to_io_result(status: c_int) -> Result<(), IoError> {
370     if status >= 0 {Ok(())} else {Err(uv_error_to_io_error(UvError(status)))}
371 }
372
373 /// The uv buffer type
374 pub type Buf = uvll::uv_buf_t;
375
376 pub fn empty_buf() -> Buf {
377     uvll::uv_buf_t {
378         base: null(),
379         len: 0,
380     }
381 }
382
383 /// Borrow a slice to a Buf
384 pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
385     let data = vec::raw::to_ptr(v);
386     uvll::uv_buf_t { base: data, len: v.len() as uvll::uv_buf_len_t }
387 }
388
389 #[cfg(test)]
390 fn local_loop() -> &'static mut Loop {
391     unsafe {
392         cast::transmute(Local::borrow(|sched: &mut Scheduler| {
393             let mut io = None;
394             sched.event_loop.io(|i| {
395                 let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
396                     cast::transmute(i);
397                 io = Some(uvio);
398             });
399             io.unwrap()
400         }).uv_loop())
401     }
402 }
403
404 #[cfg(test)]
405 mod test {
406     use std::cast::transmute;
407     use std::ptr;
408     use std::unstable::run_in_bare_thread;
409
410     use super::{slice_to_uv_buf, Loop};
411
412     #[test]
413     fn test_slice_to_uv_buf() {
414         let slice = [0, .. 20];
415         let buf = slice_to_uv_buf(slice);
416
417         assert_eq!(buf.len, 20);
418
419         unsafe {
420             let base = transmute::<*u8, *mut u8>(buf.base);
421             (*base) = 1;
422             (*ptr::mut_offset(base, 1)) = 2;
423         }
424
425         assert!(slice[0] == 1);
426         assert!(slice[1] == 2);
427     }
428
429
430     #[test]
431     fn loop_smoke_test() {
432         do run_in_bare_thread {
433             let mut loop_ = Loop::new();
434             loop_.run();
435             loop_.close();
436         }
437     }
438 }