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 = "rlib"];
45 #[crate_type = "dylib"];
47 #[feature(macro_rules, globs)];
49 use std::cast::transmute;
51 use std::libc::{c_int, malloc};
54 use std::rt::BlockedTask;
55 use std::rt::local::Local;
56 use std::rt::sched::Scheduler;
57 use std::str::raw::from_c_str;
60 use std::unstable::finally::Finally;
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;
77 /// The implementation of `rtio` for libuv
80 /// C bindings to libuv
95 /// A type that wraps a uv handle
96 pub trait UvHandle<T> {
97 fn uv_handle(&self) -> *T;
99 // FIXME(#8888) dummy self
100 fn alloc(_: Option<Self>, ty: uvll::uv_handle_type) -> *T {
102 let handle = uvll::malloc_handle(ty);
103 assert!(!handle.is_null());
108 unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut Self {
109 cast::transmute(uvll::get_data_for_uv_handle(*h))
112 fn install(~self) -> ~Self {
114 let myptr = cast::transmute::<&~Self, &*u8>(&self);
115 uvll::set_data_for_uv_handle(self.uv_handle(), *myptr);
120 fn close_async_(&mut self) {
121 // we used malloc to allocate all handles, so we must always have at
122 // least a callback to free all the handles we allocated.
123 extern fn close_cb(handle: *uvll::uv_handle_t) {
124 unsafe { uvll::free_handle(handle) }
128 uvll::set_data_for_uv_handle(self.uv_handle(), null::<()>());
129 uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb)
133 fn close(&mut self) {
137 uvll::uv_close(self.uv_handle() as *uvll::uv_handle_t, close_cb);
138 uvll::set_data_for_uv_handle(self.uv_handle(), ptr::null::<()>());
140 wait_until_woken_after(&mut slot, || {
141 uvll::set_data_for_uv_handle(self.uv_handle(), &slot);
145 extern fn close_cb(handle: *uvll::uv_handle_t) {
147 let data = uvll::get_data_for_uv_handle(handle);
148 uvll::free_handle(handle);
149 if data == ptr::null() { return }
150 let slot: &mut Option<BlockedTask> = cast::transmute(data);
151 let sched: ~Scheduler = Local::take();
152 sched.resume_blocked_task_immediately(slot.take_unwrap());
158 pub struct ForbidSwitch {
164 fn new(s: &'static str) -> ForbidSwitch {
166 msg: s, sched: Local::borrow(|s: &mut Scheduler| s.sched_id())
171 impl Drop for ForbidSwitch {
173 assert!(self.sched == Local::borrow(|s: &mut Scheduler| s.sched_id()),
174 "didnt want a scheduler switch: {}", self.msg);
178 pub struct ForbidUnwind {
180 failing_before: bool,
184 fn new(s: &'static str) -> ForbidUnwind {
186 msg: s, failing_before: task::failing(),
191 impl Drop for ForbidUnwind {
193 assert!(self.failing_before == task::failing(),
194 "didnt want an unwind during: {}", self.msg);
198 fn wait_until_woken_after(slot: *mut Option<BlockedTask>, f: ||) {
199 let _f = ForbidUnwind::new("wait_until_woken_after");
201 assert!((*slot).is_none());
202 let sched: ~Scheduler = Local::take();
203 sched.deschedule_running_task_and_then(|_, task| {
211 handle: *uvll::uv_req_t,
216 pub fn new(ty: uvll::uv_req_type) -> Request {
218 let handle = uvll::malloc_req(ty);
219 uvll::set_data_for_req(handle, null::<()>());
220 Request::wrap(handle)
224 pub fn wrap(handle: *uvll::uv_req_t) -> Request {
225 Request { handle: handle, defused: false }
228 pub fn set_data<T>(&self, t: *T) {
229 unsafe { uvll::set_data_for_req(self.handle, t) }
232 pub unsafe fn get_data<T>(&self) -> &'static mut T {
233 let data = uvll::get_data_for_req(self.handle);
234 assert!(data != null());
235 cast::transmute(data)
238 // This function should be used when the request handle has been given to an
239 // underlying uv function, and the uv function has succeeded. This means
240 // that uv will at some point invoke the callback, and in the meantime we
241 // can't deallocate the handle because libuv could be using it.
243 // This is still a problem in blocking situations due to linked failure. In
244 // the connection callback the handle should be re-wrapped with the `wrap`
245 // function to ensure its destruction.
246 pub fn defuse(&mut self) {
251 impl Drop for Request {
254 unsafe { uvll::free_req(self.handle) }
259 /// XXX: Loop(*handle) is buggy with destructors. Normal structs
260 /// with dtors may not be destructured, but tuple structs can,
261 /// but the results are not correct.
263 priv handle: *uvll::uv_loop_t
267 pub fn new() -> Loop {
268 let handle = unsafe { uvll::loop_new() };
269 assert!(handle.is_not_null());
273 pub fn wrap(handle: *uvll::uv_loop_t) -> Loop { Loop { handle: handle } }
275 pub fn run(&mut self) {
276 unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) };
279 pub fn close(&mut self) {
280 unsafe { uvll::uv_loop_delete(self.handle) };
284 // XXX: Need to define the error constants like EOF so they can be
285 // compared to the UvError type
287 pub struct UvError(c_int);
290 pub fn name(&self) -> ~str {
292 let inner = match self { &UvError(a) => a };
293 let name_str = uvll::uv_err_name(inner);
294 assert!(name_str.is_not_null());
299 pub fn desc(&self) -> ~str {
301 let inner = match self { &UvError(a) => a };
302 let desc_str = uvll::uv_strerror(inner);
303 assert!(desc_str.is_not_null());
308 pub fn is_eof(&self) -> bool {
313 impl ToStr for UvError {
314 fn to_str(&self) -> ~str {
315 format!("{}: {}", self.name(), self.desc())
320 fn error_smoke_test() {
321 let err: UvError = UvError(uvll::EOF);
322 assert_eq!(err.to_str(), ~"EOF: end of file");
325 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
327 // Importing error constants
331 // uv error descriptions are static
332 let c_desc = uvll::uv_strerror(*uverr);
333 let desc = str::raw::c_str_to_static_slice(c_desc);
335 let kind = match *uverr {
336 UNKNOWN => OtherIoError,
339 EACCES => PermissionDenied,
340 ECONNREFUSED => ConnectionRefused,
341 ECONNRESET => ConnectionReset,
342 ENOTCONN => NotConnected,
344 ECONNABORTED => ConnectionAborted,
346 uvdebug!("uverr.code {}", err as int);
347 // XXX: Need to map remaining uv error types
360 /// Given a uv error code, convert a callback status to a UvError
361 pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
365 Some(UvError(status))
369 pub fn status_to_io_result(status: c_int) -> Result<(), IoError> {
370 if status >= 0 {Ok(())} else {Err(uv_error_to_io_error(UvError(status)))}
373 /// The uv buffer type
374 pub type Buf = uvll::uv_buf_t;
376 pub fn empty_buf() -> Buf {
383 /// Borrow a slice to a Buf
384 pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
385 let data = vec::raw::to_ptr(v);
386 uvll::uv_buf_t { base: data, len: v.len() as uvll::uv_buf_len_t }
390 fn local_loop() -> &'static mut Loop {
392 cast::transmute(Local::borrow(|sched: &mut Scheduler| {
394 sched.event_loop.io(|i| {
395 let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
406 use std::cast::transmute;
408 use std::unstable::run_in_bare_thread;
410 use super::{slice_to_uv_buf, Loop};
413 fn test_slice_to_uv_buf() {
414 let slice = [0, .. 20];
415 let buf = slice_to_uv_buf(slice);
417 assert_eq!(buf.len, 20);
420 let base = transmute::<*u8, *mut u8>(buf.base);
422 (*ptr::mut_offset(base, 1)) = 2;
425 assert!(slice[0] == 1);
426 assert!(slice[1] == 2);
431 fn loop_smoke_test() {
432 do run_in_bare_thread {
433 let mut loop_ = Loop::new();