]> git.lizzy.rs Git - rust.git/blob - src/librustuv/lib.rs
Add generation of static libraries to rustc
[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 #[link(name = "rustuv",
38        package_id = "rustuv",
39        vers = "0.9-pre",
40        uuid = "f3719011-0459-9b86-b11c-29265c0d0864",
41        url = "https://github.com/mozilla/rust/tree/master/src/librustuv")];
42
43 #[license = "MIT/ASL2"];
44 #[crate_type = "lib"]; // NOTE: remove after stage0 snapshot
45 #[crate_type = "rlib"];
46 #[crate_type = "dylib"];
47
48 #[feature(macro_rules, globs)];
49
50 use std::cast::transmute;
51 use std::cast;
52 use std::libc::{c_int, malloc};
53 use std::ptr::null;
54 use std::ptr;
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;
59 use std::str;
60 use std::task;
61 use std::unstable::finally::Finally;
62 use std::vec;
63
64 use std::io::IoError;
65
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;
75
76 mod macros;
77
78 /// The implementation of `rtio` for libuv
79 pub mod uvio;
80
81 /// C bindings to libuv
82 pub mod uvll;
83
84 pub mod file;
85 pub mod net;
86 pub mod idle;
87 pub mod timer;
88 pub mod async;
89 pub mod addrinfo;
90 pub mod process;
91 pub mod pipe;
92 pub mod tty;
93 pub mod signal;
94 pub mod stream;
95
96 /// A type that wraps a uv handle
97 pub trait UvHandle<T> {
98     fn uv_handle(&self) -> *T;
99
100     // FIXME(#8888) dummy self
101     fn alloc(_: Option<Self>, ty: uvll::uv_handle_type) -> *T {
102         unsafe {
103             let handle = uvll::malloc_handle(ty);
104             assert!(!handle.is_null());
105             handle as *T
106         }
107     }
108
109     unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut Self {
110         cast::transmute(uvll::get_data_for_uv_handle(*h))
111     }
112
113     fn install(~self) -> ~Self {
114         unsafe {
115             let myptr = cast::transmute::<&~Self, &*u8>(&self);
116             uvll::set_data_for_uv_handle(self.uv_handle(), *myptr);
117         }
118         self
119     }
120
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) }
126         }
127
128         unsafe {
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)
131         }
132     }
133
134     fn close(&mut self) {
135         let mut slot = None;
136
137         unsafe {
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::<()>());
140
141             wait_until_woken_after(&mut slot, || {
142                 uvll::set_data_for_uv_handle(self.uv_handle(), &slot);
143             })
144         }
145
146         extern fn close_cb(handle: *uvll::uv_handle_t) {
147             unsafe {
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());
154             }
155         }
156     }
157 }
158
159 pub struct ForbidSwitch {
160     msg: &'static str,
161     sched: uint,
162 }
163
164 impl ForbidSwitch {
165     fn new(s: &'static str) -> ForbidSwitch {
166         ForbidSwitch {
167             msg: s, sched: Local::borrow(|s: &mut Scheduler| s.sched_id())
168         }
169     }
170 }
171
172 impl Drop for ForbidSwitch {
173     fn drop(&mut self) {
174         assert!(self.sched == Local::borrow(|s: &mut Scheduler| s.sched_id()),
175                 "didnt want a scheduler switch: {}", self.msg);
176     }
177 }
178
179 pub struct ForbidUnwind {
180     msg: &'static str,
181     failing_before: bool,
182 }
183
184 impl ForbidUnwind {
185     fn new(s: &'static str) -> ForbidUnwind {
186         ForbidUnwind {
187             msg: s, failing_before: task::failing(),
188         }
189     }
190 }
191
192 impl Drop for ForbidUnwind {
193     fn drop(&mut self) {
194         assert!(self.failing_before == task::failing(),
195                 "didnt want an unwind during: {}", self.msg);
196     }
197 }
198
199 fn wait_until_woken_after(slot: *mut Option<BlockedTask>, f: ||) {
200     let _f = ForbidUnwind::new("wait_until_woken_after");
201     unsafe {
202         assert!((*slot).is_none());
203         let sched: ~Scheduler = Local::take();
204         sched.deschedule_running_task_and_then(|_, task| {
205             f();
206             *slot = Some(task);
207         })
208     }
209 }
210
211 pub struct Request {
212     handle: *uvll::uv_req_t,
213     priv defused: bool,
214 }
215
216 impl Request {
217     pub fn new(ty: uvll::uv_req_type) -> Request {
218         unsafe {
219             let handle = uvll::malloc_req(ty);
220             uvll::set_data_for_req(handle, null::<()>());
221             Request::wrap(handle)
222         }
223     }
224
225     pub fn wrap(handle: *uvll::uv_req_t) -> Request {
226         Request { handle: handle, defused: false }
227     }
228
229     pub fn set_data<T>(&self, t: *T) {
230         unsafe { uvll::set_data_for_req(self.handle, t) }
231     }
232
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)
237     }
238
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.
243     //
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) {
248         self.defused = true;
249     }
250 }
251
252 impl Drop for Request {
253     fn drop(&mut self) {
254         if !self.defused {
255             unsafe { uvll::free_req(self.handle) }
256         }
257     }
258 }
259
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.
263 pub struct Loop {
264     priv handle: *uvll::uv_loop_t
265 }
266
267 impl Loop {
268     pub fn new() -> Loop {
269         let handle = unsafe { uvll::loop_new() };
270         assert!(handle.is_not_null());
271         Loop::wrap(handle)
272     }
273
274     pub fn wrap(handle: *uvll::uv_loop_t) -> Loop { Loop { handle: handle } }
275
276     pub fn run(&mut self) {
277         unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) };
278     }
279
280     pub fn close(&mut self) {
281         unsafe { uvll::uv_loop_delete(self.handle) };
282     }
283 }
284
285 // XXX: Need to define the error constants like EOF so they can be
286 // compared to the UvError type
287
288 pub struct UvError(c_int);
289
290 impl UvError {
291     pub fn name(&self) -> ~str {
292         unsafe {
293             let inner = match self { &UvError(a) => a };
294             let name_str = uvll::uv_err_name(inner);
295             assert!(name_str.is_not_null());
296             from_c_str(name_str)
297         }
298     }
299
300     pub fn desc(&self) -> ~str {
301         unsafe {
302             let inner = match self { &UvError(a) => a };
303             let desc_str = uvll::uv_strerror(inner);
304             assert!(desc_str.is_not_null());
305             from_c_str(desc_str)
306         }
307     }
308
309     pub fn is_eof(&self) -> bool {
310         **self == uvll::EOF
311     }
312 }
313
314 impl ToStr for UvError {
315     fn to_str(&self) -> ~str {
316         format!("{}: {}", self.name(), self.desc())
317     }
318 }
319
320 #[test]
321 fn error_smoke_test() {
322     let err: UvError = UvError(uvll::EOF);
323     assert_eq!(err.to_str(), ~"EOF: end of file");
324 }
325
326 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
327     unsafe {
328         // Importing error constants
329         use uvll::*;
330         use std::io::*;
331
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);
335
336         let kind = match *uverr {
337             UNKNOWN => OtherIoError,
338             OK => OtherIoError,
339             EOF => EndOfFile,
340             EACCES => PermissionDenied,
341             ECONNREFUSED => ConnectionRefused,
342             ECONNRESET => ConnectionReset,
343             ENOTCONN => NotConnected,
344             EPIPE => BrokenPipe,
345             ECONNABORTED => ConnectionAborted,
346             err => {
347                 uvdebug!("uverr.code {}", err as int);
348                 // XXX: Need to map remaining uv error types
349                 OtherIoError
350             }
351         };
352
353         IoError {
354             kind: kind,
355             desc: desc,
356             detail: None
357         }
358     }
359 }
360
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> {
363     if status >= 0 {
364         None
365     } else {
366         Some(UvError(status))
367     }
368 }
369
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)))}
372 }
373
374 /// The uv buffer type
375 pub type Buf = uvll::uv_buf_t;
376
377 pub fn empty_buf() -> Buf {
378     uvll::uv_buf_t {
379         base: null(),
380         len: 0,
381     }
382 }
383
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 }
388 }
389
390 #[cfg(test)]
391 fn local_loop() -> &'static mut Loop {
392     unsafe {
393         cast::transmute(Local::borrow(|sched: &mut Scheduler| {
394             let mut io = None;
395             sched.event_loop.io(|i| {
396                 let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
397                     cast::transmute(i);
398                 io = Some(uvio);
399             });
400             io.unwrap()
401         }).uv_loop())
402     }
403 }
404
405 #[cfg(test)]
406 mod test {
407     use std::cast::transmute;
408     use std::ptr;
409     use std::unstable::run_in_bare_thread;
410
411     use super::{slice_to_uv_buf, Loop};
412
413     #[test]
414     fn test_slice_to_uv_buf() {
415         let slice = [0, .. 20];
416         let buf = slice_to_uv_buf(slice);
417
418         assert_eq!(buf.len, 20);
419
420         unsafe {
421             let base = transmute::<*u8, *mut u8>(buf.base);
422             (*base) = 1;
423             (*ptr::mut_offset(base, 1)) = 2;
424         }
425
426         assert!(slice[0] == 1);
427         assert!(slice[1] == 2);
428     }
429
430
431     #[test]
432     fn loop_smoke_test() {
433         do run_in_bare_thread {
434             let mut loop_ = Loop::new();
435             loop_.run();
436             loop_.close();
437         }
438     }
439 }