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 #[link(name = "rustuv",
38 package_id = "rustuv",
40 uuid = "f3719011-0459-9b86-b11c-29265c0d0864",
41 url = "https://github.com/mozilla/rust/tree/master/src/librustuv")];
43 #[license = "MIT/ASL2"];
44 #[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
45 #[crate_type = "rlib"];
46 #[crate_type = "dylib"];
48 #[feature(macro_rules, globs)];
50 use std::cast::transmute;
52 use std::libc::{c_int, malloc};
55 use std::rt::BlockedTask;
56 use std::rt::local::Local;
57 use std::rt::sched::Scheduler;
58 use std::str::raw::from_c_str;
61 use std::unstable::finally::Finally;
66 pub use self::async::AsyncWatcher;
67 pub use self::file::{FsRequest, FileWatcher};
68 pub use self::idle::IdleWatcher;
69 pub use self::net::{TcpWatcher, TcpListener, TcpAcceptor, UdpWatcher};
70 pub use self::pipe::{PipeWatcher, PipeListener, PipeAcceptor};
71 pub use self::process::Process;
72 pub use self::signal::SignalWatcher;
73 pub use self::timer::TimerWatcher;
74 pub use self::tty::TtyWatcher;
78 /// The implementation of `rtio` for libuv
81 /// C bindings to libuv
96 /// A type that wraps a uv handle
97 pub trait UvHandle<T> {
98 fn uv_handle(&self) -> *T;
100 // FIXME(#8888) dummy self
101 fn alloc(_: Option<Self>, ty: uvll::uv_handle_type) -> *T {
103 let handle = uvll::malloc_handle(ty);
104 assert!(!handle.is_null());
109 unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut Self {
110 cast::transmute(uvll::get_data_for_uv_handle(*h))
113 fn install(~self) -> ~Self {
115 let myptr = cast::transmute::<&~Self, &*u8>(&self);
116 uvll::set_data_for_uv_handle(self.uv_handle(), *myptr);
121 fn close_async_(&mut self) {
122 // we used malloc to allocate all handles, so we must always have at
123 // least a callback to free all the handles we allocated.
124 extern fn close_cb(handle: *uvll::uv_handle_t) {
125 unsafe { uvll::free_handle(handle) }
129 uvll::set_data_for_uv_handle(self.uv_handle(), null::<()>());
130 uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb)
134 fn close(&mut self) {
138 uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb);
139 uvll::set_data_for_uv_handle(self.uv_handle(), ptr::null::<()>());
141 wait_until_woken_after(&mut slot, || {
142 uvll::set_data_for_uv_handle(self.uv_handle(), &slot);
146 extern fn close_cb(handle: *uvll::uv_handle_t) {
148 let data = uvll::get_data_for_uv_handle(handle);
149 uvll::free_handle(handle);
150 if data == ptr::null() { return }
151 let slot: &mut Option<BlockedTask> = cast::transmute(data);
152 let sched: ~Scheduler = Local::take();
153 sched.resume_blocked_task_immediately(slot.take_unwrap());
159 pub struct ForbidSwitch {
165 fn new(s: &'static str) -> ForbidSwitch {
167 msg: s, sched: Local::borrow(|s: &mut Scheduler| s.sched_id())
172 impl Drop for ForbidSwitch {
174 assert!(self.sched == Local::borrow(|s: &mut Scheduler| s.sched_id()),
175 "didnt want a scheduler switch: {}", self.msg);
179 pub struct ForbidUnwind {
181 failing_before: bool,
185 fn new(s: &'static str) -> ForbidUnwind {
187 msg: s, failing_before: task::failing(),
192 impl Drop for ForbidUnwind {
194 assert!(self.failing_before == task::failing(),
195 "didnt want an unwind during: {}", self.msg);
199 fn wait_until_woken_after(slot: *mut Option<BlockedTask>, f: ||) {
200 let _f = ForbidUnwind::new("wait_until_woken_after");
202 assert!((*slot).is_none());
203 let sched: ~Scheduler = Local::take();
204 sched.deschedule_running_task_and_then(|_, task| {
212 handle: *uvll::uv_req_t,
217 pub fn new(ty: uvll::uv_req_type) -> Request {
219 let handle = uvll::malloc_req(ty);
220 uvll::set_data_for_req(handle, null::<()>());
221 Request::wrap(handle)
225 pub fn wrap(handle: *uvll::uv_req_t) -> Request {
226 Request { handle: handle, defused: false }
229 pub fn set_data<T>(&self, t: *T) {
230 unsafe { uvll::set_data_for_req(self.handle, t) }
233 pub unsafe fn get_data<T>(&self) -> &'static mut T {
234 let data = uvll::get_data_for_req(self.handle);
235 assert!(data != null());
236 cast::transmute(data)
239 // This function should be used when the request handle has been given to an
240 // underlying uv function, and the uv function has succeeded. This means
241 // that uv will at some point invoke the callback, and in the meantime we
242 // can't deallocate the handle because libuv could be using it.
244 // This is still a problem in blocking situations due to linked failure. In
245 // the connection callback the handle should be re-wrapped with the `wrap`
246 // function to ensure its destruction.
247 pub fn defuse(&mut self) {
252 impl Drop for Request {
255 unsafe { uvll::free_req(self.handle) }
260 /// XXX: Loop(*handle) is buggy with destructors. Normal structs
261 /// with dtors may not be destructured, but tuple structs can,
262 /// but the results are not correct.
264 priv handle: *uvll::uv_loop_t
268 pub fn new() -> Loop {
269 let handle = unsafe { uvll::loop_new() };
270 assert!(handle.is_not_null());
274 pub fn wrap(handle: *uvll::uv_loop_t) -> Loop { Loop { handle: handle } }
276 pub fn run(&mut self) {
277 unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) };
280 pub fn close(&mut self) {
281 unsafe { uvll::uv_loop_delete(self.handle) };
285 // XXX: Need to define the error constants like EOF so they can be
286 // compared to the UvError type
288 pub struct UvError(c_int);
291 pub fn name(&self) -> ~str {
293 let inner = match self { &UvError(a) => a };
294 let name_str = uvll::uv_err_name(inner);
295 assert!(name_str.is_not_null());
300 pub fn desc(&self) -> ~str {
302 let inner = match self { &UvError(a) => a };
303 let desc_str = uvll::uv_strerror(inner);
304 assert!(desc_str.is_not_null());
309 pub fn is_eof(&self) -> bool {
314 impl ToStr for UvError {
315 fn to_str(&self) -> ~str {
316 format!("{}: {}", self.name(), self.desc())
321 fn error_smoke_test() {
322 let err: UvError = UvError(uvll::EOF);
323 assert_eq!(err.to_str(), ~"EOF: end of file");
326 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
328 // Importing error constants
332 // uv error descriptions are static
333 let c_desc = uvll::uv_strerror(*uverr);
334 let desc = str::raw::c_str_to_static_slice(c_desc);
336 let kind = match *uverr {
337 UNKNOWN => OtherIoError,
340 EACCES => PermissionDenied,
341 ECONNREFUSED => ConnectionRefused,
342 ECONNRESET => ConnectionReset,
343 ENOTCONN => NotConnected,
345 ECONNABORTED => ConnectionAborted,
347 uvdebug!("uverr.code {}", err as int);
348 // XXX: Need to map remaining uv error types
361 /// Given a uv error code, convert a callback status to a UvError
362 pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
366 Some(UvError(status))
370 pub fn status_to_io_result(status: c_int) -> Result<(), IoError> {
371 if status >= 0 {Ok(())} else {Err(uv_error_to_io_error(UvError(status)))}
374 /// The uv buffer type
375 pub type Buf = uvll::uv_buf_t;
377 pub fn empty_buf() -> Buf {
384 /// Borrow a slice to a Buf
385 pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
386 let data = vec::raw::to_ptr(v);
387 uvll::uv_buf_t { base: data, len: v.len() as uvll::uv_buf_len_t }
391 fn local_loop() -> &'static mut Loop {
393 cast::transmute(Local::borrow(|sched: &mut Scheduler| {
395 sched.event_loop.io(|i| {
396 let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
407 use std::cast::transmute;
409 use std::unstable::run_in_bare_thread;
411 use super::{slice_to_uv_buf, Loop};
414 fn test_slice_to_uv_buf() {
415 let slice = [0, .. 20];
416 let buf = slice_to_uv_buf(slice);
418 assert_eq!(buf.len, 20);
421 let base = transmute::<*u8, *mut u8>(buf.base);
423 (*ptr::mut_offset(base, 1)) = 2;
426 assert!(slice[0] == 1);
427 assert!(slice[1] == 2);
432 fn loop_smoke_test() {
433 do run_in_bare_thread {
434 let mut loop_ = Loop::new();