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"]
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;
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, event_loop, __test::main)
90 /// The implementation of `rtio` for libuv
93 /// C bindings to libuv
108 /// Creates a new event loop which is powered by libuv
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.
117 /// extern crate rustuv;
118 /// extern crate green;
121 /// fn start(argc: int, argv: **u8) -> int {
122 /// green::start(argc, argv, rustuv::event_loop, main)
126 /// // this code is running inside of a green task powered by libuv
129 pub fn event_loop() -> ~rtio::EventLoop:Send {
130 ~uvio::UvEventLoop::new() as ~rtio::EventLoop:Send
133 /// A type that wraps a uv handle
134 pub trait UvHandle<T> {
135 fn uv_handle(&self) -> *T;
137 fn uv_loop(&self) -> Loop {
138 Loop::wrap(unsafe { uvll::get_loop_for_uv_handle(self.uv_handle()) })
141 // FIXME(#8888) dummy self
142 fn alloc(_: Option<Self>, ty: uvll::uv_handle_type) -> *T {
144 let handle = uvll::malloc_handle(ty);
145 assert!(!handle.is_null());
150 unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut Self {
151 cast::transmute(uvll::get_data_for_uv_handle(*h))
154 fn install(~self) -> ~Self {
156 let myptr = cast::transmute::<&~Self, &*u8>(&self);
157 uvll::set_data_for_uv_handle(self.uv_handle(), *myptr);
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) }
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)
175 fn close(&mut self) {
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::<()>());
182 wait_until_woken_after(&mut slot, &self.uv_loop(), || {
183 uvll::set_data_for_uv_handle(self.uv_handle(), &slot);
187 extern fn close_cb(handle: *uvll::uv_handle_t) {
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> = cast::transmute(data);
199 pub struct ForbidSwitch {
200 priv msg: &'static str,
205 fn new(s: &'static str) -> ForbidSwitch {
208 io: homing::local_id(),
213 impl Drop for ForbidSwitch {
215 assert!(self.io == homing::local_id(),
216 "didnt want a scheduler switch: {}",
221 pub struct ForbidUnwind {
223 failing_before: bool,
227 fn new(s: &'static str) -> ForbidUnwind {
229 msg: s, failing_before: task::failing(),
234 impl Drop for ForbidUnwind {
236 assert!(self.failing_before == task::failing(),
237 "didnt want an unwind during: {}", self.msg);
241 fn wait_until_woken_after(slot: *mut Option<BlockedTask>,
244 let _f = ForbidUnwind::new("wait_until_woken_after");
246 assert!((*slot).is_none());
247 let task: ~Task = Local::take();
248 loop_.modify_blockers(1);
249 task.deschedule(1, |task| {
254 loop_.modify_blockers(-1);
258 fn wakeup(slot: &mut Option<BlockedTask>) {
259 assert!(slot.is_some());
260 let _ = slot.take_unwrap().wake().map(|t| t.reawaken());
264 handle: *uvll::uv_req_t,
269 pub fn new(ty: uvll::uv_req_type) -> Request {
271 let handle = uvll::malloc_req(ty);
272 uvll::set_data_for_req(handle, null::<()>());
273 Request::wrap(handle)
277 pub fn wrap(handle: *uvll::uv_req_t) -> Request {
278 Request { handle: handle, defused: false }
281 pub fn set_data<T>(&self, t: *T) {
282 unsafe { uvll::set_data_for_req(self.handle, t) }
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 cast::transmute(data)
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.
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) {
304 impl Drop for Request {
307 unsafe { uvll::free_req(self.handle) }
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.
316 priv handle: *uvll::uv_loop_t
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) }
327 pub fn wrap(handle: *uvll::uv_loop_t) -> Loop { Loop { handle: handle } }
329 pub fn run(&mut self) {
330 assert_eq!(unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) }, 0);
333 pub fn close(&mut self) {
334 unsafe { uvll::uv_loop_delete(self.handle) };
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) {
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)
346 fn get_blockers(&self) -> uint {
347 unsafe { uvll::get_data_for_uv_loop(self.handle) as uint }
351 // FIXME: Need to define the error constants like EOF so they can be
352 // compared to the UvError type
354 pub struct UvError(c_int);
357 pub fn name(&self) -> ~str {
359 let inner = match self { &UvError(a) => a };
360 let name_str = uvll::uv_err_name(inner);
361 assert!(name_str.is_not_null());
366 pub fn desc(&self) -> ~str {
368 let inner = match self { &UvError(a) => a };
369 let desc_str = uvll::uv_strerror(inner);
370 assert!(desc_str.is_not_null());
375 pub fn is_eof(&self) -> bool {
376 let UvError(handle) = *self;
381 impl fmt::Show for UvError {
382 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
383 write!(f.buf, "{}: {}", self.name(), self.desc())
388 fn error_smoke_test() {
389 let err: UvError = UvError(uvll::EOF);
390 assert_eq!(err.to_str(), ~"EOF: end of file");
393 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
395 // Importing error constants
397 // uv error descriptions are static
398 let UvError(errcode) = uverr;
399 let c_desc = uvll::uv_strerror(errcode);
400 let desc = str::raw::c_str_to_static_slice(c_desc);
402 let kind = match errcode {
403 uvll::UNKNOWN => io::OtherIoError,
404 uvll::OK => io::OtherIoError,
405 uvll::EOF => io::EndOfFile,
406 uvll::EACCES => io::PermissionDenied,
407 uvll::ECONNREFUSED => io::ConnectionRefused,
408 uvll::ECONNRESET => io::ConnectionReset,
409 uvll::ENOTCONN => io::NotConnected,
410 uvll::ENOENT => io::FileNotFound,
411 uvll::EPIPE => io::BrokenPipe,
412 uvll::ECONNABORTED => io::ConnectionAborted,
413 uvll::EADDRNOTAVAIL => io::ConnectionRefused,
415 uvdebug!("uverr.code {}", err as int);
416 // FIXME: Need to map remaining uv error types
429 /// Given a uv error code, convert a callback status to a UvError
430 pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
434 Some(UvError(status))
438 pub fn status_to_io_result(status: c_int) -> Result<(), IoError> {
439 if status >= 0 {Ok(())} else {Err(uv_error_to_io_error(UvError(status)))}
442 /// The uv buffer type
443 pub type Buf = uvll::uv_buf_t;
445 pub fn empty_buf() -> Buf {
452 /// Borrow a slice to a Buf
453 pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
454 let data = v.as_ptr();
455 uvll::uv_buf_t { base: data, len: v.len() as uvll::uv_buf_len_t }
458 // This function is full of lies!
460 fn local_loop() -> &'static mut uvio::UvIoFactory {
463 let mut task = Local::borrow(None::<Task>);
464 let mut io = task.get().local_io().unwrap();
465 let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
466 cast::transmute(io.get());
474 use std::cast::transmute;
475 use std::unstable::run_in_bare_thread;
477 use super::{slice_to_uv_buf, Loop};
480 fn test_slice_to_uv_buf() {
481 let slice = [0, .. 20];
482 let buf = slice_to_uv_buf(slice);
484 assert_eq!(buf.len, 20);
487 let base = transmute::<*u8, *mut u8>(buf.base);
489 (*base.offset(1)) = 2;
492 assert!(slice[0] == 1);
493 assert!(slice[1] == 2);
498 fn loop_smoke_test() {
499 run_in_bare_thread(proc() {
500 let mut loop_ = Loop::new();