mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
Register new snapshots
This commit is contained in:
parent
886819cca1
commit
e203f30bc7
18
mk/stage0.mk
18
mk/stage0.mk
@ -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)) \
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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)];
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
*/
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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 }
|
||||
}
|
||||
}
|
@ -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 }
|
||||
}
|
||||
}
|
@ -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 }
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user