]> git.lizzy.rs Git - rust.git/blob - src/librustuv/lib.rs
Bump version to 0.10
[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 #![crate_id = "rustuv#0.10"]
38 #![license = "MIT/ASL2"]
39 #![crate_type = "rlib"]
40 #![crate_type = "dylib"]
41
42 #![feature(macro_rules)]
43 #![deny(unused_result, unused_must_use)]
44 #![allow(visible_private_types)]
45
46 #[cfg(test)] extern crate green;
47 #[cfg(test)] extern crate realrustuv = "rustuv";
48
49 use std::cast;
50 use std::fmt;
51 use std::io::IoError;
52 use std::io;
53 use std::libc::{c_int, c_void};
54 use std::ptr::null;
55 use std::ptr;
56 use std::rt::local::Local;
57 use std::rt::rtio;
58 use std::rt::task::{BlockedTask, Task};
59 use std::str::raw::from_c_str;
60 use std::str;
61 use std::task;
62
63 pub use self::async::AsyncWatcher;
64 pub use self::file::{FsRequest, FileWatcher};
65 pub use self::idle::IdleWatcher;
66 pub use self::net::{TcpWatcher, TcpListener, TcpAcceptor, UdpWatcher};
67 pub use self::pipe::{PipeWatcher, PipeListener, PipeAcceptor};
68 pub use self::process::Process;
69 pub use self::signal::SignalWatcher;
70 pub use self::timer::TimerWatcher;
71 pub use self::tty::TtyWatcher;
72
73 // Run tests with libgreen instead of libnative.
74 //
75 // FIXME: This egregiously hacks around starting the test runner in a different
76 //        threading mode than the default by reaching into the auto-generated
77 //        '__test' module.
78 #[cfg(test)] #[start]
79 fn start(argc: int, argv: **u8) -> int {
80     green::start(argc, argv, event_loop, __test::main)
81 }
82
83 mod macros;
84
85 mod access;
86 mod homing;
87 mod queue;
88 mod rc;
89
90 /// The implementation of `rtio` for libuv
91 pub mod uvio;
92
93 /// C bindings to libuv
94 pub mod uvll;
95
96 pub mod file;
97 pub mod net;
98 pub mod idle;
99 pub mod timer;
100 pub mod async;
101 pub mod addrinfo;
102 pub mod process;
103 pub mod pipe;
104 pub mod tty;
105 pub mod signal;
106 pub mod stream;
107
108 /// Creates a new event loop which is powered by libuv
109 ///
110 /// This function is used in tandem with libgreen's `PoolConfig` type as a value
111 /// for the `event_loop_factory` field. Using this function as the event loop
112 /// factory will power programs with libuv and enable green threading.
113 ///
114 /// # Example
115 ///
116 /// ```
117 /// extern crate rustuv;
118 /// extern crate green;
119 ///
120 /// #[start]
121 /// fn start(argc: int, argv: **u8) -> int {
122 ///     green::start(argc, argv, rustuv::event_loop, main)
123 /// }
124 ///
125 /// fn main() {
126 ///     // this code is running inside of a green task powered by libuv
127 /// }
128 /// ```
129 pub fn event_loop() -> ~rtio::EventLoop:Send {
130     ~uvio::UvEventLoop::new() as ~rtio::EventLoop:Send
131 }
132
133 /// A type that wraps a uv handle
134 pub trait UvHandle<T> {
135     fn uv_handle(&self) -> *T;
136
137     fn uv_loop(&self) -> Loop {
138         Loop::wrap(unsafe { uvll::get_loop_for_uv_handle(self.uv_handle()) })
139     }
140
141     // FIXME(#8888) dummy self
142     fn alloc(_: Option<Self>, ty: uvll::uv_handle_type) -> *T {
143         unsafe {
144             let handle = uvll::malloc_handle(ty);
145             assert!(!handle.is_null());
146             handle as *T
147         }
148     }
149
150     unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut Self {
151         cast::transmute(uvll::get_data_for_uv_handle(*h))
152     }
153
154     fn install(~self) -> ~Self {
155         unsafe {
156             let myptr = cast::transmute::<&~Self, &*u8>(&self);
157             uvll::set_data_for_uv_handle(self.uv_handle(), *myptr);
158         }
159         self
160     }
161
162     fn close_async_(&mut self) {
163         // we used malloc to allocate all handles, so we must always have at
164         // least a callback to free all the handles we allocated.
165         extern fn close_cb(handle: *uvll::uv_handle_t) {
166             unsafe { uvll::free_handle(handle) }
167         }
168
169         unsafe {
170             uvll::set_data_for_uv_handle(self.uv_handle(), null::<()>());
171             uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb)
172         }
173     }
174
175     fn close(&mut self) {
176         let mut slot = None;
177
178         unsafe {
179             uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb);
180             uvll::set_data_for_uv_handle(self.uv_handle(), ptr::null::<()>());
181
182             wait_until_woken_after(&mut slot, &self.uv_loop(), || {
183                 uvll::set_data_for_uv_handle(self.uv_handle(), &slot);
184             })
185         }
186
187         extern fn close_cb(handle: *uvll::uv_handle_t) {
188             unsafe {
189                 let data = uvll::get_data_for_uv_handle(handle);
190                 uvll::free_handle(handle);
191                 if data == ptr::null() { return }
192                 let slot: &mut Option<BlockedTask> = cast::transmute(data);
193                 wakeup(slot);
194             }
195         }
196     }
197 }
198
199 pub struct ForbidSwitch {
200     priv msg: &'static str,
201     priv io: uint,
202 }
203
204 impl ForbidSwitch {
205     fn new(s: &'static str) -> ForbidSwitch {
206         ForbidSwitch {
207             msg: s,
208             io: homing::local_id(),
209         }
210     }
211 }
212
213 impl Drop for ForbidSwitch {
214     fn drop(&mut self) {
215         assert!(self.io == homing::local_id(),
216                 "didnt want a scheduler switch: {}",
217                 self.msg);
218     }
219 }
220
221 pub struct ForbidUnwind {
222     msg: &'static str,
223     failing_before: bool,
224 }
225
226 impl ForbidUnwind {
227     fn new(s: &'static str) -> ForbidUnwind {
228         ForbidUnwind {
229             msg: s, failing_before: task::failing(),
230         }
231     }
232 }
233
234 impl Drop for ForbidUnwind {
235     fn drop(&mut self) {
236         assert!(self.failing_before == task::failing(),
237                 "didnt want an unwind during: {}", self.msg);
238     }
239 }
240
241 fn wait_until_woken_after(slot: *mut Option<BlockedTask>,
242                           loop_: &Loop,
243                           f: ||) {
244     let _f = ForbidUnwind::new("wait_until_woken_after");
245     unsafe {
246         assert!((*slot).is_none());
247         let task: ~Task = Local::take();
248         loop_.modify_blockers(1);
249         task.deschedule(1, |task| {
250             *slot = Some(task);
251             f();
252             Ok(())
253         });
254         loop_.modify_blockers(-1);
255     }
256 }
257
258 fn wakeup(slot: &mut Option<BlockedTask>) {
259     assert!(slot.is_some());
260     let _ = slot.take_unwrap().wake().map(|t| t.reawaken());
261 }
262
263 pub struct Request {
264     handle: *uvll::uv_req_t,
265     priv defused: bool,
266 }
267
268 impl Request {
269     pub fn new(ty: uvll::uv_req_type) -> Request {
270         unsafe {
271             let handle = uvll::malloc_req(ty);
272             uvll::set_data_for_req(handle, null::<()>());
273             Request::wrap(handle)
274         }
275     }
276
277     pub fn wrap(handle: *uvll::uv_req_t) -> Request {
278         Request { handle: handle, defused: false }
279     }
280
281     pub fn set_data<T>(&self, t: *T) {
282         unsafe { uvll::set_data_for_req(self.handle, t) }
283     }
284
285     pub unsafe fn get_data<T>(&self) -> &'static mut T {
286         let data = uvll::get_data_for_req(self.handle);
287         assert!(data != null());
288         cast::transmute(data)
289     }
290
291     // This function should be used when the request handle has been given to an
292     // underlying uv function, and the uv function has succeeded. This means
293     // that uv will at some point invoke the callback, and in the meantime we
294     // can't deallocate the handle because libuv could be using it.
295     //
296     // This is still a problem in blocking situations due to linked failure. In
297     // the connection callback the handle should be re-wrapped with the `wrap`
298     // function to ensure its destruction.
299     pub fn defuse(&mut self) {
300         self.defused = true;
301     }
302 }
303
304 impl Drop for Request {
305     fn drop(&mut self) {
306         if !self.defused {
307             unsafe { uvll::free_req(self.handle) }
308         }
309     }
310 }
311
312 /// FIXME: Loop(*handle) is buggy with destructors. Normal structs
313 /// with dtors may not be destructured, but tuple structs can,
314 /// but the results are not correct.
315 pub struct Loop {
316     priv handle: *uvll::uv_loop_t
317 }
318
319 impl Loop {
320     pub fn new() -> Loop {
321         let handle = unsafe { uvll::loop_new() };
322         assert!(handle.is_not_null());
323         unsafe { uvll::set_data_for_uv_loop(handle, 0 as *c_void) }
324         Loop::wrap(handle)
325     }
326
327     pub fn wrap(handle: *uvll::uv_loop_t) -> Loop { Loop { handle: handle } }
328
329     pub fn run(&mut self) {
330         assert_eq!(unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) }, 0);
331     }
332
333     pub fn close(&mut self) {
334         unsafe { uvll::uv_loop_delete(self.handle) };
335     }
336
337     // The 'data' field of the uv_loop_t is used to count the number of tasks
338     // that are currently blocked waiting for I/O to complete.
339     fn modify_blockers(&self, amt: uint) {
340         unsafe {
341             let cur = uvll::get_data_for_uv_loop(self.handle) as uint;
342             uvll::set_data_for_uv_loop(self.handle, (cur + amt) as *c_void)
343         }
344     }
345
346     fn get_blockers(&self) -> uint {
347         unsafe { uvll::get_data_for_uv_loop(self.handle) as uint }
348     }
349 }
350
351 // FIXME: Need to define the error constants like EOF so they can be
352 // compared to the UvError type
353
354 pub struct UvError(c_int);
355
356 impl UvError {
357     pub fn name(&self) -> ~str {
358         unsafe {
359             let inner = match self { &UvError(a) => a };
360             let name_str = uvll::uv_err_name(inner);
361             assert!(name_str.is_not_null());
362             from_c_str(name_str)
363         }
364     }
365
366     pub fn desc(&self) -> ~str {
367         unsafe {
368             let inner = match self { &UvError(a) => a };
369             let desc_str = uvll::uv_strerror(inner);
370             assert!(desc_str.is_not_null());
371             from_c_str(desc_str)
372         }
373     }
374
375     pub fn is_eof(&self) -> bool {
376         let UvError(handle) = *self;
377         handle == uvll::EOF
378     }
379 }
380
381 impl fmt::Show for UvError {
382     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
383         write!(f.buf, "{}: {}", self.name(), self.desc())
384     }
385 }
386
387 #[test]
388 fn error_smoke_test() {
389     let err: UvError = UvError(uvll::EOF);
390     assert_eq!(err.to_str(), ~"EOF: end of file");
391 }
392
393 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
394     unsafe {
395         // Importing error constants
396
397         // uv error descriptions are static
398         let UvError(errcode) = uverr;
399         let c_desc = uvll::uv_strerror(errcode);
400         let desc = str::raw::c_str_to_static_slice(c_desc);
401
402         let kind = match errcode {
403             uvll::UNKNOWN => io::OtherIoError,
404             uvll::OK => io::OtherIoError,
405             uvll::EOF => io::EndOfFile,
406             uvll::EACCES => io::PermissionDenied,
407             uvll::ECONNREFUSED => io::ConnectionRefused,
408             uvll::ECONNRESET => io::ConnectionReset,
409             uvll::ENOTCONN => io::NotConnected,
410             uvll::ENOENT => io::FileNotFound,
411             uvll::EPIPE => io::BrokenPipe,
412             uvll::ECONNABORTED => io::ConnectionAborted,
413             uvll::EADDRNOTAVAIL => io::ConnectionRefused,
414             err => {
415                 uvdebug!("uverr.code {}", err as int);
416                 // FIXME: Need to map remaining uv error types
417                 io::OtherIoError
418             }
419         };
420
421         IoError {
422             kind: kind,
423             desc: desc,
424             detail: None
425         }
426     }
427 }
428
429 /// Given a uv error code, convert a callback status to a UvError
430 pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
431     if status >= 0 {
432         None
433     } else {
434         Some(UvError(status))
435     }
436 }
437
438 pub fn status_to_io_result(status: c_int) -> Result<(), IoError> {
439     if status >= 0 {Ok(())} else {Err(uv_error_to_io_error(UvError(status)))}
440 }
441
442 /// The uv buffer type
443 pub type Buf = uvll::uv_buf_t;
444
445 pub fn empty_buf() -> Buf {
446     uvll::uv_buf_t {
447         base: null(),
448         len: 0,
449     }
450 }
451
452 /// Borrow a slice to a Buf
453 pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
454     let data = v.as_ptr();
455     uvll::uv_buf_t { base: data, len: v.len() as uvll::uv_buf_len_t }
456 }
457
458 // This function is full of lies!
459 #[cfg(test)]
460 fn local_loop() -> &'static mut uvio::UvIoFactory {
461     unsafe {
462         cast::transmute({
463             let mut task = Local::borrow(None::<Task>);
464             let mut io = task.get().local_io().unwrap();
465             let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
466                 cast::transmute(io.get());
467             uvio
468         })
469     }
470 }
471
472 #[cfg(test)]
473 mod test {
474     use std::cast::transmute;
475     use std::unstable::run_in_bare_thread;
476
477     use super::{slice_to_uv_buf, Loop};
478
479     #[test]
480     fn test_slice_to_uv_buf() {
481         let slice = [0, .. 20];
482         let buf = slice_to_uv_buf(slice);
483
484         assert_eq!(buf.len, 20);
485
486         unsafe {
487             let base = transmute::<*u8, *mut u8>(buf.base);
488             (*base) = 1;
489             (*base.offset(1)) = 2;
490         }
491
492         assert!(slice[0] == 1);
493         assert!(slice[1] == 2);
494     }
495
496
497     #[test]
498     fn loop_smoke_test() {
499         run_in_bare_thread(proc() {
500             let mut loop_ = Loop::new();
501             loop_.run();
502             loop_.close();
503         });
504     }
505 }