Register new snapshots

This commit is contained in:
Alex Crichton 2013-10-29 14:14:34 -07:00
parent 886819cca1
commit e203f30bc7
19 changed files with 22 additions and 6780 deletions

View File

@ -98,17 +98,13 @@ $$(HLIB0_H_$(1))/$(CFG_EXTRALIB_$(1)): \
$$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(EXTRALIB_GLOB_$(1)) $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@))
$$(HLIB0_H_$(1))/$(CFG_LIBRUSTUV_$(1)):
touch $$@
# NOTE: this should get uncommented after a snapshot and the rule above this can
# get deleted, right now we're not expecting a librustuv in a snapshot.
# $$(HLIB0_H_$(1))/$(CFG_LIBRUSTUV_$(1)): \
# $$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTUV_$(1)) \
# | $(HLIB0_H_$(1))/
# @$$(call E, cp: $$@)
# $$(call CHECK_FOR_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
# $$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(LIBRUSTUV_GLOB_$(1)) $$@
# $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
$$(HLIB0_H_$(1))/$(CFG_LIBRUSTUV_$(1)): \
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTUV_$(1)) \
| $(HLIB0_H_$(1))/
@$$(call E, cp: $$@)
$$(call CHECK_FOR_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(LIBRUSTUV_GLOB_$(1)) $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
$$(HLIB0_H_$(1))/$(CFG_LIBRUSTC_$(1)): \
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTC_$(1)) \

View File

@ -232,15 +232,14 @@ impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W {
}
}
fn close(self, cb: NullCallback) {
let mut this = self;
fn close(mut self, cb: NullCallback) {
{
let data = this.get_watcher_data();
let data = self.get_watcher_data();
assert!(data.close_cb.is_none());
data.close_cb = Some(cb);
}
unsafe { uvll::close(this.native_handle(), close_cb); }
unsafe { uvll::close(self.native_handle(), close_cb); }
extern fn close_cb(handle: *uvll::uv_handle_t) {
let mut h: Handle = NativeHandle::from_native_handle(handle);

View File

@ -122,10 +122,9 @@ trait HomingIO {
a // return the result of the IO
}
fn home_for_io_consume<A>(self, io: &fn(Self) -> A) -> A {
let mut this = self;
let home = this.go_to_IO_home();
let a = io(this); // do IO
fn home_for_io_consume<A>(mut self, io: &fn(Self) -> A) -> A {
let home = self.go_to_IO_home();
let a = io(self); // do IO
HomingIO::restore_original_home(None::<Self>, home);
a // return the result of the IO
}
@ -239,7 +238,7 @@ impl EventLoop for UvEventLoop {
}
}
#[cfg(not(stage0), not(test))]
#[cfg(not(test))]
#[lang = "event_loop_factory"]
pub extern "C" fn new_loop() -> ~EventLoop {
~UvEventLoop::new() as ~EventLoop

View File

@ -12,7 +12,6 @@ use container::MutableSet;
use hashmap::HashSet;
use option::{Some, None, Option};
use vec::ImmutableVector;
#[cfg(not(stage0))]
use rt::rtio::EventLoop;
// Need to tell the linker on OS X to not barf on undefined symbols
@ -27,14 +26,6 @@ pub struct ModEntry<'self> {
log_level: *mut u32
}
#[cfg(stage0)]
pub struct CrateMap<'self> {
version: i32,
entries: &'self [ModEntry<'self>],
children: &'self [&'self CrateMap<'self>]
}
#[cfg(not(stage0))]
pub struct CrateMap<'self> {
version: i32,
entries: &'self [ModEntry<'self>],
@ -45,12 +36,6 @@ pub struct CrateMap<'self> {
#[cfg(not(windows))]
pub fn get_crate_map() -> Option<&'static CrateMap<'static>> {
extern {
#[cfg(stage0)]
#[weak_linkage]
#[link_name = "_rust_crate_map_toplevel"]
static CRATE_MAP: CrateMap<'static>;
#[cfg(not(stage0))]
#[crate_map]
static CRATE_MAP: CrateMap<'static>;
}

View File

@ -121,10 +121,6 @@ pub mod io;
/// The EventLoop and internal synchronous I/O interface.
pub mod rtio;
/// libuv and default rtio implementation.
#[cfg(stage0)]
pub mod uv;
/// The Local trait for types that are accessible via thread-local
/// or task-local storage.
pub mod local;
@ -463,13 +459,6 @@ pub fn in_green_task_context() -> bool {
}
}
#[cfg(stage0)]
pub fn new_event_loop() -> ~rtio::EventLoop {
use rt::uv::uvio::UvEventLoop;
~UvEventLoop::new() as ~rtio::EventLoop
}
#[cfg(not(stage0))]
pub fn new_event_loop() -> ~rtio::EventLoop {
#[fixed_stack_segment]; #[allow(cstack)];

View File

@ -1,276 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use cast::transmute;
use cell::Cell;
use c_str::ToCStr;
use libc::{c_int, c_void};
use option::{Option, Some, None};
use ptr::null;
use rt::uv::uvll;
use rt::uv::uvll::UV_GETADDRINFO;
use rt::uv::{Loop, UvError, NativeHandle};
use rt::uv::status_to_maybe_uv_error;
use rt::uv::net;
use ai = rt::io::net::addrinfo;
type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &net::UvAddrInfo, Option<UvError>);
pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t);
pub struct RequestData {
priv getaddrinfo_cb: Option<GetAddrInfoCallback>,
}
impl GetAddrInfoRequest {
pub fn new() -> GetAddrInfoRequest {
let req = unsafe { uvll::malloc_req(UV_GETADDRINFO) };
assert!(req.is_not_null());
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
req.install_req_data();
return req;
}
pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>,
service: Option<&str>, hints: Option<ai::Hint>,
cb: GetAddrInfoCallback) {
assert!(node.is_some() || service.is_some());
let (c_node, c_node_ptr) = match node {
Some(n) => {
let c_node = n.to_c_str();
let c_node_ptr = c_node.with_ref(|r| r);
(Some(c_node), c_node_ptr)
}
None => (None, null())
};
let (c_service, c_service_ptr) = match service {
Some(s) => {
let c_service = s.to_c_str();
let c_service_ptr = c_service.with_ref(|r| r);
(Some(c_service), c_service_ptr)
}
None => (None, null())
};
let cb = Cell::new(cb);
let wrapper_cb: GetAddrInfoCallback = |req, addrinfo, err| {
// Capture some heap values that need to stay alive for the
// getaddrinfo call
let _ = &c_node;
let _ = &c_service;
let cb = cb.take();
cb(req, addrinfo, err)
};
let hint = hints.map(|hint| {
let mut flags = 0;
do each_ai_flag |cval, aival| {
if hint.flags & (aival as uint) != 0 {
flags |= cval as i32;
}
}
/* XXX: do we really want to support these?
let socktype = match hint.socktype {
Some(ai::Stream) => uvll::rust_SOCK_STREAM(),
Some(ai::Datagram) => uvll::rust_SOCK_DGRAM(),
Some(ai::Raw) => uvll::rust_SOCK_RAW(),
None => 0,
};
let protocol = match hint.protocol {
Some(ai::UDP) => uvll::rust_IPPROTO_UDP(),
Some(ai::TCP) => uvll::rust_IPPROTO_TCP(),
_ => 0,
};
*/
let socktype = 0;
let protocol = 0;
uvll::addrinfo {
ai_flags: flags,
ai_family: hint.family as c_int,
ai_socktype: socktype,
ai_protocol: protocol,
ai_addrlen: 0,
ai_canonname: null(),
ai_addr: null(),
ai_next: null(),
}
});
let hint_ptr = hint.as_ref().map_default(null(), |x| x as *uvll::addrinfo);
self.get_req_data().getaddrinfo_cb = Some(wrapper_cb);
unsafe {
assert!(0 == uvll::getaddrinfo(loop_.native_handle(),
self.native_handle(),
getaddrinfo_cb,
c_node_ptr,
c_service_ptr,
hint_ptr));
}
extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
status: c_int,
res: *uvll::addrinfo) {
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
let err = status_to_maybe_uv_error(status);
let addrinfo = net::UvAddrInfo(res);
let data = req.get_req_data();
(*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err);
unsafe {
uvll::freeaddrinfo(res);
}
}
}
fn get_loop(&self) -> Loop {
unsafe {
Loop {
handle: uvll::get_loop_from_fs_req(self.native_handle())
}
}
}
fn install_req_data(&mut self) {
let req = self.native_handle() as *uvll::uv_getaddrinfo_t;
let data = ~RequestData {
getaddrinfo_cb: None
};
unsafe {
let data = transmute::<~RequestData, *c_void>(data);
uvll::set_data_for_req(req, data);
}
}
fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
return &mut **data;
}
}
fn delete(self) {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
let _data = transmute::<*c_void, ~RequestData>(data);
uvll::set_data_for_req(self.native_handle(), null::<()>());
uvll::free_req(self.native_handle());
}
}
}
fn each_ai_flag(_f: &fn(c_int, ai::Flag)) {
/* XXX: do we really want to support these?
unsafe {
f(uvll::rust_AI_ADDRCONFIG(), ai::AddrConfig);
f(uvll::rust_AI_ALL(), ai::All);
f(uvll::rust_AI_CANONNAME(), ai::CanonName);
f(uvll::rust_AI_NUMERICHOST(), ai::NumericHost);
f(uvll::rust_AI_NUMERICSERV(), ai::NumericServ);
f(uvll::rust_AI_PASSIVE(), ai::Passive);
f(uvll::rust_AI_V4MAPPED(), ai::V4Mapped);
}
*/
}
// Traverse the addrinfo linked list, producing a vector of Rust socket addresses
pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] {
unsafe {
let &net::UvAddrInfo(addr) = addr;
let mut addr = addr;
let mut addrs = ~[];
loop {
let uvaddr = net::sockaddr_to_UvSocketAddr((*addr).ai_addr);
let rustaddr = net::uv_socket_addr_to_socket_addr(uvaddr);
let mut flags = 0;
do each_ai_flag |cval, aival| {
if (*addr).ai_flags & cval != 0 {
flags |= aival as uint;
}
}
/* XXX: do we really want to support these
let protocol = match (*addr).ai_protocol {
p if p == uvll::rust_IPPROTO_UDP() => Some(ai::UDP),
p if p == uvll::rust_IPPROTO_TCP() => Some(ai::TCP),
_ => None,
};
let socktype = match (*addr).ai_socktype {
p if p == uvll::rust_SOCK_STREAM() => Some(ai::Stream),
p if p == uvll::rust_SOCK_DGRAM() => Some(ai::Datagram),
p if p == uvll::rust_SOCK_RAW() => Some(ai::Raw),
_ => None,
};
*/
let protocol = None;
let socktype = None;
addrs.push(ai::Info {
address: rustaddr,
family: (*addr).ai_family as uint,
socktype: socktype,
protocol: protocol,
flags: flags,
});
if (*addr).ai_next.is_not_null() {
addr = (*addr).ai_next;
} else {
break;
}
}
return addrs;
}
}
impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest {
fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest {
GetAddrInfoRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_getaddrinfo_t {
match self { &GetAddrInfoRequest(ptr) => ptr }
}
}
#[cfg(test)]
mod test {
use option::{Some, None};
use rt::uv::Loop;
use rt::io::net::ip::{SocketAddr, Ipv4Addr};
use super::*;
#[test]
fn getaddrinfo_test() {
let mut loop_ = Loop::new();
let mut req = GetAddrInfoRequest::new();
do req.getaddrinfo(&loop_, Some("localhost"), None, None) |_, addrinfo, _| {
let sockaddrs = accum_addrinfo(addrinfo);
let mut found_local = false;
let local_addr = &SocketAddr {
ip: Ipv4Addr(127, 0, 0, 1),
port: 0
};
for addr in sockaddrs.iter() {
found_local = found_local || addr.address == *local_addr;
}
assert!(found_local);
}
loop_.run();
loop_.close();
req.delete();
}
}

View File

@ -1,85 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use libc::c_int;
use option::Some;
use rt::uv::uvll;
use rt::uv::uvll::UV_ASYNC;
use rt::uv::{Watcher, Loop, NativeHandle, AsyncCallback};
use rt::uv::WatcherInterop;
use rt::uv::status_to_maybe_uv_error;
pub struct AsyncWatcher(*uvll::uv_async_t);
impl Watcher for AsyncWatcher { }
impl AsyncWatcher {
pub fn new(loop_: &mut Loop, cb: AsyncCallback) -> AsyncWatcher {
unsafe {
let handle = uvll::malloc_handle(UV_ASYNC);
assert!(handle.is_not_null());
let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
let data = watcher.get_watcher_data();
data.async_cb = Some(cb);
assert_eq!(0, uvll::async_init(loop_.native_handle(), handle, async_cb));
return watcher;
}
extern fn async_cb(handle: *uvll::uv_async_t, status: c_int) {
let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
let status = status_to_maybe_uv_error(status);
let data = watcher.get_watcher_data();
let cb = data.async_cb.get_ref();
(*cb)(watcher, status);
}
}
pub fn send(&mut self) {
unsafe {
let handle = self.native_handle();
uvll::async_send(handle);
}
}
}
impl NativeHandle<*uvll::uv_async_t> for AsyncWatcher {
fn from_native_handle(handle: *uvll::uv_async_t) -> AsyncWatcher {
AsyncWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_async_t {
match self { &AsyncWatcher(ptr) => ptr }
}
}
#[cfg(test)]
mod test {
use super::*;
use rt::uv::Loop;
use unstable::run_in_bare_thread;
use rt::thread::Thread;
use cell::Cell;
#[test]
fn smoke_test() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let watcher = AsyncWatcher::new(&mut loop_, |w, _| w.close(||()) );
let watcher_cell = Cell::new(watcher);
let thread = do Thread::start {
let mut watcher = watcher_cell.take();
watcher.send();
};
loop_.run();
loop_.close();
thread.join();
}
}
}

View File

@ -1,648 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use prelude::*;
use ptr::null;
use c_str;
use c_str::CString;
use libc::c_void;
use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf,
status_to_maybe_uv_error, UvError};
use rt::uv::uvll;
use rt::uv::uvll::*;
use cast::transmute;
use libc;
use libc::{c_int};
use option::{None, Some, Option};
pub struct FsRequest(*uvll::uv_fs_t);
impl Request for FsRequest {}
pub struct RequestData {
priv complete_cb: Option<FsCallback>
}
impl FsRequest {
pub fn new() -> FsRequest {
let fs_req = unsafe { malloc_req(UV_FS) };
assert!(fs_req.is_not_null());
let fs_req: FsRequest = NativeHandle::from_native_handle(fs_req);
fs_req
}
pub fn open(self, loop_: &Loop, path: &CString, flags: int, mode: int,
cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_open(loop_.native_handle(),
self.native_handle(), p, flags, mode, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
pub fn open_sync(self, loop_: &Loop, path: &CString,
flags: int, mode: int) -> Result<c_int, UvError> {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(None)
};
let result = path.with_ref(|p| unsafe {
uvll::fs_open(loop_.native_handle(),
self.native_handle(), p, flags, mode, complete_cb_ptr)
});
self.sync_cleanup(result)
}
pub fn unlink(self, loop_: &Loop, path: &CString, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_unlink(loop_.native_handle(),
self.native_handle(), p, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
pub fn unlink_sync(self, loop_: &Loop, path: &CString)
-> Result<c_int, UvError> {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(None)
};
let result = path.with_ref(|p| unsafe {
uvll::fs_unlink(loop_.native_handle(),
self.native_handle(), p, complete_cb_ptr)
});
self.sync_cleanup(result)
}
pub fn stat(self, loop_: &Loop, path: &CString, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_stat(loop_.native_handle(),
self.native_handle(), p, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
pub fn write(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let base_ptr = buf.base as *c_void;
let len = buf.len as uint;
let ret = unsafe {
uvll::fs_write(loop_.native_handle(), self.native_handle(),
fd, base_ptr,
len, offset, complete_cb_ptr)
};
assert_eq!(ret, 0);
}
pub fn write_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
-> Result<c_int, UvError> {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(None)
};
let base_ptr = buf.base as *c_void;
let len = buf.len as uint;
let result = unsafe {
uvll::fs_write(loop_.native_handle(), self.native_handle(),
fd, base_ptr,
len, offset, complete_cb_ptr)
};
self.sync_cleanup(result)
}
pub fn read(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let buf_ptr = buf.base as *c_void;
let len = buf.len as uint;
let ret = unsafe {
uvll::fs_read(loop_.native_handle(), self.native_handle(),
fd, buf_ptr,
len, offset, complete_cb_ptr)
};
assert_eq!(ret, 0);
}
pub fn read_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
-> Result<c_int, UvError> {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(None)
};
let buf_ptr = buf.base as *c_void;
let len = buf.len as uint;
let result = unsafe {
uvll::fs_read(loop_.native_handle(), self.native_handle(),
fd, buf_ptr,
len, offset, complete_cb_ptr)
};
self.sync_cleanup(result)
}
pub fn close(self, loop_: &Loop, fd: c_int, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = unsafe {
uvll::fs_close(loop_.native_handle(), self.native_handle(),
fd, complete_cb_ptr)
};
assert_eq!(ret, 0);
}
pub fn close_sync(self, loop_: &Loop, fd: c_int) -> Result<c_int, UvError> {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(None)
};
let result = unsafe {
uvll::fs_close(loop_.native_handle(), self.native_handle(),
fd, complete_cb_ptr)
};
self.sync_cleanup(result)
}
pub fn mkdir(self, loop_: &Loop, path: &CString, mode: int, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_mkdir(loop_.native_handle(),
self.native_handle(), p, mode, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
pub fn rmdir(self, loop_: &Loop, path: &CString, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_rmdir(loop_.native_handle(),
self.native_handle(), p, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
pub fn readdir(self, loop_: &Loop, path: &CString,
flags: c_int, cb: FsCallback) {
let complete_cb_ptr = {
let mut me = self;
me.req_boilerplate(Some(cb))
};
let ret = path.with_ref(|p| unsafe {
uvll::fs_readdir(loop_.native_handle(),
self.native_handle(), p, flags, complete_cb_ptr)
});
assert_eq!(ret, 0);
}
// accessors/utility funcs
fn sync_cleanup(self, result: c_int)
-> Result<c_int, UvError> {
self.cleanup_and_delete();
match status_to_maybe_uv_error(result as i32) {
Some(err) => Err(err),
None => Ok(result)
}
}
fn req_boilerplate(&mut self, cb: Option<FsCallback>) -> *u8 {
let result = match cb {
Some(_) => {
compl_cb as *u8
},
None => 0 as *u8
};
self.install_req_data(cb);
result
}
pub fn install_req_data(&mut self, cb: Option<FsCallback>) {
let fs_req = (self.native_handle()) as *uvll::uv_write_t;
let data = ~RequestData {
complete_cb: cb
};
unsafe {
let data = transmute::<~RequestData, *c_void>(data);
uvll::set_data_for_req(fs_req, data);
}
}
fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
unsafe {
let data = uvll::get_data_for_req((self.native_handle()));
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
&mut **data
}
}
pub fn get_result(&mut self) -> c_int {
unsafe {
uvll::get_result_from_fs_req(self.native_handle())
}
}
pub fn get_loop(&self) -> Loop {
unsafe { Loop{handle:uvll::get_loop_from_fs_req(self.native_handle())} }
}
pub fn get_stat(&self) -> uv_stat_t {
let stat = uv_stat_t::new();
unsafe { uvll::populate_stat(self.native_handle(), &stat); }
stat
}
pub fn get_ptr(&self) -> *libc::c_void {
unsafe {
uvll::get_ptr_from_fs_req(self.native_handle())
}
}
pub fn each_path(&mut self, f: &fn(&CString)) {
let ptr = self.get_ptr();
match self.get_result() {
n if (n <= 0) => {}
n => {
let n_len = n as uint;
// we pass in the len that uv tells us is there
// for the entries and we don't continue past that..
// it appears that sometimes the multistring isn't
// correctly delimited and we stray into garbage memory?
// in any case, passing Some(n_len) fixes it and ensures
// good results
unsafe {
c_str::from_c_multistring(ptr as *libc::c_char,
Some(n_len), f);
}
}
}
}
fn cleanup_and_delete(self) {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
let _data = transmute::<*c_void, ~RequestData>(data);
uvll::set_data_for_req(self.native_handle(), null::<()>());
uvll::fs_req_cleanup(self.native_handle());
free_req(self.native_handle() as *c_void)
}
}
}
impl NativeHandle<*uvll::uv_fs_t> for FsRequest {
fn from_native_handle(handle: *uvll:: uv_fs_t) -> FsRequest {
FsRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_fs_t {
match self { &FsRequest(ptr) => ptr }
}
}
fn sync_cleanup(result: int)
-> Result<int, UvError> {
match status_to_maybe_uv_error(result as i32) {
Some(err) => Err(err),
None => Ok(result)
}
}
extern fn compl_cb(req: *uv_fs_t) {
let mut req: FsRequest = NativeHandle::from_native_handle(req);
// pull the user cb out of the req data
let cb = {
let data = req.get_req_data();
assert!(data.complete_cb.is_some());
// option dance, option dance. oooooh yeah.
data.complete_cb.take_unwrap()
};
// in uv_fs_open calls, the result will be the fd in the
// case of success, otherwise it's -1 indicating an error
let result = req.get_result();
let status = status_to_maybe_uv_error(result);
// we have a req and status, call the user cb..
// only giving the user a ref to the FsRequest, as we
// have to clean it up, afterwards (and they aren't really
// reusable, anyways
cb(&mut req, status);
// clean up the req (and its data!) after calling the user cb
req.cleanup_and_delete();
}
#[cfg(test)]
mod test {
use super::*;
//use rt::test::*;
use libc::{STDOUT_FILENO};
use vec;
use str;
use unstable::run_in_bare_thread;
use rt::uv::{Loop, Buf, slice_to_uv_buf};
use libc::{O_CREAT, O_RDWR, O_RDONLY, S_IWUSR, S_IRUSR};
#[test]
fn file_test_full_simple() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let create_flags = O_RDWR | O_CREAT;
let read_flags = O_RDONLY;
// 0644 BZZT! WRONG! 0600! See below.
let mode = S_IWUSR |S_IRUSR;
// these aren't defined in std::libc :(
//map_mode(S_IRGRP) |
//map_mode(S_IROTH);
let path_str = "./tmp/file_full_simple.txt";
let write_val = "hello".as_bytes().to_owned();
let write_buf = slice_to_uv_buf(write_val);
let write_buf_ptr: *Buf = &write_buf;
let read_buf_len = 1028;
let read_mem = vec::from_elem(read_buf_len, 0u8);
let read_buf = slice_to_uv_buf(read_mem);
let read_buf_ptr: *Buf = &read_buf;
let open_req = FsRequest::new();
do open_req.open(&loop_, &path_str.to_c_str(), create_flags as int,
mode as int) |req, uverr| {
assert!(uverr.is_none());
let fd = req.get_result();
let buf = unsafe { *write_buf_ptr };
let write_req = FsRequest::new();
do write_req.write(&req.get_loop(), fd, buf, -1) |req, uverr| {
let close_req = FsRequest::new();
do close_req.close(&req.get_loop(), fd) |req, _| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let open_req = FsRequest::new();
do open_req.open(&loop_, &path_str.to_c_str(),
read_flags as int,0) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let fd = req.get_result();
let read_buf = unsafe { *read_buf_ptr };
let read_req = FsRequest::new();
do read_req.read(&loop_, fd, read_buf, 0) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
// we know nread >=0 because uverr is none..
let nread = req.get_result() as uint;
// nread == 0 would be EOF
if nread > 0 {
let read_str = unsafe {
let read_buf = *read_buf_ptr;
str::from_utf8(
vec::from_buf(
read_buf.base, nread))
};
assert!(read_str == ~"hello");
let close_req = FsRequest::new();
do close_req.close(&loop_, fd) |req,uverr| {
assert!(uverr.is_none());
let loop_ = &req.get_loop();
let unlink_req = FsRequest::new();
do unlink_req.unlink(loop_,
&path_str.to_c_str())
|_,uverr| {
assert!(uverr.is_none());
};
};
};
};
};
};
};
};
loop_.run();
loop_.close();
}
}
#[test]
fn file_test_full_simple_sync() {
do run_in_bare_thread {
// setup
let mut loop_ = Loop::new();
let create_flags = O_RDWR |
O_CREAT;
let read_flags = O_RDONLY;
// 0644
let mode = S_IWUSR |
S_IRUSR;
//S_IRGRP |
//S_IROTH;
let path_str = "./tmp/file_full_simple_sync.txt";
let write_val = "hello".as_bytes().to_owned();
let write_buf = slice_to_uv_buf(write_val);
// open/create
let open_req = FsRequest::new();
let result = open_req.open_sync(&loop_, &path_str.to_c_str(),
create_flags as int, mode as int);
assert!(result.is_ok());
let fd = result.unwrap();
// write
let write_req = FsRequest::new();
let result = write_req.write_sync(&loop_, fd, write_buf, -1);
assert!(result.is_ok());
// close
let close_req = FsRequest::new();
let result = close_req.close_sync(&loop_, fd);
assert!(result.is_ok());
// re-open
let open_req = FsRequest::new();
let result = open_req.open_sync(&loop_, &path_str.to_c_str(),
read_flags as int,0);
assert!(result.is_ok());
let len = 1028;
let fd = result.unwrap();
// read
let read_mem: ~[u8] = vec::from_elem(len, 0u8);
let buf = slice_to_uv_buf(read_mem);
let read_req = FsRequest::new();
let result = read_req.read_sync(&loop_, fd, buf, 0);
assert!(result.is_ok());
let nread = result.unwrap();
// nread == 0 would be EOF.. we know it's >= zero because otherwise
// the above assert would fail
if nread > 0 {
let read_str = str::from_utf8(
read_mem.slice(0, nread as uint));
assert!(read_str == ~"hello");
// close
let close_req = FsRequest::new();
let result = close_req.close_sync(&loop_, fd);
assert!(result.is_ok());
// unlink
let unlink_req = FsRequest::new();
let result = unlink_req.unlink_sync(&loop_, &path_str.to_c_str());
assert!(result.is_ok());
} else { fail!("nread was 0.. wudn't expectin' that."); }
loop_.close();
}
}
fn naive_print(loop_: &Loop, input: &str) {
let write_val = input.as_bytes();
let write_buf = slice_to_uv_buf(write_val);
let write_req = FsRequest::new();
write_req.write_sync(loop_, STDOUT_FILENO, write_buf, -1);
}
#[test]
fn file_test_write_to_stdout() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
naive_print(&loop_, "zanzibar!\n");
loop_.run();
loop_.close();
};
}
#[test]
fn file_test_stat_simple() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let path = "./tmp/file_test_stat_simple.txt";
let create_flags = O_RDWR |
O_CREAT;
let mode = S_IWUSR |
S_IRUSR;
let write_val = "hello".as_bytes().to_owned();
let write_buf = slice_to_uv_buf(write_val);
let write_buf_ptr: *Buf = &write_buf;
let open_req = FsRequest::new();
do open_req.open(&loop_, &path.to_c_str(), create_flags as int,
mode as int) |req, uverr| {
assert!(uverr.is_none());
let fd = req.get_result();
let buf = unsafe { *write_buf_ptr };
let write_req = FsRequest::new();
do write_req.write(&req.get_loop(), fd, buf, 0) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat_req = FsRequest::new();
do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat = req.get_stat();
let sz: uint = stat.st_size as uint;
assert!(sz > 0);
let close_req = FsRequest::new();
do close_req.close(&loop_, fd) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let unlink_req = FsRequest::new();
do unlink_req.unlink(&loop_,
&path.to_c_str()) |req,uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat_req = FsRequest::new();
do stat_req.stat(&loop_,
&path.to_c_str()) |_, uverr| {
// should cause an error because the
// file doesn't exist anymore
assert!(uverr.is_some());
};
};
};
};
};
};
loop_.run();
loop_.close();
}
}
#[test]
fn file_test_mk_rm_dir() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let path = "./tmp/mk_rm_dir";
let mode = S_IWUSR |
S_IRUSR;
let mkdir_req = FsRequest::new();
do mkdir_req.mkdir(&loop_, &path.to_c_str(),
mode as int) |req,uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat_req = FsRequest::new();
do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat = req.get_stat();
naive_print(&loop_, format!("{:?}", stat));
assert!(stat.is_dir());
let rmdir_req = FsRequest::new();
do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let stat_req = FsRequest::new();
do stat_req.stat(&loop_, &path.to_c_str()) |_req, uverr| {
assert!(uverr.is_some());
}
}
}
}
loop_.run();
loop_.close();
}
}
#[test]
fn file_test_mkdir_chokes_on_double_create() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let path = "./tmp/double_create_dir";
let mode = S_IWUSR |
S_IRUSR;
let mkdir_req = FsRequest::new();
do mkdir_req.mkdir(&loop_, &path.to_c_str(), mode as int) |req,uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
let mkdir_req = FsRequest::new();
do mkdir_req.mkdir(&loop_, &path.to_c_str(),
mode as int) |req,uverr| {
assert!(uverr.is_some());
let loop_ = req.get_loop();
let _stat = req.get_stat();
let rmdir_req = FsRequest::new();
do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| {
assert!(uverr.is_none());
let _loop = req.get_loop();
}
}
}
loop_.run();
loop_.close();
}
}
#[test]
fn file_test_rmdir_chokes_on_nonexistant_path() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let path = "./tmp/never_existed_dir";
let rmdir_req = FsRequest::new();
do rmdir_req.rmdir(&loop_, &path.to_c_str()) |_req, uverr| {
assert!(uverr.is_some());
}
loop_.run();
loop_.close();
}
}
}

View File

@ -1,138 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use libc::c_int;
use option::Some;
use rt::uv::uvll;
use rt::uv::{Watcher, Loop, NativeHandle, IdleCallback};
use rt::uv::status_to_maybe_uv_error;
pub struct IdleWatcher(*uvll::uv_idle_t);
impl Watcher for IdleWatcher { }
impl IdleWatcher {
pub fn new(loop_: &mut Loop) -> IdleWatcher {
unsafe {
let handle = uvll::malloc_handle(uvll::UV_IDLE);
assert!(handle.is_not_null());
assert_eq!(uvll::idle_init(loop_.native_handle(), handle), 0);
let mut watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
return watcher
}
}
pub fn start(&mut self, cb: IdleCallback) {
{
let data = self.get_watcher_data();
data.idle_cb = Some(cb);
}
unsafe {
assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0)
}
}
pub fn restart(&mut self) {
unsafe {
assert!(self.get_watcher_data().idle_cb.is_some());
assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0)
}
}
pub fn stop(&mut self) {
// NB: Not resetting the Rust idle_cb to None here because `stop` is
// likely called from *within* the idle callback, causing a use after
// free
unsafe {
assert_eq!(uvll::idle_stop(self.native_handle()), 0);
}
}
}
impl NativeHandle<*uvll::uv_idle_t> for IdleWatcher {
fn from_native_handle(handle: *uvll::uv_idle_t) -> IdleWatcher {
IdleWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_idle_t {
match self { &IdleWatcher(ptr) => ptr }
}
}
extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
let data = idle_watcher.get_watcher_data();
let cb: &IdleCallback = data.idle_cb.get_ref();
let status = status_to_maybe_uv_error(status);
(*cb)(idle_watcher, status);
}
#[cfg(test)]
mod test {
use rt::uv::Loop;
use super::*;
use unstable::run_in_bare_thread;
#[test]
#[ignore(reason = "valgrind - loop destroyed before watcher?")]
fn idle_new_then_close() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let idle_watcher = { IdleWatcher::new(&mut loop_) };
idle_watcher.close(||());
}
}
#[test]
fn idle_smoke_test() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let mut idle_watcher = { IdleWatcher::new(&mut loop_) };
let mut count = 10;
let count_ptr: *mut int = &mut count;
do idle_watcher.start |idle_watcher, status| {
let mut idle_watcher = idle_watcher;
assert!(status.is_none());
if unsafe { *count_ptr == 10 } {
idle_watcher.stop();
idle_watcher.close(||());
} else {
unsafe { *count_ptr = *count_ptr + 1; }
}
}
loop_.run();
loop_.close();
assert_eq!(count, 10);
}
}
#[test]
fn idle_start_stop_start() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let mut idle_watcher = { IdleWatcher::new(&mut loop_) };
do idle_watcher.start |idle_watcher, status| {
let mut idle_watcher = idle_watcher;
assert!(status.is_none());
idle_watcher.stop();
do idle_watcher.start |idle_watcher, status| {
assert!(status.is_none());
let mut idle_watcher = idle_watcher;
idle_watcher.stop();
idle_watcher.close(||());
}
}
loop_.run();
loop_.close();
}
}
}

View File

@ -1,416 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
Bindings to libuv, along with the default implementation of `std::rt::rtio`.
UV types consist of the event loop (Loop), Watchers, Requests and
Callbacks.
Watchers and Requests encapsulate pointers to uv *handles*, which have
subtyping relationships with each other. This subtyping is reflected
in the bindings with explicit or implicit coercions. For example, an
upcast from TcpWatcher to StreamWatcher is done with
`tcp_watcher.as_stream()`. In other cases a callback on a specific
type of watcher will be passed a watcher of a supertype.
Currently all use of Request types (connect/write requests) are
encapsulated in the bindings and don't need to be dealt with by the
caller.
# Safety note
Due to the complex lifecycle of uv handles, as well as compiler bugs,
this module is not memory safe and requires explicit memory management,
via `close` and `delete` methods.
*/
use container::Container;
use option::*;
use str::raw::from_c_str;
use to_str::ToStr;
use ptr::RawPtr;
use vec;
use vec::ImmutableVector;
use ptr;
use str;
use libc::{c_void, c_int, size_t, malloc, free};
use cast::transmute;
use ptr::null;
use unstable::finally::Finally;
use rt::io::net::ip::SocketAddr;
use rt::io::signal::Signum;
use rt::io::IoError;
//#[cfg(test)] use unstable::run_in_bare_thread;
pub use self::file::{FsRequest};
pub use self::net::{StreamWatcher, TcpWatcher, UdpWatcher};
pub use self::idle::IdleWatcher;
pub use self::timer::TimerWatcher;
pub use self::async::AsyncWatcher;
pub use self::process::Process;
pub use self::pipe::Pipe;
pub use self::signal::SignalWatcher;
/// The implementation of `rtio` for libuv
pub mod uvio;
/// C bindings to libuv
pub mod uvll;
pub mod file;
pub mod net;
pub mod idle;
pub mod timer;
pub mod async;
pub mod addrinfo;
pub mod process;
pub mod pipe;
pub mod tty;
pub mod signal;
/// XXX: Loop(*handle) is buggy with destructors. Normal structs
/// with dtors may not be destructured, but tuple structs can,
/// but the results are not correct.
pub struct Loop {
priv handle: *uvll::uv_loop_t
}
pub struct Handle(*uvll::uv_handle_t);
impl Watcher for Handle {}
impl NativeHandle<*uvll::uv_handle_t> for Handle {
fn from_native_handle(h: *uvll::uv_handle_t) -> Handle { Handle(h) }
fn native_handle(&self) -> *uvll::uv_handle_t { **self }
}
/// The trait implemented by uv 'watchers' (handles). Watchers are
/// non-owning wrappers around the uv handles and are not completely
/// safe - there may be multiple instances for a single underlying
/// handle. Watchers are generally created, then `start`ed, `stop`ed
/// and `close`ed, but due to their complex life cycle may not be
/// entirely memory safe if used in unanticipated patterns.
pub trait Watcher { }
pub trait Request { }
/// A type that wraps a native handle
pub trait NativeHandle<T> {
fn from_native_handle(T) -> Self;
fn native_handle(&self) -> T;
}
impl Loop {
pub fn new() -> Loop {
let handle = unsafe { uvll::loop_new() };
assert!(handle.is_not_null());
NativeHandle::from_native_handle(handle)
}
pub fn run(&mut self) {
unsafe { uvll::run(self.native_handle()) };
}
pub fn close(&mut self) {
unsafe { uvll::loop_delete(self.native_handle()) };
}
}
impl NativeHandle<*uvll::uv_loop_t> for Loop {
fn from_native_handle(handle: *uvll::uv_loop_t) -> Loop {
Loop { handle: handle }
}
fn native_handle(&self) -> *uvll::uv_loop_t {
self.handle
}
}
// XXX: The uv alloc callback also has a *uv_handle_t arg
pub type AllocCallback = ~fn(uint) -> Buf;
pub type ReadCallback = ~fn(StreamWatcher, int, Buf, Option<UvError>);
pub type NullCallback = ~fn();
pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>);
pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>);
pub type FsCallback = ~fn(&mut FsRequest, Option<UvError>);
// first int is exit_status, second is term_signal
pub type ExitCallback = ~fn(Process, int, int, Option<UvError>);
pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>);
pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>);
pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>);
pub type UdpSendCallback = ~fn(UdpWatcher, Option<UvError>);
pub type SignalCallback = ~fn(SignalWatcher, Signum);
/// Callbacks used by StreamWatchers, set as custom data on the foreign handle.
/// XXX: Would be better not to have all watchers allocate room for all callback types.
struct WatcherData {
read_cb: Option<ReadCallback>,
write_cb: Option<ConnectionCallback>,
connect_cb: Option<ConnectionCallback>,
close_cb: Option<NullCallback>,
alloc_cb: Option<AllocCallback>,
idle_cb: Option<IdleCallback>,
timer_cb: Option<TimerCallback>,
async_cb: Option<AsyncCallback>,
udp_recv_cb: Option<UdpReceiveCallback>,
udp_send_cb: Option<UdpSendCallback>,
exit_cb: Option<ExitCallback>,
signal_cb: Option<SignalCallback>,
}
pub trait WatcherInterop {
fn event_loop(&self) -> Loop;
fn install_watcher_data(&mut self);
fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData;
fn drop_watcher_data(&mut self);
fn close(self, cb: NullCallback);
fn close_async(self);
}
impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W {
/// Get the uv event loop from a Watcher
fn event_loop(&self) -> Loop {
unsafe {
let handle = self.native_handle();
let loop_ = uvll::get_loop_for_uv_handle(handle);
NativeHandle::from_native_handle(loop_)
}
}
fn install_watcher_data(&mut self) {
unsafe {
let data = ~WatcherData {
read_cb: None,
write_cb: None,
connect_cb: None,
close_cb: None,
alloc_cb: None,
idle_cb: None,
timer_cb: None,
async_cb: None,
udp_recv_cb: None,
udp_send_cb: None,
exit_cb: None,
signal_cb: None,
};
let data = transmute::<~WatcherData, *c_void>(data);
uvll::set_data_for_uv_handle(self.native_handle(), data);
}
}
fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData {
unsafe {
let data = uvll::get_data_for_uv_handle(self.native_handle());
let data = transmute::<&*c_void, &mut ~WatcherData>(&data);
return &mut **data;
}
}
fn drop_watcher_data(&mut self) {
unsafe {
let data = uvll::get_data_for_uv_handle(self.native_handle());
let _data = transmute::<*c_void, ~WatcherData>(data);
uvll::set_data_for_uv_handle(self.native_handle(), null::<()>());
}
}
fn close(mut self, cb: NullCallback) {
{
let data = self.get_watcher_data();
assert!(data.close_cb.is_none());
data.close_cb = Some(cb);
}
unsafe { uvll::close(self.native_handle(), close_cb); }
extern fn close_cb(handle: *uvll::uv_handle_t) {
let mut h: Handle = NativeHandle::from_native_handle(handle);
h.get_watcher_data().close_cb.take_unwrap()();
h.drop_watcher_data();
unsafe { uvll::free_handle(handle as *c_void) }
}
}
fn close_async(self) {
unsafe { uvll::close(self.native_handle(), close_cb); }
extern fn close_cb(handle: *uvll::uv_handle_t) {
let mut h: Handle = NativeHandle::from_native_handle(handle);
h.drop_watcher_data();
unsafe { uvll::free_handle(handle as *c_void) }
}
}
}
// XXX: Need to define the error constants like EOF so they can be
// compared to the UvError type
pub struct UvError(c_int);
impl UvError {
pub fn name(&self) -> ~str {
unsafe {
let inner = match self { &UvError(a) => a };
let name_str = uvll::err_name(inner);
assert!(name_str.is_not_null());
from_c_str(name_str)
}
}
pub fn desc(&self) -> ~str {
unsafe {
let inner = match self { &UvError(a) => a };
let desc_str = uvll::strerror(inner);
assert!(desc_str.is_not_null());
from_c_str(desc_str)
}
}
pub fn is_eof(&self) -> bool {
**self == uvll::EOF
}
}
impl ToStr for UvError {
fn to_str(&self) -> ~str {
format!("{}: {}", self.name(), self.desc())
}
}
#[test]
fn error_smoke_test() {
let err: UvError = UvError(uvll::EOF);
assert_eq!(err.to_str(), ~"EOF: end of file");
}
pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
unsafe {
// Importing error constants
use rt::uv::uvll::*;
use rt::io::*;
// uv error descriptions are static
let c_desc = uvll::strerror(*uverr);
let desc = str::raw::c_str_to_static_slice(c_desc);
let kind = match *uverr {
UNKNOWN => OtherIoError,
OK => OtherIoError,
EOF => EndOfFile,
EACCES => PermissionDenied,
ECONNREFUSED => ConnectionRefused,
ECONNRESET => ConnectionReset,
ENOTCONN => NotConnected,
EPIPE => BrokenPipe,
ECONNABORTED => ConnectionAborted,
err => {
rtdebug!("uverr.code {}", err as int);
// XXX: Need to map remaining uv error types
OtherIoError
}
};
IoError {
kind: kind,
desc: desc,
detail: None
}
}
}
/// Given a uv handle, convert a callback status to a UvError
pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError>
{
if status >= 0 {
None
} else {
Some(UvError(status))
}
}
/// The uv buffer type
pub type Buf = uvll::uv_buf_t;
pub fn empty_buf() -> Buf {
uvll::uv_buf_t {
base: null(),
len: 0,
}
}
/// Borrow a slice to a Buf
pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
let data = vec::raw::to_ptr(v);
unsafe { uvll::buf_init(data, v.len()) }
}
// XXX: Do these conversions without copying
/// Transmute an owned vector to a Buf
pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
let data = malloc(v.len() as size_t) as *u8;
assert!(data.is_not_null());
do v.as_imm_buf |b, l| {
let data = data as *mut u8;
ptr::copy_memory(data, b, l)
}
uvll::buf_init(data, v.len())
}
}
/// Transmute a Buf that was once a ~[u8] back to ~[u8]
pub fn vec_from_uv_buf(buf: Buf) -> Option<~[u8]> {
#[fixed_stack_segment]; #[inline(never)];
if !(buf.len == 0 && buf.base.is_null()) {
let v = unsafe { vec::from_buf(buf.base, buf.len as uint) };
unsafe { free(buf.base as *c_void) };
return Some(v);
} else {
// No buffer
rtdebug!("No buffer!");
return None;
}
}
/*
#[test]
fn test_slice_to_uv_buf() {
let slice = [0, .. 20];
let buf = slice_to_uv_buf(slice);
assert!(buf.len == 20);
unsafe {
let base = transmute::<*u8, *mut u8>(buf.base);
(*base) = 1;
(*ptr::mut_offset(base, 1)) = 2;
}
assert!(slice[0] == 1);
assert!(slice[1] == 2);
}
#[test]
fn loop_smoke_test() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
loop_.run();
loop_.close();
}
}
*/

View File

@ -1,853 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use prelude::*;
use libc::{size_t, ssize_t, c_int, c_void, c_uint};
use rt::uv::uvll;
use rt::uv::uvll::*;
use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback, UdpReceiveCallback, UdpSendCallback};
use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle,
status_to_maybe_uv_error, empty_buf};
use rt::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
use vec;
use str;
use from_str::{FromStr};
pub struct UvAddrInfo(*uvll::addrinfo);
pub enum UvSocketAddr {
UvIpv4SocketAddr(*sockaddr_in),
UvIpv6SocketAddr(*sockaddr_in6),
}
pub fn sockaddr_to_UvSocketAddr(addr: *uvll::sockaddr) -> UvSocketAddr {
unsafe {
assert!((is_ip4_addr(addr) || is_ip6_addr(addr)));
assert!(!(is_ip4_addr(addr) && is_ip6_addr(addr)));
match addr {
_ if is_ip4_addr(addr) => UvIpv4SocketAddr(addr as *uvll::sockaddr_in),
_ if is_ip6_addr(addr) => UvIpv6SocketAddr(addr as *uvll::sockaddr_in6),
_ => fail!(),
}
}
}
fn socket_addr_as_uv_socket_addr<T>(addr: SocketAddr, f: &fn(UvSocketAddr) -> T) -> T {
let malloc = match addr.ip {
Ipv4Addr(*) => malloc_ip4_addr,
Ipv6Addr(*) => malloc_ip6_addr,
};
let wrap = match addr.ip {
Ipv4Addr(*) => UvIpv4SocketAddr,
Ipv6Addr(*) => UvIpv6SocketAddr,
};
let free = match addr.ip {
Ipv4Addr(*) => free_ip4_addr,
Ipv6Addr(*) => free_ip6_addr,
};
let addr = unsafe { malloc(addr.ip.to_str(), addr.port as int) };
do (|| {
f(wrap(addr))
}).finally {
unsafe { free(addr) };
}
}
fn uv_socket_addr_as_socket_addr<T>(addr: UvSocketAddr, f: &fn(SocketAddr) -> T) -> T {
let ip_size = match addr {
UvIpv4SocketAddr(*) => 4/*groups of*/ * 3/*digits separated by*/ + 3/*periods*/,
UvIpv6SocketAddr(*) => 8/*groups of*/ * 4/*hex digits separated by*/ + 7 /*colons*/,
};
let ip_name = {
let buf = vec::from_elem(ip_size + 1 /*null terminated*/, 0u8);
unsafe {
let buf_ptr = vec::raw::to_ptr(buf);
match addr {
UvIpv4SocketAddr(addr) => uvll::ip4_name(addr, buf_ptr, ip_size as size_t),
UvIpv6SocketAddr(addr) => uvll::ip6_name(addr, buf_ptr, ip_size as size_t),
}
};
buf
};
let ip_port = unsafe {
let port = match addr {
UvIpv4SocketAddr(addr) => uvll::ip4_port(addr),
UvIpv6SocketAddr(addr) => uvll::ip6_port(addr),
};
port as u16
};
let ip_str = str::from_utf8_slice(ip_name).trim_right_chars(&'\x00');
let ip_addr = FromStr::from_str(ip_str).unwrap();
// finally run the closure
f(SocketAddr { ip: ip_addr, port: ip_port })
}
pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr {
use util;
uv_socket_addr_as_socket_addr(addr, util::id)
}
#[cfg(test)]
#[test]
fn test_ip4_conversion() {
use rt;
let ip4 = rt::test::next_test_ip4();
assert_eq!(ip4, socket_addr_as_uv_socket_addr(ip4, uv_socket_addr_to_socket_addr));
}
#[cfg(test)]
#[test]
fn test_ip6_conversion() {
use rt;
let ip6 = rt::test::next_test_ip6();
assert_eq!(ip6, socket_addr_as_uv_socket_addr(ip6, uv_socket_addr_to_socket_addr));
}
// uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t, uv_tty_t
// and uv_file_t
pub struct StreamWatcher(*uvll::uv_stream_t);
impl Watcher for StreamWatcher { }
impl StreamWatcher {
pub fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) {
unsafe {
match uvll::read_start(self.native_handle(), alloc_cb, read_cb) {
0 => {
let data = self.get_watcher_data();
data.alloc_cb = Some(alloc);
data.read_cb = Some(cb);
}
n => {
cb(*self, 0, empty_buf(), Some(UvError(n)))
}
}
}
extern fn alloc_cb(stream: *uvll::uv_stream_t, suggested_size: size_t) -> Buf {
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream);
let alloc_cb = stream_watcher.get_watcher_data().alloc_cb.get_ref();
return (*alloc_cb)(suggested_size as uint);
}
extern fn read_cb(stream: *uvll::uv_stream_t, nread: ssize_t, buf: Buf) {
rtdebug!("buf addr: {}", buf.base);
rtdebug!("buf len: {}", buf.len);
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream);
let cb = stream_watcher.get_watcher_data().read_cb.get_ref();
let status = status_to_maybe_uv_error(nread as c_int);
(*cb)(stream_watcher, nread as int, buf, status);
}
}
pub fn read_stop(&mut self) {
// It would be nice to drop the alloc and read callbacks here,
// but read_stop may be called from inside one of them and we
// would end up freeing the in-use environment
let handle = self.native_handle();
unsafe { assert_eq!(uvll::read_stop(handle), 0); }
}
pub fn write(&mut self, buf: Buf, cb: ConnectionCallback) {
let req = WriteRequest::new();
return unsafe {
match uvll::write(req.native_handle(), self.native_handle(),
[buf], write_cb) {
0 => {
let data = self.get_watcher_data();
assert!(data.write_cb.is_none());
data.write_cb = Some(cb);
}
n => {
req.delete();
cb(*self, Some(UvError(n)))
}
}
};
extern fn write_cb(req: *uvll::uv_write_t, status: c_int) {
let write_request: WriteRequest = NativeHandle::from_native_handle(req);
let mut stream_watcher = write_request.stream();
write_request.delete();
let cb = stream_watcher.get_watcher_data().write_cb.take_unwrap();
let status = status_to_maybe_uv_error(status);
cb(stream_watcher, status);
}
}
pub fn listen(&mut self, cb: ConnectionCallback) -> Result<(), UvError> {
{
let data = self.get_watcher_data();
assert!(data.connect_cb.is_none());
data.connect_cb = Some(cb);
}
return unsafe {
static BACKLOG: c_int = 128; // XXX should be configurable
match uvll::listen(self.native_handle(), BACKLOG, connection_cb) {
0 => Ok(()),
n => Err(UvError(n))
}
};
extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) {
rtdebug!("connection_cb");
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle);
let cb = stream_watcher.get_watcher_data().connect_cb.get_ref();
let status = status_to_maybe_uv_error(status);
(*cb)(stream_watcher, status);
}
}
pub fn accept(&mut self, stream: StreamWatcher) {
let self_handle = self.native_handle() as *c_void;
let stream_handle = stream.native_handle() as *c_void;
assert_eq!(0, unsafe { uvll::accept(self_handle, stream_handle) } );
}
}
impl NativeHandle<*uvll::uv_stream_t> for StreamWatcher {
fn from_native_handle(handle: *uvll::uv_stream_t) -> StreamWatcher {
StreamWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_stream_t {
match self { &StreamWatcher(ptr) => ptr }
}
}
pub struct TcpWatcher(*uvll::uv_tcp_t);
impl Watcher for TcpWatcher { }
impl TcpWatcher {
pub fn new(loop_: &Loop) -> TcpWatcher {
unsafe {
let handle = malloc_handle(UV_TCP);
assert!(handle.is_not_null());
assert_eq!(0, uvll::tcp_init(loop_.native_handle(), handle));
let mut watcher: TcpWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
return watcher;
}
}
pub fn bind(&mut self, address: SocketAddr) -> Result<(), UvError> {
do socket_addr_as_uv_socket_addr(address) |addr| {
let result = unsafe {
match addr {
UvIpv4SocketAddr(addr) => uvll::tcp_bind(self.native_handle(), addr),
UvIpv6SocketAddr(addr) => uvll::tcp_bind6(self.native_handle(), addr),
}
};
match result {
0 => Ok(()),
_ => Err(UvError(result)),
}
}
}
pub fn connect(&mut self, address: SocketAddr, cb: ConnectionCallback) {
unsafe {
assert!(self.get_watcher_data().connect_cb.is_none());
self.get_watcher_data().connect_cb = Some(cb);
let connect_handle = ConnectRequest::new().native_handle();
rtdebug!("connect_t: {}", connect_handle);
do socket_addr_as_uv_socket_addr(address) |addr| {
let result = match addr {
UvIpv4SocketAddr(addr) => uvll::tcp_connect(connect_handle,
self.native_handle(), addr, connect_cb),
UvIpv6SocketAddr(addr) => uvll::tcp_connect6(connect_handle,
self.native_handle(), addr, connect_cb),
};
assert_eq!(0, result);
}
extern fn connect_cb(req: *uvll::uv_connect_t, status: c_int) {
rtdebug!("connect_t: {}", req);
let connect_request: ConnectRequest = NativeHandle::from_native_handle(req);
let mut stream_watcher = connect_request.stream();
connect_request.delete();
let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap();
let status = status_to_maybe_uv_error(status);
cb(stream_watcher, status);
}
}
}
pub fn as_stream(&self) -> StreamWatcher {
NativeHandle::from_native_handle(self.native_handle() as *uvll::uv_stream_t)
}
}
impl NativeHandle<*uvll::uv_tcp_t> for TcpWatcher {
fn from_native_handle(handle: *uvll::uv_tcp_t) -> TcpWatcher {
TcpWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_tcp_t {
match self { &TcpWatcher(ptr) => ptr }
}
}
pub struct UdpWatcher(*uvll::uv_udp_t);
impl Watcher for UdpWatcher { }
impl UdpWatcher {
pub fn new(loop_: &Loop) -> UdpWatcher {
unsafe {
let handle = malloc_handle(UV_UDP);
assert!(handle.is_not_null());
assert_eq!(0, uvll::udp_init(loop_.native_handle(), handle));
let mut watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
return watcher;
}
}
pub fn bind(&mut self, address: SocketAddr) -> Result<(), UvError> {
do socket_addr_as_uv_socket_addr(address) |addr| {
let result = unsafe {
match addr {
UvIpv4SocketAddr(addr) => uvll::udp_bind(self.native_handle(), addr, 0u32),
UvIpv6SocketAddr(addr) => uvll::udp_bind6(self.native_handle(), addr, 0u32),
}
};
match result {
0 => Ok(()),
_ => Err(UvError(result)),
}
}
}
pub fn recv_start(&mut self, alloc: AllocCallback, cb: UdpReceiveCallback) {
{
let data = self.get_watcher_data();
data.alloc_cb = Some(alloc);
data.udp_recv_cb = Some(cb);
}
unsafe { uvll::udp_recv_start(self.native_handle(), alloc_cb, recv_cb); }
extern fn alloc_cb(handle: *uvll::uv_udp_t, suggested_size: size_t) -> Buf {
let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
let alloc_cb = udp_watcher.get_watcher_data().alloc_cb.get_ref();
return (*alloc_cb)(suggested_size as uint);
}
extern fn recv_cb(handle: *uvll::uv_udp_t, nread: ssize_t, buf: Buf,
addr: *uvll::sockaddr, flags: c_uint) {
// When there's no data to read the recv callback can be a no-op.
// This can happen if read returns EAGAIN/EWOULDBLOCK. By ignoring
// this we just drop back to kqueue and wait for the next callback.
if nread == 0 {
return;
}
rtdebug!("buf addr: {}", buf.base);
rtdebug!("buf len: {}", buf.len);
let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
let cb = udp_watcher.get_watcher_data().udp_recv_cb.get_ref();
let status = status_to_maybe_uv_error(nread as c_int);
let addr = uv_socket_addr_to_socket_addr(sockaddr_to_UvSocketAddr(addr));
(*cb)(udp_watcher, nread as int, buf, addr, flags as uint, status);
}
}
pub fn recv_stop(&mut self) {
unsafe { uvll::udp_recv_stop(self.native_handle()); }
}
pub fn send(&mut self, buf: Buf, address: SocketAddr, cb: UdpSendCallback) {
{
let data = self.get_watcher_data();
assert!(data.udp_send_cb.is_none());
data.udp_send_cb = Some(cb);
}
let req = UdpSendRequest::new();
do socket_addr_as_uv_socket_addr(address) |addr| {
let result = unsafe {
match addr {
UvIpv4SocketAddr(addr) => uvll::udp_send(req.native_handle(),
self.native_handle(), [buf], addr, send_cb),
UvIpv6SocketAddr(addr) => uvll::udp_send6(req.native_handle(),
self.native_handle(), [buf], addr, send_cb),
}
};
assert_eq!(0, result);
}
extern fn send_cb(req: *uvll::uv_udp_send_t, status: c_int) {
let send_request: UdpSendRequest = NativeHandle::from_native_handle(req);
let mut udp_watcher = send_request.handle();
send_request.delete();
let cb = udp_watcher.get_watcher_data().udp_send_cb.take_unwrap();
let status = status_to_maybe_uv_error(status);
cb(udp_watcher, status);
}
}
}
impl NativeHandle<*uvll::uv_udp_t> for UdpWatcher {
fn from_native_handle(handle: *uvll::uv_udp_t) -> UdpWatcher {
UdpWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_udp_t {
match self { &UdpWatcher(ptr) => ptr }
}
}
// uv_connect_t is a subclass of uv_req_t
pub struct ConnectRequest(*uvll::uv_connect_t);
impl Request for ConnectRequest { }
impl ConnectRequest {
pub fn new() -> ConnectRequest {
let connect_handle = unsafe { malloc_req(UV_CONNECT) };
assert!(connect_handle.is_not_null());
ConnectRequest(connect_handle as *uvll::uv_connect_t)
}
fn stream(&self) -> StreamWatcher {
unsafe {
let stream_handle = uvll::get_stream_handle_from_connect_req(self.native_handle());
NativeHandle::from_native_handle(stream_handle)
}
}
fn delete(self) {
unsafe { free_req(self.native_handle() as *c_void) }
}
}
impl NativeHandle<*uvll::uv_connect_t> for ConnectRequest {
fn from_native_handle(handle: *uvll:: uv_connect_t) -> ConnectRequest {
ConnectRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_connect_t {
match self { &ConnectRequest(ptr) => ptr }
}
}
pub struct WriteRequest(*uvll::uv_write_t);
impl Request for WriteRequest { }
impl WriteRequest {
pub fn new() -> WriteRequest {
let write_handle = unsafe { malloc_req(UV_WRITE) };
assert!(write_handle.is_not_null());
WriteRequest(write_handle as *uvll::uv_write_t)
}
pub fn stream(&self) -> StreamWatcher {
unsafe {
let stream_handle = uvll::get_stream_handle_from_write_req(self.native_handle());
NativeHandle::from_native_handle(stream_handle)
}
}
pub fn delete(self) {
unsafe { free_req(self.native_handle() as *c_void) }
}
}
impl NativeHandle<*uvll::uv_write_t> for WriteRequest {
fn from_native_handle(handle: *uvll:: uv_write_t) -> WriteRequest {
WriteRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_write_t {
match self { &WriteRequest(ptr) => ptr }
}
}
pub struct UdpSendRequest(*uvll::uv_udp_send_t);
impl Request for UdpSendRequest { }
impl UdpSendRequest {
pub fn new() -> UdpSendRequest {
let send_handle = unsafe { malloc_req(UV_UDP_SEND) };
assert!(send_handle.is_not_null());
UdpSendRequest(send_handle as *uvll::uv_udp_send_t)
}
pub fn handle(&self) -> UdpWatcher {
let send_request_handle = unsafe {
uvll::get_udp_handle_from_send_req(self.native_handle())
};
NativeHandle::from_native_handle(send_request_handle)
}
pub fn delete(self) {
unsafe { free_req(self.native_handle() as *c_void) }
}
}
impl NativeHandle<*uvll::uv_udp_send_t> for UdpSendRequest {
fn from_native_handle(handle: *uvll::uv_udp_send_t) -> UdpSendRequest {
UdpSendRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_udp_send_t {
match self { &UdpSendRequest(ptr) => ptr }
}
}
#[cfg(test)]
mod test {
use super::*;
use util::ignore;
use cell::Cell;
use vec;
use unstable::run_in_bare_thread;
use rt::thread::Thread;
use rt::test::*;
use rt::uv::{Loop, AllocCallback};
use rt::uv::{vec_from_uv_buf, vec_to_uv_buf, slice_to_uv_buf};
use prelude::*;
#[test]
fn connect_close_ip4() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
// Connect to a port where nobody is listening
let addr = next_test_ip4();
do tcp_watcher.connect(addr) |stream_watcher, status| {
rtdebug!("tcp_watcher.connect!");
assert!(status.is_some());
assert_eq!(status.unwrap().name(), ~"ECONNREFUSED");
stream_watcher.close(||());
}
loop_.run();
loop_.close();
}
}
#[test]
fn connect_close_ip6() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
// Connect to a port where nobody is listening
let addr = next_test_ip6();
do tcp_watcher.connect(addr) |stream_watcher, status| {
rtdebug!("tcp_watcher.connect!");
assert!(status.is_some());
assert_eq!(status.unwrap().name(), ~"ECONNREFUSED");
stream_watcher.close(||());
}
loop_.run();
loop_.close();
}
}
#[test]
fn udp_bind_close_ip4() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
let mut udp_watcher = { UdpWatcher::new(&mut loop_) };
let addr = next_test_ip4();
udp_watcher.bind(addr);
udp_watcher.close(||());
loop_.run();
loop_.close();
}
}
#[test]
fn udp_bind_close_ip6() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
let mut udp_watcher = { UdpWatcher::new(&mut loop_) };
let addr = next_test_ip6();
udp_watcher.bind(addr);
udp_watcher.close(||());
loop_.run();
loop_.close();
}
}
#[test]
fn listen_ip4() {
do run_in_bare_thread() {
static MAX: int = 10;
let mut loop_ = Loop::new();
let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) };
let addr = next_test_ip4();
server_tcp_watcher.bind(addr);
let loop_ = loop_;
rtdebug!("listening");
let mut stream = server_tcp_watcher.as_stream();
let res = do stream.listen |mut server_stream_watcher, status| {
rtdebug!("listened!");
assert!(status.is_none());
let mut loop_ = loop_;
let client_tcp_watcher = TcpWatcher::new(&mut loop_);
let mut client_tcp_watcher = client_tcp_watcher.as_stream();
server_stream_watcher.accept(client_tcp_watcher);
let count_cell = Cell::new(0);
let server_stream_watcher = server_stream_watcher;
rtdebug!("starting read");
let alloc: AllocCallback = |size| {
vec_to_uv_buf(vec::from_elem(size, 0u8))
};
do client_tcp_watcher.read_start(alloc) |stream_watcher, nread, buf, status| {
rtdebug!("i'm reading!");
let buf = vec_from_uv_buf(buf);
let mut count = count_cell.take();
if status.is_none() {
rtdebug!("got {} bytes", nread);
let buf = buf.unwrap();
for byte in buf.slice(0, nread as uint).iter() {
assert!(*byte == count as u8);
rtdebug!("{}", *byte as uint);
count += 1;
}
} else {
assert_eq!(count, MAX);
do stream_watcher.close {
server_stream_watcher.close(||());
}
}
count_cell.put_back(count);
}
};
assert!(res.is_ok());
let client_thread = do Thread::start {
rtdebug!("starting client thread");
let mut loop_ = Loop::new();
let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
do tcp_watcher.connect(addr) |mut stream_watcher, status| {
rtdebug!("connecting");
assert!(status.is_none());
let msg = ~[0, 1, 2, 3, 4, 5, 6 ,7 ,8, 9];
let buf = slice_to_uv_buf(msg);
let msg_cell = Cell::new(msg);
do stream_watcher.write(buf) |stream_watcher, status| {
rtdebug!("writing");
assert!(status.is_none());
let msg_cell = Cell::new(msg_cell.take());
stream_watcher.close(||ignore(msg_cell.take()));
}
}
loop_.run();
loop_.close();
};
let mut loop_ = loop_;
loop_.run();
loop_.close();
client_thread.join();
};
}
#[test]
fn listen_ip6() {
do run_in_bare_thread() {
static MAX: int = 10;
let mut loop_ = Loop::new();
let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) };
let addr = next_test_ip6();
server_tcp_watcher.bind(addr);
let loop_ = loop_;
rtdebug!("listening");
let mut stream = server_tcp_watcher.as_stream();
let res = do stream.listen |mut server_stream_watcher, status| {
rtdebug!("listened!");
assert!(status.is_none());
let mut loop_ = loop_;
let client_tcp_watcher = TcpWatcher::new(&mut loop_);
let mut client_tcp_watcher = client_tcp_watcher.as_stream();
server_stream_watcher.accept(client_tcp_watcher);
let count_cell = Cell::new(0);
let server_stream_watcher = server_stream_watcher;
rtdebug!("starting read");
let alloc: AllocCallback = |size| {
vec_to_uv_buf(vec::from_elem(size, 0u8))
};
do client_tcp_watcher.read_start(alloc)
|stream_watcher, nread, buf, status| {
rtdebug!("i'm reading!");
let buf = vec_from_uv_buf(buf);
let mut count = count_cell.take();
if status.is_none() {
rtdebug!("got {} bytes", nread);
let buf = buf.unwrap();
let r = buf.slice(0, nread as uint);
for byte in r.iter() {
assert!(*byte == count as u8);
rtdebug!("{}", *byte as uint);
count += 1;
}
} else {
assert_eq!(count, MAX);
do stream_watcher.close {
server_stream_watcher.close(||());
}
}
count_cell.put_back(count);
}
};
assert!(res.is_ok());
let client_thread = do Thread::start {
rtdebug!("starting client thread");
let mut loop_ = Loop::new();
let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
do tcp_watcher.connect(addr) |mut stream_watcher, status| {
rtdebug!("connecting");
assert!(status.is_none());
let msg = ~[0, 1, 2, 3, 4, 5, 6 ,7 ,8, 9];
let buf = slice_to_uv_buf(msg);
let msg_cell = Cell::new(msg);
do stream_watcher.write(buf) |stream_watcher, status| {
rtdebug!("writing");
assert!(status.is_none());
let msg_cell = Cell::new(msg_cell.take());
stream_watcher.close(||ignore(msg_cell.take()));
}
}
loop_.run();
loop_.close();
};
let mut loop_ = loop_;
loop_.run();
loop_.close();
client_thread.join();
}
}
#[test]
fn udp_recv_ip4() {
do run_in_bare_thread() {
static MAX: int = 10;
let mut loop_ = Loop::new();
let server_addr = next_test_ip4();
let client_addr = next_test_ip4();
let mut server = UdpWatcher::new(&loop_);
assert!(server.bind(server_addr).is_ok());
rtdebug!("starting read");
let alloc: AllocCallback = |size| {
vec_to_uv_buf(vec::from_elem(size, 0u8))
};
do server.recv_start(alloc) |mut server, nread, buf, src, flags, status| {
server.recv_stop();
rtdebug!("i'm reading!");
assert!(status.is_none());
assert_eq!(flags, 0);
assert_eq!(src, client_addr);
let buf = vec_from_uv_buf(buf);
let mut count = 0;
rtdebug!("got {} bytes", nread);
let buf = buf.unwrap();
for &byte in buf.slice(0, nread as uint).iter() {
assert!(byte == count as u8);
rtdebug!("{}", byte as uint);
count += 1;
}
assert_eq!(count, MAX);
server.close(||{});
}
let thread = do Thread::start {
let mut loop_ = Loop::new();
let mut client = UdpWatcher::new(&loop_);
assert!(client.bind(client_addr).is_ok());
let msg = ~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let buf = slice_to_uv_buf(msg);
do client.send(buf, server_addr) |client, status| {
rtdebug!("writing");
assert!(status.is_none());
client.close(||{});
}
loop_.run();
loop_.close();
};
loop_.run();
loop_.close();
thread.join();
}
}
#[test]
fn udp_recv_ip6() {
do run_in_bare_thread() {
static MAX: int = 10;
let mut loop_ = Loop::new();
let server_addr = next_test_ip6();
let client_addr = next_test_ip6();
let mut server = UdpWatcher::new(&loop_);
assert!(server.bind(server_addr).is_ok());
rtdebug!("starting read");
let alloc: AllocCallback = |size| {
vec_to_uv_buf(vec::from_elem(size, 0u8))
};
do server.recv_start(alloc) |mut server, nread, buf, src, flags, status| {
server.recv_stop();
rtdebug!("i'm reading!");
assert!(status.is_none());
assert_eq!(flags, 0);
assert_eq!(src, client_addr);
let buf = vec_from_uv_buf(buf);
let mut count = 0;
rtdebug!("got {} bytes", nread);
let buf = buf.unwrap();
for &byte in buf.slice(0, nread as uint).iter() {
assert!(byte == count as u8);
rtdebug!("{}", byte as uint);
count += 1;
}
assert_eq!(count, MAX);
server.close(||{});
}
let thread = do Thread::start {
let mut loop_ = Loop::new();
let mut client = UdpWatcher::new(&loop_);
assert!(client.bind(client_addr).is_ok());
let msg = ~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let buf = slice_to_uv_buf(msg);
do client.send(buf, server_addr) |client, status| {
rtdebug!("writing");
assert!(status.is_none());
client.close(||{});
}
loop_.run();
loop_.close();
};
loop_.run();
loop_.close();
thread.join();
}
}
}

View File

@ -1,98 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use prelude::*;
use libc;
use c_str::CString;
use rt::uv;
use rt::uv::net;
use rt::uv::uvll;
pub struct Pipe(*uvll::uv_pipe_t);
impl uv::Watcher for Pipe {}
impl Pipe {
pub fn new(loop_: &uv::Loop, ipc: bool) -> Pipe {
unsafe {
let handle = uvll::malloc_handle(uvll::UV_NAMED_PIPE);
assert!(handle.is_not_null());
let ipc = ipc as libc::c_int;
assert_eq!(uvll::pipe_init(loop_.native_handle(), handle, ipc), 0);
let mut ret: Pipe =
uv::NativeHandle::from_native_handle(handle);
ret.install_watcher_data();
ret
}
}
pub fn as_stream(&self) -> net::StreamWatcher {
net::StreamWatcher(**self as *uvll::uv_stream_t)
}
#[fixed_stack_segment] #[inline(never)]
pub fn open(&mut self, file: libc::c_int) -> Result<(), uv::UvError> {
match unsafe { uvll::pipe_open(self.native_handle(), file) } {
0 => Ok(()),
n => Err(uv::UvError(n))
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn bind(&mut self, name: &CString) -> Result<(), uv::UvError> {
do name.with_ref |name| {
match unsafe { uvll::pipe_bind(self.native_handle(), name) } {
0 => Ok(()),
n => Err(uv::UvError(n))
}
}
}
#[fixed_stack_segment] #[inline(never)]
pub fn connect(&mut self, name: &CString, cb: uv::ConnectionCallback) {
{
let data = self.get_watcher_data();
assert!(data.connect_cb.is_none());
data.connect_cb = Some(cb);
}
let connect = net::ConnectRequest::new();
let name = do name.with_ref |p| { p };
unsafe {
uvll::pipe_connect(connect.native_handle(),
self.native_handle(),
name,
connect_cb)
}
extern "C" fn connect_cb(req: *uvll::uv_connect_t, status: libc::c_int) {
let connect_request: net::ConnectRequest =
uv::NativeHandle::from_native_handle(req);
let mut stream_watcher = connect_request.stream();
connect_request.delete();
let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap();
let status = uv::status_to_maybe_uv_error(status);
cb(stream_watcher, status);
}
}
}
impl uv::NativeHandle<*uvll::uv_pipe_t> for Pipe {
fn from_native_handle(handle: *uvll::uv_pipe_t) -> Pipe {
Pipe(handle)
}
fn native_handle(&self) -> *uvll::uv_pipe_t {
match self { &Pipe(ptr) => ptr }
}
}

View File

@ -1,202 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use prelude::*;
use cell::Cell;
use libc;
use ptr;
use vec;
use rt::io::process::*;
use rt::uv;
use rt::uv::uvio::{UvPipeStream, UvUnboundPipe};
use rt::uv::uvll;
/// A process wraps the handle of the underlying uv_process_t.
pub struct Process(*uvll::uv_process_t);
impl uv::Watcher for Process {}
impl Process {
/// Creates a new process, ready to spawn inside an event loop
pub fn new() -> Process {
let handle = unsafe { uvll::malloc_handle(uvll::UV_PROCESS) };
assert!(handle.is_not_null());
let mut ret: Process = uv::NativeHandle::from_native_handle(handle);
ret.install_watcher_data();
return ret;
}
/// Spawn a new process inside the specified event loop.
///
/// The `config` variable will be passed down to libuv, and the `exit_cb`
/// will be run only once, when the process exits.
///
/// Returns either the corresponding process object or an error which
/// occurred.
pub fn spawn(&mut self, loop_: &uv::Loop, config: ProcessConfig,
exit_cb: uv::ExitCallback)
-> Result<~[Option<~UvPipeStream>], uv::UvError>
{
let cwd = config.cwd.map(|s| s.to_c_str());
extern fn on_exit(p: *uvll::uv_process_t,
exit_status: libc::c_int,
term_signal: libc::c_int) {
let mut p: Process = uv::NativeHandle::from_native_handle(p);
let err = match exit_status {
0 => None,
_ => uv::status_to_maybe_uv_error(-1)
};
p.get_watcher_data().exit_cb.take_unwrap()(p,
exit_status as int,
term_signal as int,
err);
}
let io = config.io;
let mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(io.len());
let mut ret_io = vec::with_capacity(io.len());
unsafe {
vec::raw::set_len(&mut stdio, io.len());
for (slot, other) in stdio.iter().zip(io.iter()) {
let io = set_stdio(slot as *uvll::uv_stdio_container_t, other,
loop_);
ret_io.push(io);
}
}
let exit_cb = Cell::new(exit_cb);
let ret_io = Cell::new(ret_io);
do with_argv(config.program, config.args) |argv| {
do with_env(config.env) |envp| {
let options = uvll::uv_process_options_t {
exit_cb: on_exit,
file: unsafe { *argv },
args: argv,
env: envp,
cwd: match cwd {
Some(ref cwd) => cwd.with_ref(|p| p),
None => ptr::null(),
},
flags: 0,
stdio_count: stdio.len() as libc::c_int,
stdio: stdio.as_imm_buf(|p, _| p),
uid: 0,
gid: 0,
};
match unsafe {
uvll::spawn(loop_.native_handle(), **self, options)
} {
0 => {
(*self).get_watcher_data().exit_cb = Some(exit_cb.take());
Ok(ret_io.take())
}
err => Err(uv::UvError(err))
}
}
}
}
/// Sends a signal to this process.
///
/// This is a wrapper around `uv_process_kill`
pub fn kill(&self, signum: int) -> Result<(), uv::UvError> {
match unsafe {
uvll::process_kill(self.native_handle(), signum as libc::c_int)
} {
0 => Ok(()),
err => Err(uv::UvError(err))
}
}
/// Returns the process id of a spawned process
pub fn pid(&self) -> libc::pid_t {
unsafe { uvll::process_pid(**self) as libc::pid_t }
}
}
unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t,
io: &StdioContainer,
loop_: &uv::Loop) -> Option<~UvPipeStream> {
match *io {
Ignored => {
uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE);
None
}
InheritFd(fd) => {
uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
uvll::set_stdio_container_fd(dst, fd);
None
}
CreatePipe(readable, writable) => {
let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int;
if readable {
flags |= uvll::STDIO_READABLE_PIPE as libc::c_int;
}
if writable {
flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int;
}
let pipe = UvUnboundPipe::new(loop_);
let handle = pipe.pipe.as_stream().native_handle();
uvll::set_stdio_container_flags(dst, flags);
uvll::set_stdio_container_stream(dst, handle);
Some(~UvPipeStream::new(pipe))
}
}
}
/// Converts the program and arguments to the argv array expected by libuv
fn with_argv<T>(prog: &str, args: &[~str], f: &fn(**libc::c_char) -> T) -> T {
// First, allocation space to put all the C-strings (we need to have
// ownership of them somewhere
let mut c_strs = vec::with_capacity(args.len() + 1);
c_strs.push(prog.to_c_str());
for arg in args.iter() {
c_strs.push(arg.to_c_str());
}
// Next, create the char** array
let mut c_args = vec::with_capacity(c_strs.len() + 1);
for s in c_strs.iter() {
c_args.push(s.with_ref(|p| p));
}
c_args.push(ptr::null());
c_args.as_imm_buf(|buf, _| f(buf))
}
/// Converts the environment to the env array expected by libuv
fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
let env = match env {
Some(s) => s,
None => { return f(ptr::null()); }
};
// As with argv, create some temporary storage and then the actual array
let mut envp = vec::with_capacity(env.len());
for &(ref key, ref value) in env.iter() {
envp.push(format!("{}={}", *key, *value).to_c_str());
}
let mut c_envp = vec::with_capacity(envp.len() + 1);
for s in envp.iter() {
c_envp.push(s.with_ref(|p| p));
}
c_envp.push(ptr::null());
c_envp.as_imm_buf(|buf, _| f(buf))
}
impl uv::NativeHandle<*uvll::uv_process_t> for Process {
fn from_native_handle(handle: *uvll::uv_process_t) -> Process {
Process(handle)
}
fn native_handle(&self) -> *uvll::uv_process_t {
match self { &Process(ptr) => ptr }
}
}

View File

@ -1,73 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use cast;
use option::Some;
use libc::c_int;
use result::{Err, Ok, Result};
use rt::io::signal::Signum;
use rt::uv::{Loop, NativeHandle, SignalCallback, UvError, Watcher};
use rt::uv::uvll;
pub struct SignalWatcher(*uvll::uv_signal_t);
impl Watcher for SignalWatcher { }
impl SignalWatcher {
pub fn new(loop_: &mut Loop) -> SignalWatcher {
unsafe {
let handle = uvll::malloc_handle(uvll::UV_SIGNAL);
assert!(handle.is_not_null());
assert!(0 == uvll::signal_init(loop_.native_handle(), handle));
let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
return watcher;
}
}
pub fn start(&mut self, signum: Signum, callback: SignalCallback)
-> Result<(), UvError>
{
return unsafe {
match uvll::signal_start(self.native_handle(), signal_cb,
signum as c_int) {
0 => {
let data = self.get_watcher_data();
data.signal_cb = Some(callback);
Ok(())
}
n => Err(UvError(n)),
}
};
extern fn signal_cb(handle: *uvll::uv_signal_t, signum: c_int) {
let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle);
let data = watcher.get_watcher_data();
let cb = data.signal_cb.get_ref();
(*cb)(watcher, unsafe { cast::transmute(signum as int) });
}
}
pub fn stop(&mut self) {
unsafe {
uvll::signal_stop(self.native_handle());
}
}
}
impl NativeHandle<*uvll::uv_signal_t> for SignalWatcher {
fn from_native_handle(handle: *uvll::uv_signal_t) -> SignalWatcher {
SignalWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_signal_t {
match self { &SignalWatcher(ptr) => ptr }
}
}

View File

@ -1,158 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use libc::c_int;
use option::Some;
use rt::uv::uvll;
use rt::uv::{Watcher, Loop, NativeHandle, TimerCallback};
use rt::uv::status_to_maybe_uv_error;
pub struct TimerWatcher(*uvll::uv_timer_t);
impl Watcher for TimerWatcher { }
impl TimerWatcher {
pub fn new(loop_: &mut Loop) -> TimerWatcher {
unsafe {
let handle = uvll::malloc_handle(uvll::UV_TIMER);
assert!(handle.is_not_null());
assert!(0 == uvll::timer_init(loop_.native_handle(), handle));
let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
watcher.install_watcher_data();
return watcher;
}
}
pub fn start(&mut self, timeout: u64, repeat: u64, cb: TimerCallback) {
{
let data = self.get_watcher_data();
data.timer_cb = Some(cb);
}
unsafe {
uvll::timer_start(self.native_handle(), timer_cb, timeout, repeat);
}
extern fn timer_cb(handle: *uvll::uv_timer_t, status: c_int) {
let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
let data = watcher.get_watcher_data();
let cb = data.timer_cb.get_ref();
let status = status_to_maybe_uv_error(status);
(*cb)(watcher, status);
}
}
pub fn stop(&mut self) {
unsafe {
uvll::timer_stop(self.native_handle());
}
}
}
impl NativeHandle<*uvll::uv_timer_t> for TimerWatcher {
fn from_native_handle(handle: *uvll::uv_timer_t) -> TimerWatcher {
TimerWatcher(handle)
}
fn native_handle(&self) -> *uvll::uv_idle_t {
match self { &TimerWatcher(ptr) => ptr }
}
}
#[cfg(test)]
mod test {
use super::*;
use rt::uv::Loop;
use unstable::run_in_bare_thread;
#[test]
fn smoke_test() {
do run_in_bare_thread {
let mut count = 0;
let count_ptr: *mut int = &mut count;
let mut loop_ = Loop::new();
let mut timer = TimerWatcher::new(&mut loop_);
do timer.start(10, 0) |timer, status| {
assert!(status.is_none());
unsafe { *count_ptr += 1 };
timer.close(||());
}
loop_.run();
loop_.close();
assert!(count == 1);
}
}
#[test]
fn start_twice() {
do run_in_bare_thread {
let mut count = 0;
let count_ptr: *mut int = &mut count;
let mut loop_ = Loop::new();
let mut timer = TimerWatcher::new(&mut loop_);
do timer.start(10, 0) |timer, status| {
let mut timer = timer;
assert!(status.is_none());
unsafe { *count_ptr += 1 };
do timer.start(10, 0) |timer, status| {
assert!(status.is_none());
unsafe { *count_ptr += 1 };
timer.close(||());
}
}
loop_.run();
loop_.close();
assert!(count == 2);
}
}
#[test]
fn repeat_stop() {
do run_in_bare_thread {
let mut count = 0;
let count_ptr: *mut int = &mut count;
let mut loop_ = Loop::new();
let mut timer = TimerWatcher::new(&mut loop_);
do timer.start(1, 2) |timer, status| {
assert!(status.is_none());
unsafe {
*count_ptr += 1;
if *count_ptr == 10 {
// Stop the timer and do something else
let mut timer = timer;
timer.stop();
// Freeze timer so it can be captured
let timer = timer;
let mut loop_ = timer.event_loop();
let mut timer2 = TimerWatcher::new(&mut loop_);
do timer2.start(10, 0) |timer2, _| {
*count_ptr += 1;
timer2.close(||());
// Restart the original timer
let mut timer = timer;
do timer.start(1, 0) |timer, _| {
*count_ptr += 1;
timer.close(||());
}
}
}
};
}
loop_.run();
loop_.close();
assert!(count == 12);
}
}
}

View File

@ -1,84 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use prelude::*;
use libc;
use rt::uv;
use rt::uv::net;
use rt::uv::uvll;
/// A process wraps the handle of the underlying uv_process_t.
pub struct TTY(*uvll::uv_tty_t);
impl uv::Watcher for TTY {}
impl TTY {
#[fixed_stack_segment] #[inline(never)]
pub fn new(loop_: &uv::Loop, fd: libc::c_int, readable: bool) ->
Result<TTY, uv::UvError>
{
let handle = unsafe { uvll::malloc_handle(uvll::UV_TTY) };
assert!(handle.is_not_null());
let ret = unsafe {
uvll::tty_init(loop_.native_handle(), handle, fd as libc::c_int,
readable as libc::c_int)
};
match ret {
0 => {
let mut ret: TTY = uv::NativeHandle::from_native_handle(handle);
ret.install_watcher_data();
Ok(ret)
}
n => {
unsafe { uvll::free_handle(handle); }
Err(uv::UvError(n))
}
}
}
pub fn as_stream(&self) -> net::StreamWatcher {
net::StreamWatcher(**self as *uvll::uv_stream_t)
}
#[fixed_stack_segment] #[inline(never)]
pub fn set_mode(&self, raw: bool) -> Result<(), uv::UvError> {
let raw = raw as libc::c_int;
match unsafe { uvll::tty_set_mode(self.native_handle(), raw) } {
0 => Ok(()),
n => Err(uv::UvError(n))
}
}
#[fixed_stack_segment] #[inline(never)] #[allow(unused_mut)]
pub fn get_winsize(&self) -> Result<(int, int), uv::UvError> {
let mut width: libc::c_int = 0;
let mut height: libc::c_int = 0;
let widthptr: *libc::c_int = &width;
let heightptr: *libc::c_int = &width;
match unsafe { uvll::tty_get_winsize(self.native_handle(),
widthptr, heightptr) } {
0 => Ok((width as int, height as int)),
n => Err(uv::UvError(n))
}
}
}
impl uv::NativeHandle<*uvll::uv_tty_t> for TTY {
fn from_native_handle(handle: *uvll::uv_tty_t) -> TTY {
TTY(handle)
}
fn native_handle(&self) -> *uvll::uv_tty_t {
match self { &TTY(ptr) => ptr }
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,11 @@
S 2013-10-29 fed48cc
freebsd-x86_64 4a43216b432511a5fd6b727753aedb749f6a68dc
linux-i386 53f65d4b1377c17fc12d05d7c4a0fbd92eea071f
linux-x86_64 afa5f19a37a2cf137e5d4277951fa07efda8e072
macos-i386 7522c24f78ed35020e2877e3eada058ea8a11f35
macos-x86_64 a18afdcbbdbb81c1fdf08788b24f0d3ea8701eb1
winnt-i386 c78f0839c9524eda33c54a5232121886021b5352
S 2013-10-28 2ab4a6f
freebsd-x86_64 08af04bcf739930bdb7d0ad244b2c8094cd5096a
linux-i386 c233de1ed09872d5c7a3e1ce9ab9eb6e16631201