]> git.lizzy.rs Git - rust.git/blob - src/librustuv/lib.rs
74caf86a6310242832f360dbb893eb7a61792cc7
[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.11.0-pre"]
38 #![experimental]
39 #![license = "MIT/ASL2"]
40 #![crate_type = "rlib"]
41 #![crate_type = "dylib"]
42
43 #![feature(macro_rules, unsafe_destructor)]
44 #![deny(unused_result, unused_must_use)]
45 #![allow(visible_private_types)]
46
47 #[cfg(test)] extern crate green;
48 #[cfg(test)] extern crate debug;
49 #[cfg(test)] extern crate realrustuv = "rustuv";
50 extern crate libc;
51 extern crate alloc;
52
53 use libc::{c_int, c_void};
54 use std::fmt;
55 use std::mem;
56 use std::ptr::null;
57 use std::ptr;
58 use std::rt::local::Local;
59 use std::rt::rtio;
60 use std::rt::rtio::{IoResult, IoError};
61 use std::rt::task::{BlockedTask, Task};
62 use std::str::raw::from_c_str;
63 use std::task;
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 // Run tests with libgreen instead of libnative.
76 //
77 // FIXME: This egregiously hacks around starting the test runner in a different
78 //        threading mode than the default by reaching into the auto-generated
79 //        '__test' module.
80 #[cfg(test)] #[start]
81 fn start(argc: int, argv: **u8) -> int {
82     green::start(argc, argv, event_loop, __test::main)
83 }
84
85 mod macros;
86
87 mod access;
88 mod timeout;
89 mod homing;
90 mod queue;
91 mod rc;
92
93 pub mod uvio;
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() -> Box<rtio::EventLoop + Send> {
130     box uvio::UvEventLoop::new() as Box<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         mem::transmute(uvll::get_data_for_uv_handle(*h))
152     }
153
154     fn install(~self) -> Box<Self> {
155         unsafe {
156             let myptr = mem::transmute::<&Box<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> = mem::transmute(data);
193                 wakeup(slot);
194             }
195         }
196     }
197 }
198
199 pub struct ForbidSwitch {
200     msg: &'static str,
201     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                 "didn't 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: Box<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     pub handle: *uvll::uv_req_t,
265     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         mem::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     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) -> String {
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).to_string()
363         }
364     }
365
366     pub fn desc(&self) -> String {
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).to_string()
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, "{}: {}", 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".to_string());
391 }
392
393 #[cfg(unix)]
394 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
395     let UvError(errcode) = uverr;
396     IoError {
397         code: if errcode == uvll::EOF {libc::EOF as uint} else {-errcode as uint},
398         extra: 0,
399         detail: Some(uverr.desc()),
400     }
401 }
402
403 #[cfg(windows)]
404 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
405     let UvError(errcode) = uverr;
406     IoError {
407         code: match errcode {
408             uvll::EOF => libc::EOF,
409             uvll::EACCES => libc::ERROR_ACCESS_DENIED,
410             uvll::ECONNREFUSED => libc::WSAECONNREFUSED,
411             uvll::ECONNRESET => libc::WSAECONNRESET,
412             uvll::ENOTCONN => libc::WSAENOTCONN,
413             uvll::ENOENT => libc::ERROR_FILE_NOT_FOUND,
414             uvll::EPIPE => libc::ERROR_NO_DATA,
415             uvll::ECONNABORTED => libc::WSAECONNABORTED,
416             uvll::EADDRNOTAVAIL => libc::WSAEADDRNOTAVAIL,
417             uvll::ECANCELED => libc::ERROR_OPERATION_ABORTED,
418             uvll::EADDRINUSE => libc::WSAEADDRINUSE,
419             err => {
420                 uvdebug!("uverr.code {}", err as int);
421                 // FIXME: Need to map remaining uv error types
422                 -1
423             }
424         } as uint,
425         extra: 0,
426         detail: Some(uverr.desc()),
427     }
428 }
429
430 /// Given a uv error code, convert a callback status to a UvError
431 pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
432     if status >= 0 {
433         None
434     } else {
435         Some(UvError(status))
436     }
437 }
438
439 pub fn status_to_io_result(status: c_int) -> IoResult<()> {
440     if status >= 0 {Ok(())} else {Err(uv_error_to_io_error(UvError(status)))}
441 }
442
443 /// The uv buffer type
444 pub type Buf = uvll::uv_buf_t;
445
446 pub fn empty_buf() -> Buf {
447     uvll::uv_buf_t {
448         base: null(),
449         len: 0,
450     }
451 }
452
453 /// Borrow a slice to a Buf
454 pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
455     let data = v.as_ptr();
456     uvll::uv_buf_t { base: data, len: v.len() as uvll::uv_buf_len_t }
457 }
458
459 // This function is full of lies!
460 #[cfg(test)]
461 fn local_loop() -> &'static mut uvio::UvIoFactory {
462     unsafe {
463         mem::transmute({
464             let mut task = Local::borrow(None::<Task>);
465             let mut io = task.local_io().unwrap();
466             let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
467                 mem::transmute(io.get());
468             uvio
469         })
470     }
471 }
472
473 #[cfg(test)]
474 fn next_test_ip4() -> std::rt::rtio::SocketAddr {
475     use std::io;
476     use std::rt::rtio;
477
478     let io::net::ip::SocketAddr { ip, port } = io::test::next_test_ip4();
479     let ip = match ip {
480         io::net::ip::Ipv4Addr(a, b, c, d) => rtio::Ipv4Addr(a, b, c, d),
481         _ => unreachable!(),
482     };
483     rtio::SocketAddr { ip: ip, port: port }
484 }
485
486 #[cfg(test)]
487 fn next_test_ip6() -> std::rt::rtio::SocketAddr {
488     use std::io;
489     use std::rt::rtio;
490
491     let io::net::ip::SocketAddr { ip, port } = io::test::next_test_ip6();
492     let ip = match ip {
493         io::net::ip::Ipv6Addr(a, b, c, d, e, f, g, h) =>
494             rtio::Ipv6Addr(a, b, c, d, e, f, g, h),
495         _ => unreachable!(),
496     };
497     rtio::SocketAddr { ip: ip, port: port }
498 }
499
500 #[cfg(test)]
501 mod test {
502     use std::mem::transmute;
503     use std::rt::thread::Thread;
504
505     use super::{slice_to_uv_buf, Loop};
506
507     #[test]
508     fn test_slice_to_uv_buf() {
509         let slice = [0, .. 20];
510         let buf = slice_to_uv_buf(slice);
511
512         assert_eq!(buf.len, 20);
513
514         unsafe {
515             let base = transmute::<*u8, *mut u8>(buf.base);
516             (*base) = 1;
517             (*base.offset(1)) = 2;
518         }
519
520         assert!(slice[0] == 1);
521         assert!(slice[1] == 2);
522     }
523
524
525     #[test]
526     fn loop_smoke_test() {
527         Thread::start(proc() {
528             let mut loop_ = Loop::new();
529             loop_.run();
530             loop_.close();
531         }).join();
532     }
533 }