]> git.lizzy.rs Git - rust.git/blob - src/librustuv/lib.rs
auto merge of #13049 : alexcrichton/rust/io-fill, r=huonw
[rust.git] / src / librustuv / lib.rs
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.
4 //
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.
10
11 /*!
12
13 Bindings to libuv, along with the default implementation of `std::rt::rtio`.
14
15 UV types consist of the event loop (Loop), Watchers, Requests and
16 Callbacks.
17
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.
24
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
27 caller.
28
29 # Safety note
30
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.
34
35 */
36
37 #[crate_id = "rustuv#0.10-pre"];
38 #[license = "MIT/ASL2"];
39 #[crate_type = "rlib"];
40 #[crate_type = "dylib"];
41
42 #[feature(macro_rules)];
43 #[deny(unused_result, unused_must_use)];
44 #[allow(visible_private_types)];
45
46 #[cfg(test)] extern crate green;
47 #[cfg(test)] extern crate realrustuv = "rustuv";
48
49 use std::cast;
50 use std::fmt;
51 use std::io::IoError;
52 use std::io;
53 use std::libc::{c_int, c_void};
54 use std::ptr::null;
55 use std::ptr;
56 use std::rt::local::Local;
57 use std::rt::task::{BlockedTask, Task};
58 use std::str::raw::from_c_str;
59 use std::str;
60 use std::task;
61
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;
71
72 // Run tests with libgreen instead of libnative.
73 //
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
76 //        '__test' module.
77 #[cfg(test)] #[start]
78 fn start(argc: int, argv: **u8) -> int {
79     green::start(argc, argv, __test::main)
80 }
81
82 mod macros;
83
84 mod access;
85 mod homing;
86 mod queue;
87 mod rc;
88
89 /// The implementation of `rtio` for libuv
90 pub mod uvio;
91
92 /// C bindings to libuv
93 pub mod uvll;
94
95 pub mod file;
96 pub mod net;
97 pub mod idle;
98 pub mod timer;
99 pub mod async;
100 pub mod addrinfo;
101 pub mod process;
102 pub mod pipe;
103 pub mod tty;
104 pub mod signal;
105 pub mod stream;
106
107 /// A type that wraps a uv handle
108 pub trait UvHandle<T> {
109     fn uv_handle(&self) -> *T;
110
111     fn uv_loop(&self) -> Loop {
112         Loop::wrap(unsafe { uvll::get_loop_for_uv_handle(self.uv_handle()) })
113     }
114
115     // FIXME(#8888) dummy self
116     fn alloc(_: Option<Self>, ty: uvll::uv_handle_type) -> *T {
117         unsafe {
118             let handle = uvll::malloc_handle(ty);
119             assert!(!handle.is_null());
120             handle as *T
121         }
122     }
123
124     unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut Self {
125         cast::transmute(uvll::get_data_for_uv_handle(*h))
126     }
127
128     fn install(~self) -> ~Self {
129         unsafe {
130             let myptr = cast::transmute::<&~Self, &*u8>(&self);
131             uvll::set_data_for_uv_handle(self.uv_handle(), *myptr);
132         }
133         self
134     }
135
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) }
141         }
142
143         unsafe {
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)
146         }
147     }
148
149     fn close(&mut self) {
150         let mut slot = None;
151
152         unsafe {
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::<()>());
155
156             wait_until_woken_after(&mut slot, &self.uv_loop(), || {
157                 uvll::set_data_for_uv_handle(self.uv_handle(), &slot);
158             })
159         }
160
161         extern fn close_cb(handle: *uvll::uv_handle_t) {
162             unsafe {
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);
167                 wakeup(slot);
168             }
169         }
170     }
171 }
172
173 pub struct ForbidSwitch {
174     priv msg: &'static str,
175     priv io: uint,
176 }
177
178 impl ForbidSwitch {
179     fn new(s: &'static str) -> ForbidSwitch {
180         ForbidSwitch {
181             msg: s,
182             io: homing::local_id(),
183         }
184     }
185 }
186
187 impl Drop for ForbidSwitch {
188     fn drop(&mut self) {
189         assert!(self.io == homing::local_id(),
190                 "didnt want a scheduler switch: {}",
191                 self.msg);
192     }
193 }
194
195 pub struct ForbidUnwind {
196     msg: &'static str,
197     failing_before: bool,
198 }
199
200 impl ForbidUnwind {
201     fn new(s: &'static str) -> ForbidUnwind {
202         ForbidUnwind {
203             msg: s, failing_before: task::failing(),
204         }
205     }
206 }
207
208 impl Drop for ForbidUnwind {
209     fn drop(&mut self) {
210         assert!(self.failing_before == task::failing(),
211                 "didnt want an unwind during: {}", self.msg);
212     }
213 }
214
215 fn wait_until_woken_after(slot: *mut Option<BlockedTask>,
216                           loop_: &Loop,
217                           f: ||) {
218     let _f = ForbidUnwind::new("wait_until_woken_after");
219     unsafe {
220         assert!((*slot).is_none());
221         let task: ~Task = Local::take();
222         loop_.modify_blockers(1);
223         task.deschedule(1, |task| {
224             *slot = Some(task);
225             f();
226             Ok(())
227         });
228         loop_.modify_blockers(-1);
229     }
230 }
231
232 fn wakeup(slot: &mut Option<BlockedTask>) {
233     assert!(slot.is_some());
234     let _ = slot.take_unwrap().wake().map(|t| t.reawaken());
235 }
236
237 pub struct Request {
238     handle: *uvll::uv_req_t,
239     priv defused: bool,
240 }
241
242 impl Request {
243     pub fn new(ty: uvll::uv_req_type) -> Request {
244         unsafe {
245             let handle = uvll::malloc_req(ty);
246             uvll::set_data_for_req(handle, null::<()>());
247             Request::wrap(handle)
248         }
249     }
250
251     pub fn wrap(handle: *uvll::uv_req_t) -> Request {
252         Request { handle: handle, defused: false }
253     }
254
255     pub fn set_data<T>(&self, t: *T) {
256         unsafe { uvll::set_data_for_req(self.handle, t) }
257     }
258
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)
263     }
264
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.
269     //
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) {
274         self.defused = true;
275     }
276 }
277
278 impl Drop for Request {
279     fn drop(&mut self) {
280         if !self.defused {
281             unsafe { uvll::free_req(self.handle) }
282         }
283     }
284 }
285
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.
289 pub struct Loop {
290     priv handle: *uvll::uv_loop_t
291 }
292
293 impl Loop {
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) }
298         Loop::wrap(handle)
299     }
300
301     pub fn wrap(handle: *uvll::uv_loop_t) -> Loop { Loop { handle: handle } }
302
303     pub fn run(&mut self) {
304         assert_eq!(unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) }, 0);
305     }
306
307     pub fn close(&mut self) {
308         unsafe { uvll::uv_loop_delete(self.handle) };
309     }
310
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) {
314         unsafe {
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)
317         }
318     }
319
320     fn get_blockers(&self) -> uint {
321         unsafe { uvll::get_data_for_uv_loop(self.handle) as uint }
322     }
323 }
324
325 // FIXME: Need to define the error constants like EOF so they can be
326 // compared to the UvError type
327
328 pub struct UvError(c_int);
329
330 impl UvError {
331     pub fn name(&self) -> ~str {
332         unsafe {
333             let inner = match self { &UvError(a) => a };
334             let name_str = uvll::uv_err_name(inner);
335             assert!(name_str.is_not_null());
336             from_c_str(name_str)
337         }
338     }
339
340     pub fn desc(&self) -> ~str {
341         unsafe {
342             let inner = match self { &UvError(a) => a };
343             let desc_str = uvll::uv_strerror(inner);
344             assert!(desc_str.is_not_null());
345             from_c_str(desc_str)
346         }
347     }
348
349     pub fn is_eof(&self) -> bool {
350         let UvError(handle) = *self;
351         handle == uvll::EOF
352     }
353 }
354
355 impl fmt::Show for UvError {
356     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
357         write!(f.buf, "{}: {}", self.name(), self.desc())
358     }
359 }
360
361 #[test]
362 fn error_smoke_test() {
363     let err: UvError = UvError(uvll::EOF);
364     assert_eq!(err.to_str(), ~"EOF: end of file");
365 }
366
367 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
368     unsafe {
369         // Importing error constants
370
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);
375
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,
388             err => {
389                 uvdebug!("uverr.code {}", err as int);
390                 // FIXME: Need to map remaining uv error types
391                 io::OtherIoError
392             }
393         };
394
395         IoError {
396             kind: kind,
397             desc: desc,
398             detail: None
399         }
400     }
401 }
402
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> {
405     if status >= 0 {
406         None
407     } else {
408         Some(UvError(status))
409     }
410 }
411
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)))}
414 }
415
416 /// The uv buffer type
417 pub type Buf = uvll::uv_buf_t;
418
419 pub fn empty_buf() -> Buf {
420     uvll::uv_buf_t {
421         base: null(),
422         len: 0,
423     }
424 }
425
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 }
430 }
431
432 // This function is full of lies!
433 #[cfg(test)]
434 fn local_loop() -> &'static mut uvio::UvIoFactory {
435     unsafe {
436         cast::transmute({
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());
441             uvio
442         })
443     }
444 }
445
446 #[cfg(test)]
447 mod test {
448     use std::cast::transmute;
449     use std::unstable::run_in_bare_thread;
450
451     use super::{slice_to_uv_buf, Loop};
452
453     #[test]
454     fn test_slice_to_uv_buf() {
455         let slice = [0, .. 20];
456         let buf = slice_to_uv_buf(slice);
457
458         assert_eq!(buf.len, 20);
459
460         unsafe {
461             let base = transmute::<*u8, *mut u8>(buf.base);
462             (*base) = 1;
463             (*base.offset(1)) = 2;
464         }
465
466         assert!(slice[0] == 1);
467         assert!(slice[1] == 2);
468     }
469
470
471     #[test]
472     fn loop_smoke_test() {
473         run_in_bare_thread(proc() {
474             let mut loop_ = Loop::new();
475             loop_.run();
476             loop_.close();
477         });
478     }
479 }