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.
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.
13 Bindings to libuv, along with the default implementation of `std::rt::rtio`.
15 UV types consist of the event loop (Loop), Watchers, Requests and
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.
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
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.
37 #[crate_id = "rustuv#0.10-pre"];
38 #[license = "MIT/ASL2"];
39 #[crate_type = "rlib"];
40 #[crate_type = "dylib"];
42 #[feature(macro_rules)];
43 #[deny(unused_result, unused_must_use)];
44 #[allow(visible_private_types)];
46 #[cfg(test)] extern crate green;
47 #[cfg(test)] extern crate realrustuv = "rustuv";
53 use std::libc::{c_int, c_void};
56 use std::rt::local::Local;
57 use std::rt::task::{BlockedTask, Task};
58 use std::str::raw::from_c_str;
62 pub use self::async::AsyncWatcher;
63 pub use self::file::{FsRequest, FileWatcher};
64 pub use self::idle::IdleWatcher;
65 pub use self::net::{TcpWatcher, TcpListener, TcpAcceptor, UdpWatcher};
66 pub use self::pipe::{PipeWatcher, PipeListener, PipeAcceptor};
67 pub use self::process::Process;
68 pub use self::signal::SignalWatcher;
69 pub use self::timer::TimerWatcher;
70 pub use self::tty::TtyWatcher;
72 // Run tests with libgreen instead of libnative.
74 // FIXME: This egregiously hacks around starting the test runner in a different
75 // threading mode than the default by reaching into the auto-generated
78 fn start(argc: int, argv: **u8) -> int {
79 green::start(argc, argv, __test::main)
89 /// The implementation of `rtio` for libuv
92 /// C bindings to libuv
107 /// A type that wraps a uv handle
108 pub trait UvHandle<T> {
109 fn uv_handle(&self) -> *T;
111 fn uv_loop(&self) -> Loop {
112 Loop::wrap(unsafe { uvll::get_loop_for_uv_handle(self.uv_handle()) })
115 // FIXME(#8888) dummy self
116 fn alloc(_: Option<Self>, ty: uvll::uv_handle_type) -> *T {
118 let handle = uvll::malloc_handle(ty);
119 assert!(!handle.is_null());
124 unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut Self {
125 cast::transmute(uvll::get_data_for_uv_handle(*h))
128 fn install(~self) -> ~Self {
130 let myptr = cast::transmute::<&~Self, &*u8>(&self);
131 uvll::set_data_for_uv_handle(self.uv_handle(), *myptr);
136 fn close_async_(&mut self) {
137 // we used malloc to allocate all handles, so we must always have at
138 // least a callback to free all the handles we allocated.
139 extern fn close_cb(handle: *uvll::uv_handle_t) {
140 unsafe { uvll::free_handle(handle) }
144 uvll::set_data_for_uv_handle(self.uv_handle(), null::<()>());
145 uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb)
149 fn close(&mut self) {
153 uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb);
154 uvll::set_data_for_uv_handle(self.uv_handle(), ptr::null::<()>());
156 wait_until_woken_after(&mut slot, &self.uv_loop(), || {
157 uvll::set_data_for_uv_handle(self.uv_handle(), &slot);
161 extern fn close_cb(handle: *uvll::uv_handle_t) {
163 let data = uvll::get_data_for_uv_handle(handle);
164 uvll::free_handle(handle);
165 if data == ptr::null() { return }
166 let slot: &mut Option<BlockedTask> = cast::transmute(data);
173 pub struct ForbidSwitch {
174 priv msg: &'static str,
179 fn new(s: &'static str) -> ForbidSwitch {
182 io: homing::local_id(),
187 impl Drop for ForbidSwitch {
189 assert!(self.io == homing::local_id(),
190 "didnt want a scheduler switch: {}",
195 pub struct ForbidUnwind {
197 failing_before: bool,
201 fn new(s: &'static str) -> ForbidUnwind {
203 msg: s, failing_before: task::failing(),
208 impl Drop for ForbidUnwind {
210 assert!(self.failing_before == task::failing(),
211 "didnt want an unwind during: {}", self.msg);
215 fn wait_until_woken_after(slot: *mut Option<BlockedTask>,
218 let _f = ForbidUnwind::new("wait_until_woken_after");
220 assert!((*slot).is_none());
221 let task: ~Task = Local::take();
222 loop_.modify_blockers(1);
223 task.deschedule(1, |task| {
228 loop_.modify_blockers(-1);
232 fn wakeup(slot: &mut Option<BlockedTask>) {
233 assert!(slot.is_some());
234 let _ = slot.take_unwrap().wake().map(|t| t.reawaken());
238 handle: *uvll::uv_req_t,
243 pub fn new(ty: uvll::uv_req_type) -> Request {
245 let handle = uvll::malloc_req(ty);
246 uvll::set_data_for_req(handle, null::<()>());
247 Request::wrap(handle)
251 pub fn wrap(handle: *uvll::uv_req_t) -> Request {
252 Request { handle: handle, defused: false }
255 pub fn set_data<T>(&self, t: *T) {
256 unsafe { uvll::set_data_for_req(self.handle, t) }
259 pub unsafe fn get_data<T>(&self) -> &'static mut T {
260 let data = uvll::get_data_for_req(self.handle);
261 assert!(data != null());
262 cast::transmute(data)
265 // This function should be used when the request handle has been given to an
266 // underlying uv function, and the uv function has succeeded. This means
267 // that uv will at some point invoke the callback, and in the meantime we
268 // can't deallocate the handle because libuv could be using it.
270 // This is still a problem in blocking situations due to linked failure. In
271 // the connection callback the handle should be re-wrapped with the `wrap`
272 // function to ensure its destruction.
273 pub fn defuse(&mut self) {
278 impl Drop for Request {
281 unsafe { uvll::free_req(self.handle) }
286 /// FIXME: Loop(*handle) is buggy with destructors. Normal structs
287 /// with dtors may not be destructured, but tuple structs can,
288 /// but the results are not correct.
290 priv handle: *uvll::uv_loop_t
294 pub fn new() -> Loop {
295 let handle = unsafe { uvll::loop_new() };
296 assert!(handle.is_not_null());
297 unsafe { uvll::set_data_for_uv_loop(handle, 0 as *c_void) }
301 pub fn wrap(handle: *uvll::uv_loop_t) -> Loop { Loop { handle: handle } }
303 pub fn run(&mut self) {
304 assert_eq!(unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) }, 0);
307 pub fn close(&mut self) {
308 unsafe { uvll::uv_loop_delete(self.handle) };
311 // The 'data' field of the uv_loop_t is used to count the number of tasks
312 // that are currently blocked waiting for I/O to complete.
313 fn modify_blockers(&self, amt: uint) {
315 let cur = uvll::get_data_for_uv_loop(self.handle) as uint;
316 uvll::set_data_for_uv_loop(self.handle, (cur + amt) as *c_void)
320 fn get_blockers(&self) -> uint {
321 unsafe { uvll::get_data_for_uv_loop(self.handle) as uint }
325 // FIXME: Need to define the error constants like EOF so they can be
326 // compared to the UvError type
328 pub struct UvError(c_int);
331 pub fn name(&self) -> ~str {
333 let inner = match self { &UvError(a) => a };
334 let name_str = uvll::uv_err_name(inner);
335 assert!(name_str.is_not_null());
340 pub fn desc(&self) -> ~str {
342 let inner = match self { &UvError(a) => a };
343 let desc_str = uvll::uv_strerror(inner);
344 assert!(desc_str.is_not_null());
349 pub fn is_eof(&self) -> bool {
350 let UvError(handle) = *self;
355 impl fmt::Show for UvError {
356 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
357 write!(f.buf, "{}: {}", self.name(), self.desc())
362 fn error_smoke_test() {
363 let err: UvError = UvError(uvll::EOF);
364 assert_eq!(err.to_str(), ~"EOF: end of file");
367 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
369 // Importing error constants
371 // uv error descriptions are static
372 let UvError(errcode) = uverr;
373 let c_desc = uvll::uv_strerror(errcode);
374 let desc = str::raw::c_str_to_static_slice(c_desc);
376 let kind = match errcode {
377 uvll::UNKNOWN => io::OtherIoError,
378 uvll::OK => io::OtherIoError,
379 uvll::EOF => io::EndOfFile,
380 uvll::EACCES => io::PermissionDenied,
381 uvll::ECONNREFUSED => io::ConnectionRefused,
382 uvll::ECONNRESET => io::ConnectionReset,
383 uvll::ENOTCONN => io::NotConnected,
384 uvll::ENOENT => io::FileNotFound,
385 uvll::EPIPE => io::BrokenPipe,
386 uvll::ECONNABORTED => io::ConnectionAborted,
387 uvll::EADDRNOTAVAIL => io::ConnectionRefused,
389 uvdebug!("uverr.code {}", err as int);
390 // FIXME: Need to map remaining uv error types
403 /// Given a uv error code, convert a callback status to a UvError
404 pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
408 Some(UvError(status))
412 pub fn status_to_io_result(status: c_int) -> Result<(), IoError> {
413 if status >= 0 {Ok(())} else {Err(uv_error_to_io_error(UvError(status)))}
416 /// The uv buffer type
417 pub type Buf = uvll::uv_buf_t;
419 pub fn empty_buf() -> Buf {
426 /// Borrow a slice to a Buf
427 pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
428 let data = v.as_ptr();
429 uvll::uv_buf_t { base: data, len: v.len() as uvll::uv_buf_len_t }
432 // This function is full of lies!
434 fn local_loop() -> &'static mut uvio::UvIoFactory {
437 let mut task = Local::borrow(None::<Task>);
438 let mut io = task.get().local_io().unwrap();
439 let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
440 cast::transmute(io.get());
448 use std::cast::transmute;
449 use std::unstable::run_in_bare_thread;
451 use super::{slice_to_uv_buf, Loop};
454 fn test_slice_to_uv_buf() {
455 let slice = [0, .. 20];
456 let buf = slice_to_uv_buf(slice);
458 assert_eq!(buf.len, 20);
461 let base = transmute::<*u8, *mut u8>(buf.base);
463 (*base.offset(1)) = 2;
466 assert!(slice[0] == 1);
467 assert!(slice[1] == 2);
472 fn loop_smoke_test() {
473 run_in_bare_thread(proc() {
474 let mut loop_ = Loop::new();