diff --git a/src/libextra/extra.rs b/src/libextra/extra.rs index 66ee52f53db31..f4fb7bcd76c99 100644 --- a/src/libextra/extra.rs +++ b/src/libextra/extra.rs @@ -36,23 +36,9 @@ use std::str::{StrSlice, OwnedStr}; pub use std::os; -pub mod uv_ll; - -// General io and system-services modules - -#[path = "net/mod.rs"] -pub mod net; - -// libuv modules -pub mod uv; -pub mod uv_iotask; -pub mod uv_global_loop; - - // Utility modules pub mod c_vec; -pub mod timer; pub mod io_util; pub mod rc; @@ -90,6 +76,7 @@ pub mod sha2; // And ... other stuff +pub mod url; pub mod ebml; pub mod dbg; pub mod getopts; diff --git a/src/libextra/flatpipes.rs b/src/libextra/flatpipes.rs index 5a5aacc8d5409..7840345e2763f 100644 --- a/src/libextra/flatpipes.rs +++ b/src/libextra/flatpipes.rs @@ -639,7 +639,6 @@ mod test { use flatpipes::serial; use io_util::BufReader; use flatpipes::{BytePort, FlatChan, FlatPort}; - use net::tcp::TcpSocketBuf; use std::comm; use std::int; @@ -728,7 +727,8 @@ mod test { } // FIXME #2064: Networking doesn't work on x86 - #[test] + // XXX Broken until networking support is added back + /*#[test] #[cfg(target_arch = "x86_64")] fn test_pod_tcp_stream() { fn reader_port(buf: TcpSocketBuf @@ -745,6 +745,7 @@ mod test { #[test] #[cfg(target_arch = "x86_64")] fn test_serializing_tcp_stream() { + // XXX Broken until networking support is added back fn reader_port(buf: TcpSocketBuf ) -> serial::ReaderPort { serial::reader_port(buf) @@ -860,7 +861,7 @@ mod test { } finish_port.recv(); - } + }*/ // Tests that the different backends behave the same when the // binary streaming protocol is broken diff --git a/src/libextra/net/ip.rs b/src/libextra/net/ip.rs deleted file mode 100644 index c1633ffa04114..0000000000000 --- a/src/libextra/net/ip.rs +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Types/fns concerning Internet Protocol (IP), versions 4 & 6 - -#[allow(missing_doc)]; - - -use std::libc; -use std::comm::{stream, SharedChan}; -use std::ptr; -use std::result; -use std::str; - -use iotask = uv::iotask::IoTask; -use interact = uv::iotask::interact; - -use sockaddr_in = uv_ll::sockaddr_in; -use sockaddr_in6 = uv_ll::sockaddr_in6; -use addrinfo = uv_ll::addrinfo; -use uv_getaddrinfo_t = uv_ll::uv_getaddrinfo_t; -use uv_ip4_name = uv_ll::ip4_name; -use uv_ip4_port = uv_ll::ip4_port; -use uv_ip6_name = uv_ll::ip6_name; -use uv_ip6_port = uv_ll::ip6_port; -use uv_getaddrinfo = uv_ll::getaddrinfo; -use uv_freeaddrinfo = uv_ll::freeaddrinfo; -use create_uv_getaddrinfo_t = uv_ll::getaddrinfo_t; -use set_data_for_req = uv_ll::set_data_for_req; -use get_data_for_req = uv_ll::get_data_for_req; -use ll = uv_ll; - -/// An IP address -#[deriving(Clone)] -pub enum IpAddr { - /// An IPv4 address - Ipv4(sockaddr_in), - Ipv6(sockaddr_in6) -} - -/// Human-friendly feedback on why a parse_addr attempt failed -pub struct ParseAddrErr { - err_msg: ~str, -} - -/** - * Convert a `IpAddr` to a str - * - * # Arguments - * - * * ip - a `extra::net::ip::IpAddr` - */ -pub fn format_addr(ip: &IpAddr) -> ~str { - match *ip { - Ipv4(ref addr) => unsafe { - let result = uv_ip4_name(addr); - if result == ~"" { - fail!("failed to convert inner sockaddr_in address to str") - } - result - }, - Ipv6(ref addr) => unsafe { - let result = uv_ip6_name(addr); - if result == ~"" { - fail!("failed to convert inner sockaddr_in address to str") - } - result - } - } -} - -/** - * Get the associated port - * - * # Arguments - * * ip - a `extra::net::ip::IpAddr` - */ -pub fn get_port(ip: &IpAddr) -> uint { - match *ip { - Ipv4(ref addr) => unsafe { - uv_ip4_port(addr) - }, - Ipv6(ref addr) => unsafe { - uv_ip6_port(addr) - } - } -} - -/// Represents errors returned from `net::ip::get_addr()` -enum IpGetAddrErr { - GetAddrUnknownError -} - -/** - * Attempts name resolution on the provided `node` string - * - * # Arguments - * - * * `node` - a string representing some host address - * * `iotask` - a `uv::iotask` used to interact with the underlying event loop - * - * # Returns - * - * A `result<~[ip_addr], ip_get_addr_err>` instance that will contain - * a vector of `ip_addr` results, in the case of success, or an error - * object in the case of failure -*/ -pub fn get_addr(node: &str, iotask: &iotask) - -> result::Result<~[IpAddr], IpGetAddrErr> { - let (output_po, output_ch) = stream(); - let mut output_ch = Some(SharedChan::new(output_ch)); - do str::as_buf(node) |node_ptr, len| { - let output_ch = output_ch.take_unwrap(); - debug!("slice len %?", len); - let handle = create_uv_getaddrinfo_t(); - let handle_ptr: *uv_getaddrinfo_t = &handle; - let handle_data = GetAddrData { - output_ch: output_ch.clone() - }; - let handle_data_ptr: *GetAddrData = &handle_data; - do interact(iotask) |loop_ptr| { - unsafe { - let result = uv_getaddrinfo( - loop_ptr, - handle_ptr, - get_addr_cb, - node_ptr, - ptr::null(), - ptr::null()); - match result { - 0i32 => { - set_data_for_req(handle_ptr, handle_data_ptr); - } - _ => { - output_ch.send(result::Err(GetAddrUnknownError)); - } - } - } - }; - output_po.recv() - } -} - -pub mod v4 { - - use net::ip::{IpAddr, Ipv4, ParseAddrErr}; - use uv::ll; - use uv_ip4_addr = uv::ll::ip4_addr; - use uv_ip4_name = uv::ll::ip4_name; - - use std::cast::transmute; - use std::result; - use std::uint; - - /** - * Convert a str to `ip_addr` - * - * # Failure - * - * Fails if the string is not a valid IPv4 address - * - * # Arguments - * - * * ip - a string of the format `x.x.x.x` - * - * # Returns - * - * * an `ip_addr` of the `ipv4` variant - */ - pub fn parse_addr(ip: &str) -> IpAddr { - match try_parse_addr(ip) { - result::Ok(addr) => addr, - result::Err(ref err_data) => fail!(err_data.err_msg.clone()) - } - } - - // the simple, old style numberic representation of - // ipv4 - #[deriving(Clone)] - pub struct Ipv4Rep { - a: u8, - b: u8, - c: u8, - d: u8, - } - - pub trait AsUnsafeU32 { - unsafe fn as_u32(&self) -> u32; - } - - impl AsUnsafeU32 for Ipv4Rep { - // this is pretty dastardly, i know - unsafe fn as_u32(&self) -> u32 { - let this: &mut u32 = transmute(self); - *this - } - } - pub fn parse_to_ipv4_rep(ip: &str) -> result::Result { - let parts: ~[uint] = ip.split_iter('.').transform(|s| { - match uint::from_str(s) { - Some(n) if n <= 255 => n, - _ => 256 - } - }).collect(); - if parts.len() != 4 { - Err(fmt!("'%s' doesn't have 4 parts", ip)) - } else if parts.iter().any(|x| *x == 256u) { - Err(fmt!("invalid octal in addr '%s'", ip)) - } else { - Ok(Ipv4Rep { - a: parts[0] as u8, b: parts[1] as u8, - c: parts[2] as u8, d: parts[3] as u8, - }) - } - } - pub fn try_parse_addr(ip: &str) -> result::Result { - unsafe { - let INADDR_NONE = ll::get_INADDR_NONE(); - let ip_rep_result = parse_to_ipv4_rep(ip); - if result::is_err(&ip_rep_result) { - let err_str = result::get_err(&ip_rep_result); - return result::Err(ParseAddrErr { err_msg: err_str }) - } - // ipv4_rep.as_u32 is unsafe :/ - let input_is_inaddr_none = - result::get(&ip_rep_result).as_u32() == INADDR_NONE; - - let new_addr = uv_ip4_addr(ip, 22); - let reformatted_name = uv_ip4_name(&new_addr); - debug!("try_parse_addr: input ip: %s reparsed ip: %s", - ip, reformatted_name); - let ref_ip_rep_result = parse_to_ipv4_rep(reformatted_name); - if result::is_err(&ref_ip_rep_result) { - let err_str = result::get_err(&ref_ip_rep_result); - return Err(ParseAddrErr { err_msg: err_str }) - } - - if result::get(&ref_ip_rep_result).as_u32() == INADDR_NONE && - !input_is_inaddr_none { - Err(ParseAddrErr { - err_msg: ~"uv_ip4_name produced invalid result.", - }) - } else { - Ok(Ipv4(new_addr)) - } - } - } -} -pub mod v6 { - - use net::ip::{IpAddr, Ipv6, ParseAddrErr}; - use uv_ip6_addr = uv::ll::ip6_addr; - use uv_ip6_name = uv::ll::ip6_name; - - use std::result; - - /** - * Convert a str to `ip_addr` - * - * # Failure - * - * Fails if the string is not a valid IPv6 address - * - * # Arguments - * - * * ip - an ipv6 string. See RFC2460 for spec. - * - * # Returns - * - * * an `ip_addr` of the `ipv6` variant - */ - pub fn parse_addr(ip: &str) -> IpAddr { - match try_parse_addr(ip) { - result::Ok(addr) => addr, - result::Err(err_data) => fail!(err_data.err_msg.clone()) - } - } - pub fn try_parse_addr(ip: &str) -> result::Result { - unsafe { - // need to figure out how to establish a parse failure.. - let new_addr = uv_ip6_addr(ip, 22); - let reparsed_name = uv_ip6_name(&new_addr); - debug!("v6::try_parse_addr ip: '%s' reparsed '%s'", - ip, reparsed_name); - // '::' appears to be uv_ip6_name() returns for bogus - // parses.. - if ip != &"::" && reparsed_name == ~"::" { - Err(ParseAddrErr { err_msg:fmt!("failed to parse '%s'", ip) }) - } - else { - Ok(Ipv6(new_addr)) - } - } - } -} - -struct GetAddrData { - output_ch: SharedChan> -} - -extern fn get_addr_cb(handle: *uv_getaddrinfo_t, - status: libc::c_int, - res: *addrinfo) { - unsafe { - debug!("in get_addr_cb"); - let handle_data = get_data_for_req(handle) as - *GetAddrData; - let output_ch = (*handle_data).output_ch.clone(); - if status == 0i32 { - if res != (ptr::null::()) { - let mut out_vec = ~[]; - debug!("initial addrinfo: %?", res); - let mut curr_addr = res; - loop { - let new_ip_addr = if ll::is_ipv4_addrinfo(curr_addr) { - Ipv4(*ll::addrinfo_as_sockaddr_in(curr_addr)) - } - else if ll::is_ipv6_addrinfo(curr_addr) { - Ipv6(*ll::addrinfo_as_sockaddr_in6(curr_addr)) - } - else { - debug!("curr_addr is not of family AF_INET or \ - AF_INET6. Error."); - output_ch.send( - result::Err(GetAddrUnknownError)); - break; - }; - out_vec.push(new_ip_addr); - - let next_addr = ll::get_next_addrinfo(curr_addr); - if next_addr == ptr::null::() as *addrinfo { - debug!("null next_addr encountered. no mas"); - break; - } - else { - curr_addr = next_addr; - debug!("next_addr addrinfo: %?", curr_addr); - } - } - debug!("successful process addrinfo result, len: %?", - out_vec.len()); - output_ch.send(result::Ok(out_vec)); - } - else { - debug!("addrinfo pointer is NULL"); - output_ch.send( - result::Err(GetAddrUnknownError)); - } - } - else { - debug!("status != 0 error in get_addr_cb"); - output_ch.send( - result::Err(GetAddrUnknownError)); - } - if res != (ptr::null::()) { - uv_freeaddrinfo(res); - } - debug!("leaving get_addr_cb"); - } -} - -#[cfg(test)] -mod test { - - use net::ip::*; - use net::ip::v4; - use net::ip::v6; - use uv; - - use std::result; - - #[test] - fn test_ip_ipv4_parse_and_format_ip() { - let localhost_str = ~"127.0.0.1"; - assert!(format_addr(&v4::parse_addr(localhost_str)) - == localhost_str) - } - #[test] - fn test_ip_ipv6_parse_and_format_ip() { - let localhost_str = ~"::1"; - let format_result = format_addr(&v6::parse_addr(localhost_str)); - debug!("results: expected: '%s' actual: '%s'", - localhost_str, format_result); - assert_eq!(format_result, localhost_str); - } - #[test] - fn test_ip_ipv4_bad_parse() { - match v4::try_parse_addr("b4df00d") { - result::Err(ref err_info) => { - debug!("got error as expected %?", err_info); - assert!(true); - } - result::Ok(ref addr) => { - fail!("Expected failure, but got addr %?", addr); - } - } - } - #[test] - #[ignore(target_os="win32")] - fn test_ip_ipv6_bad_parse() { - match v6::try_parse_addr("::,~2234k;") { - result::Err(ref err_info) => { - debug!("got error as expected %?", err_info); - assert!(true); - } - result::Ok(ref addr) => { - fail!("Expected failure, but got addr %?", addr); - } - } - } - #[test] - #[ignore(reason = "valgrind says it's leaky")] - fn test_ip_get_addr() { - let localhost_name = ~"localhost"; - let iotask = &uv::global_loop::get(); - let ga_result = get_addr(localhost_name, iotask); - if result::is_err(&ga_result) { - fail!("got err result from net::ip::get_addr();") - } - // note really sure how to reliably test/assert - // this.. mostly just wanting to see it work, atm. - let results = result::unwrap(ga_result); - debug!("test_get_addr: Number of results for %s: %?", - localhost_name, results.len()); - for results.iter().advance |r| { - let ipv_prefix = match *r { - Ipv4(_) => ~"IPv4", - Ipv6(_) => ~"IPv6" - }; - debug!("test_get_addr: result %s: '%s'", - ipv_prefix, format_addr(r)); - } - // at least one result.. this is going to vary from system - // to system, based on stuff like the contents of /etc/hosts - assert!(!results.is_empty()); - } - #[test] - #[ignore(reason = "valgrind says it's leaky")] - fn test_ip_get_addr_bad_input() { - let localhost_name = ~"sjkl234m,./sdf"; - let iotask = &uv::global_loop::get(); - let ga_result = get_addr(localhost_name, iotask); - assert!(result::is_err(&ga_result)); - } -} diff --git a/src/libextra/net/mod.rs b/src/libextra/net/mod.rs deleted file mode 100644 index 463260bd3dcdf..0000000000000 --- a/src/libextra/net/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -Top-level module for network-related functionality. - -Basically, including this module gives you: - -* `tcp` -* `ip` -* `url` - -See each of those three modules for documentation on what they do. -*/ - -pub mod tcp; -pub mod ip; -pub mod url; diff --git a/src/libextra/net/tcp.rs b/src/libextra/net/tcp.rs deleted file mode 100644 index 038ffd5788cc7..0000000000000 --- a/src/libextra/net/tcp.rs +++ /dev/null @@ -1,1959 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! High-level interface to libuv's TCP functionality -// FIXME #4425: Need FFI fixes - -#[allow(missing_doc)]; - - -use future; -use future_spawn = future::spawn; -use ip = net::ip; -use uv; -use uv::iotask; -use uv::iotask::IoTask; - -use std::io; -use std::libc::size_t; -use std::libc; -use std::comm::{stream, Port, SharedChan}; -use std::ptr; -use std::result::{Result}; -use std::result; -use std::num; -use std::vec; - -pub mod rustrt { - use std::libc; - - #[nolink] - extern { - pub unsafe fn rust_uv_current_kernel_malloc(size: libc::c_uint) - -> *libc::c_void; - pub unsafe fn rust_uv_current_kernel_free(mem: *libc::c_void); - pub unsafe fn rust_uv_helper_uv_tcp_t_size() -> libc::c_uint; - } -} - -/** - * Encapsulates an open TCP/IP connection through libuv - * - * `TcpSocket` is non-copyable/sendable and automagically handles closing the - * underlying libuv data structures when it goes out of scope. This is the - * data structure that is used for read/write operations over a TCP stream. - */ -pub struct TcpSocket { - socket_data: @TcpSocketData, -} - -#[unsafe_destructor] -impl Drop for TcpSocket { - fn drop(&self) { - tear_down_socket_data(self.socket_data) - } -} - -pub fn TcpSocket(socket_data: @TcpSocketData) -> TcpSocket { - TcpSocket { - socket_data: socket_data - } -} - -/** - * A buffered wrapper for `net::tcp::TcpSocket` - * - * It is created with a call to `net::tcp::socket_buf()` and has impls that - * satisfy both the `io::Reader` and `io::Writer` traits. - */ -pub struct TcpSocketBuf { - data: @mut TcpBufferedSocketData, - end_of_stream: @mut bool -} - -pub fn TcpSocketBuf(data: @mut TcpBufferedSocketData) -> TcpSocketBuf { - TcpSocketBuf { - data: data, - end_of_stream: @mut false - } -} - -/// Contains raw, string-based, error information returned from libuv -#[deriving(Clone)] -pub struct TcpErrData { - err_name: ~str, - err_msg: ~str, -} - -/// Details returned as part of a `Result::Err` result from `tcp::listen` -#[deriving(Clone)] -pub enum TcpListenErrData { - /** - * Some unplanned-for error. The first and second fields correspond - * to libuv's `err_name` and `err_msg` fields, respectively. - */ - GenericListenErr(~str, ~str), - /** - * Failed to bind to the requested IP/Port, because it is already in use. - * - * # Possible Causes - * - * * Attempting to bind to a port already bound to another listener - */ - AddressInUse, - /** - * Request to bind to an IP/Port was denied by the system. - * - * # Possible Causes - * - * * Attemping to binding to an IP/Port as a non-Administrator - * on Windows Vista+ - * * Attempting to bind, as a non-priv'd - * user, to 'privileged' ports (< 1024) on *nix - */ - AccessDenied -} -/// Details returned as part of a `Result::Err` result from `tcp::connect` -#[deriving(Clone)] -pub enum TcpConnectErrData { - /** - * Some unplanned-for error. The first and second fields correspond - * to libuv's `err_name` and `err_msg` fields, respectively. - */ - GenericConnectErr(~str, ~str), - /// Invalid IP or invalid port - ConnectionRefused -} - -/** - * Initiate a client connection over TCP/IP - * - * # Arguments - * - * * `input_ip` - The IP address (versions 4 or 6) of the remote host - * * `port` - the unsigned integer of the desired remote host port - * * `iotask` - a `uv::iotask` that the tcp request will run on - * - * # Returns - * - * A `result` that, if the operation succeeds, contains a - * `net::net::TcpSocket` that can be used to send and receive data to/from - * the remote host. In the event of failure, a - * `net::tcp::TcpConnectErrData` instance will be returned - */ -pub fn connect(input_ip: ip::IpAddr, port: uint, - iotask: &IoTask) - -> result::Result { - unsafe { - let (result_po, result_ch) = stream::(); - let result_ch = SharedChan::new(result_ch); - let (closed_signal_po, closed_signal_ch) = stream::<()>(); - let closed_signal_ch = SharedChan::new(closed_signal_ch); - let conn_data = ConnectReqData { - result_ch: result_ch, - closed_signal_ch: closed_signal_ch - }; - let conn_data_ptr: *ConnectReqData = &conn_data; - let (reader_po, reader_ch) = stream::>(); - let reader_ch = SharedChan::new(reader_ch); - let stream_handle_ptr = malloc_uv_tcp_t(); - *(stream_handle_ptr as *mut uv::ll::uv_tcp_t) = uv::ll::tcp_t(); - let socket_data = @TcpSocketData { - reader_po: @reader_po, - reader_ch: reader_ch, - stream_handle_ptr: stream_handle_ptr, - connect_req: uv::ll::connect_t(), - write_req: uv::ll::write_t(), - ipv6: match input_ip { - ip::Ipv4(_) => { false } - ip::Ipv6(_) => { true } - }, - iotask: iotask.clone() - }; - let socket_data_ptr: *TcpSocketData = &*socket_data; - // get an unsafe representation of our stream_handle_ptr that - // we can send into the interact cb to be handled in libuv.. - debug!("stream_handle_ptr outside interact %?", - stream_handle_ptr); - do iotask::interact(iotask) |loop_ptr| { - debug!("in interact cb for tcp client connect.."); - debug!("stream_handle_ptr in interact %?", - stream_handle_ptr); - match uv::ll::tcp_init( loop_ptr, stream_handle_ptr) { - 0i32 => { - debug!("tcp_init successful"); - debug!("dealing w/ ipv4 connection.."); - let connect_req_ptr: *uv::ll::uv_connect_t = - &(*socket_data_ptr).connect_req; - let addr_str = ip::format_addr(&input_ip); - let connect_result = match input_ip { - ip::Ipv4(ref addr) => { - // have to "recreate" the - // sockaddr_in/6 since the ip_addr - // discards the port info.. should - // probably add an additional rust - // type that actually is closer to - // what the libuv API expects (ip str - // + port num) - debug!("addr: %?", addr); - let in_addr = uv::ll::ip4_addr(addr_str, - port as int); - uv::ll::tcp_connect( - connect_req_ptr, - stream_handle_ptr, - &in_addr, - tcp_connect_on_connect_cb) - } - ip::Ipv6(ref addr) => { - debug!("addr: %?", addr); - let in_addr = uv::ll::ip6_addr(addr_str, - port as int); - uv::ll::tcp_connect6( - connect_req_ptr, - stream_handle_ptr, - &in_addr, - tcp_connect_on_connect_cb) - } - }; - match connect_result { - 0i32 => { - debug!("tcp_connect successful: \ - stream %x, - socket data %x", - stream_handle_ptr as uint, - socket_data_ptr as uint); - // reusable data that we'll have for the - // duration.. - uv::ll::set_data_for_uv_handle( - stream_handle_ptr, - socket_data_ptr as - *libc::c_void); - // just so the connect_cb can send the - // outcome.. - uv::ll::set_data_for_req(connect_req_ptr, - conn_data_ptr); - debug!("leaving tcp_connect interact cb..."); - // let tcp_connect_on_connect_cb send on - // the result_ch, now.. - } - _ => { - // immediate connect - // failure.. probably a garbage ip or - // somesuch - let err_data = - uv::ll::get_last_err_data(loop_ptr); - let result_ch = (*conn_data_ptr) - .result_ch.clone(); - result_ch.send(ConnFailure(err_data)); - uv::ll::set_data_for_uv_handle( - stream_handle_ptr, - conn_data_ptr); - uv::ll::close(stream_handle_ptr, - stream_error_close_cb); - } - } - } - _ => { - // failure to create a tcp handle - let err_data = uv::ll::get_last_err_data(loop_ptr); - let result_ch = (*conn_data_ptr).result_ch.clone(); - result_ch.send(ConnFailure(err_data)); - } - } - } - match result_po.recv() { - ConnSuccess => { - debug!("tcp::connect - received success on result_po"); - result::Ok(TcpSocket(socket_data)) - } - ConnFailure(ref err_data) => { - closed_signal_po.recv(); - debug!("tcp::connect - received failure on result_po"); - // still have to free the malloc'd stream handle.. - rustrt::rust_uv_current_kernel_free(stream_handle_ptr - as *libc::c_void); - let tcp_conn_err = match err_data.err_name { - ~"ECONNREFUSED" => ConnectionRefused, - _ => GenericConnectErr(err_data.err_name.clone(), - err_data.err_msg.clone()) - }; - result::Err(tcp_conn_err) - } - } - } -} - -/** - * Write binary data to a tcp stream; Blocks until operation completes - * - * # Arguments - * - * * sock - a `TcpSocket` to write to - * * raw_write_data - a vector of `~[u8]` that will be written to the stream. - * This value must remain valid for the duration of the `write` call - * - * # Returns - * - * A `Result` object with a `()` value as the `Ok` variant, or a - * `TcpErrData` value as the `Err` variant - */ -pub fn write(sock: &TcpSocket, raw_write_data: ~[u8]) - -> result::Result<(), TcpErrData> { - let socket_data_ptr: *TcpSocketData = &*sock.socket_data; - write_common_impl(socket_data_ptr, raw_write_data) -} - -/** - * Write binary data to tcp stream; Returns a `future::Future` value - * immediately - * - * # Safety - * - * This function can produce unsafe results if: - * - * 1. the call to `write_future` is made - * 2. the `future::Future` value returned is never resolved via - * `Future::get` - * 3. and then the `TcpSocket` passed in to `write_future` leaves - * scope and is destructed before the task that runs the libuv write - * operation completes. - * - * As such: If using `write_future`, always be sure to resolve the returned - * `Future` so as to ensure libuv doesn't try to access a released write - * handle. Otherwise, use the blocking `tcp::write` function instead. - * - * # Arguments - * - * * sock - a `TcpSocket` to write to - * * raw_write_data - a vector of `~[u8]` that will be written to the stream. - * This value must remain valid for the duration of the `write` call - * - * # Returns - * - * A `Future` value that, once the `write` operation completes, resolves to a - * `Result` object with a `nil` value as the `Ok` variant, or a `TcpErrData` - * value as the `Err` variant - */ -pub fn write_future(sock: &TcpSocket, raw_write_data: ~[u8]) - -> future::Future> -{ - let socket_data_ptr: *TcpSocketData = &*sock.socket_data; - do future_spawn { - let data_copy = raw_write_data.clone(); - write_common_impl(socket_data_ptr, data_copy) - } -} - -/** - * Begin reading binary data from an open TCP connection; used with - * `read_stop` - * - * # Arguments - * - * * sock -- a `net::tcp::TcpSocket` for the connection to read from - * - * # Returns - * - * * A `Result` instance that will either contain a - * `std::comm::Port>` that the user can read - * (and * optionally, loop on) from until `read_stop` is called, or a - * `TcpErrData` record - */ -pub fn read_start(sock: &TcpSocket) - -> result::Result<@Port>, - TcpErrData> { - let socket_data: *TcpSocketData = &*sock.socket_data; - read_start_common_impl(socket_data) -} - -/** - * Stop reading from an open TCP connection; used with `read_start` - * - * # Arguments - * - * * `sock` - a `net::tcp::TcpSocket` that you wish to stop reading on - */ -pub fn read_stop(sock: &TcpSocket) -> result::Result<(), TcpErrData> { - let socket_data: *TcpSocketData = &*sock.socket_data; - read_stop_common_impl(socket_data) -} - -/** - * Reads a single chunk of data from `TcpSocket`; block until data/error - * recv'd - * - * Does a blocking read operation for a single chunk of data from a - * `TcpSocket` until a data arrives or an error is received. The provided - * `timeout_msecs` value is used to raise an error if the timeout period - * passes without any data received. - * - * # Arguments - * - * * `sock` - a `net::tcp::TcpSocket` that you wish to read from - * * `timeout_msecs` - a `uint` value, in msecs, to wait before dropping the - * read attempt. Pass `0u` to wait indefinitely - */ -pub fn read(sock: &TcpSocket, timeout_msecs: uint) - -> result::Result<~[u8],TcpErrData> { - let socket_data: *TcpSocketData = &*sock.socket_data; - read_common_impl(socket_data, timeout_msecs) -} - -/** - * Reads a single chunk of data; returns a `future::Future<~[u8]>` - * immediately - * - * Does a non-blocking read operation for a single chunk of data from a - * `TcpSocket` and immediately returns a `Future` value representing the - * result. When resolving the returned `Future`, it will block until data - * arrives or an error is received. The provided `timeout_msecs` - * value is used to raise an error if the timeout period passes without any - * data received. - * - * # Safety - * - * This function can produce unsafe results if the call to `read_future` is - * made, the `future::Future` value returned is never resolved via - * `Future::get`, and then the `TcpSocket` passed in to `read_future` leaves - * scope and is destructed before the task that runs the libuv read - * operation completes. - * - * As such: If using `read_future`, always be sure to resolve the returned - * `Future` so as to ensure libuv doesn't try to access a released read - * handle. Otherwise, use the blocking `tcp::read` function instead. - * - * # Arguments - * - * * `sock` - a `net::tcp::TcpSocket` that you wish to read from - * * `timeout_msecs` - a `uint` value, in msecs, to wait before dropping the - * read attempt. Pass `0u` to wait indefinitely - */ -fn read_future(sock: &TcpSocket, timeout_msecs: uint) - -> future::Future> { - let socket_data: *TcpSocketData = &*sock.socket_data; - do future_spawn { - read_common_impl(socket_data, timeout_msecs) - } -} - -/** - * Bind an incoming client connection to a `net::tcp::TcpSocket` - * - * # Notes - * - * It is safe to call `net::tcp::accept` _only_ within the context of the - * `new_connect_cb` callback provided as the final argument to the - * `net::tcp::listen` function. - * - * The `new_conn` opaque value is provided _only_ as the first argument to the - * `new_connect_cb` provided as a part of `net::tcp::listen`. - * It can be safely sent to another task but it _must_ be - * used (via `net::tcp::accept`) before the `new_connect_cb` call it was - * provided to returns. - * - * This implies that a port/chan pair must be used to make sure that the - * `new_connect_cb` call blocks until an attempt to create a - * `net::tcp::TcpSocket` is completed. - * - * # Example - * - * Here, the `new_conn` is used in conjunction with `accept` from within - * a task spawned by the `new_connect_cb` passed into `listen` - * - * ~~~ {.rust} - * do net::tcp::listen(remote_ip, remote_port, backlog, iotask, - * // this callback is ran once after the connection is successfully - * // set up - * |kill_ch| { - * // pass the kill_ch to your main loop or wherever you want - * // to be able to externally kill the server from - * }) - * // this callback is ran when a new connection arrives - * |new_conn, kill_ch| { - * let (cont_po, cont_ch) = comm::stream::>(); - * do task::spawn { - * let accept_result = net::tcp::accept(new_conn); - * match accept_result { - * Err(accept_error) => { - * cont_ch.send(Some(accept_error)); - * // fail? - * }, - * Ok(sock) => { - * cont_ch.send(None); - * // do work here - * } - * } - * }; - * match cont_po.recv() { - * // shut down listen() - * Some(err_data) => kill_ch.send(Some(err_data)), - * // wait for next connection - * None => () - * } - * }; - * ~~~ - * - * # Arguments - * - * * `new_conn` - an opaque value used to create a new `TcpSocket` - * - * # Returns - * - * On success, this function will return a `net::tcp::TcpSocket` as the - * `Ok` variant of a `Result`. The `net::tcp::TcpSocket` is anchored within - * the task that `accept` was called within for its lifetime. On failure, - * this function will return a `net::tcp::TcpErrData` record - * as the `Err` variant of a `Result`. - */ -pub fn accept(new_conn: TcpNewConnection) - -> result::Result { - unsafe { - match new_conn{ - NewTcpConn(server_handle_ptr) => { - let server_data_ptr = uv::ll::get_data_for_uv_handle( - server_handle_ptr) as *TcpListenFcData; - let (reader_po, reader_ch) = stream::< - Result<~[u8], TcpErrData>>(); - let reader_ch = SharedChan::new(reader_ch); - let iotask = &(*server_data_ptr).iotask; - let stream_handle_ptr = malloc_uv_tcp_t(); - *(stream_handle_ptr as *mut uv::ll::uv_tcp_t) = - uv::ll::tcp_t(); - let client_socket_data: @TcpSocketData = @TcpSocketData { - reader_po: @reader_po, - reader_ch: reader_ch, - stream_handle_ptr : stream_handle_ptr, - connect_req : uv::ll::connect_t(), - write_req : uv::ll::write_t(), - ipv6: (*server_data_ptr).ipv6, - iotask : iotask.clone() - }; - let client_socket_data_ptr: *TcpSocketData = - &*client_socket_data; - let client_stream_handle_ptr = - (*client_socket_data_ptr).stream_handle_ptr; - - let (result_po, result_ch) = stream::>(); - let result_ch = SharedChan::new(result_ch); - - // UNSAFE LIBUV INTERACTION BEGIN - // .. normally this happens within the context of - // a call to uv::hl::interact.. but we're breaking - // the rules here because this always has to be - // called within the context of a listen() new_connect_cb - // callback (or it will likely fail and drown your cat) - debug!("in interact cb for tcp::accept"); - let loop_ptr = uv::ll::get_loop_for_uv_handle( - server_handle_ptr); - match uv::ll::tcp_init(loop_ptr, client_stream_handle_ptr) { - 0i32 => { - debug!("uv_tcp_init successful for \ - client stream"); - match uv::ll::accept( - server_handle_ptr as *libc::c_void, - client_stream_handle_ptr as *libc::c_void) { - 0i32 => { - debug!("successfully accepted client \ - connection: \ - stream %x, \ - socket data %x", - client_stream_handle_ptr as uint, - client_socket_data_ptr as uint); - uv::ll::set_data_for_uv_handle( - client_stream_handle_ptr, - client_socket_data_ptr - as *libc::c_void); - let ptr = uv::ll::get_data_for_uv_handle( - client_stream_handle_ptr); - debug!("ptrs: %x %x", - client_socket_data_ptr as uint, - ptr as uint); - result_ch.send(None); - } - _ => { - debug!("failed to accept client conn"); - result_ch.send(Some( - uv::ll::get_last_err_data( - loop_ptr).to_tcp_err())); - } - } - } - _ => { - debug!("failed to accept client stream"); - result_ch.send(Some( - uv::ll::get_last_err_data( - loop_ptr).to_tcp_err())); - } - } - // UNSAFE LIBUV INTERACTION END - match result_po.recv() { - Some(err_data) => result::Err(err_data), - None => result::Ok(TcpSocket(client_socket_data)) - } - } - } - } -} - -/** - * Bind to a given IP/port and listen for new connections - * - * # Arguments - * - * * `host_ip` - a `net::ip::IpAddr` representing a unique IP - * (versions 4 or 6) - * * `port` - a uint representing the port to listen on - * * `backlog` - a uint representing the number of incoming connections - * to cache in memory - * * `hl_loop` - a `uv_iotask::IoTask` that the tcp request will run on - * * `on_establish_cb` - a callback that is evaluated if/when the listener - * is successfully established. it takes no parameters - * * `new_connect_cb` - a callback to be evaluated, on the libuv thread, - * whenever a client attempts to conect on the provided ip/port. the - * callback's arguments are: - * * `new_conn` - an opaque type that can be passed to - * `net::tcp::accept` in order to be converted to a `TcpSocket`. - * * `kill_ch` - channel of type `std::comm::Chan>`. - * this channel can be used to send a message to cause `listen` to begin - * closing the underlying libuv data structures. - * - * # returns - * - * a `Result` instance containing empty data of type `()` on a - * successful/normal shutdown, and a `TcpListenErrData` enum in the event - * of listen exiting because of an error - */ -pub fn listen(host_ip: ip::IpAddr, port: uint, backlog: uint, - iotask: &IoTask, - on_establish_cb: ~fn(SharedChan>), - new_connect_cb: ~fn(TcpNewConnection, - SharedChan>)) - -> result::Result<(), TcpListenErrData> { - do listen_common(host_ip, port, backlog, iotask, - on_establish_cb) - // on_connect_cb - |handle| { - unsafe { - let server_data_ptr = uv::ll::get_data_for_uv_handle(handle) - as *TcpListenFcData; - let new_conn = NewTcpConn(handle); - let kill_ch = (*server_data_ptr).kill_ch.clone(); - new_connect_cb(new_conn, kill_ch); - } - } -} - -fn listen_common(host_ip: ip::IpAddr, - port: uint, - backlog: uint, - iotask: &IoTask, - on_establish_cb: ~fn(SharedChan>), - on_connect_cb: ~fn(*uv::ll::uv_tcp_t)) - -> result::Result<(), TcpListenErrData> { - let (stream_closed_po, stream_closed_ch) = stream::<()>(); - let stream_closed_ch = SharedChan::new(stream_closed_ch); - let (kill_po, kill_ch) = stream::>(); - let kill_ch = SharedChan::new(kill_ch); - let server_stream = uv::ll::tcp_t(); - let server_stream_ptr: *uv::ll::uv_tcp_t = &server_stream; - let server_data: TcpListenFcData = TcpListenFcData { - server_stream_ptr: server_stream_ptr, - stream_closed_ch: stream_closed_ch, - kill_ch: kill_ch.clone(), - on_connect_cb: on_connect_cb, - iotask: iotask.clone(), - ipv6: match &host_ip { - &ip::Ipv4(_) => { false } - &ip::Ipv6(_) => { true } - }, - active: @mut true - }; - let server_data_ptr: *TcpListenFcData = &server_data; - - let (setup_po, setup_ch) = stream(); - - // this is to address a compiler warning about - // an implicit copy.. it seems that double nested - // will defeat a move sigil, as is done to the host_ip - // arg above.. this same pattern works w/o complaint in - // tcp::connect (because the iotask::interact cb isn't - // nested within a core::comm::listen block) - let loc_ip = host_ip; - do iotask::interact(iotask) |loop_ptr| { - unsafe { - match uv::ll::tcp_init(loop_ptr, server_stream_ptr) { - 0i32 => { - uv::ll::set_data_for_uv_handle( - server_stream_ptr, - server_data_ptr); - let addr_str = ip::format_addr(&loc_ip); - let bind_result = match loc_ip { - ip::Ipv4(ref addr) => { - debug!("addr: %?", addr); - let in_addr = uv::ll::ip4_addr( - addr_str, - port as int); - uv::ll::tcp_bind(server_stream_ptr, &in_addr) - } - ip::Ipv6(ref addr) => { - debug!("addr: %?", addr); - let in_addr = uv::ll::ip6_addr( - addr_str, - port as int); - uv::ll::tcp_bind6(server_stream_ptr, &in_addr) - } - }; - match bind_result { - 0i32 => { - match uv::ll::listen( - server_stream_ptr, - backlog as libc::c_int, - tcp_lfc_on_connection_cb) { - 0i32 => setup_ch.send(None), - _ => { - debug!( - "failure to uv_tcp_init"); - let err_data = - uv::ll::get_last_err_data( - loop_ptr); - setup_ch.send(Some(err_data)); - } - } - } - _ => { - debug!("failure to uv_tcp_bind"); - let err_data = uv::ll::get_last_err_data( - loop_ptr); - setup_ch.send(Some(err_data)); - } - } - } - _ => { - debug!("failure to uv_tcp_bind"); - let err_data = uv::ll::get_last_err_data( - loop_ptr); - setup_ch.send(Some(err_data)); - } - } - } - } - - let setup_result = setup_po.recv(); - - match setup_result { - Some(ref err_data) => { - do iotask::interact(iotask) |loop_ptr| { - unsafe { - debug!( - "tcp::listen post-kill recv hl interact %?", - loop_ptr); - *(*server_data_ptr).active = false; - uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); - } - }; - stream_closed_po.recv(); - match err_data.err_name { - ~"EACCES" => { - debug!("Got EACCES error"); - result::Err(AccessDenied) - } - ~"EADDRINUSE" => { - debug!("Got EADDRINUSE error"); - result::Err(AddressInUse) - } - _ => { - debug!("Got '%s' '%s' libuv error", - err_data.err_name, err_data.err_msg); - result::Err( - GenericListenErr(err_data.err_name.clone(), - err_data.err_msg.clone())) - } - } - } - None => { - on_establish_cb(kill_ch.clone()); - let kill_result = kill_po.recv(); - do iotask::interact(iotask) |loop_ptr| { - unsafe { - debug!( - "tcp::listen post-kill recv hl interact %?", - loop_ptr); - *(*server_data_ptr).active = false; - uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); - } - }; - stream_closed_po.recv(); - match kill_result { - // some failure post bind/listen - Some(ref err_data) => result::Err(GenericListenErr( - err_data.err_name.clone(), - err_data.err_msg.clone())), - // clean exit - None => result::Ok(()) - } - } - } -} - - -/** - * Convert a `net::tcp::TcpSocket` to a `net::tcp::TcpSocketBuf`. - * - * This function takes ownership of a `net::tcp::TcpSocket`, returning it - * stored within a buffered wrapper, which can be converted to a `io::Reader` - * or `io::Writer` - * - * # Arguments - * - * * `sock` -- a `net::tcp::TcpSocket` that you want to buffer - * - * # Returns - * - * A buffered wrapper that you can cast as an `io::Reader` or `io::Writer` - */ -pub fn socket_buf(sock: TcpSocket) -> TcpSocketBuf { - TcpSocketBuf(@mut TcpBufferedSocketData { - sock: sock, buf: ~[], buf_off: 0 - }) -} - -/// Convenience methods extending `net::tcp::TcpSocket` -impl TcpSocket { - pub fn read_start(&self) -> result::Result<@Port< - result::Result<~[u8], TcpErrData>>, TcpErrData> { - read_start(self) - } - pub fn read_stop(&self) -> - result::Result<(), TcpErrData> { - read_stop(self) - } - pub fn read(&self, timeout_msecs: uint) -> - result::Result<~[u8], TcpErrData> { - read(self, timeout_msecs) - } - pub fn read_future(&self, timeout_msecs: uint) -> - future::Future> { - read_future(self, timeout_msecs) - } - pub fn write(&self, raw_write_data: ~[u8]) - -> result::Result<(), TcpErrData> { - write(self, raw_write_data) - } - pub fn write_future(&self, raw_write_data: ~[u8]) - -> future::Future> { - write_future(self, raw_write_data) - } - pub fn get_peer_addr(&self) -> ip::IpAddr { - unsafe { - if self.socket_data.ipv6 { - let addr = uv::ll::ip6_addr("", 0); - uv::ll::tcp_getpeername6(self.socket_data.stream_handle_ptr, - &addr); - ip::Ipv6(addr) - } else { - let addr = uv::ll::ip4_addr("", 0); - uv::ll::tcp_getpeername(self.socket_data.stream_handle_ptr, - &addr); - ip::Ipv4(addr) - } - } - } -} - -/// Implementation of `io::Reader` trait for a buffered `net::tcp::TcpSocket` -impl io::Reader for TcpSocketBuf { - fn read(&self, buf: &mut [u8], len: uint) -> uint { - if len == 0 { return 0 } - let mut count: uint = 0; - - loop { - assert!(count < len); - - // If possible, copy up to `len` bytes from the internal - // `data.buf` into `buf` - let nbuffered = self.data.buf.len() - self.data.buf_off; - let needed = len - count; - if nbuffered > 0 { - unsafe { - let ncopy = num::min(nbuffered, needed); - let dst = ptr::mut_offset( - vec::raw::to_mut_ptr(buf), count); - let src = ptr::offset( - vec::raw::to_ptr(self.data.buf), - self.data.buf_off); - ptr::copy_memory(dst, src, ncopy); - self.data.buf_off += ncopy; - count += ncopy; - } - } - - assert!(count <= len); - if count == len { - break; - } - - // We copied all the bytes we had in the internal buffer into - // the result buffer, but the caller wants more bytes, so we - // need to read in data from the socket. Note that the internal - // buffer is of no use anymore as we read all bytes from it, - // so we can throw it away. - let read_result = { - let data = &*self.data; - read(&data.sock, 0) - }; - if read_result.is_err() { - let err_data = read_result.get_err(); - - if err_data.err_name == ~"EOF" { - *self.end_of_stream = true; - break; - } else { - debug!("ERROR sock_buf as io::reader.read err %? %?", - err_data.err_name, err_data.err_msg); - // As we have already copied data into result buffer, - // we cannot simply return 0 here. Instead the error - // should show up in a later call to read(). - break; - } - } else { - self.data.buf = result::unwrap(read_result); - self.data.buf_off = 0; - } - } - - count - } - fn read_byte(&self) -> int { - loop { - if self.data.buf.len() > self.data.buf_off { - let c = self.data.buf[self.data.buf_off]; - self.data.buf_off += 1; - return c as int - } - - let read_result = { - let data = &*self.data; - read(&data.sock, 0) - }; - if read_result.is_err() { - let err_data = read_result.get_err(); - - if err_data.err_name == ~"EOF" { - *self.end_of_stream = true; - return -1 - } else { - debug!("ERROR sock_buf as io::reader.read err %? %?", - err_data.err_name, err_data.err_msg); - fail!() - } - } else { - self.data.buf = result::unwrap(read_result); - self.data.buf_off = 0; - } - } - } - fn eof(&self) -> bool { - *self.end_of_stream - } - fn seek(&self, dist: int, seek: io::SeekStyle) { - debug!("tcp_socket_buf seek stub %? %?", dist, seek); - // noop - } - fn tell(&self) -> uint { - 0u // noop - } -} - -/// Implementation of `io::Reader` trait for a buffered `net::tcp::TcpSocket` -impl io::Writer for TcpSocketBuf { - pub fn write(&self, data: &[u8]) { - let socket_data_ptr: *TcpSocketData = - &(*((*(self.data)).sock).socket_data); - let w_result = write_common_impl(socket_data_ptr, - data.slice(0, data.len()).to_owned()); - if w_result.is_err() { - let err_data = w_result.get_err(); - debug!( - "ERROR sock_buf as io::writer.writer err: %? %?", - err_data.err_name, err_data.err_msg); - } - } - fn seek(&self, dist: int, seek: io::SeekStyle) { - debug!("tcp_socket_buf seek stub %? %?", dist, seek); - // noop - } - fn tell(&self) -> uint { - 0u - } - fn flush(&self) -> int { - 0 - } - fn get_type(&self) -> io::WriterType { - io::File - } -} - -// INTERNAL API - -fn tear_down_socket_data(socket_data: @TcpSocketData) { - unsafe { - let (closed_po, closed_ch) = stream::<()>(); - let closed_ch = SharedChan::new(closed_ch); - let close_data = TcpSocketCloseData { - closed_ch: closed_ch - }; - let close_data_ptr: *TcpSocketCloseData = &close_data; - let stream_handle_ptr = (*socket_data).stream_handle_ptr; - do iotask::interact(&(*socket_data).iotask) |loop_ptr| { - debug!( - "interact dtor for tcp_socket stream %? loop %?", - stream_handle_ptr, loop_ptr); - uv::ll::set_data_for_uv_handle(stream_handle_ptr, - close_data_ptr); - uv::ll::close(stream_handle_ptr, tcp_socket_dtor_close_cb); - }; - closed_po.recv(); - //the line below will most likely crash - //log(debug, fmt!("about to free socket_data at %?", socket_data)); - rustrt::rust_uv_current_kernel_free(stream_handle_ptr - as *libc::c_void); - debug!("exiting dtor for tcp_socket"); - } -} - -// shared implementation for tcp::read -fn read_common_impl(socket_data: *TcpSocketData, timeout_msecs: uint) - -> result::Result<~[u8],TcpErrData> { - unsafe { - use timer; - - debug!("starting tcp::read"); - let iotask = &(*socket_data).iotask; - let rs_result = read_start_common_impl(socket_data); - if result::is_err(&rs_result) { - let err_data = result::get_err(&rs_result); - result::Err(err_data) - } - else { - debug!("tcp::read before recv_timeout"); - let read_result = if timeout_msecs > 0u { - timer::recv_timeout( - iotask, timeout_msecs, result::unwrap(rs_result)) - } else { - Some(result::get(&rs_result).recv()) - }; - debug!("tcp::read after recv_timeout"); - match read_result { - None => { - debug!("tcp::read: timed out.."); - let err_data = TcpErrData { - err_name: ~"TIMEOUT", - err_msg: ~"req timed out" - }; - read_stop_common_impl(socket_data); - result::Err(err_data) - } - Some(data_result) => { - debug!("tcp::read got data"); - read_stop_common_impl(socket_data); - data_result - } - } - } - } -} - -// shared impl for read_stop -fn read_stop_common_impl(socket_data: *TcpSocketData) -> - result::Result<(), TcpErrData> { - unsafe { - let stream_handle_ptr = (*socket_data).stream_handle_ptr; - let (stop_po, stop_ch) = stream::>(); - do iotask::interact(&(*socket_data).iotask) |loop_ptr| { - debug!("in interact cb for tcp::read_stop"); - match uv::ll::read_stop(stream_handle_ptr - as *uv::ll::uv_stream_t) { - 0i32 => { - debug!("successfully called uv_read_stop"); - stop_ch.send(None); - } - _ => { - debug!("failure in calling uv_read_stop"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - stop_ch.send(Some(err_data.to_tcp_err())); - } - } - } - match stop_po.recv() { - Some(err_data) => Err(err_data), - None => Ok(()) - } - } -} - -// shared impl for read_start -fn read_start_common_impl(socket_data: *TcpSocketData) - -> result::Result<@Port< - result::Result<~[u8], TcpErrData>>, TcpErrData> { - unsafe { - let stream_handle_ptr = (*socket_data).stream_handle_ptr; - let (start_po, start_ch) = stream::>(); - debug!("in tcp::read_start before interact loop"); - do iotask::interact(&(*socket_data).iotask) |loop_ptr| { - debug!("in tcp::read_start interact cb %?", - loop_ptr); - match uv::ll::read_start(stream_handle_ptr - as *uv::ll::uv_stream_t, - on_alloc_cb, - on_tcp_read_cb) { - 0i32 => { - debug!("success doing uv_read_start"); - start_ch.send(None); - } - _ => { - debug!("error attempting uv_read_start"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - start_ch.send(Some(err_data)); - } - } - } - match start_po.recv() { - Some(ref err_data) => result::Err( - err_data.to_tcp_err()), - None => { - result::Ok((*socket_data).reader_po) - } - } - } -} - -// helper to convert a "class" vector of [u8] to a *[uv::ll::uv_buf_t] - -// shared implementation used by write and write_future -fn write_common_impl(socket_data_ptr: *TcpSocketData, - raw_write_data: ~[u8]) - -> result::Result<(), TcpErrData> { - unsafe { - let write_req_ptr: *uv::ll::uv_write_t = - &(*socket_data_ptr).write_req; - let stream_handle_ptr = - (*socket_data_ptr).stream_handle_ptr; - let write_buf_vec = ~[ - uv::ll::buf_init(vec::raw::to_ptr(raw_write_data), - raw_write_data.len()) - ]; - let write_buf_vec_ptr: *~[uv::ll::uv_buf_t] = &write_buf_vec; - let (result_po, result_ch) = stream::(); - let result_ch = SharedChan::new(result_ch); - let write_data = WriteReqData { - result_ch: result_ch - }; - let write_data_ptr: *WriteReqData = &write_data; - do iotask::interact(&(*socket_data_ptr).iotask) |loop_ptr| { - debug!("in interact cb for tcp::write %?", - loop_ptr); - match uv::ll::write(write_req_ptr, - stream_handle_ptr, - write_buf_vec_ptr, - tcp_write_complete_cb) { - 0i32 => { - debug!("uv_write() invoked successfully"); - uv::ll::set_data_for_req(write_req_ptr, - write_data_ptr); - } - _ => { - debug!("error invoking uv_write()"); - let err_data = uv::ll::get_last_err_data(loop_ptr); - let result_ch = (*write_data_ptr).result_ch.clone(); - result_ch.send(TcpWriteError(err_data.to_tcp_err())); - } - } - } - // FIXME (#2656): Instead of passing unsafe pointers to local data, - // and waiting here for the write to complete, we should transfer - // ownership of everything to the I/O task and let it deal with the - // aftermath, so we don't have to sit here blocking. - match result_po.recv() { - TcpWriteSuccess => Ok(()), - TcpWriteError(err_data) => Err(err_data) - } - } -} - -enum TcpNewConnection { - NewTcpConn(*uv::ll::uv_tcp_t) -} - -struct TcpListenFcData { - server_stream_ptr: *uv::ll::uv_tcp_t, - stream_closed_ch: SharedChan<()>, - kill_ch: SharedChan>, - on_connect_cb: ~fn(*uv::ll::uv_tcp_t), - iotask: IoTask, - ipv6: bool, - active: @mut bool, -} - -extern fn tcp_lfc_close_cb(handle: *uv::ll::uv_tcp_t) { - unsafe { - let server_data_ptr = uv::ll::get_data_for_uv_handle( - handle) as *TcpListenFcData; - let stream_closed_ch = (*server_data_ptr).stream_closed_ch.clone(); - stream_closed_ch.send(()); - } -} - -extern fn tcp_lfc_on_connection_cb(handle: *uv::ll::uv_tcp_t, - status: libc::c_int) { - unsafe { - let server_data_ptr = uv::ll::get_data_for_uv_handle(handle) - as *TcpListenFcData; - let kill_ch = (*server_data_ptr).kill_ch.clone(); - if *(*server_data_ptr).active { - match status { - 0i32 => ((*server_data_ptr).on_connect_cb)(handle), - _ => { - let loop_ptr = uv::ll::get_loop_for_uv_handle(handle); - kill_ch.send( - Some(uv::ll::get_last_err_data(loop_ptr) - .to_tcp_err())); - *(*server_data_ptr).active = false; - } - } - } - } -} - -fn malloc_uv_tcp_t() -> *uv::ll::uv_tcp_t { - unsafe { - rustrt::rust_uv_current_kernel_malloc( - rustrt::rust_uv_helper_uv_tcp_t_size()) as *uv::ll::uv_tcp_t - } -} - -enum TcpConnectResult { - TcpConnected(TcpSocket), - TcpConnectError(TcpErrData) -} - -enum TcpWriteResult { - TcpWriteSuccess, - TcpWriteError(TcpErrData) -} - -enum TcpReadStartResult { - TcpReadStartSuccess(Port), - TcpReadStartError(TcpErrData) -} - -enum TcpReadResult { - TcpReadData(~[u8]), - TcpReadDone, - TcpReadErr(TcpErrData) -} - -trait ToTcpErr { - fn to_tcp_err(&self) -> TcpErrData; -} - -impl ToTcpErr for uv::ll::uv_err_data { - fn to_tcp_err(&self) -> TcpErrData { - TcpErrData { - err_name: self.err_name.clone(), - err_msg: self.err_msg.clone(), - } - } -} - -extern fn on_tcp_read_cb(stream: *uv::ll::uv_stream_t, - nread: libc::ssize_t, - buf: uv::ll::uv_buf_t) { - unsafe { - debug!("entering on_tcp_read_cb stream: %x nread: %?", - stream as uint, nread); - let loop_ptr = uv::ll::get_loop_for_uv_handle(stream); - let socket_data_ptr = uv::ll::get_data_for_uv_handle(stream) - as *TcpSocketData; - debug!("socket data is %x", socket_data_ptr as uint); - match nread as int { - // incoming err.. probably eof - -1 => { - let err_data = uv::ll::get_last_err_data(loop_ptr).to_tcp_err(); - debug!("on_tcp_read_cb: incoming err.. name %? msg %?", - err_data.err_name, err_data.err_msg); - let reader_ch = &(*socket_data_ptr).reader_ch; - reader_ch.send(result::Err(err_data)); - } - // do nothing .. unneeded buf - 0 => (), - // have data - _ => { - // we have data - debug!("tcp on_read_cb nread: %d", nread as int); - let reader_ch = &(*socket_data_ptr).reader_ch; - let buf_base = uv::ll::get_base_from_buf(buf); - let new_bytes = vec::from_buf(buf_base, nread as uint); - reader_ch.send(result::Ok(new_bytes)); - } - } - uv::ll::free_base_of_buf(buf); - debug!("exiting on_tcp_read_cb"); - } -} - -extern fn on_alloc_cb(handle: *libc::c_void, - suggested_size: size_t) - -> uv::ll::uv_buf_t { - unsafe { - debug!("tcp read on_alloc_cb!"); - let char_ptr = uv::ll::malloc_buf_base_of(suggested_size); - debug!("tcp read on_alloc_cb h: %? char_ptr: %u sugsize: %u", - handle, - char_ptr as uint, - suggested_size as uint); - uv::ll::buf_init(char_ptr, suggested_size as uint) - } -} - -struct TcpSocketCloseData { - closed_ch: SharedChan<()>, -} - -extern fn tcp_socket_dtor_close_cb(handle: *uv::ll::uv_tcp_t) { - unsafe { - let data = uv::ll::get_data_for_uv_handle(handle) - as *TcpSocketCloseData; - let closed_ch = (*data).closed_ch.clone(); - closed_ch.send(()); - debug!("tcp_socket_dtor_close_cb exiting.."); - } -} - -extern fn tcp_write_complete_cb(write_req: *uv::ll::uv_write_t, - status: libc::c_int) { - unsafe { - let write_data_ptr = uv::ll::get_data_for_req(write_req) - as *WriteReqData; - if status == 0i32 { - debug!("successful write complete"); - let result_ch = (*write_data_ptr).result_ch.clone(); - result_ch.send(TcpWriteSuccess); - } else { - let stream_handle_ptr = uv::ll::get_stream_handle_from_write_req( - write_req); - let loop_ptr = uv::ll::get_loop_for_uv_handle(stream_handle_ptr); - let err_data = uv::ll::get_last_err_data(loop_ptr); - debug!("failure to write"); - let result_ch = (*write_data_ptr).result_ch.clone(); - result_ch.send(TcpWriteError(err_data.to_tcp_err())); - } - } -} - -struct WriteReqData { - result_ch: SharedChan, -} - -struct ConnectReqData { - result_ch: SharedChan, - closed_signal_ch: SharedChan<()>, -} - -extern fn stream_error_close_cb(handle: *uv::ll::uv_tcp_t) { - unsafe { - let data = uv::ll::get_data_for_uv_handle(handle) as - *ConnectReqData; - let closed_signal_ch = (*data).closed_signal_ch.clone(); - closed_signal_ch.send(()); - debug!("exiting steam_error_close_cb for %?", handle); - } -} - -extern fn tcp_connect_close_cb(handle: *uv::ll::uv_tcp_t) { - debug!("closed client tcp handle %?", handle); -} - -extern fn tcp_connect_on_connect_cb(connect_req_ptr: *uv::ll::uv_connect_t, - status: libc::c_int) { - unsafe { - let conn_data_ptr = (uv::ll::get_data_for_req(connect_req_ptr) - as *ConnectReqData); - let result_ch = (*conn_data_ptr).result_ch.clone(); - debug!("tcp_connect result_ch %?", result_ch); - let tcp_stream_ptr = - uv::ll::get_stream_handle_from_connect_req(connect_req_ptr); - match status { - 0i32 => { - debug!("successful tcp connection!"); - result_ch.send(ConnSuccess); - } - _ => { - debug!("error in tcp_connect_on_connect_cb"); - let loop_ptr = uv::ll::get_loop_for_uv_handle(tcp_stream_ptr); - let err_data = uv::ll::get_last_err_data(loop_ptr); - debug!("err_data %? %?", err_data.err_name, - err_data.err_msg); - result_ch.send(ConnFailure(err_data)); - uv::ll::set_data_for_uv_handle(tcp_stream_ptr, - conn_data_ptr); - uv::ll::close(tcp_stream_ptr, stream_error_close_cb); - } - } - debug!("leaving tcp_connect_on_connect_cb"); - } -} - -enum ConnAttempt { - ConnSuccess, - ConnFailure(uv::ll::uv_err_data) -} - -struct TcpSocketData { - reader_po: @Port>, - reader_ch: SharedChan>, - stream_handle_ptr: *uv::ll::uv_tcp_t, - connect_req: uv::ll::uv_connect_t, - write_req: uv::ll::uv_write_t, - ipv6: bool, - iotask: IoTask, -} - -struct TcpBufferedSocketData { - sock: TcpSocket, - buf: ~[u8], - buf_off: uint -} - -#[cfg(test)] -mod test { - - use net::ip; - use net::tcp::{GenericListenErr, TcpConnectErrData, TcpListenErrData}; - use net::tcp::{connect, accept, read, listen, TcpSocket, socket_buf}; - use net; - use uv::iotask::IoTask; - use uv; - - use std::cell::Cell; - use std::comm::{stream, SharedChan}; - use std::io; - use std::result; - use std::str; - use std::task; - - // FIXME don't run on fbsd or linux 32 bit (#2064) - #[cfg(target_os="win32")] - #[cfg(target_os="darwin")] - #[cfg(target_os="linux")] - #[cfg(target_os="android")] - mod tcp_ipv4_server_and_client_test { - #[cfg(target_arch="x86_64")] - mod impl64 { - use net::tcp::test::*; - - #[test] - fn test_gl_tcp_server_and_client_ipv4() { - impl_gl_tcp_ipv4_server_and_client(); - } - #[test] - fn test_gl_tcp_get_peer_addr() { - impl_gl_tcp_ipv4_get_peer_addr(); - } - #[test] - fn test_gl_tcp_ipv4_client_error_connection_refused() { - impl_gl_tcp_ipv4_client_error_connection_refused(); - } - #[test] - fn test_gl_tcp_server_address_in_use() { - impl_gl_tcp_ipv4_server_address_in_use(); - } - #[test] - fn test_gl_tcp_server_access_denied() { - impl_gl_tcp_ipv4_server_access_denied(); - } - // Strange failure on Windows. --pcwalton - #[test] - #[ignore(cfg(target_os = "win32"))] - fn test_gl_tcp_ipv4_server_client_reader_writer() { - impl_gl_tcp_ipv4_server_client_reader_writer(); - } - #[test] - fn test_tcp_socket_impl_reader_handles_eof() { - impl_tcp_socket_impl_reader_handles_eof(); - } - } - #[cfg(target_arch="x86")] - #[cfg(target_arch="arm")] - #[cfg(target_arch="mips")] - mod impl32 { - use net::tcp::test::*; - - #[test] - #[ignore(cfg(target_os = "linux"))] - fn test_gl_tcp_server_and_client_ipv4() { - unsafe { - impl_gl_tcp_ipv4_server_and_client(); - } - } - #[test] - #[ignore(cfg(target_os = "linux"))] - fn test_gl_tcp_get_peer_addr() { - unsafe { - impl_gl_tcp_ipv4_get_peer_addr(); - } - } - #[test] - #[ignore(cfg(target_os = "linux"))] - fn test_gl_tcp_ipv4_client_error_connection_refused() { - unsafe { - impl_gl_tcp_ipv4_client_error_connection_refused(); - } - } - #[test] - #[ignore(cfg(target_os = "linux"))] - fn test_gl_tcp_server_address_in_use() { - unsafe { - impl_gl_tcp_ipv4_server_address_in_use(); - } - } - #[test] - #[ignore(cfg(target_os = "linux"))] - #[ignore(cfg(windows), reason = "deadlocking bots")] - fn test_gl_tcp_server_access_denied() { - unsafe { - impl_gl_tcp_ipv4_server_access_denied(); - } - } - #[test] - #[ignore(cfg(target_os = "linux"))] - #[ignore(cfg(target_os = "win32"))] - fn test_gl_tcp_ipv4_server_client_reader_writer() { - impl_gl_tcp_ipv4_server_client_reader_writer(); - } - } - } - pub fn impl_gl_tcp_ipv4_server_and_client() { - let hl_loop = &uv::global_loop::get(); - let server_ip = "127.0.0.1"; - let server_port = 8888u; - let expected_req = ~"ping"; - let expected_resp = "pong"; - - let (server_result_po, server_result_ch) = stream::<~str>(); - - let (cont_po, cont_ch) = stream::<()>(); - let cont_ch = SharedChan::new(cont_ch); - // server - let hl_loop_clone = hl_loop.clone(); - do task::spawn_sched(task::ManualThreads(1u)) { - let cont_ch = cont_ch.clone(); - let actual_req = run_tcp_test_server( - server_ip, - server_port, - expected_resp.to_str(), - cont_ch.clone(), - &hl_loop_clone); - server_result_ch.send(actual_req); - }; - cont_po.recv(); - // client - debug!("server started, firing up client.."); - let actual_resp_result = run_tcp_test_client( - server_ip, - server_port, - expected_req, - hl_loop); - assert!(actual_resp_result.is_ok()); - let actual_resp = actual_resp_result.get(); - let actual_req = server_result_po.recv(); - debug!("REQ: expected: '%s' actual: '%s'", - expected_req, actual_req); - debug!("RESP: expected: '%s' actual: '%s'", - expected_resp, actual_resp); - assert!(actual_req.contains(expected_req)); - assert!(actual_resp.contains(expected_resp)); - } - pub fn impl_gl_tcp_ipv4_get_peer_addr() { - let hl_loop = &uv::global_loop::get(); - let server_ip = "127.0.0.1"; - let server_port = 8887u; - let expected_resp = "pong"; - - let (cont_po, cont_ch) = stream::<()>(); - let cont_ch = SharedChan::new(cont_ch); - // server - let hl_loop_clone = hl_loop.clone(); - do task::spawn_sched(task::ManualThreads(1u)) { - let cont_ch = cont_ch.clone(); - run_tcp_test_server( - server_ip, - server_port, - expected_resp.to_str(), - cont_ch.clone(), - &hl_loop_clone); - }; - cont_po.recv(); - // client - debug!("server started, firing up client.."); - let server_ip_addr = ip::v4::parse_addr(server_ip); - let iotask = uv::global_loop::get(); - let connect_result = connect(server_ip_addr, server_port, - &iotask); - - let sock = result::unwrap(connect_result); - - debug!("testing peer address"); - // This is what we are actually testing! - assert!(net::ip::format_addr(&sock.get_peer_addr()) == - ~"127.0.0.1"); - assert_eq!(net::ip::get_port(&sock.get_peer_addr()), 8887); - - // Fulfill the protocol the test server expects - let resp_bytes = "ping".as_bytes().to_owned(); - tcp_write_single(&sock, resp_bytes); - debug!("message sent"); - sock.read(0u); - debug!("result read"); - } - pub fn impl_gl_tcp_ipv4_client_error_connection_refused() { - let hl_loop = &uv::global_loop::get(); - let server_ip = "127.0.0.1"; - let server_port = 8889u; - let expected_req = ~"ping"; - // client - debug!("firing up client.."); - let actual_resp_result = run_tcp_test_client( - server_ip, - server_port, - expected_req, - hl_loop); - match actual_resp_result.get_err() { - ConnectionRefused => (), - _ => fail!("unknown error.. expected connection_refused") - } - } - pub fn impl_gl_tcp_ipv4_server_address_in_use() { - let hl_loop = &uv::global_loop::get(); - let server_ip = "127.0.0.1"; - let server_port = 8890u; - let expected_req = ~"ping"; - let expected_resp = "pong"; - - let (cont_po, cont_ch) = stream::<()>(); - let cont_ch = SharedChan::new(cont_ch); - // server - let hl_loop_clone = hl_loop.clone(); - do task::spawn_sched(task::ManualThreads(1u)) { - let cont_ch = cont_ch.clone(); - run_tcp_test_server( - server_ip, - server_port, - expected_resp.to_str(), - cont_ch.clone(), - &hl_loop_clone); - } - cont_po.recv(); - // this one should fail.. - let listen_err = run_tcp_test_server_fail( - server_ip, - server_port, - hl_loop); - // client.. just doing this so that the first server tears down - debug!("server started, firing up client.."); - run_tcp_test_client( - server_ip, - server_port, - expected_req, - hl_loop); - match listen_err { - AddressInUse => { - assert!(true); - } - _ => { - fail!("expected address_in_use listen error, \ - but got a different error varient. check logs."); - } - } - } - pub fn impl_gl_tcp_ipv4_server_access_denied() { - let hl_loop = &uv::global_loop::get(); - let server_ip = "127.0.0.1"; - let server_port = 80u; - // this one should fail.. - let listen_err = run_tcp_test_server_fail( - server_ip, - server_port, - hl_loop); - match listen_err { - AccessDenied => { - assert!(true); - } - _ => { - fail!("expected address_in_use listen error, \ - but got a different error varient. check logs."); - } - } - } - pub fn impl_gl_tcp_ipv4_server_client_reader_writer() { - - let iotask = &uv::global_loop::get(); - let server_ip = "127.0.0.1"; - let server_port = 8891u; - let expected_req = ~"ping"; - let expected_resp = "pong"; - - let (server_result_po, server_result_ch) = stream::<~str>(); - - let (cont_po, cont_ch) = stream::<()>(); - let cont_ch = SharedChan::new(cont_ch); - // server - let iotask_clone = iotask.clone(); - do task::spawn_sched(task::ManualThreads(1u)) { - let cont_ch = cont_ch.clone(); - let actual_req = run_tcp_test_server( - server_ip, - server_port, - expected_resp.to_str(), - cont_ch.clone(), - &iotask_clone); - server_result_ch.send(actual_req); - }; - cont_po.recv(); - // client - let server_addr = ip::v4::parse_addr(server_ip); - let conn_result = connect(server_addr, server_port, iotask); - if result::is_err(&conn_result) { - assert!(false); - } - let sock_buf = @socket_buf(result::unwrap(conn_result)); - buf_write(sock_buf, expected_req); - - // so contrived! - let actual_resp = buf_read(sock_buf, expected_resp.as_bytes().len()); - - let actual_req = server_result_po.recv(); - debug!("REQ: expected: '%s' actual: '%s'", - expected_req, actual_req); - debug!("RESP: expected: '%s' actual: '%s'", - expected_resp, actual_resp); - assert!(actual_req.contains(expected_req)); - assert!(actual_resp.contains(expected_resp)); - } - - pub fn impl_tcp_socket_impl_reader_handles_eof() { - use std::io::{Reader,ReaderUtil}; - - let hl_loop = &uv::global_loop::get(); - let server_ip = "127.0.0.1"; - let server_port = 10041u; - let expected_req = ~"GET /"; - let expected_resp = "A string\nwith multiple lines\n"; - - let (cont_po, cont_ch) = stream::<()>(); - let cont_ch = SharedChan::new(cont_ch); - // server - let hl_loop_clone = hl_loop.clone(); - do task::spawn_sched(task::ManualThreads(1u)) { - let cont_ch = cont_ch.clone(); - run_tcp_test_server( - server_ip, - server_port, - expected_resp.to_str(), - cont_ch.clone(), - &hl_loop_clone); - }; - cont_po.recv(); - // client - debug!("server started, firing up client.."); - let server_addr = ip::v4::parse_addr(server_ip); - let conn_result = connect(server_addr, server_port, hl_loop); - if result::is_err(&conn_result) { - assert!(false); - } - let sock_buf = @socket_buf(result::unwrap(conn_result)); - buf_write(sock_buf, expected_req); - - let buf_reader = sock_buf as @Reader; - let actual_response = str::from_bytes(buf_reader.read_whole_stream()); - debug!("Actual response: %s", actual_response); - assert!(expected_resp == actual_response); - } - - fn buf_write(w: &W, val: &str) { - debug!("BUF_WRITE: val len %?", val.len()); - let b_slice = val.as_bytes(); - debug!("BUF_WRITE: b_slice len %?", - b_slice.len()); - w.write(b_slice) - } - - fn buf_read(r: &R, len: uint) -> ~str { - let new_bytes = (*r).read_bytes(len); - debug!("in buf_read.. new_bytes len: %?", - new_bytes.len()); - str::from_bytes(new_bytes) - } - - fn run_tcp_test_server(server_ip: &str, server_port: uint, resp: ~str, - cont_ch: SharedChan<()>, - iotask: &IoTask) -> ~str { - let (server_po, server_ch) = stream::<~str>(); - let server_ch = SharedChan::new(server_ch); - let server_ip_addr = ip::v4::parse_addr(server_ip); - let resp_cell = Cell::new(resp); - let listen_result = listen(server_ip_addr, server_port, 128, - iotask, - // on_establish_cb -- called when listener is set up - |kill_ch| { - debug!("establish_cb %?", - kill_ch); - cont_ch.send(()); - }, - // risky to run this on the loop, but some users - // will want the POWER - |new_conn, kill_ch| { - let resp_cell2 = Cell::new(resp_cell.take()); - debug!("SERVER: new connection!"); - let (cont_po, cont_ch) = stream(); - let server_ch = server_ch.clone(); - do task::spawn_sched(task::ManualThreads(1u)) { - debug!("SERVER: starting worker for new req"); - - let accept_result = accept(new_conn); - debug!("SERVER: after accept()"); - if result::is_err(&accept_result) { - debug!("SERVER: error accept connection"); - let err_data = result::get_err(&accept_result); - kill_ch.send(Some(err_data)); - debug!( - "SERVER/WORKER: send on err cont ch"); - cont_ch.send(()); - } - else { - debug!("SERVER/WORKER: send on cont ch"); - cont_ch.send(()); - let sock = result::unwrap(accept_result); - let peer_addr = sock.get_peer_addr(); - debug!("SERVER: successfully accepted \ - connection from %s:%u", - ip::format_addr(&peer_addr), - ip::get_port(&peer_addr)); - let received_req_bytes = read(&sock, 0u); - match received_req_bytes { - result::Ok(data) => { - debug!("SERVER: got REQ str::from_bytes.."); - debug!("SERVER: REQ data len: %?", - data.len()); - server_ch.send( - str::from_bytes(data)); - debug!("SERVER: before write"); - let s = resp_cell2.take(); - tcp_write_single(&sock, s.as_bytes().to_owned()); - debug!("SERVER: after write.. die"); - kill_ch.send(None); - } - result::Err(err_data) => { - debug!("SERVER: error recvd: %s %s", - err_data.err_name, err_data.err_msg); - kill_ch.send(Some(err_data)); - server_ch.send(~""); - } - } - debug!("SERVER: worker spinning down"); - } - } - debug!("SERVER: waiting to recv on cont_ch"); - cont_po.recv(); - }); - // err check on listen_result - if result::is_err(&listen_result) { - match result::get_err(&listen_result) { - GenericListenErr(ref name, ref msg) => { - fail!("SERVER: exited abnormally name %s msg %s", *name, *msg); - } - AccessDenied => { - fail!("SERVER: exited abnormally, got access denied.."); - } - AddressInUse => { - fail!("SERVER: exited abnormally, got address in use..."); - } - } - } - let ret_val = server_po.recv(); - debug!("SERVER: exited and got return val: '%s'", ret_val); - ret_val - } - - fn run_tcp_test_server_fail(server_ip: &str, server_port: uint, - iotask: &IoTask) -> TcpListenErrData { - let server_ip_addr = ip::v4::parse_addr(server_ip); - let listen_result = listen(server_ip_addr, server_port, 128, - iotask, - // on_establish_cb -- called when listener is set up - |kill_ch| { - debug!("establish_cb %?", kill_ch); - }, - |new_conn, kill_ch| { - fail!("SERVER: shouldn't be called.. %? %?", new_conn, kill_ch); - }); - // err check on listen_result - if result::is_err(&listen_result) { - result::get_err(&listen_result) - } - else { - fail!("SERVER: did not fail as expected") - } - } - - fn run_tcp_test_client(server_ip: &str, server_port: uint, resp: &str, - iotask: &IoTask) -> result::Result<~str, - TcpConnectErrData> { - let server_ip_addr = ip::v4::parse_addr(server_ip); - - debug!("CLIENT: starting.."); - let connect_result = connect(server_ip_addr, server_port, - iotask); - if result::is_err(&connect_result) { - debug!("CLIENT: failed to connect"); - let err_data = result::get_err(&connect_result); - Err(err_data) - } - else { - let sock = result::unwrap(connect_result); - let resp_bytes = resp.as_bytes().to_owned(); - tcp_write_single(&sock, resp_bytes); - let read_result = sock.read(0u); - if read_result.is_err() { - debug!("CLIENT: failure to read"); - Ok(~"") - } - else { - let ret_val = str::from_bytes(read_result.get()); - debug!("CLIENT: after client_ch recv ret: '%s'", - ret_val); - Ok(ret_val) - } - } - } - - fn tcp_write_single(sock: &TcpSocket, val: ~[u8]) { - let mut write_result_future = sock.write_future(val); - let write_result = write_result_future.get(); - if result::is_err(&write_result) { - debug!("tcp_write_single: write failed!"); - let err_data = result::get_err(&write_result); - debug!("tcp_write_single err name: %s msg: %s", - err_data.err_name, err_data.err_msg); - // meh. torn on what to do here. - fail!("tcp_write_single failed"); - } - } -} diff --git a/src/libextra/tempfile.rs b/src/libextra/tempfile.rs index f8948f41101e8..c5fb4b9292e34 100644 --- a/src/libextra/tempfile.rs +++ b/src/libextra/tempfile.rs @@ -48,10 +48,11 @@ mod tests { fn recursive_mkdir_rel() { use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os; + use std::unstable::change_dir_locked; let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel"). expect("recursive_mkdir_rel"); - assert!(do os::change_dir_locked(&root) { + assert!(do change_dir_locked(&root) { let path = Path("frob"); debug!("recursive_mkdir_rel: Making: %s in cwd %s [%?]", path.to_str(), os::getcwd().to_str(), @@ -78,10 +79,11 @@ mod tests { fn recursive_mkdir_rel_2() { use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use std::os; + use std::unstable::change_dir_locked; let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel_2"). expect("recursive_mkdir_rel_2"); - assert!(do os::change_dir_locked(&root) { + assert!(do change_dir_locked(&root) { let path = Path("./frob/baz"); debug!("recursive_mkdir_rel_2: Making: %s in cwd %s [%?]", path.to_str(), os::getcwd().to_str(), os::path_exists(&path)); diff --git a/src/libextra/timer.rs b/src/libextra/timer.rs deleted file mode 100644 index 1cfbeb9e514dd..0000000000000 --- a/src/libextra/timer.rs +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Utilities that leverage libuv's `uv_timer_*` API - - -use uv; -use uv::iotask; -use uv::iotask::IoTask; - -use std::cast::transmute; -use std::cast; -use std::comm::{stream, Chan, SharedChan, Port, select2i}; -use std::either; -use std::libc::c_void; -use std::libc; - -/** - * Wait for timeout period then send provided value over a channel - * - * This call returns immediately. Useful as the building block for a number - * of higher-level timer functions. - * - * Is not guaranteed to wait for exactly the specified time, but will wait - * for *at least* that period of time. - * - * # Arguments - * - * * `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on - * * msecs - a timeout period, in milliseconds, to wait - * * ch - a channel of type T to send a `val` on - * * val - a value of type T to send over the provided `ch` - */ -pub fn delayed_send(iotask: &IoTask, - msecs: uint, - ch: &Chan, - val: T) { - let (timer_done_po, timer_done_ch) = stream::<()>(); - let timer_done_ch = SharedChan::new(timer_done_ch); - let timer = uv::ll::timer_t(); - let timer_ptr: *uv::ll::uv_timer_t = &timer; - do iotask::interact(iotask) |loop_ptr| { - unsafe { - let init_result = uv::ll::timer_init(loop_ptr, timer_ptr); - if (init_result == 0i32) { - let start_result = uv::ll::timer_start( - timer_ptr, delayed_send_cb, msecs, 0u); - if (start_result == 0i32) { - // Note: putting the channel into a ~ - // to cast to *c_void - let timer_done_ch_clone = ~timer_done_ch.clone(); - let timer_done_ch_ptr = transmute::< - ~SharedChan<()>, *c_void>( - timer_done_ch_clone); - uv::ll::set_data_for_uv_handle( - timer_ptr, - timer_done_ch_ptr); - } else { - let error_msg = uv::ll::get_last_err_info( - loop_ptr); - fail!("timer::delayed_send() start failed: %s", error_msg); - } - } else { - let error_msg = uv::ll::get_last_err_info(loop_ptr); - fail!("timer::delayed_send() init failed: %s", error_msg); - } - } - }; - // delayed_send_cb has been processed by libuv - timer_done_po.recv(); - // notify the caller immediately - ch.send(val); - // uv_close for this timer has been processed - timer_done_po.recv(); -} - -/** - * Blocks the current task for (at least) the specified time period. - * - * Is not guaranteed to sleep for exactly the specified time, but will sleep - * for *at least* that period of time. - * - * # Arguments - * - * * `iotask` - a `uv::iotask` that the tcp request will run on - * * msecs - an amount of time, in milliseconds, for the current task to block - */ -pub fn sleep(iotask: &IoTask, msecs: uint) { - let (exit_po, exit_ch) = stream::<()>(); - delayed_send(iotask, msecs, &exit_ch, ()); - exit_po.recv(); -} - -/** - * Receive on a port for (up to) a specified time, then return an `Option` - * - * This call will block to receive on the provided port for up to the - * specified timeout. Depending on whether the provided port receives in that - * time period, `recv_timeout` will return an `Option` representing the - * result. - * - * # Arguments - * - * * `iotask' - `uv::iotask` that the tcp request will run on - * * msecs - an mount of time, in milliseconds, to wait to receive - * * wait_port - a `std::comm::port` to receive on - * - * # Returns - * - * An `Option` representing the outcome of the call. If the call `recv`'d - * on the provided port in the allotted timeout period, then the result will - * be a `Some(T)`. If not, then `None` will be returned. - */ -pub fn recv_timeout(iotask: &IoTask, msecs: uint, wait_po: &Port) - -> Option { - let (timeout_po, timeout_ch) = stream::<()>(); - let mut timeout_po = timeout_po; - delayed_send(iotask, msecs, &timeout_ch, ()); - - // XXX: Workaround due to ports and channels not being &mut. They should - // be. - unsafe { - let wait_po = cast::transmute_mut(wait_po); - - either::either( - |_| { - None - }, |_| { - Some(wait_po.recv()) - }, &select2i(&mut timeout_po, wait_po) - ) - } -} - -// INTERNAL API -extern fn delayed_send_cb(handle: *uv::ll::uv_timer_t, status: libc::c_int) { - unsafe { - debug!( - "delayed_send_cb handle %? status %?", handle, status); - // Faking a borrowed pointer to our ~SharedChan - let timer_done_ch_ptr: &*c_void = &uv::ll::get_data_for_uv_handle( - handle); - let timer_done_ch_ptr = transmute::<&*c_void, &~SharedChan<()>>( - timer_done_ch_ptr); - let stop_result = uv::ll::timer_stop(handle); - if (stop_result == 0i32) { - timer_done_ch_ptr.send(()); - uv::ll::close(handle, delayed_send_close_cb); - } else { - let loop_ptr = uv::ll::get_loop_for_uv_handle(handle); - let error_msg = uv::ll::get_last_err_info(loop_ptr); - fail!("timer::sleep() init failed: %s", error_msg); - } - } -} - -extern fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) { - unsafe { - debug!("delayed_send_close_cb handle %?", handle); - let timer_done_ch_ptr = uv::ll::get_data_for_uv_handle(handle); - let timer_done_ch = transmute::<*c_void, ~SharedChan<()>>( - timer_done_ch_ptr); - timer_done_ch.send(()); - } -} - -#[cfg(test)] -mod test { - - use timer::*; - use uv; - - use std::cell::Cell; - use std::pipes::{stream, SharedChan}; - use std::rand::RngUtil; - use std::rand; - use std::task; - - #[test] - fn test_gl_timer_simple_sleep_test() { - let hl_loop = &uv::global_loop::get(); - sleep(hl_loop, 1u); - } - - #[test] - fn test_gl_timer_sleep_stress1() { - let hl_loop = &uv::global_loop::get(); - for 50u.times { - sleep(hl_loop, 1u); - } - } - - #[test] - fn test_gl_timer_sleep_stress2() { - let (po, ch) = stream(); - let ch = SharedChan::new(ch); - let hl_loop = &uv::global_loop::get(); - - let repeat = 20u; - let spec = { - - ~[(1u, 20u), - (10u, 10u), - (20u, 2u)] - - }; - - for repeat.times { - let ch = ch.clone(); - for spec.iter().advance |spec| { - let (times, maxms) = *spec; - let ch = ch.clone(); - let hl_loop_clone = hl_loop.clone(); - do task::spawn { - use std::rand::*; - let mut rng = rng(); - for times.times { - sleep(&hl_loop_clone, rng.next() as uint % maxms); - } - ch.send(()); - } - } - } - - for (repeat * spec.len()).times { - po.recv() - } - } - - // Because valgrind serializes multithreaded programs it can - // make timing-sensitive tests fail in wierd ways. In these - // next test we run them many times and expect them to pass - // the majority of tries. - - #[test] - #[cfg(ignore)] - fn test_gl_timer_recv_timeout_before_time_passes() { - let times = 100; - let mut successes = 0; - let mut failures = 0; - let hl_loop = uv::global_loop::get(); - - for (times as uint).times { - task::yield(); - - let expected = rand::rng().gen_str(16u); - let (test_po, test_ch) = stream::<~str>(); - - do task::spawn() { - delayed_send(hl_loop, 1u, &test_ch, expected); - }; - - match recv_timeout(hl_loop, 10u, &test_po) { - Some(val) => { - assert_eq!(val, expected); - successes += 1; - } - _ => failures += 1 - }; - } - - assert!(successes > times / 2); - } - - #[test] - fn test_gl_timer_recv_timeout_after_time_passes() { - let times = 100; - let mut successes = 0; - let mut failures = 0; - let hl_loop = uv::global_loop::get(); - - for (times as uint).times { - let mut rng = rand::rng(); - let expected = Cell::new(rng.gen_str(16u)); - let (test_po, test_ch) = stream::<~str>(); - let hl_loop_clone = hl_loop.clone(); - do task::spawn() { - delayed_send(&hl_loop_clone, 50u, &test_ch, expected.take()); - }; - - match recv_timeout(&hl_loop, 1u, &test_po) { - None => successes += 1, - _ => failures += 1 - }; - } - - assert!(successes > times / 2); - } -} diff --git a/src/libextra/net/url.rs b/src/libextra/url.rs similarity index 99% rename from src/libextra/net/url.rs rename to src/libextra/url.rs index 307f75dc98bea..563619bb52d60 100644 --- a/src/libextra/net/url.rs +++ b/src/libextra/url.rs @@ -800,7 +800,7 @@ fn test_get_path() { #[cfg(test)] mod tests { - use net::url::*; + use super::*; use std::hashmap::HashMap; diff --git a/src/libextra/uv.rs b/src/libextra/uv.rs deleted file mode 100644 index e055b40705773..0000000000000 --- a/src/libextra/uv.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - * Rust bindings to libuv - * - * This is the base-module for various levels of bindings to - * the libuv library. - * - * These modules are seeing heavy work, currently, and the final - * API layout should not be inferred from its current form. - * - * This base module currently contains a historical, rust-based - * implementation of a few libuv operations that hews closely to - * the patterns of the libuv C-API. It was used, mostly, to explore - * some implementation details and will most likely be deprecated - * in the near future. - * - * The `ll` module contains low-level mappings for working directly - * with the libuv C-API. - * - * The `hl` module contains a set of tools library developers can - * use for interacting with an active libuv loop. This modules's - * API is meant to be used to write high-level, - * rust-idiomatic abstractions for utilizes libuv's asynchronous IO - * facilities. - */ - -pub use ll = super::uv_ll; -pub use iotask = uv_iotask; -pub use global_loop = uv_global_loop; diff --git a/src/libextra/uv_global_loop.rs b/src/libextra/uv_global_loop.rs deleted file mode 100644 index 5501d73ac8680..0000000000000 --- a/src/libextra/uv_global_loop.rs +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A process-wide libuv event loop for library use. - - -use iotask = uv_iotask; -use uv_iotask::{IoTask, spawn_iotask}; - -use std::comm::Chan; -use std::option::{Some, None}; -use std::task::task; -use std::unstable::global::{global_data_clone_create, global_data_clone}; -use std::unstable::weak_task::weaken_task; - -/** - * Race-free helper to get access to a global task where a libuv - * loop is running. - * - * Use `uv::hl::interact` to do operations against the global - * loop that this function returns. - * - * # Return - * - * * A `hl::high_level_loop` that encapsulates communication with the global - * loop. - */ -pub fn get() -> IoTask { - return get_monitor_task_gl(); -} - -#[doc(hidden)] -fn get_monitor_task_gl() -> IoTask { - - type MonChan = Chan; - - struct GlobalIoTask(IoTask); - - impl Clone for GlobalIoTask { - fn clone(&self) -> GlobalIoTask { - GlobalIoTask((**self).clone()) - } - } - - fn key(_: GlobalIoTask) { } - - match unsafe { global_data_clone(key) } { - Some(GlobalIoTask(iotask)) => iotask, - None => { - let iotask: IoTask = spawn_loop(); - let mut installed = false; - let final_iotask = unsafe { - do global_data_clone_create(key) { - installed = true; - ~GlobalIoTask(iotask.clone()) - } - }; - if installed { - let mut task = task(); - task.unlinked(); - do task.spawn { - unsafe { - debug!("global monitor task starting"); - // As a weak task the runtime will notify us - // when to exit - do weaken_task |weak_exit_po| { - debug!("global monitor task is weak"); - weak_exit_po.recv(); - iotask::exit(&iotask); - debug!("global monitor task is unweak"); - }; - debug!("global monitor task exiting"); - } - } - } else { - iotask::exit(&iotask); - } - - match final_iotask { - GlobalIoTask(iotask) => iotask - } - } - } -} - -fn spawn_loop() -> IoTask { - let mut builder = task(); - - do builder.add_wrapper |task_body| { - let result: ~fn() = || { - // The I/O loop task also needs to be weak so it doesn't keep - // the runtime alive - unsafe { - do weaken_task |_| { - debug!("global libuv task is now weak"); - task_body(); - - // We don't wait for the exit message on weak_exit_po - // because the monitor task will tell the uv loop when to - // exit - - debug!("global libuv task is leaving weakened state"); - } - } - }; - result - }; - - builder.unlinked(); - spawn_iotask(builder) -} - -#[cfg(test)] -mod test { - - use get_gl = uv_global_loop::get; - use uv::iotask; - use uv::ll; - use uv_iotask::IoTask; - - use std::libc; - use std::task; - use std::cast::transmute; - use std::libc::c_void; - use std::comm::{stream, SharedChan, Chan}; - - extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) { - unsafe { - let exit_ch_ptr = ll::get_data_for_uv_handle( - timer_ptr as *libc::c_void); - let exit_ch = transmute::<*c_void, ~Chan>(exit_ch_ptr); - exit_ch.send(true); - debug!("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?", - exit_ch_ptr); - } - } - extern fn simple_timer_cb(timer_ptr: *ll::uv_timer_t, - _status: libc::c_int) { - unsafe { - debug!(~"in simple timer cb"); - ll::timer_stop(timer_ptr); - let hl_loop = &get_gl(); - do iotask::interact(hl_loop) |_loop_ptr| { - debug!(~"closing timer"); - ll::close(timer_ptr, simple_timer_close_cb); - debug!(~"about to deref exit_ch_ptr"); - debug!(~"after msg sent on deref'd exit_ch"); - }; - debug!(~"exiting simple timer cb"); - } - } - - fn impl_uv_hl_simple_timer(iotask: &IoTask) { - unsafe { - let (exit_po, exit_ch) = stream::(); - let exit_ch_ptr: *libc::c_void = transmute(~exit_ch); - debug!("EXIT_CH_PTR newly created exit_ch_ptr: %?", - exit_ch_ptr); - let timer_handle = ll::timer_t(); - let timer_ptr: *ll::uv_timer_t = &timer_handle; - do iotask::interact(iotask) |loop_ptr| { - debug!(~"user code inside interact loop!!!"); - let init_status = ll::timer_init(loop_ptr, timer_ptr); - if(init_status == 0i32) { - ll::set_data_for_uv_handle( - timer_ptr as *libc::c_void, - exit_ch_ptr); - let start_status = ll::timer_start(timer_ptr, - simple_timer_cb, - 1u, 0u); - if(start_status != 0i32) { - fail!("failure on ll::timer_start()"); - } - } - else { - fail!("failure on ll::timer_init()"); - } - }; - exit_po.recv(); - debug!( - ~"global_loop timer test: msg recv on exit_po, done.."); - } - } - - #[test] - fn test_gl_uv_global_loop_high_level_global_timer() { - let hl_loop = &get_gl(); - let (exit_po, exit_ch) = stream::<()>(); - task::spawn_sched(task::ManualThreads(1u), || { - let hl_loop = &get_gl(); - impl_uv_hl_simple_timer(hl_loop); - exit_ch.send(()); - }); - impl_uv_hl_simple_timer(hl_loop); - exit_po.recv(); - } - - // keeping this test ignored until some kind of stress-test-harness - // is set up for the build bots - #[test] - #[ignore] - fn test_stress_gl_uv_global_loop_high_level_global_timer() { - let (exit_po, exit_ch) = stream::<()>(); - let exit_ch = SharedChan::new(exit_ch); - let cycles = 5000u; - for cycles.times { - let exit_ch_clone = exit_ch.clone(); - task::spawn_sched(task::ManualThreads(1u), || { - let hl_loop = &get_gl(); - impl_uv_hl_simple_timer(hl_loop); - exit_ch_clone.send(()); - }); - }; - for cycles.times { - exit_po.recv(); - }; - debug!("test_stress_gl_uv_global_loop_high_level_global_timer \ - exiting successfully!"); - } -} diff --git a/src/libextra/uv_iotask.rs b/src/libextra/uv_iotask.rs deleted file mode 100644 index 0a564045d32f0..0000000000000 --- a/src/libextra/uv_iotask.rs +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - * A task-based interface to the uv loop - * - * The I/O task runs in its own single-threaded scheduler. By using the - * `interact` function you can execute code in a uv callback. - */ - -#[allow(missing_doc)]; - - -use ll = uv_ll; - -use std::comm::{stream, Port, Chan, SharedChan}; -use std::libc::c_void; -use std::libc; -use std::task; - -/// Used to abstract-away direct interaction with a libuv loop. -pub struct IoTask { - async_handle: *ll::uv_async_t, - op_chan: SharedChan -} - -impl Clone for IoTask { - fn clone(&self) -> IoTask { - IoTask{ - async_handle: self.async_handle, - op_chan: self.op_chan.clone() - } - } -} - -pub fn spawn_iotask(mut task: task::TaskBuilder) -> IoTask { - let (iotask_port, iotask_chan) = stream(); - - task.sched_mode(task::SingleThreaded); - do task.spawn { - debug!("entering libuv task"); - run_loop(&iotask_chan); - debug!("libuv task exiting"); - }; - - iotask_port.recv() -} - - -/** - * Provide a callback to be processed by `iotask` - * - * The primary way to do operations again a running `iotask` that - * doesn't involve creating a uv handle via `safe_handle` - * - * # Warning - * - * This function is the only safe way to interact with _any_ `iotask`. - * Using functions in the `uv::ll` module outside of the `cb` passed into - * this function is _very dangerous_. - * - * # Arguments - * - * * iotask - a uv I/O task that you want to do operations against - * * cb - a function callback to be processed on the running loop's - * thread. The only parameter passed in is an opaque pointer representing the - * running `uv_loop_t*`. In the context of this callback, it is safe to use - * this pointer to do various uv_* API calls contained within the `uv::ll` - * module. It is not safe to send the `loop_ptr` param to this callback out - * via ports/chans. - */ -pub fn interact(iotask: &IoTask, cb: ~fn(*c_void)) { - send_msg(iotask, Interaction(cb)); -} - -/** - * Shut down the I/O task - * - * Is used to signal to the loop that it should close the internally-held - * async handle and do a sanity check to make sure that all other handles are - * closed, causing a failure otherwise. - */ -pub fn exit(iotask: &IoTask) { - send_msg(iotask, TeardownLoop); -} - - -// INTERNAL API - -enum IoTaskMsg { - Interaction(~fn(*libc::c_void)), - TeardownLoop -} - -/// Run the loop and begin handling messages -fn run_loop(iotask_ch: &Chan) { - - unsafe { - debug!("creating loop"); - let loop_ptr = ll::loop_new(); - - // set up the special async handle we'll use to allow multi-task - // communication with this loop - let async = ll::async_t(); - let async_handle: *ll::uv_async_t = &async; - - // associate the async handle with the loop - ll::async_init(loop_ptr, async_handle, wake_up_cb); - - let (msg_po, msg_ch) = stream::(); - - // initialize our loop data and store it in the loop - let data: IoTaskLoopData = IoTaskLoopData { - async_handle: async_handle, - msg_po: msg_po - }; - ll::set_data_for_uv_handle(async_handle, &data); - - // Send out a handle through which folks can talk to us - // while we dwell in the I/O loop - let iotask = IoTask { - async_handle: async_handle, - op_chan: SharedChan::new(msg_ch) - }; - iotask_ch.send(iotask); - - debug!("about to run uv loop"); - // enter the loop... this blocks until the loop is done.. - ll::run(loop_ptr); - debug!("uv loop ended"); - ll::loop_delete(loop_ptr); - } -} - -// data that lives for the lifetime of the high-evel oo -struct IoTaskLoopData { - async_handle: *ll::uv_async_t, - msg_po: Port, -} - -fn send_msg(iotask: &IoTask, - msg: IoTaskMsg) { - iotask.op_chan.send(msg); - unsafe { - ll::async_send(iotask.async_handle); - } -} - -/// Dispatch all pending messages -extern fn wake_up_cb(async_handle: *ll::uv_async_t, - status: int) { - - debug!("wake_up_cb extern.. handle: %? status: %?", - async_handle, status); - - unsafe { - let loop_ptr = ll::get_loop_for_uv_handle(async_handle); - let data = - ll::get_data_for_uv_handle(async_handle) as *IoTaskLoopData; - let msg_po = &(*data).msg_po; - - while msg_po.peek() { - match msg_po.recv() { - Interaction(ref cb) => (*cb)(loop_ptr), - TeardownLoop => begin_teardown(data) - } - } - } -} - -fn begin_teardown(data: *IoTaskLoopData) { - unsafe { - debug!("iotask begin_teardown() called, close async_handle"); - let async_handle = (*data).async_handle; - ll::close(async_handle as *c_void, tear_down_close_cb); - } -} -extern fn tear_down_walk_cb(handle: *libc::c_void, arg: *libc::c_void) { - debug!("IN TEARDOWN WALK CB"); - // pretty much, if we still have an active handle and it is *not* - // the async handle that facilities global loop communication, we - // want to barf out and fail - assert_eq!(handle, arg); -} - -extern fn tear_down_close_cb(handle: *ll::uv_async_t) { - unsafe { - let loop_ptr = ll::get_loop_for_uv_handle(handle); - debug!("in tear_down_close_cb"); - ll::walk(loop_ptr, tear_down_walk_cb, handle as *libc::c_void); - } -} - -#[cfg(test)] -extern fn async_close_cb(handle: *ll::uv_async_t) { - unsafe { - debug!("async_close_cb handle %?", handle); - let exit_ch = &(*(ll::get_data_for_uv_handle(handle) - as *AhData)).exit_ch; - let exit_ch = exit_ch.clone(); - exit_ch.send(()); - } -} - -#[cfg(test)] -extern fn async_handle_cb(handle: *ll::uv_async_t, status: libc::c_int) { - unsafe { - debug!("async_handle_cb handle %? status %?",handle,status); - ll::close(handle, async_close_cb); - } -} - -#[cfg(test)] -struct AhData { - iotask: IoTask, - exit_ch: SharedChan<()> -} - -#[cfg(test)] -fn impl_uv_iotask_async(iotask: &IoTask) { - use std::ptr; - - let async_handle = ll::async_t(); - let ah_ptr: *ll::uv_async_t = &async_handle; - let (exit_po, exit_ch) = stream::<()>(); - let ah_data = AhData { - iotask: iotask.clone(), - exit_ch: SharedChan::new(exit_ch) - }; - let ah_data_ptr: *AhData = ptr::to_unsafe_ptr(&ah_data); - debug!("about to interact"); - do interact(iotask) |loop_ptr| { - unsafe { - debug!("interacting"); - ll::async_init(loop_ptr, ah_ptr, async_handle_cb); - ll::set_data_for_uv_handle( - ah_ptr, ah_data_ptr as *libc::c_void); - ll::async_send(ah_ptr); - } - }; - debug!("waiting for async close"); - exit_po.recv(); -} - -// this fn documents the bear minimum necessary to roll your own -// high_level_loop -#[cfg(test)] -fn spawn_test_loop(exit_ch: ~Chan<()>) -> IoTask { - let (iotask_port, iotask_ch) = stream::(); - do task::spawn_sched(task::ManualThreads(1u)) { - debug!("about to run a test loop"); - run_loop(&iotask_ch); - exit_ch.send(()); - }; - return iotask_port.recv(); -} - -#[cfg(test)] -extern fn lifetime_handle_close(handle: *libc::c_void) { - debug!("lifetime_handle_close ptr %?", handle); -} - -#[cfg(test)] -extern fn lifetime_async_callback(handle: *libc::c_void, - status: libc::c_int) { - debug!("lifetime_handle_close ptr %? status %?", - handle, status); -} - -#[test] -fn test_uv_iotask_async() { - let (exit_po, exit_ch) = stream::<()>(); - let iotask = &spawn_test_loop(~exit_ch); - - debug!("spawned iotask"); - - // using this handle to manage the lifetime of the - // high_level_loop, as it will exit the first time one of - // the impl_uv_hl_async() is cleaned up with no one ref'd - // handles on the loop (Which can happen under - // race-condition type situations.. this ensures that the - // loop lives until, at least, all of the - // impl_uv_hl_async() runs have been called, at least. - let (work_exit_po, work_exit_ch) = stream::<()>(); - let work_exit_ch = SharedChan::new(work_exit_ch); - for 7u.times { - let iotask_clone = iotask.clone(); - let work_exit_ch_clone = work_exit_ch.clone(); - do task::spawn_sched(task::ManualThreads(1u)) { - debug!("async"); - impl_uv_iotask_async(&iotask_clone); - debug!("done async"); - work_exit_ch_clone.send(()); - }; - }; - for 7u.times { - debug!("waiting"); - work_exit_po.recv(); - }; - debug!(~"sending teardown_loop msg.."); - exit(iotask); - exit_po.recv(); - debug!(~"after recv on exit_po.. exiting.."); -} diff --git a/src/libextra/uv_ll.rs b/src/libextra/uv_ll.rs deleted file mode 100644 index 1527b090f94c8..0000000000000 --- a/src/libextra/uv_ll.rs +++ /dev/null @@ -1,1928 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - * Low-level bindings to the libuv library. - * - * This module contains a set of direct, 'bare-metal' wrappers around - * the libuv C-API. - * - * Also contained herein are a set of rust records that map, in - * approximate memory-size, to the libuv data structures. The record - * implementations are adjusted, per-platform, to match their respective - * representations. - * - * There are also a collection of helper functions to ease interacting - * with the low-level API (such as a function to return the latest - * libuv error as a rust-formatted string). - * - * As new functionality, existant in uv.h, is added to the rust stdlib, - * the mappings should be added in this module. - * - * This module's implementation will hopefully be, eventually, replaced - * with per-platform, generated source files from rust-bindgen. - */ - -#[allow(non_camel_case_types)]; // C types -#[allow(missing_doc)]; - - -use std::libc::{c_void, size_t}; -use std::libc; -use std::ptr::to_unsafe_ptr; -use std::ptr; -use std::str; -use std::vec; - -pub type uv_handle_t = c_void; -pub type uv_loop_t = c_void; -pub type uv_idle_t = c_void; -pub type uv_idle_cb = *u8; - -// libuv struct mappings -pub struct uv_ip4_addr { - ip: ~[u8], - port: int, -} -pub type uv_ip6_addr = uv_ip4_addr; - -pub enum uv_handle_type { - UNKNOWN_HANDLE = 0, - UV_TCP, - UV_UDP, - UV_NAMED_PIPE, - UV_TTY, - UV_FILE, - UV_TIMER, - UV_PREPARE, - UV_CHECK, - UV_IDLE, - UV_ASYNC, - UV_ARES_TASK, - UV_ARES_EVENT, - UV_PROCESS, - UV_FS_EVENT -} - -pub type handle_type = libc::c_uint; - -pub struct uv_handle_fields { - loop_handle: *libc::c_void, - type_: handle_type, - close_cb: *u8, - data: *libc::c_void, -} - -// unix size: 8 -pub struct uv_err_t { - code: libc::c_int, - sys_errno_: libc::c_int -} - -// don't create one of these directly. instead, -// count on it appearing in libuv callbacks or embedded -// in other types as a pointer to be used in other -// operations (so mostly treat it as opaque, once you -// have it in this form..) -pub struct uv_stream_t { - fields: uv_handle_fields, -} - -// 64bit unix size: 216 -#[cfg(target_os="macos")] -pub struct uv_tcp_t { - fields: uv_handle_fields, - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8, - a08: *u8, a09: *u8, a10: *u8, a11: *u8, - a12: *u8, a13: *u8, a14: *u8, a15: *u8, - a16: *u8, a17: *u8, a18: *u8, a19: *u8, - a20: *u8, a21: *u8, a22: *u8, - a23: uv_tcp_t_osx_riders -} -#[cfg(target_arch="x86_64")] -pub struct uv_tcp_t_osx_riders { - a23: *u8, -} -#[cfg(target_arch="x86")] -#[cfg(target_arch="arm")] -pub struct uv_tcp_t_osx_riders { - a23: *u8, - a24: *u8, a25: *u8, -} -#[cfg(target_os="linux")] -#[cfg(target_os="freebsd")] -#[cfg(target_os="android")] -pub struct uv_tcp_t { - fields: uv_handle_fields, - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8, - a08: *u8, a09: *u8, a10: *u8, a11: *u8, - a12: *u8, a13: *u8, a14: *u8, a15: *u8, - a16: *u8, a17: *u8, a18: *u8, a19: *u8, - a20: *u8, a21: *u8, - a22: uv_tcp_t_32bit_unix_riders, -} -// 32bit unix size: 328 (164) -#[cfg(target_arch="x86_64")] -pub struct uv_tcp_t_32bit_unix_riders { - a29: *u8, -} -#[cfg(target_arch="x86")] -#[cfg(target_arch="arm")] -#[cfg(target_arch="mips")] -pub struct uv_tcp_t_32bit_unix_riders { - a29: *u8, a30: *u8, a31: *u8, -} - -// 32bit win32 size: 240 (120) -#[cfg(windows)] -pub struct uv_tcp_t { - fields: uv_handle_fields, - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8, - a08: *u8, a09: *u8, a10: *u8, a11: *u8, - a12: *u8, a13: *u8, a14: *u8, a15: *u8, - a16: *u8, a17: *u8, a18: *u8, a19: *u8, - a20: *u8, a21: *u8, a22: *u8, a23: *u8, - a24: *u8, a25: *u8, -} - -// unix size: 64 -#[cfg(unix)] -pub struct uv_connect_t { - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8 -} -// win32 size: 88 (44) -#[cfg(windows)] -pub struct uv_connect_t { - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8, - a08: *u8, a09: *u8, a10: *u8, -} - -// unix size: 16 -pub struct uv_buf_t { - base: *u8, - len: libc::size_t, -} -// no gen stub method.. should create -// it via uv::direct::buf_init() - -// unix size: 160 -#[cfg(unix)] -pub struct uv_write_t { - fields: uv_handle_fields, - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8, - a08: *u8, a09: *u8, a10: *u8, a11: *u8, - a12: *u8, - a14: uv_write_t_32bit_unix_riders, -} -#[cfg(target_arch="x86_64")] -pub struct uv_write_t_32bit_unix_riders { - a13: *u8, a14: *u8, a15: *u8 -} -#[cfg(target_arch="x86")] -#[cfg(target_arch="arm")] -#[cfg(target_arch="mips")] -pub struct uv_write_t_32bit_unix_riders { - a13: *u8, a14: *u8, a15: *u8, - a16: *u8, -} -// win32 size: 136 (68) -#[cfg(windows)] -pub struct uv_write_t { - fields: uv_handle_fields, - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8, - a08: *u8, a09: *u8, a10: *u8, a11: *u8, - a12: *u8, -} -// 64bit unix size: 96 -// 32bit unix size: 152 (76) -#[cfg(unix)] -pub struct uv_async_t { - fields: uv_handle_fields, - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, - a07: uv_async_t_32bit_unix_riders, -} -#[cfg(target_arch="x86_64")] -pub struct uv_async_t_32bit_unix_riders { - a10: *u8, -} -#[cfg(target_arch="x86")] -#[cfg(target_arch="arm")] -#[cfg(target_arch="mips")] -pub struct uv_async_t_32bit_unix_riders { - a10: *u8, -} -// win32 size 132 (68) -#[cfg(windows)] -pub struct uv_async_t { - fields: uv_handle_fields, - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8, - a08: *u8, a09: *u8, a10: *u8, a11: *u8, - a12: *u8, -} - -// 64bit unix size: 120 -// 32bit unix size: 84 -#[cfg(unix)] -pub struct uv_timer_t { - fields: uv_handle_fields, - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8, - a08: *u8, a09: *u8, - a11: uv_timer_t_32bit_unix_riders, -} -#[cfg(target_arch="x86_64")] -pub struct uv_timer_t_32bit_unix_riders { - a10: *u8, -} -#[cfg(target_arch="x86")] -#[cfg(target_arch="arm")] -#[cfg(target_arch="mips")] -pub struct uv_timer_t_32bit_unix_riders { - a10: *u8, a11: *u8, a12: *u8 -} -// win32 size: 64 -#[cfg(windows)] -pub struct uv_timer_t { - fields: uv_handle_fields, - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8, - a08: *u8, a09: *u8, a10: *u8, a11: *u8, -} - -// unix size: 16 -#[deriving(Clone)] -pub struct sockaddr_in { - sin_family: u16, - sin_port: u16, - sin_addr: u32, // in_addr: this is an opaque, per-platform struct - sin_zero: (u8, u8, u8, u8, u8, u8, u8, u8), -} - -// unix size: 28 .. FIXME #1645 -// stuck with 32 because of rust padding structs? -#[cfg(target_arch="x86_64")] -pub struct sockaddr_in6 { - a0: *u8, a1: *u8, - a2: *u8, a3: *u8, -} - -#[cfg(target_arch="x86")] -#[cfg(target_arch="arm")] -#[cfg(target_arch="mips")] -pub struct sockaddr_in6 { - a0: *u8, a1: *u8, - a2: *u8, a3: *u8, - a4: *u8, a5: *u8, - a6: *u8, a7: *u8, -} - -impl Clone for sockaddr_in6 { - fn clone(&self) -> sockaddr_in6 { - *self - } -} - -// unix size: 28 .. FIXME #1645 -// stuck with 32 because of rust padding structs? -pub type addr_in = addr_in_impl::addr_in; -#[cfg(unix)] -pub mod addr_in_impl { - #[cfg(target_arch="x86_64")] - pub struct addr_in { - a0: *u8, a1: *u8, - a2: *u8, a3: *u8, - } - #[cfg(target_arch="x86")] - #[cfg(target_arch="arm")] - #[cfg(target_arch="mips")] - pub struct addr_in { - a0: *u8, a1: *u8, - a2: *u8, a3: *u8, - a4: *u8, a5: *u8, - a6: *u8, a7: *u8, - } -} -#[cfg(windows)] -pub mod addr_in_impl { - pub struct addr_in { - a0: *u8, a1: *u8, - a2: *u8, a3: *u8, - } -} - -// unix size: 48, 32bit: 32 -pub type addrinfo = addrinfo_impl::addrinfo; -#[cfg(target_os="linux")] -#[cfg(target_os="android")] -pub mod addrinfo_impl { - #[cfg(target_arch="x86_64")] - pub struct addrinfo { - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, - } - #[cfg(target_arch="x86")] - #[cfg(target_arch="arm")] - #[cfg(target_arch="mips")] - pub struct addrinfo { - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, a06: *u8, a07: *u8, - } -} -#[cfg(target_os="macos")] -#[cfg(target_os="freebsd")] -pub mod addrinfo_impl { - pub struct addrinfo { - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, - } -} -#[cfg(windows)] -pub mod addrinfo_impl { - pub struct addrinfo { - a00: *u8, a01: *u8, a02: *u8, a03: *u8, - a04: *u8, a05: *u8, - } -} - -// unix size: 72 -pub struct uv_getaddrinfo_t { - a00: *u8, a01: *u8, a02: *u8, a03: *u8, a04: *u8, a05: *u8, - a06: *u8, a07: *u8, a08: *u8, a09: *u8, - a10: *u8, a11: *u8, a12: *u8, a13: *u8, a14: *u8, a15: *u8 -} - -pub mod uv_ll_struct_stubgen { - - use std::ptr; - - use super::{ - uv_async_t, - uv_connect_t, - uv_getaddrinfo_t, - uv_handle_fields, - uv_tcp_t, - uv_timer_t, - uv_write_t, - }; - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - use super::{ - uv_async_t_32bit_unix_riders, - uv_timer_t_32bit_unix_riders, - uv_write_t_32bit_unix_riders, - }; - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - #[cfg(target_os = "freebsd")] - use super::uv_tcp_t_32bit_unix_riders; - - pub fn gen_stub_uv_tcp_t() -> uv_tcp_t { - return gen_stub_os(); - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - #[cfg(target_os = "freebsd")] - pub fn gen_stub_os() -> uv_tcp_t { - return gen_stub_arch(); - #[cfg(target_arch="x86_64")] - pub fn gen_stub_arch() -> uv_tcp_t { - uv_tcp_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - a11: 0 as *u8, - a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8, - a15: 0 as *u8, - a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8, - a19: 0 as *u8, - a20: 0 as *u8, a21: 0 as *u8, - a22: uv_tcp_t_32bit_unix_riders { a29: 0 as *u8 }, - } - } - #[cfg(target_arch="x86")] - #[cfg(target_arch="arm")] - #[cfg(target_arch="mips")] - pub fn gen_stub_arch() -> uv_tcp_t { - uv_tcp_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - a11: 0 as *u8, - a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8, - a15: 0 as *u8, - a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8, - a19: 0 as *u8, - a20: 0 as *u8, a21: 0 as *u8, - a22: uv_tcp_t_32bit_unix_riders { - a29: 0 as *u8, a30: 0 as *u8, a31: 0 as *u8, - }, - } - } - } - #[cfg(windows)] - pub fn gen_stub_os() -> uv_tcp_t { - uv_tcp_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - a11: 0 as *u8, - a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8, - a15: 0 as *u8, - a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8, - a19: 0 as *u8, - a20: 0 as *u8, a21: 0 as *u8, a22: 0 as *u8, - a23: 0 as *u8, - a24: 0 as *u8, a25: 0 as *u8, - } - } - #[cfg(target_os = "macos")] - pub fn gen_stub_os() -> uv_tcp_t { - use super::uv_tcp_t_osx_riders; - - return gen_stub_arch(); - - #[cfg(target_arch = "x86_64")] - fn gen_stub_arch() -> uv_tcp_t { - uv_tcp_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - a11: 0 as *u8, - a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8, - a15: 0 as *u8, - a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8, - a19: 0 as *u8, - a20: 0 as *u8, a21: 0 as *u8, a22: 0 as *u8, - a23: uv_tcp_t_osx_riders { - a23: 0 as *u8, - } - } - } - - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "arm")] - fn gen_stub_arch() -> uv_tcp_t { - uv_tcp_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - a11: 0 as *u8, - a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8, - a15: 0 as *u8, - a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8, - a19: 0 as *u8, - a20: 0 as *u8, a21: 0 as *u8, a22: 0 as *u8, - a23: uv_tcp_t_osx_riders { - a23: 0 as *u8, - a24: 0 as *u8, a25: 0 as *u8, - } - } - } - } - } - #[cfg(unix)] - pub fn gen_stub_uv_connect_t() -> uv_connect_t { - uv_connect_t { - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8 - } - } - #[cfg(windows)] - pub fn gen_stub_uv_connect_t() -> uv_connect_t { - uv_connect_t { - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - } - } - #[cfg(unix)] - pub fn gen_stub_uv_async_t() -> uv_async_t { - return gen_stub_arch(); - #[cfg(target_arch = "x86_64")] - pub fn gen_stub_arch() -> uv_async_t { - uv_async_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: uv_async_t_32bit_unix_riders { a10: 0 as *u8 }, - } - } - #[cfg(target_arch = "x86")] - #[cfg(target_arch="arm")] - #[cfg(target_arch="mips")] - pub fn gen_stub_arch() -> uv_async_t { - uv_async_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: uv_async_t_32bit_unix_riders { - a10: 0 as *u8, - } - } - } - } - #[cfg(windows)] - pub fn gen_stub_uv_async_t() -> uv_async_t { - uv_async_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - a11: 0 as *u8, - a12: 0 as *u8, - } - } - #[cfg(unix)] - pub fn gen_stub_uv_timer_t() -> uv_timer_t { - return gen_stub_arch(); - #[cfg(target_arch = "x86_64")] - pub fn gen_stub_arch() -> uv_timer_t { - uv_timer_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, - a11: uv_timer_t_32bit_unix_riders { - a10: 0 as *u8 - }, - } - } - #[cfg(target_arch = "x86")] - #[cfg(target_arch="arm")] - #[cfg(target_arch="mips")] - pub fn gen_stub_arch() -> uv_timer_t { - uv_timer_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, - a11: uv_timer_t_32bit_unix_riders { - a10: 0 as *u8, a11: 0 as *u8, - a12: 0 as *u8, - }, - } - } - } - #[cfg(windows)] - pub fn gen_stub_uv_timer_t() -> uv_timer_t { - uv_timer_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - a11: 0 as *u8, - } - } - #[cfg(unix)] - pub fn gen_stub_uv_write_t() -> uv_write_t { - return gen_stub_arch(); - #[cfg(target_arch="x86_64")] - pub fn gen_stub_arch() -> uv_write_t { - uv_write_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - a11: 0 as *u8, - a12: 0 as *u8, - a14: uv_write_t_32bit_unix_riders { a13: 0 as *u8, - a14: 0 as *u8, - a15: 0 as *u8}, - } - } - #[cfg(target_arch="x86")] - #[cfg(target_arch="arm")] - #[cfg(target_arch="mips")] - pub fn gen_stub_arch() -> uv_write_t { - uv_write_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - a11: 0 as *u8, - a12: 0 as *u8, - a14: uv_write_t_32bit_unix_riders { - a13: 0 as *u8, - a14: 0 as *u8, - a15: 0 as *u8, - a16: 0 as *u8, - } - } - } - } - #[cfg(windows)] - pub fn gen_stub_uv_write_t() -> uv_write_t { - uv_write_t { - fields: uv_handle_fields { - loop_handle: ptr::null(), type_: 0u32, - close_cb: ptr::null(), - data: ptr::null(), - }, - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, - a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, - a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8, - a11: 0 as *u8, - a12: 0 as *u8 - } - } - pub fn gen_stub_uv_getaddrinfo_t() -> uv_getaddrinfo_t { - uv_getaddrinfo_t { - a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, a03: 0 as *u8, - a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, a07: 0 as *u8, - a08: 0 as *u8, a09: 0 as *u8, - a10: 1 as *u8, a11: 1 as *u8, a12: 1 as *u8, a13: 1 as *u8, - a14: 1 as *u8, a15: 1 as *u8 - } - } -} - -#[nolink] -extern { - // libuv public API - unsafe fn rust_uv_loop_new() -> *libc::c_void; - unsafe fn rust_uv_loop_delete(lp: *libc::c_void); - unsafe fn rust_uv_run(loop_handle: *libc::c_void); - unsafe fn rust_uv_close(handle: *libc::c_void, cb: *u8); - unsafe fn rust_uv_walk(loop_handle: *libc::c_void, cb: *u8, - arg: *libc::c_void); - - unsafe fn rust_uv_idle_new() -> *uv_idle_t; - unsafe fn rust_uv_idle_delete(handle: *uv_idle_t); - unsafe fn rust_uv_idle_init(loop_handle: *uv_loop_t, - handle: *uv_idle_t) -> libc::c_int; - unsafe fn rust_uv_idle_start(handle: *uv_idle_t, - cb: uv_idle_cb) -> libc::c_int; - unsafe fn rust_uv_idle_stop(handle: *uv_idle_t) -> libc::c_int; - - unsafe fn rust_uv_async_send(handle: *uv_async_t); - unsafe fn rust_uv_async_init(loop_handle: *libc::c_void, - async_handle: *uv_async_t, - cb: *u8) -> libc::c_int; - unsafe fn rust_uv_tcp_init( - loop_handle: *libc::c_void, - handle_ptr: *uv_tcp_t) -> libc::c_int; - // FIXME ref #2604 .. ? - unsafe fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, - len: libc::size_t); - unsafe fn rust_uv_last_error(loop_handle: *libc::c_void) -> uv_err_t; - // FIXME ref #2064 - unsafe fn rust_uv_strerror(err: *uv_err_t) -> *libc::c_char; - // FIXME ref #2064 - unsafe fn rust_uv_err_name(err: *uv_err_t) -> *libc::c_char; - unsafe fn rust_uv_ip4_addr(ip: *u8, port: libc::c_int) - -> sockaddr_in; - unsafe fn rust_uv_ip6_addr(ip: *u8, port: libc::c_int) - -> sockaddr_in6; - unsafe fn rust_uv_ip4_name(src: *sockaddr_in, - dst: *u8, - size: libc::size_t) - -> libc::c_int; - unsafe fn rust_uv_ip6_name(src: *sockaddr_in6, - dst: *u8, - size: libc::size_t) - -> libc::c_int; - unsafe fn rust_uv_ip4_port(src: *sockaddr_in) -> libc::c_uint; - unsafe fn rust_uv_ip6_port(src: *sockaddr_in6) -> libc::c_uint; - // FIXME ref #2064 - unsafe fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - after_cb: *u8, - addr: *sockaddr_in) - -> libc::c_int; - // FIXME ref #2064 - unsafe fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, - addr: *sockaddr_in) -> libc::c_int; - // FIXME ref #2064 - unsafe fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - after_cb: *u8, - addr: *sockaddr_in6) -> libc::c_int; - // FIXME ref #2064 - unsafe fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, - addr: *sockaddr_in6) -> libc::c_int; - unsafe fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, - name: *sockaddr_in) -> libc::c_int; - unsafe fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, - name: *sockaddr_in6) ->libc::c_int; - unsafe fn rust_uv_listen(stream: *libc::c_void, - backlog: libc::c_int, - cb: *u8) -> libc::c_int; - unsafe fn rust_uv_accept(server: *libc::c_void, client: *libc::c_void) - -> libc::c_int; - unsafe fn rust_uv_write(req: *libc::c_void, - stream: *libc::c_void, - buf_in: *uv_buf_t, - buf_cnt: libc::c_int, - cb: *u8) - -> libc::c_int; - unsafe fn rust_uv_read_start(stream: *libc::c_void, - on_alloc: *u8, - on_read: *u8) - -> libc::c_int; - unsafe fn rust_uv_read_stop(stream: *libc::c_void) -> libc::c_int; - unsafe fn rust_uv_timer_init(loop_handle: *libc::c_void, - timer_handle: *uv_timer_t) - -> libc::c_int; - unsafe fn rust_uv_timer_start( - timer_handle: *uv_timer_t, - cb: *u8, - timeout: libc::uint64_t, - repeat: libc::uint64_t) -> libc::c_int; - unsafe fn rust_uv_timer_stop(handle: *uv_timer_t) -> libc::c_int; - - unsafe fn rust_uv_getaddrinfo(loop_ptr: *libc::c_void, - handle: *uv_getaddrinfo_t, - cb: *u8, - node_name_ptr: *u8, - service_name_ptr: *u8, - // should probably only pass ptr::null() - hints: *addrinfo) - -> libc::c_int; - unsafe fn rust_uv_freeaddrinfo(res: *addrinfo); - - // data accessors/helpers for rust-mapped uv structs - unsafe fn rust_uv_helper_get_INADDR_NONE() -> u32; - unsafe fn rust_uv_is_ipv4_addrinfo(input: *addrinfo) -> bool; - unsafe fn rust_uv_is_ipv6_addrinfo(input: *addrinfo) -> bool; - unsafe fn rust_uv_get_next_addrinfo(input: *addrinfo) -> *addrinfo; - unsafe fn rust_uv_addrinfo_as_sockaddr_in(input: *addrinfo) - -> *sockaddr_in; - unsafe fn rust_uv_addrinfo_as_sockaddr_in6(input: *addrinfo) - -> *sockaddr_in6; - unsafe fn rust_uv_malloc_buf_base_of(sug_size: libc::size_t) -> *u8; - unsafe fn rust_uv_free_base_of_buf(buf: uv_buf_t); - unsafe fn rust_uv_get_stream_handle_from_connect_req( - connect_req: *uv_connect_t) - -> *uv_stream_t; - unsafe fn rust_uv_get_stream_handle_from_write_req( - write_req: *uv_write_t) - -> *uv_stream_t; - unsafe fn rust_uv_get_loop_for_uv_handle(handle: *libc::c_void) - -> *libc::c_void; - unsafe fn rust_uv_get_data_for_uv_loop(loop_ptr: *libc::c_void) - -> *libc::c_void; - unsafe fn rust_uv_set_data_for_uv_loop(loop_ptr: *libc::c_void, - data: *libc::c_void); - unsafe fn rust_uv_get_data_for_uv_handle(handle: *libc::c_void) - -> *libc::c_void; - unsafe fn rust_uv_set_data_for_uv_handle(handle: *libc::c_void, - data: *libc::c_void); - unsafe fn rust_uv_get_data_for_req(req: *libc::c_void) - -> *libc::c_void; - unsafe fn rust_uv_set_data_for_req(req: *libc::c_void, - data: *libc::c_void); - unsafe fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8; - unsafe fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> libc::size_t; - - // sizeof testing helpers - unsafe fn rust_uv_helper_uv_tcp_t_size() -> libc::c_uint; - unsafe fn rust_uv_helper_uv_connect_t_size() -> libc::c_uint; - unsafe fn rust_uv_helper_uv_buf_t_size() -> libc::c_uint; - unsafe fn rust_uv_helper_uv_write_t_size() -> libc::c_uint; - unsafe fn rust_uv_helper_uv_err_t_size() -> libc::c_uint; - unsafe fn rust_uv_helper_sockaddr_in_size() -> libc::c_uint; - unsafe fn rust_uv_helper_sockaddr_in6_size() -> libc::c_uint; - unsafe fn rust_uv_helper_uv_async_t_size() -> libc::c_uint; - unsafe fn rust_uv_helper_uv_timer_t_size() -> libc::c_uint; - unsafe fn rust_uv_helper_uv_getaddrinfo_t_size() -> libc::c_uint; - unsafe fn rust_uv_helper_addrinfo_size() -> libc::c_uint; - unsafe fn rust_uv_helper_addr_in_size() -> libc::c_uint; -} - -pub unsafe fn loop_new() -> *libc::c_void { - return rust_uv_loop_new(); -} - -pub unsafe fn loop_delete(loop_handle: *libc::c_void) { - rust_uv_loop_delete(loop_handle); -} - -pub unsafe fn run(loop_handle: *libc::c_void) { - rust_uv_run(loop_handle); -} - -pub unsafe fn close(handle: *T, cb: *u8) { - rust_uv_close(handle as *libc::c_void, cb); -} - -pub unsafe fn walk(loop_handle: *libc::c_void, cb: *u8, arg: *libc::c_void) { - rust_uv_walk(loop_handle, cb, arg); -} - -pub unsafe fn idle_new() -> *uv_idle_t { - rust_uv_idle_new() -} - -pub unsafe fn idle_delete(handle: *uv_idle_t) { - rust_uv_idle_delete(handle) -} - -pub unsafe fn idle_init(loop_handle: *uv_loop_t, - handle: *uv_idle_t) -> libc::c_int { - rust_uv_idle_init(loop_handle, handle) -} - -pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> libc::c_int { - rust_uv_idle_start(handle, cb) -} - -pub unsafe fn idle_stop(handle: *uv_idle_t) -> libc::c_int { - rust_uv_idle_stop(handle) -} - -pub unsafe fn tcp_init(loop_handle: *libc::c_void, handle: *uv_tcp_t) - -> libc::c_int { - return rust_uv_tcp_init(loop_handle, handle); -} -// FIXME ref #2064 -pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in, - after_connect_cb: *u8) --> libc::c_int { - return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, - after_connect_cb, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in6, - after_connect_cb: *u8) --> libc::c_int { - return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, - after_connect_cb, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in) -> libc::c_int { - return rust_uv_tcp_bind(tcp_server_ptr, - addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in6) -> libc::c_int { - return rust_uv_tcp_bind6(tcp_server_ptr, - addr_ptr); -} - -pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, - name: *sockaddr_in) -> libc::c_int { - return rust_uv_tcp_getpeername(tcp_handle_ptr, name); -} - -pub unsafe fn tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, - name: *sockaddr_in6) ->libc::c_int { - return rust_uv_tcp_getpeername6(tcp_handle_ptr, name); -} - -pub unsafe fn listen(stream: *T, backlog: libc::c_int, - cb: *u8) -> libc::c_int { - return rust_uv_listen(stream as *libc::c_void, backlog, cb); -} - -pub unsafe fn accept(server: *libc::c_void, client: *libc::c_void) - -> libc::c_int { - return rust_uv_accept(server as *libc::c_void, - client as *libc::c_void); -} - -pub unsafe fn write(req: *uv_write_t, stream: *T, - buf_in: *~[uv_buf_t], cb: *u8) -> libc::c_int { - let buf_ptr = vec::raw::to_ptr(*buf_in); - let buf_cnt = (*buf_in).len() as i32; - return rust_uv_write(req as *libc::c_void, - stream as *libc::c_void, - buf_ptr, buf_cnt, cb); -} -pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, - on_read: *u8) -> libc::c_int { - return rust_uv_read_start(stream as *libc::c_void, - on_alloc, on_read); -} - -pub unsafe fn read_stop(stream: *uv_stream_t) -> libc::c_int { - return rust_uv_read_stop(stream as *libc::c_void); -} - -pub unsafe fn last_error(loop_handle: *libc::c_void) -> uv_err_t { - return rust_uv_last_error(loop_handle); -} - -pub unsafe fn strerror(err: *uv_err_t) -> *libc::c_char { - return rust_uv_strerror(err); -} -pub unsafe fn err_name(err: *uv_err_t) -> *libc::c_char { - return rust_uv_err_name(err); -} - -pub unsafe fn async_init(loop_handle: *libc::c_void, - async_handle: *uv_async_t, - cb: *u8) -> libc::c_int { - return rust_uv_async_init(loop_handle, - async_handle, - cb); -} - -pub unsafe fn async_send(async_handle: *uv_async_t) { - return rust_uv_async_send(async_handle); -} -pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t { - let out_buf = uv_buf_t { base: ptr::null(), len: 0 as libc::size_t }; - let out_buf_ptr: *uv_buf_t = &out_buf; - rust_uv_buf_init(out_buf_ptr, input, len as size_t); - return out_buf; -} -pub unsafe fn ip4_addr(ip: &str, port: int) -> sockaddr_in { - do str::as_c_str(ip) |ip_buf| { - rust_uv_ip4_addr(ip_buf as *u8, - port as libc::c_int) - } -} -pub unsafe fn ip6_addr(ip: &str, port: int) -> sockaddr_in6 { - do str::as_c_str(ip) |ip_buf| { - rust_uv_ip6_addr(ip_buf as *u8, - port as libc::c_int) - } -} -pub unsafe fn ip4_name(src: &sockaddr_in) -> ~str { - // ipv4 addr max size: 15 + 1 trailing null byte - let dst: ~[u8] = ~[0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8]; - do dst.as_imm_buf |dst_buf, size| { - rust_uv_ip4_name(to_unsafe_ptr(src), - dst_buf, size as libc::size_t); - // seems that checking the result of uv_ip4_name - // doesn't work too well.. - // you're stuck looking at the value of dst_buf - // to see if it is the string representation of - // INADDR_NONE (0xffffffff or 255.255.255.255 on - // many platforms) - str::raw::from_buf(dst_buf) - } -} -pub unsafe fn ip6_name(src: &sockaddr_in6) -> ~str { - // ipv6 addr max size: 45 + 1 trailing null byte - let dst: ~[u8] = ~[0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8, - 0u8,0u8,0u8,0u8,0u8,0u8]; - do dst.as_imm_buf |dst_buf, size| { - let src_unsafe_ptr = to_unsafe_ptr(src); - let result = rust_uv_ip6_name(src_unsafe_ptr, - dst_buf, size as libc::size_t); - match result { - 0i32 => str::raw::from_buf(dst_buf), - _ => ~"" - } - } -} -pub unsafe fn ip4_port(src: &sockaddr_in) -> uint { - rust_uv_ip4_port(to_unsafe_ptr(src)) as uint -} -pub unsafe fn ip6_port(src: &sockaddr_in6) -> uint { - rust_uv_ip6_port(to_unsafe_ptr(src)) as uint -} - -pub unsafe fn timer_init(loop_ptr: *libc::c_void, - timer_ptr: *uv_timer_t) -> libc::c_int { - return rust_uv_timer_init(loop_ptr, timer_ptr); -} -pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: uint, - repeat: uint) -> libc::c_int { - return rust_uv_timer_start(timer_ptr, cb, timeout as libc::uint64_t, - repeat as libc::uint64_t); -} -pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> libc::c_int { - return rust_uv_timer_stop(timer_ptr); -} -pub unsafe fn getaddrinfo(loop_ptr: *libc::c_void, - handle: *uv_getaddrinfo_t, - cb: *u8, - node_name_ptr: *u8, - service_name_ptr: *u8, - hints: *addrinfo) -> libc::c_int { - rust_uv_getaddrinfo(loop_ptr, - handle, - cb, - node_name_ptr, - service_name_ptr, - hints) -} -pub unsafe fn freeaddrinfo(res: *addrinfo) { - rust_uv_freeaddrinfo(res); -} - -// libuv struct initializers -pub fn tcp_t() -> uv_tcp_t { - return uv_ll_struct_stubgen::gen_stub_uv_tcp_t(); -} -pub fn connect_t() -> uv_connect_t { - return uv_ll_struct_stubgen::gen_stub_uv_connect_t(); -} -pub fn write_t() -> uv_write_t { - return uv_ll_struct_stubgen::gen_stub_uv_write_t(); -} -pub fn async_t() -> uv_async_t { - return uv_ll_struct_stubgen::gen_stub_uv_async_t(); -} -pub fn timer_t() -> uv_timer_t { - return uv_ll_struct_stubgen::gen_stub_uv_timer_t(); -} -pub fn getaddrinfo_t() -> uv_getaddrinfo_t { - return uv_ll_struct_stubgen::gen_stub_uv_getaddrinfo_t(); -} - -// data access helpers -pub unsafe fn get_loop_for_uv_handle(handle: *T) - -> *libc::c_void { - return rust_uv_get_loop_for_uv_handle(handle as *libc::c_void); -} -pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) - -> *uv_stream_t { - return rust_uv_get_stream_handle_from_connect_req( - connect); -} -pub unsafe fn get_stream_handle_from_write_req( - write_req: *uv_write_t) - -> *uv_stream_t { - return rust_uv_get_stream_handle_from_write_req( - write_req); -} -pub unsafe fn get_data_for_uv_loop(loop_ptr: *libc::c_void) -> *libc::c_void { - rust_uv_get_data_for_uv_loop(loop_ptr) -} -pub unsafe fn set_data_for_uv_loop(loop_ptr: *libc::c_void, - data: *libc::c_void) { - rust_uv_set_data_for_uv_loop(loop_ptr, data); -} -pub unsafe fn get_data_for_uv_handle(handle: *T) -> *libc::c_void { - return rust_uv_get_data_for_uv_handle(handle as *libc::c_void); -} -pub unsafe fn set_data_for_uv_handle(handle: *T, data: *U) { - rust_uv_set_data_for_uv_handle(handle as *libc::c_void, - data as *libc::c_void); -} -pub unsafe fn get_data_for_req(req: *T) -> *libc::c_void { - return rust_uv_get_data_for_req(req as *libc::c_void); -} -pub unsafe fn set_data_for_req(req: *T, - data: *U) { - rust_uv_set_data_for_req(req as *libc::c_void, - data as *libc::c_void); -} -pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 { - return rust_uv_get_base_from_buf(buf); -} -pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> libc::size_t { - return rust_uv_get_len_from_buf(buf); -} -pub unsafe fn malloc_buf_base_of(suggested_size: libc::size_t) - -> *u8 { - return rust_uv_malloc_buf_base_of(suggested_size); -} -pub unsafe fn free_base_of_buf(buf: uv_buf_t) { - rust_uv_free_base_of_buf(buf); -} - -pub unsafe fn get_last_err_info(uv_loop: *libc::c_void) -> ~str { - let err = last_error(uv_loop); - let err_ptr: *uv_err_t = &err; - let err_name = str::raw::from_c_str(err_name(err_ptr)); - let err_msg = str::raw::from_c_str(strerror(err_ptr)); - return fmt!("LIBUV ERROR: name: %s msg: %s", - err_name, err_msg); -} - -pub unsafe fn get_last_err_data(uv_loop: *libc::c_void) -> uv_err_data { - let err = last_error(uv_loop); - let err_ptr: *uv_err_t = &err; - let err_name = str::raw::from_c_str(err_name(err_ptr)); - let err_msg = str::raw::from_c_str(strerror(err_ptr)); - uv_err_data { err_name: err_name, err_msg: err_msg } -} - -pub struct uv_err_data { - err_name: ~str, - err_msg: ~str, -} - -pub unsafe fn is_ipv4_addrinfo(input: *addrinfo) -> bool { - rust_uv_is_ipv4_addrinfo(input) -} -pub unsafe fn is_ipv6_addrinfo(input: *addrinfo) -> bool { - rust_uv_is_ipv6_addrinfo(input) -} -pub unsafe fn get_INADDR_NONE() -> u32 { - rust_uv_helper_get_INADDR_NONE() -} -pub unsafe fn get_next_addrinfo(input: *addrinfo) -> *addrinfo { - rust_uv_get_next_addrinfo(input) -} -pub unsafe fn addrinfo_as_sockaddr_in(input: *addrinfo) -> *sockaddr_in { - rust_uv_addrinfo_as_sockaddr_in(input) -} -pub unsafe fn addrinfo_as_sockaddr_in6(input: *addrinfo) -> *sockaddr_in6 { - rust_uv_addrinfo_as_sockaddr_in6(input) -} - -#[cfg(test)] -mod test { - - use super::*; - - use std::comm::{SharedChan, stream, GenericChan, GenericPort}; - use std::libc; - use std::str; - use std::sys; - use std::task; - use std::vec; - - enum tcp_read_data { - tcp_read_eof, - tcp_read_more(~[u8]), - tcp_read_error - } - - struct request_wrapper { - write_req: *uv_write_t, - req_buf: *~[uv_buf_t], - read_chan: SharedChan<~str>, - } - - extern fn after_close_cb(handle: *libc::c_void) { - debug!("after uv_close! handle ptr: %?", - handle); - } - - extern fn on_alloc_cb(handle: *libc::c_void, - suggested_size: libc::size_t) - -> uv_buf_t { - unsafe { - debug!(~"on_alloc_cb!"); - let char_ptr = malloc_buf_base_of(suggested_size); - debug!("on_alloc_cb h: %? char_ptr: %u sugsize: %u", - handle, - char_ptr as uint, - suggested_size as uint); - return buf_init(char_ptr, suggested_size as uint); - } - } - - extern fn on_read_cb(stream: *uv_stream_t, - nread: libc::ssize_t, - buf: uv_buf_t) { - unsafe { - let nread = nread as int; - debug!("CLIENT entering on_read_cb nred: %d", - nread); - if (nread > 0) { - // we have data - debug!("CLIENT read: data! nread: %d", nread); - read_stop(stream); - let client_data = - get_data_for_uv_handle(stream as *libc::c_void) - as *request_wrapper; - let buf_base = get_base_from_buf(buf); - let bytes = vec::from_buf(buf_base, nread as uint); - let read_chan = (*client_data).read_chan.clone(); - let msg_from_server = str::from_bytes(bytes); - read_chan.send(msg_from_server); - close(stream as *libc::c_void, after_close_cb) - } - else if (nread == -1) { - // err .. possibly EOF - debug!(~"read: eof!"); - } - else { - // nread == 0 .. do nothing, just free buf as below - debug!(~"read: do nothing!"); - } - // when we're done - free_base_of_buf(buf); - debug!(~"CLIENT exiting on_read_cb"); - } - } - - extern fn on_write_complete_cb(write_req: *uv_write_t, - status: libc::c_int) { - unsafe { - debug!( - "CLIENT beginning on_write_complete_cb status: %d", - status as int); - let stream = get_stream_handle_from_write_req(write_req); - debug!( - "CLIENT on_write_complete_cb: tcp:%d write_handle:%d", - stream as int, write_req as int); - let result = read_start(stream, on_alloc_cb, on_read_cb); - debug!("CLIENT ending on_write_complete_cb .. status: %d", - result as int); - } - } - - extern fn on_connect_cb(connect_req_ptr: *uv_connect_t, - status: libc::c_int) { - unsafe { - debug!("beginning on_connect_cb .. status: %d", - status as int); - let stream = - get_stream_handle_from_connect_req(connect_req_ptr); - if (status == 0i32) { - debug!(~"on_connect_cb: in status=0 if.."); - let client_data = get_data_for_req( - connect_req_ptr as *libc::c_void) - as *request_wrapper; - let write_handle = (*client_data).write_req; - debug!("on_connect_cb: tcp: %d write_hdl: %d", - stream as int, write_handle as int); - let write_result = write(write_handle, - stream as *libc::c_void, - (*client_data).req_buf, - on_write_complete_cb); - debug!("on_connect_cb: write() status: %d", - write_result as int); - } - else { - let test_loop = get_loop_for_uv_handle( - stream as *libc::c_void); - let err_msg = get_last_err_info(test_loop); - debug!(err_msg); - assert!(false); - } - debug!(~"finishing on_connect_cb"); - } - } - - fn impl_uv_tcp_request(ip: &str, port: int, req_str: &str, - client_chan: SharedChan<~str>) { - unsafe { - let test_loop = loop_new(); - let tcp_handle = tcp_t(); - let tcp_handle_ptr: *uv_tcp_t = &tcp_handle; - let connect_handle = connect_t(); - let connect_req_ptr: *uv_connect_t = &connect_handle; - - // this is the persistent payload of data that we - // need to pass around to get this example to work. - // In C, this would be a malloc'd or stack-allocated - // struct that we'd cast to a void* and store as the - // data field in our uv_connect_t struct - let req_str_bytes = req_str.as_bytes(); - let req_msg_ptr: *u8 = vec::raw::to_ptr(req_str_bytes); - debug!("req_msg ptr: %u", req_msg_ptr as uint); - let req_msg = ~[ - buf_init(req_msg_ptr, req_str_bytes.len()) - ]; - // this is the enclosing record, we'll pass a ptr to - // this to C.. - let write_handle = write_t(); - let write_handle_ptr: *uv_write_t = &write_handle; - debug!("tcp req: tcp stream: %d write_handle: %d", - tcp_handle_ptr as int, - write_handle_ptr as int); - let client_data = request_wrapper { - write_req: write_handle_ptr, - req_buf: &req_msg, - read_chan: client_chan - }; - - let tcp_init_result = tcp_init(test_loop as *libc::c_void, - tcp_handle_ptr); - if (tcp_init_result == 0) { - debug!(~"successful tcp_init_result"); - - debug!(~"building addr..."); - let addr = ip4_addr(ip, port); - // FIXME ref #2064 - let addr_ptr: *sockaddr_in = &addr; - debug!("after build addr in rust. port: %u", - addr.sin_port as uint); - - // this should set up the connection request.. - debug!("b4 call tcp_connect connect cb: %u ", - on_connect_cb as uint); - let tcp_connect_result = tcp_connect(connect_req_ptr, - tcp_handle_ptr, - addr_ptr, - on_connect_cb); - if (tcp_connect_result == 0) { - // not set the data on the connect_req - // until its initialized - set_data_for_req(connect_req_ptr as *libc::c_void, - &client_data); - set_data_for_uv_handle(tcp_handle_ptr as *libc::c_void, - &client_data); - debug!(~"before run tcp req loop"); - run(test_loop); - debug!(~"after run tcp req loop"); - } - else { - debug!(~"tcp_connect() failure"); - assert!(false); - } - } - else { - debug!(~"tcp_init() failure"); - assert!(false); - } - loop_delete(test_loop); - } - } - - extern fn server_after_close_cb(handle: *libc::c_void) { - debug!("SERVER server stream closed, should exit. h: %?", - handle); - } - - extern fn client_stream_after_close_cb(handle: *libc::c_void) { - unsafe { - debug!(~"SERVER: closed client stream, now closing server stream"); - let client_data = get_data_for_uv_handle( - handle) as - *tcp_server_data; - close((*client_data).server as *libc::c_void, - server_after_close_cb); - } - } - - extern fn after_server_resp_write(req: *uv_write_t) { - unsafe { - let client_stream_ptr = - get_stream_handle_from_write_req(req); - debug!(~"SERVER: resp sent... closing client stream"); - close(client_stream_ptr as *libc::c_void, - client_stream_after_close_cb) - } - } - - extern fn on_server_read_cb(client_stream_ptr: *uv_stream_t, - nread: libc::ssize_t, - buf: uv_buf_t) { - unsafe { - let nread = nread as int; - if (nread > 0) { - // we have data - debug!("SERVER read: data! nread: %d", nread); - - // pull out the contents of the write from the client - let buf_base = get_base_from_buf(buf); - let buf_len = get_len_from_buf(buf) as uint; - debug!("SERVER buf base: %u, len: %u, nread: %d", - buf_base as uint, - buf_len as uint, - nread); - let bytes = vec::from_buf(buf_base, nread as uint); - let request_str = str::from_bytes(bytes); - - let client_data = get_data_for_uv_handle( - client_stream_ptr as *libc::c_void) as *tcp_server_data; - - let server_kill_msg = (*client_data).server_kill_msg.clone(); - let write_req = (*client_data).server_write_req; - if request_str.contains(server_kill_msg) { - debug!(~"SERVER: client req contains kill_msg!"); - debug!(~"SERVER: sending response to client"); - read_stop(client_stream_ptr); - let server_chan = (*client_data).server_chan.clone(); - server_chan.send(request_str); - let write_result = write( - write_req, - client_stream_ptr as *libc::c_void, - (*client_data).server_resp_buf, - after_server_resp_write); - debug!("SERVER: resp write result: %d", - write_result as int); - if (write_result != 0i32) { - debug!(~"bad result for server resp write()"); - debug!(get_last_err_info( - get_loop_for_uv_handle(client_stream_ptr - as *libc::c_void))); - assert!(false); - } - } - else { - debug!(~"SERVER: client req !contain kill_msg!"); - } - } - else if (nread == -1) { - // err .. possibly EOF - debug!(~"read: eof!"); - } - else { - // nread == 0 .. do nothing, just free buf as below - debug!(~"read: do nothing!"); - } - // when we're done - free_base_of_buf(buf); - debug!(~"SERVER exiting on_read_cb"); - } - } - - extern fn server_connection_cb(server_stream_ptr: - *uv_stream_t, - status: libc::c_int) { - unsafe { - debug!(~"client connecting!"); - let test_loop = get_loop_for_uv_handle( - server_stream_ptr as *libc::c_void); - if status != 0i32 { - let err_msg = get_last_err_info(test_loop); - debug!("server_connect_cb: non-zero status: %?", - err_msg); - return; - } - let server_data = get_data_for_uv_handle( - server_stream_ptr as *libc::c_void) as *tcp_server_data; - let client_stream_ptr = (*server_data).client; - let client_init_result = tcp_init(test_loop, - client_stream_ptr); - set_data_for_uv_handle( - client_stream_ptr as *libc::c_void, - server_data as *libc::c_void); - if (client_init_result == 0i32) { - debug!(~"successfully initialized client stream"); - let accept_result = accept(server_stream_ptr as - *libc::c_void, - client_stream_ptr as - *libc::c_void); - if (accept_result == 0i32) { - // start reading - let read_result = read_start( - client_stream_ptr as *uv_stream_t, - on_alloc_cb, - on_server_read_cb); - if (read_result == 0i32) { - debug!(~"successful server read start"); - } - else { - debug!("server_connection_cb: bad read:%d", - read_result as int); - assert!(false); - } - } - else { - debug!("server_connection_cb: bad accept: %d", - accept_result as int); - assert!(false); - } - } - else { - debug!("server_connection_cb: bad client init: %d", - client_init_result as int); - assert!(false); - } - } - } - - struct tcp_server_data { - client: *uv_tcp_t, - server: *uv_tcp_t, - server_kill_msg: ~str, - server_resp_buf: *~[uv_buf_t], - server_chan: SharedChan<~str>, - server_write_req: *uv_write_t, - } - - struct async_handle_data { - continue_chan: SharedChan, - } - - extern fn async_close_cb(handle: *libc::c_void) { - debug!("SERVER: closing async cb... h: %?", - handle); - } - - extern fn continue_async_cb(async_handle: *uv_async_t, - status: libc::c_int) { - unsafe { - // once we're in the body of this callback, - // the tcp server's loop is set up, so we - // can continue on to let the tcp client - // do its thang - let data = get_data_for_uv_handle( - async_handle as *libc::c_void) as *async_handle_data; - let continue_chan = (*data).continue_chan.clone(); - let should_continue = status == 0i32; - continue_chan.send(should_continue); - close(async_handle as *libc::c_void, async_close_cb); - } - } - - fn impl_uv_tcp_server(server_ip: &str, - server_port: int, - kill_server_msg: ~str, - server_resp_msg: ~str, - server_chan: SharedChan<~str>, - continue_chan: SharedChan) { - unsafe { - let test_loop = loop_new(); - let tcp_server = tcp_t(); - let tcp_server_ptr: *uv_tcp_t = &tcp_server; - - let tcp_client = tcp_t(); - let tcp_client_ptr: *uv_tcp_t = &tcp_client; - - let server_write_req = write_t(); - let server_write_req_ptr: *uv_write_t = &server_write_req; - - let resp_str_bytes = server_resp_msg.as_bytes(); - let resp_msg_ptr: *u8 = vec::raw::to_ptr(resp_str_bytes); - debug!("resp_msg ptr: %u", resp_msg_ptr as uint); - let resp_msg = ~[ - buf_init(resp_msg_ptr, resp_str_bytes.len()) - ]; - - let continue_async_handle = async_t(); - let continue_async_handle_ptr: *uv_async_t = - &continue_async_handle; - let async_data = - async_handle_data { continue_chan: continue_chan }; - let async_data_ptr: *async_handle_data = &async_data; - - let server_data = tcp_server_data { - client: tcp_client_ptr, - server: tcp_server_ptr, - server_kill_msg: kill_server_msg, - server_resp_buf: &resp_msg, - server_chan: server_chan, - server_write_req: server_write_req_ptr - }; - let server_data_ptr: *tcp_server_data = &server_data; - set_data_for_uv_handle(tcp_server_ptr as *libc::c_void, - server_data_ptr as *libc::c_void); - - // uv_tcp_init() - let tcp_init_result = tcp_init( - test_loop as *libc::c_void, tcp_server_ptr); - if (tcp_init_result == 0i32) { - let server_addr = ip4_addr(server_ip, server_port); - // FIXME ref #2064 - let server_addr_ptr: *sockaddr_in = &server_addr; - - // uv_tcp_bind() - let bind_result = tcp_bind(tcp_server_ptr, server_addr_ptr); - if (bind_result == 0i32) { - debug!(~"successful uv_tcp_bind, listening"); - - // uv_listen() - let listen_result = listen(tcp_server_ptr as - *libc::c_void, - 128i32, - server_connection_cb); - if (listen_result == 0i32) { - // let the test know it can set up the tcp server, - // now.. this may still present a race, not sure.. - let async_result = async_init(test_loop, - continue_async_handle_ptr, - continue_async_cb); - if (async_result == 0i32) { - set_data_for_uv_handle( - continue_async_handle_ptr as *libc::c_void, - async_data_ptr as *libc::c_void); - async_send(continue_async_handle_ptr); - // uv_run() - run(test_loop); - debug!(~"server uv::run() has returned"); - } - else { - debug!("uv_async_init failure: %d", - async_result as int); - assert!(false); - } - } - else { - debug!("non-zero result on uv_listen: %d", - listen_result as int); - assert!(false); - } - } - else { - debug!("non-zero result on uv_tcp_bind: %d", - bind_result as int); - assert!(false); - } - } - else { - debug!("non-zero result on uv_tcp_init: %d", - tcp_init_result as int); - assert!(false); - } - loop_delete(test_loop); - } - } - - // this is the impl for a test that is (maybe) ran on a - // per-platform/arch basis below - pub fn impl_uv_tcp_server_and_request() { - let bind_ip = ~"0.0.0.0"; - let request_ip = ~"127.0.0.1"; - let port = 8886; - let kill_server_msg = ~"does a dog have buddha nature?"; - let server_resp_msg = ~"mu!"; - let (client_port, client_chan) = stream::<~str>(); - let client_chan = SharedChan::new(client_chan); - let (server_port, server_chan) = stream::<~str>(); - let server_chan = SharedChan::new(server_chan); - - let (continue_port, continue_chan) = stream::(); - let continue_chan = SharedChan::new(continue_chan); - - let kill_server_msg_copy = kill_server_msg.clone(); - let server_resp_msg_copy = server_resp_msg.clone(); - do task::spawn_sched(task::ManualThreads(1)) { - impl_uv_tcp_server(bind_ip, port, - kill_server_msg_copy.clone(), - server_resp_msg_copy.clone(), - server_chan.clone(), - continue_chan.clone()); - }; - - // block until the server up is.. possibly a race? - debug!(~"before receiving on server continue_port"); - continue_port.recv(); - debug!(~"received on continue port, set up tcp client"); - - let kill_server_msg_copy = kill_server_msg.clone(); - do task::spawn_sched(task::ManualThreads(1u)) { - impl_uv_tcp_request(request_ip, port, - kill_server_msg_copy, - client_chan.clone()); - }; - - let msg_from_client = server_port.recv(); - let msg_from_server = client_port.recv(); - - assert!(msg_from_client.contains(kill_server_msg)); - assert!(msg_from_server.contains(server_resp_msg)); - } - - // FIXME don't run on fbsd or linux 32 bit(#2064) - #[cfg(target_os="win32")] - #[cfg(target_os="darwin")] - #[cfg(target_os="linux")] - #[cfg(target_os="android")] - mod tcp_and_server_client_test { - #[cfg(target_arch="x86_64")] - mod impl64 { - #[test] - fn test_uv_ll_tcp_server_and_request() { - super::super::impl_uv_tcp_server_and_request(); - } - } - #[cfg(target_arch="x86")] - #[cfg(target_arch="arm")] - #[cfg(target_arch="mips")] - mod impl32 { - #[test] - #[ignore(cfg(target_os = "linux"))] - fn test_uv_ll_tcp_server_and_request() { - unsafe { - super::super::impl_uv_tcp_server_and_request(); - } - } - } - } - - fn struct_size_check_common(t_name: ~str, - foreign_size: libc::c_uint) { - let rust_size = sys::size_of::(); - let sizes_match = foreign_size as uint == rust_size; - if !sizes_match { - let output = fmt!( - "STRUCT_SIZE FAILURE: %s -- actual: %u expected: %u", - t_name, rust_size, foreign_size as uint); - debug!(output); - } - assert!(sizes_match); - } - - // struct size tests - #[test] - fn test_uv_ll_struct_size_uv_tcp_t() { - unsafe { - struct_size_check_common::( - ~"uv_tcp_t", - super::rust_uv_helper_uv_tcp_t_size() - ); - } - } - #[test] - fn test_uv_ll_struct_size_uv_connect_t() { - unsafe { - struct_size_check_common::( - ~"uv_connect_t", - super::rust_uv_helper_uv_connect_t_size() - ); - } - } - #[test] - fn test_uv_ll_struct_size_uv_buf_t() { - unsafe { - struct_size_check_common::( - ~"uv_buf_t", - super::rust_uv_helper_uv_buf_t_size() - ); - } - } - #[test] - fn test_uv_ll_struct_size_uv_write_t() { - unsafe { - struct_size_check_common::( - ~"uv_write_t", - super::rust_uv_helper_uv_write_t_size() - ); - } - } - - #[test] - fn test_uv_ll_struct_size_sockaddr_in() { - unsafe { - struct_size_check_common::( - ~"sockaddr_in", - super::rust_uv_helper_sockaddr_in_size() - ); - } - } - #[test] - fn test_uv_ll_struct_size_sockaddr_in6() { - unsafe { - let foreign_handle_size = - super::rust_uv_helper_sockaddr_in6_size(); - let rust_handle_size = sys::size_of::(); - let output = fmt!("sockaddr_in6 -- foreign: %u rust: %u", - foreign_handle_size as uint, rust_handle_size); - debug!(output); - // FIXME #1645 .. rust appears to pad structs to the nearest - // byte..? - // .. can't get the uv::ll::sockaddr_in6 to == 28 :/ - // .. so the type always appears to be 32 in size.. which is - // good, i guess.. better too big than too little - assert!((4u+foreign_handle_size as uint) == - rust_handle_size); - } - } - #[test] - #[ignore(reason = "questionable size calculations")] - fn test_uv_ll_struct_size_addr_in() { - unsafe { - let foreign_handle_size = - super::rust_uv_helper_addr_in_size(); - let rust_handle_size = sys::size_of::(); - let output = fmt!("addr_in -- foreign: %u rust: %u", - foreign_handle_size as uint, rust_handle_size); - debug!(output); - // FIXME #1645 .. see note above about struct padding - assert!((4u+foreign_handle_size as uint) == - rust_handle_size); - } - } - - #[test] - fn test_uv_ll_struct_size_uv_async_t() { - unsafe { - struct_size_check_common::( - ~"uv_async_t", - super::rust_uv_helper_uv_async_t_size() - ); - } - } - - #[test] - fn test_uv_ll_struct_size_uv_timer_t() { - unsafe { - struct_size_check_common::( - ~"uv_timer_t", - super::rust_uv_helper_uv_timer_t_size() - ); - } - } - - #[test] - #[ignore(cfg(target_os = "win32"))] - fn test_uv_ll_struct_size_uv_getaddrinfo_t() { - unsafe { - struct_size_check_common::( - ~"uv_getaddrinfo_t", - super::rust_uv_helper_uv_getaddrinfo_t_size() - ); - } - } - #[test] - #[ignore(cfg(target_os = "macos"))] - #[ignore(cfg(target_os = "win32"))] - fn test_uv_ll_struct_size_addrinfo() { - unsafe { - struct_size_check_common::( - ~"addrinfo", - super::rust_uv_helper_uv_timer_t_size() - ); - } - } -} diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index e6cda8286aace..286b1f84802c3 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -791,12 +791,14 @@ fn rust_path_test() { #[test] fn rust_path_contents() { + use std::unstable::change_dir_locked; + let dir = mkdtemp(&os::tmpdir(), "rust_path").expect("rust_path_contents failed"); let abc = &dir.push("A").push("B").push("C"); assert!(os::mkdir_recursive(&abc.push(".rust"), U_RWX)); assert!(os::mkdir_recursive(&abc.pop().push(".rust"), U_RWX)); assert!(os::mkdir_recursive(&abc.pop().pop().push(".rust"), U_RWX)); - assert!(do os::change_dir_locked(&dir.push("A").push("B").push("C")) { + assert!(do change_dir_locked(&dir.push("A").push("B").push("C")) { let p = rust_path(); let cwd = os::getcwd().push(".rust"); let parent = cwd.pop().pop().push(".rust"); diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 4bfd3bbcd3ff1..5981926fce30c 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -863,34 +863,6 @@ pub fn change_dir(p: &Path) -> bool { } } -/// Changes the current working directory to the specified -/// path while acquiring a global lock, then calls `action`. -/// If the change is successful, releases the lock and restores the -/// CWD to what it was before, returning true. -/// Returns false if the directory doesn't exist or if the directory change -/// is otherwise unsuccessful. -pub fn change_dir_locked(p: &Path, action: &fn()) -> bool { - use unstable::global::global_data_clone_create; - use unstable::sync::{Exclusive, exclusive}; - - fn key(_: Exclusive<()>) { } - - unsafe { - let result = global_data_clone_create(key, || { ~exclusive(()) }); - - do result.with_imm() |_| { - let old_dir = os::getcwd(); - if change_dir(p) { - action(); - change_dir(&old_dir) - } - else { - false - } - } - } -} - /// Copies a file from one location to another pub fn copy_file(from: &Path, to: &Path) -> bool { return do_copy_file(from, to); diff --git a/src/libstd/unstable/at_exit.rs b/src/libstd/unstable/at_exit.rs deleted file mode 100644 index 20ddf941a7b95..0000000000000 --- a/src/libstd/unstable/at_exit.rs +++ /dev/null @@ -1,100 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cast; -use libc::size_t; -use rand::RngUtil; -use rand; -use sys; -use task; -use vec; - -#[cfg(test)] use uint; - -/** -Register a function to be run during runtime shutdown. - -After all non-weak tasks have exited, registered exit functions will -execute, in random order, on the primary scheduler. Each function runs -in its own unsupervised task. -*/ -pub fn at_exit(f: ~fn()) { - unsafe { - let runner: &fn(*ExitFunctions) = exit_runner; - let runner_pair: sys::Closure = cast::transmute(runner); - let runner_ptr = runner_pair.code; - let runner_ptr = cast::transmute(runner_ptr); - rustrt::rust_register_exit_function(runner_ptr, ~f); - } -} - -// NB: The double pointer indirection here is because ~fn() is a fat -// pointer and due to FFI problems I am more comfortable making the -// interface use a normal pointer -mod rustrt { - use libc::c_void; - - extern { - pub fn rust_register_exit_function(runner: *c_void, f: ~~fn()); - } -} - -struct ExitFunctions { - // The number of exit functions - count: size_t, - // The buffer of exit functions - start: *~~fn() -} - -fn exit_runner(exit_fns: *ExitFunctions) { - let exit_fns = unsafe { &*exit_fns }; - let count = (*exit_fns).count; - let start = (*exit_fns).start; - - // NB: from_buf memcpys from the source, which will - // give us ownership of the array of functions - let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) }; - // Let's not make any promises about execution order - let mut rng = rand::rng(); - rng.shuffle_mut(exit_fns_vec); - - debug!("running %u exit functions", exit_fns_vec.len()); - - while !exit_fns_vec.is_empty() { - match exit_fns_vec.pop() { - ~f => { - let mut task = task::task(); - task.supervised(); - task.spawn(f); - } - } - } -} - -#[test] -fn test_at_exit() { - let i = 10; - do at_exit { - debug!("at_exit1"); - assert_eq!(i, 10); - } -} - -#[test] -fn test_at_exit_many() { - let i = 10; - for uint::range(20, 100) |j| { - do at_exit { - debug!("at_exit2"); - assert_eq!(i, 10); - assert!(j > i); - } - } -} diff --git a/src/libstd/unstable/global.rs b/src/libstd/unstable/global.rs deleted file mode 100644 index af28879f73971..0000000000000 --- a/src/libstd/unstable/global.rs +++ /dev/null @@ -1,281 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -Global data - -An interface for creating and retrieving values with global -(per-runtime) scope. - -Global values are stored in a map and protected by a single global -mutex. Operations are provided for accessing and cloning the value -under the mutex. - -Because all globals go through a single mutex, they should be used -sparingly. The interface is intended to be used with clonable, -atomically reference counted synchronization types, like ARCs, in -which case the value should be cached locally whenever possible to -avoid hitting the mutex. -*/ - -use cast::{transmute}; -use clone::Clone; -use kinds::Send; -use libc::{c_void, intptr_t}; -use option::{Option, Some, None}; -use ops::Drop; -use unstable::sync::{Exclusive, exclusive}; -use unstable::at_exit::at_exit; -use unstable::intrinsics::atomic_cxchg; -use hashmap::HashMap; -use sys::Closure; - -#[cfg(test)] use unstable::sync::{UnsafeAtomicRcBox}; -#[cfg(test)] use task::spawn; -#[cfg(test)] use uint; - -pub type GlobalDataKey<'self,T> = &'self fn(v: T); - -pub unsafe fn global_data_clone_create( - key: GlobalDataKey, create: &fn() -> ~T) -> T { - /*! - * Clone a global value or, if it has not been created, - * first construct the value then return a clone. - * - * # Safety note - * - * Both the clone operation and the constructor are - * called while the global lock is held. Recursive - * use of the global interface in either of these - * operations will result in deadlock. - */ - global_data_clone_create_(key_ptr(key), create) -} - -unsafe fn global_data_clone_create_( - key: uint, create: &fn() -> ~T) -> T { - - let mut clone_value: Option = None; - do global_data_modify_(key) |value: Option<~T>| { - match value { - None => { - let value = create(); - clone_value = Some((*value).clone()); - Some(value) - } - Some(value) => { - clone_value = Some((*value).clone()); - Some(value) - } - } - } - return clone_value.unwrap(); -} - -unsafe fn global_data_modify( - key: GlobalDataKey, op: &fn(Option<~T>) -> Option<~T>) { - - global_data_modify_(key_ptr(key), op) -} - -unsafe fn global_data_modify_( - key: uint, op: &fn(Option<~T>) -> Option<~T>) { - - let mut old_dtor = None; - do get_global_state().with |gs| { - let (maybe_new_value, maybe_dtor) = match gs.map.pop(&key) { - Some((ptr, dtor)) => { - let value: ~T = transmute(ptr); - (op(Some(value)), Some(dtor)) - } - None => { - (op(None), None) - } - }; - match maybe_new_value { - Some(value) => { - let data: *c_void = transmute(value); - let dtor: ~fn() = match maybe_dtor { - Some(dtor) => dtor, - None => { - let dtor: ~fn() = || { - let _destroy_value: ~T = transmute(data); - }; - dtor - } - }; - let value = (data, dtor); - gs.map.insert(key, value); - } - None => { - match maybe_dtor { - Some(dtor) => old_dtor = Some(dtor), - None => () - } - } - } - } -} - -pub unsafe fn global_data_clone( - key: GlobalDataKey) -> Option { - let mut maybe_clone: Option = None; - do global_data_modify(key) |current| { - match ¤t { - &Some(~ref value) => { - maybe_clone = Some(value.clone()); - } - &None => () - } - current - } - return maybe_clone; -} - -// GlobalState is a map from keys to unique pointers and a -// destructor. Keys are pointers derived from the type of the -// global value. There is a single GlobalState instance per runtime. -struct GlobalState { - map: HashMap -} - -impl Drop for GlobalState { - fn drop(&self) { - for self.map.each_value |v| { - match v { - &(_, ref dtor) => (*dtor)() - } - } - } -} - -fn get_global_state() -> Exclusive { - - static POISON: int = -1; - - // FIXME #4728: Doing atomic_cxchg to initialize the global state - // lazily, which wouldn't be necessary with a runtime written - // in Rust - let global_ptr = unsafe { rust_get_global_data_ptr() }; - - if unsafe { *global_ptr } == 0 { - // Global state doesn't exist yet, probably - - // The global state object - let state = GlobalState { - map: HashMap::new() - }; - - // It's under a reference-counted mutex - let state = ~exclusive(state); - - // Convert it to an integer - let state_i: int = unsafe { - let state_ptr: &Exclusive = state; - transmute(state_ptr) - }; - - // Swap our structure into the global pointer - let prev_i = unsafe { atomic_cxchg(&mut *global_ptr, 0, state_i) }; - - // Sanity check that we're not trying to reinitialize after shutdown - assert!(prev_i != POISON); - - if prev_i == 0 { - // Successfully installed the global pointer - - // Take a handle to return - let clone = (*state).clone(); - - // Install a runtime exit function to destroy the global object - do at_exit { - // Poison the global pointer - let prev_i = unsafe { - atomic_cxchg(&mut *global_ptr, state_i, POISON) - }; - assert_eq!(prev_i, state_i); - - // Capture the global state object in the at_exit closure - // so that it is destroyed at the right time - let _capture_global_state = &state; - }; - return clone; - } else { - // Somebody else initialized the globals first - let state: &Exclusive = unsafe { transmute(prev_i) }; - return state.clone(); - } - } else { - let state: &Exclusive = unsafe { - transmute(*global_ptr) - }; - return state.clone(); - } -} - -fn key_ptr(key: GlobalDataKey) -> uint { - unsafe { - let closure: Closure = transmute(key); - return transmute(closure.code); - } -} - -extern { - fn rust_get_global_data_ptr() -> *mut intptr_t; -} - -#[test] -fn test_clone_rc() { - fn key(_v: UnsafeAtomicRcBox) { } - - for uint::range(0, 100) |_| { - do spawn { - unsafe { - let val = do global_data_clone_create(key) { - ~UnsafeAtomicRcBox::new(10) - }; - - assert!(val.get() == &10); - } - } - } -} - -#[test] -fn test_modify() { - fn key(_v: UnsafeAtomicRcBox) { } - - unsafe { - do global_data_modify(key) |v| { - match v { - None => { Some(~UnsafeAtomicRcBox::new(10)) } - _ => fail!() - } - } - - do global_data_modify(key) |v| { - match v { - Some(sms) => { - let v = sms.get(); - assert!(*v == 10); - None - }, - _ => fail!() - } - } - - do global_data_modify(key) |v| { - match v { - None => { Some(~UnsafeAtomicRcBox::new(10)) } - _ => fail!() - } - } - } -} diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index 0a46ef619afd9..d6fd2cbcd1e4d 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -16,13 +16,9 @@ use libc; use prelude::*; use task; -pub mod at_exit; - pub mod dynamic_lib; -pub mod global; pub mod finally; -pub mod weak_task; pub mod intrinsics; pub mod simd; pub mod extfmt; @@ -80,3 +76,53 @@ extern { fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread; fn rust_raw_thread_join_delete(thread: *raw_thread); } + + +/// Changes the current working directory to the specified +/// path while acquiring a global lock, then calls `action`. +/// If the change is successful, releases the lock and restores the +/// CWD to what it was before, returning true. +/// Returns false if the directory doesn't exist or if the directory change +/// is otherwise unsuccessful. +/// +/// This is used by test cases to avoid cwd races. +/// +/// # Safety Note +/// +/// This uses a pthread mutex so descheduling in the action callback +/// can lead to deadlock. Calling change_dir_locked recursively will +/// also deadlock. +pub fn change_dir_locked(p: &Path, action: &fn()) -> bool { + use os; + use os::change_dir; + use task; + use unstable::finally::Finally; + + unsafe { + // This is really sketchy. Using a pthread mutex so descheduling + // in the `action` callback can cause deadlock. Doing it in + // `task::atomically` to try to avoid that, but ... I don't know + // this is all bogus. + return do task::atomically { + rust_take_change_dir_lock(); + + do (||{ + let old_dir = os::getcwd(); + if change_dir(p) { + action(); + change_dir(&old_dir) + } + else { + false + } + }).finally { + rust_drop_change_dir_lock(); + } + } + } + + extern { + fn rust_take_change_dir_lock(); + fn rust_drop_change_dir_lock(); + } +} diff --git a/src/libstd/unstable/weak_task.rs b/src/libstd/unstable/weak_task.rs deleted file mode 100644 index f5dfa1feb9b13..0000000000000 --- a/src/libstd/unstable/weak_task.rs +++ /dev/null @@ -1,211 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -Weak tasks - -Weak tasks are a runtime feature for building global services that -do not keep the runtime alive. Normally the runtime exits when all -tasks exits, but if a task is weak then the runtime may exit while -it is running, sending a notification to the task that the runtime -is trying to shut down. -*/ - -use cell::Cell; -use comm::{GenericSmartChan, stream}; -use comm::{Port, Chan, SharedChan, GenericChan, GenericPort}; -use hashmap::HashMap; -use option::{Some, None}; -use unstable::at_exit::at_exit; -use unstable::finally::Finally; -use unstable::global::global_data_clone_create; -use task::rt::{task_id, get_task_id}; -use task::task; - -#[cfg(test)] use task::spawn; - -type ShutdownMsg = (); - -// FIXME #4729: This could be a PortOne but I've experienced bugginess -// with oneshot pipes and try_send -pub unsafe fn weaken_task(f: &fn(Port)) { - let service = global_data_clone_create(global_data_key, - create_global_service); - let (shutdown_port, shutdown_chan) = stream::(); - let shutdown_port = Cell::new(shutdown_port); - let task = get_task_id(); - // Expect the weak task service to be alive - assert!(service.try_send(RegisterWeakTask(task, shutdown_chan))); - rust_dec_kernel_live_count(); - do (|| { - f(shutdown_port.take()) - }).finally || { - rust_inc_kernel_live_count(); - // Service my have already exited - service.send(UnregisterWeakTask(task)); - } -} - -type WeakTaskService = SharedChan; -type TaskHandle = task_id; - -fn global_data_key(_v: WeakTaskService) { } - -enum ServiceMsg { - RegisterWeakTask(TaskHandle, Chan), - UnregisterWeakTask(TaskHandle), - Shutdown -} - -fn create_global_service() -> ~WeakTaskService { - - debug!("creating global weak task service"); - let (port, chan) = stream::(); - let port = Cell::new(port); - let chan = SharedChan::new(chan); - let chan_clone = chan.clone(); - - let mut task = task(); - task.unlinked(); - do task.spawn { - debug!("running global weak task service"); - let port = Cell::new(port.take()); - do (|| { - let port = port.take(); - // The weak task service is itself a weak task - debug!("weakening the weak service task"); - unsafe { rust_dec_kernel_live_count(); } - run_weak_task_service(port); - }).finally { - debug!("unweakening the weak service task"); - unsafe { rust_inc_kernel_live_count(); } - } - } - - do at_exit { - debug!("shutting down weak task service"); - chan.send(Shutdown); - } - - return ~chan_clone; -} - -fn run_weak_task_service(port: Port) { - - let mut shutdown_map = HashMap::new(); - - loop { - match port.recv() { - RegisterWeakTask(task, shutdown_chan) => { - let previously_unregistered = - shutdown_map.insert(task, shutdown_chan); - assert!(previously_unregistered); - } - UnregisterWeakTask(task) => { - match shutdown_map.pop(&task) { - Some(shutdown_chan) => { - // Oneshot pipes must send, even though - // nobody will receive this - shutdown_chan.send(()); - } - None => fail!() - } - } - Shutdown => break - } - } - - for shutdown_map.consume().advance |(_, shutdown_chan)| { - // Weak task may have already exited - shutdown_chan.send(()); - } -} - -extern { - unsafe fn rust_inc_kernel_live_count(); - unsafe fn rust_dec_kernel_live_count(); -} - -#[test] -fn test_simple() { - let (port, chan) = stream(); - do spawn { - unsafe { - do weaken_task |_signal| { - } - } - chan.send(()); - } - port.recv(); -} - -#[test] -fn test_weak_weak() { - let (port, chan) = stream(); - do spawn { - unsafe { - do weaken_task |_signal| { - } - do weaken_task |_signal| { - } - } - chan.send(()); - } - port.recv(); -} - -#[test] -fn test_wait_for_signal() { - do spawn { - unsafe { - do weaken_task |signal| { - signal.recv(); - } - } - } -} - -#[test] -fn test_wait_for_signal_many() { - use uint; - for uint::range(0, 100) |_| { - do spawn { - unsafe { - do weaken_task |signal| { - signal.recv(); - } - } - } - } -} - -#[test] -fn test_select_stream_and_oneshot() { - use comm::select2i; - use either::{Left, Right}; - - let (port, chan) = stream(); - let port = Cell::new(port); - let (waitport, waitchan) = stream(); - do spawn { - unsafe { - do weaken_task |mut signal| { - let mut port = port.take(); - match select2i(&mut port, &mut signal) { - Left(*) => (), - Right(*) => fail!() - } - } - } - waitchan.send(()); - } - chan.send(()); - waitport.recv(); -} diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 7e69e2e4ccb99..06b09bcedd2d0 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -757,30 +757,6 @@ rust_raw_thread_join_delete(raw_thread *thread) { delete thread; } -extern "C" void -rust_register_exit_function(spawn_fn runner, fn_env_pair *f) { - rust_task *task = rust_get_current_task(); - task->kernel->register_exit_function(runner, f); -} - -extern "C" intptr_t* -rust_get_global_data_ptr() { - rust_task *task = rust_get_current_task(); - return &task->kernel->global_data; -} - -extern "C" void -rust_inc_kernel_live_count() { - rust_task *task = rust_get_current_task(); - task->kernel->inc_live_count(); -} - -extern "C" void -rust_dec_kernel_live_count() { - rust_task *task = rust_get_current_task(); - task->kernel->dec_live_count(); -} - #ifndef _WIN32 #include #include @@ -959,6 +935,18 @@ rust_get_exit_status_newrt() { return exit_status; } +static lock_and_signal change_dir_lock; + +extern "C" CDECL void +rust_take_change_dir_lock() { + global_args_lock.lock(); +} + +extern "C" CDECL void +rust_drop_change_dir_lock() { + global_args_lock.unlock(); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 583f836c0d66c..814cfbb310a79 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -31,10 +31,7 @@ rust_kernel::rust_kernel(rust_env *env) : sched_reaper(this), osmain_driver(NULL), non_weak_tasks(0), - at_exit_runner(NULL), - at_exit_started(false), - env(env), - global_data(0) + env(env) { // Create the single threaded scheduler that will run on the platform's // main thread @@ -311,54 +308,9 @@ rust_kernel::begin_shutdown() { } } - run_exit_functions(); allow_scheduler_exit(); } -void -rust_kernel::register_exit_function(spawn_fn runner, fn_env_pair *f) { - scoped_lock with(at_exit_lock); - - assert(!at_exit_started && "registering at_exit function after exit"); - - if (at_exit_runner) { - // FIXME #2912 Would be very nice to assert this but we can't because - // of the way coretest works (the test case ends up using its own - // function) - //assert(runner == at_exit_runner - // && "there can be only one at_exit_runner"); - } - - at_exit_runner = runner; - at_exit_fns.push_back(f); -} - -void -rust_kernel::run_exit_functions() { - rust_task *task; - - { - scoped_lock with(at_exit_lock); - - assert(!at_exit_started && "running exit functions twice?"); - - at_exit_started = true; - - if (at_exit_runner == NULL) { - return; - } - - rust_scheduler *sched = get_scheduler_by_id(main_sched_id()); - assert(sched); - task = sched->create_task(NULL, "at_exit"); - - final_exit_fns.count = at_exit_fns.size(); - final_exit_fns.start = at_exit_fns.data(); - } - - task->start(at_exit_runner, NULL, &final_exit_fns); -} - // // Local Variables: // mode: C++ diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index 09f73f9b7d855..0fe3f7610403f 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -63,13 +63,6 @@ typedef intptr_t rust_task_id; typedef std::map sched_map; -// This is defined as a struct only because we need a single pointer to pass -// to the Rust function that runs the at_exit functions -struct exit_functions { - size_t count; - fn_env_pair **start; -}; - class rust_kernel { rust_exchange_alloc exchange_alloc; rust_log _log; @@ -114,17 +107,8 @@ class rust_kernel { void allow_scheduler_exit(); void begin_shutdown(); - lock_and_signal at_exit_lock; - spawn_fn at_exit_runner; - bool at_exit_started; - std::vector at_exit_fns; - exit_functions final_exit_fns; - - void run_exit_functions(); - public: struct rust_env *env; - intptr_t global_data; rust_kernel(rust_env *env); @@ -157,7 +141,6 @@ class rust_kernel { void inc_live_count(); void dec_live_count(); - void register_exit_function(spawn_fn runner, fn_env_pair *f); }; template struct kernel_owned { diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 3c3e9a56827b3..db9fe2479526c 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -214,10 +214,6 @@ linenoiseHistorySave linenoiseHistoryLoad rust_raw_thread_start rust_raw_thread_join_delete -rust_register_exit_function -rust_get_global_data_ptr -rust_inc_kernel_live_count -rust_dec_kernel_live_count rust_get_rt_tls_key swap_registers rust_readdir @@ -270,3 +266,5 @@ rust_take_global_args_lock rust_drop_global_args_lock rust_set_exit_status_newrt rust_get_exit_status_newrt +rust_take_change_dir_lock +rust_drop_change_dir_lock \ No newline at end of file diff --git a/src/test/run-pass/issue-4241.rs b/src/test/run-pass/issue-4241.rs index 387b0a68d2178..1f5da69018ab5 100644 --- a/src/test/run-pass/issue-4241.rs +++ b/src/test/run-pass/issue-4241.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-fast +// xfail-test needs networking extern mod extra; diff --git a/src/test/run-pass/pipe-detect-term.rs b/src/test/run-pass/pipe-detect-term.rs index abee0f36330e9..42cd4081eda10 100644 --- a/src/test/run-pass/pipe-detect-term.rs +++ b/src/test/run-pass/pipe-detect-term.rs @@ -13,6 +13,7 @@ // Make sure that we can detect when one end of the pipe is closed. // xfail-win32 +// xfail-test needs sleep extern mod extra; use extra::timer::sleep; diff --git a/src/test/run-pass/pipe-peek.rs b/src/test/run-pass/pipe-peek.rs index cbc822060cec2..a61aad2e55c7a 100644 --- a/src/test/run-pass/pipe-peek.rs +++ b/src/test/run-pass/pipe-peek.rs @@ -10,9 +10,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod extra; -use extra::timer::sleep; -use extra::uv; use std::pipes; proto! oneshot ( diff --git a/src/test/run-pass/pipe-select.rs b/src/test/run-pass/pipe-select.rs index 36f144152f2a3..d9e887fcee8bf 100644 --- a/src/test/run-pass/pipe-select.rs +++ b/src/test/run-pass/pipe-select.rs @@ -12,6 +12,7 @@ // xfail-pretty // xfail-win32 +// xfail-test needs sleep extern mod extra; use extra::timer::sleep; diff --git a/src/test/run-pass/pipe-sleep.rs b/src/test/run-pass/pipe-sleep.rs index dbf860cd04075..549c733244049 100644 --- a/src/test/run-pass/pipe-sleep.rs +++ b/src/test/run-pass/pipe-sleep.rs @@ -10,6 +10,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test needs sleep + extern mod extra; use extra::timer::sleep;