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)];
45 #[allow(deprecated_owned_vector)]; // NOTE: remove after stage0
47 #[cfg(test)] extern crate green;
48 #[cfg(test)] extern crate realrustuv = "rustuv";
54 use std::libc::{c_int, c_void};
57 use std::rt::local::Local;
58 use std::rt::task::{BlockedTask, Task};
59 use std::str::raw::from_c_str;
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;
73 // Run tests with libgreen instead of libnative.
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
79 fn start(argc: int, argv: **u8) -> int {
80 green::start(argc, argv, __test::main)
90 /// The implementation of `rtio` for libuv
93 /// C bindings to libuv
108 /// A type that wraps a uv handle
109 pub trait UvHandle<T> {
110 fn uv_handle(&self) -> *T;
112 fn uv_loop(&self) -> Loop {
113 Loop::wrap(unsafe { uvll::get_loop_for_uv_handle(self.uv_handle()) })
116 // FIXME(#8888) dummy self
117 fn alloc(_: Option<Self>, ty: uvll::uv_handle_type) -> *T {
119 let handle = uvll::malloc_handle(ty);
120 assert!(!handle.is_null());
125 unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut Self {
126 cast::transmute(uvll::get_data_for_uv_handle(*h))
129 fn install(~self) -> ~Self {
131 let myptr = cast::transmute::<&~Self, &*u8>(&self);
132 uvll::set_data_for_uv_handle(self.uv_handle(), *myptr);
137 fn close_async_(&mut self) {
138 // we used malloc to allocate all handles, so we must always have at
139 // least a callback to free all the handles we allocated.
140 extern fn close_cb(handle: *uvll::uv_handle_t) {
141 unsafe { uvll::free_handle(handle) }
145 uvll::set_data_for_uv_handle(self.uv_handle(), null::<()>());
146 uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb)
150 fn close(&mut self) {
154 uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb);
155 uvll::set_data_for_uv_handle(self.uv_handle(), ptr::null::<()>());
157 wait_until_woken_after(&mut slot, &self.uv_loop(), || {
158 uvll::set_data_for_uv_handle(self.uv_handle(), &slot);
162 extern fn close_cb(handle: *uvll::uv_handle_t) {
164 let data = uvll::get_data_for_uv_handle(handle);
165 uvll::free_handle(handle);
166 if data == ptr::null() { return }
167 let slot: &mut Option<BlockedTask> = cast::transmute(data);
174 pub struct ForbidSwitch {
175 priv msg: &'static str,
180 fn new(s: &'static str) -> ForbidSwitch {
183 io: homing::local_id(),
188 impl Drop for ForbidSwitch {
190 assert!(self.io == homing::local_id(),
191 "didnt want a scheduler switch: {}",
196 pub struct ForbidUnwind {
198 failing_before: bool,
202 fn new(s: &'static str) -> ForbidUnwind {
204 msg: s, failing_before: task::failing(),
209 impl Drop for ForbidUnwind {
211 assert!(self.failing_before == task::failing(),
212 "didnt want an unwind during: {}", self.msg);
216 fn wait_until_woken_after(slot: *mut Option<BlockedTask>,
219 let _f = ForbidUnwind::new("wait_until_woken_after");
221 assert!((*slot).is_none());
222 let task: ~Task = Local::take();
223 loop_.modify_blockers(1);
224 task.deschedule(1, |task| {
229 loop_.modify_blockers(-1);
233 fn wakeup(slot: &mut Option<BlockedTask>) {
234 assert!(slot.is_some());
235 let _ = slot.take_unwrap().wake().map(|t| t.reawaken());
239 handle: *uvll::uv_req_t,
244 pub fn new(ty: uvll::uv_req_type) -> Request {
246 let handle = uvll::malloc_req(ty);
247 uvll::set_data_for_req(handle, null::<()>());
248 Request::wrap(handle)
252 pub fn wrap(handle: *uvll::uv_req_t) -> Request {
253 Request { handle: handle, defused: false }
256 pub fn set_data<T>(&self, t: *T) {
257 unsafe { uvll::set_data_for_req(self.handle, t) }
260 pub unsafe fn get_data<T>(&self) -> &'static mut T {
261 let data = uvll::get_data_for_req(self.handle);
262 assert!(data != null());
263 cast::transmute(data)
266 // This function should be used when the request handle has been given to an
267 // underlying uv function, and the uv function has succeeded. This means
268 // that uv will at some point invoke the callback, and in the meantime we
269 // can't deallocate the handle because libuv could be using it.
271 // This is still a problem in blocking situations due to linked failure. In
272 // the connection callback the handle should be re-wrapped with the `wrap`
273 // function to ensure its destruction.
274 pub fn defuse(&mut self) {
279 impl Drop for Request {
282 unsafe { uvll::free_req(self.handle) }
287 /// FIXME: Loop(*handle) is buggy with destructors. Normal structs
288 /// with dtors may not be destructured, but tuple structs can,
289 /// but the results are not correct.
291 priv handle: *uvll::uv_loop_t
295 pub fn new() -> Loop {
296 let handle = unsafe { uvll::loop_new() };
297 assert!(handle.is_not_null());
298 unsafe { uvll::set_data_for_uv_loop(handle, 0 as *c_void) }
302 pub fn wrap(handle: *uvll::uv_loop_t) -> Loop { Loop { handle: handle } }
304 pub fn run(&mut self) {
305 assert_eq!(unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) }, 0);
308 pub fn close(&mut self) {
309 unsafe { uvll::uv_loop_delete(self.handle) };
312 // The 'data' field of the uv_loop_t is used to count the number of tasks
313 // that are currently blocked waiting for I/O to complete.
314 fn modify_blockers(&self, amt: uint) {
316 let cur = uvll::get_data_for_uv_loop(self.handle) as uint;
317 uvll::set_data_for_uv_loop(self.handle, (cur + amt) as *c_void)
321 fn get_blockers(&self) -> uint {
322 unsafe { uvll::get_data_for_uv_loop(self.handle) as uint }
326 // FIXME: Need to define the error constants like EOF so they can be
327 // compared to the UvError type
329 pub struct UvError(c_int);
332 pub fn name(&self) -> ~str {
334 let inner = match self { &UvError(a) => a };
335 let name_str = uvll::uv_err_name(inner);
336 assert!(name_str.is_not_null());
341 pub fn desc(&self) -> ~str {
343 let inner = match self { &UvError(a) => a };
344 let desc_str = uvll::uv_strerror(inner);
345 assert!(desc_str.is_not_null());
350 pub fn is_eof(&self) -> bool {
351 let UvError(handle) = *self;
356 impl fmt::Show for UvError {
357 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
358 write!(f.buf, "{}: {}", self.name(), self.desc())
363 fn error_smoke_test() {
364 let err: UvError = UvError(uvll::EOF);
365 assert_eq!(err.to_str(), ~"EOF: end of file");
368 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
370 // Importing error constants
372 // uv error descriptions are static
373 let UvError(errcode) = uverr;
374 let c_desc = uvll::uv_strerror(errcode);
375 let desc = str::raw::c_str_to_static_slice(c_desc);
377 let kind = match errcode {
378 uvll::UNKNOWN => io::OtherIoError,
379 uvll::OK => io::OtherIoError,
380 uvll::EOF => io::EndOfFile,
381 uvll::EACCES => io::PermissionDenied,
382 uvll::ECONNREFUSED => io::ConnectionRefused,
383 uvll::ECONNRESET => io::ConnectionReset,
384 uvll::ENOTCONN => io::NotConnected,
385 uvll::ENOENT => io::FileNotFound,
386 uvll::EPIPE => io::BrokenPipe,
387 uvll::ECONNABORTED => io::ConnectionAborted,
388 uvll::EADDRNOTAVAIL => io::ConnectionRefused,
390 uvdebug!("uverr.code {}", err as int);
391 // FIXME: Need to map remaining uv error types
404 /// Given a uv error code, convert a callback status to a UvError
405 pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
409 Some(UvError(status))
413 pub fn status_to_io_result(status: c_int) -> Result<(), IoError> {
414 if status >= 0 {Ok(())} else {Err(uv_error_to_io_error(UvError(status)))}
417 /// The uv buffer type
418 pub type Buf = uvll::uv_buf_t;
420 pub fn empty_buf() -> Buf {
427 /// Borrow a slice to a Buf
428 pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
429 let data = v.as_ptr();
430 uvll::uv_buf_t { base: data, len: v.len() as uvll::uv_buf_len_t }
433 // This function is full of lies!
435 fn local_loop() -> &'static mut uvio::UvIoFactory {
438 let mut task = Local::borrow(None::<Task>);
439 let mut io = task.get().local_io().unwrap();
440 let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
441 cast::transmute(io.get());
449 use std::cast::transmute;
450 use std::unstable::run_in_bare_thread;
452 use super::{slice_to_uv_buf, Loop};
455 fn test_slice_to_uv_buf() {
456 let slice = [0, .. 20];
457 let buf = slice_to_uv_buf(slice);
459 assert_eq!(buf.len, 20);
462 let base = transmute::<*u8, *mut u8>(buf.base);
464 (*base.offset(1)) = 2;
467 assert!(slice[0] == 1);
468 assert!(slice[1] == 2);
473 fn loop_smoke_test() {
474 run_in_bare_thread(proc() {
475 let mut loop_ = Loop::new();