Migrate uv getaddrinfo away from ~fn()

This commit is contained in:
Alex Crichton 2013-11-04 22:52:33 -08:00
parent be896288a3
commit 5842b606a7
2 changed files with 70 additions and 142 deletions

View File

@ -8,41 +8,44 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cast::transmute;
use std::cell::Cell;
use std::libc::{c_int, c_void};
use std::ptr::null;
use ai = std::rt::io::net::addrinfo;
use std::cast;
use std::libc::c_int;
use std::ptr::null;
use std::rt::BlockedTask;
use std::rt::local::Local;
use std::rt::sched::Scheduler;
use uvll;
use uvll::UV_GETADDRINFO;
use super::{Loop, UvError, NativeHandle, status_to_maybe_uv_error};
use net;
use super::{Loop, UvError, NativeHandle};
use uvll::UV_GETADDRINFO;
use uvll;
type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &net::UvAddrInfo, Option<UvError>);
struct GetAddrInfoRequest {
handle: *uvll::uv_getaddrinfo_t,
}
pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t);
struct Addrinfo {
handle: *uvll::addrinfo,
}
pub struct RequestData {
priv getaddrinfo_cb: Option<GetAddrInfoCallback>,
struct Ctx {
slot: Option<BlockedTask>,
status: c_int,
addrinfo: Option<Addrinfo>,
}
impl GetAddrInfoRequest {
pub fn new() -> GetAddrInfoRequest {
let req = unsafe { uvll::malloc_req(UV_GETADDRINFO) };
assert!(req.is_not_null());
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
req.install_req_data();
return req;
GetAddrInfoRequest {
handle: unsafe { uvll::malloc_req(uvll::UV_GETADDRINFO) },
}
}
pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>,
service: Option<&str>, hints: Option<ai::Hint>,
cb: GetAddrInfoCallback) {
pub fn run(loop_: &Loop, node: Option<&str>, service: Option<&str>,
hints: Option<ai::Hint>) -> Result<~[ai::Info], UvError> {
assert!(node.is_some() || service.is_some());
let (c_node, c_node_ptr) = match node {
let (_c_node, c_node_ptr) = match node {
Some(n) => {
let c_node = n.to_c_str();
let c_node_ptr = c_node.with_ref(|r| r);
@ -51,7 +54,7 @@ impl GetAddrInfoRequest {
None => (None, null())
};
let (c_service, c_service_ptr) = match service {
let (_c_service, c_service_ptr) = match service {
Some(s) => {
let c_service = s.to_c_str();
let c_service_ptr = c_service.with_ref(|r| r);
@ -60,17 +63,6 @@ impl GetAddrInfoRequest {
None => (None, null())
};
let cb = Cell::new(cb);
let wrapper_cb: GetAddrInfoCallback = |req, addrinfo, err| {
// Capture some heap values that need to stay alive for the
// getaddrinfo call
let _ = &c_node;
let _ = &c_service;
let cb = cb.take();
cb(req, addrinfo, err)
};
let hint = hints.map(|hint| {
let mut flags = 0;
do each_ai_flag |cval, aival| {
@ -78,19 +70,6 @@ impl GetAddrInfoRequest {
flags |= cval as i32;
}
}
/* XXX: do we really want to support these?
let socktype = match hint.socktype {
Some(ai::Stream) => uvll::rust_SOCK_STREAM(),
Some(ai::Datagram) => uvll::rust_SOCK_DGRAM(),
Some(ai::Raw) => uvll::rust_SOCK_RAW(),
None => 0,
};
let protocol = match hint.protocol {
Some(ai::UDP) => uvll::rust_IPPROTO_UDP(),
Some(ai::TCP) => uvll::rust_IPPROTO_TCP(),
_ => 0,
};
*/
let socktype = 0;
let protocol = 0;
@ -106,66 +85,54 @@ impl GetAddrInfoRequest {
}
});
let hint_ptr = hint.as_ref().map_default(null(), |x| x as *uvll::addrinfo);
let req = GetAddrInfoRequest::new();
self.get_req_data().getaddrinfo_cb = Some(wrapper_cb);
return match unsafe {
uvll::uv_getaddrinfo(loop_.native_handle(), req.handle,
getaddrinfo_cb, c_node_ptr, c_service_ptr,
hint_ptr)
} {
0 => {
let mut cx = Ctx { slot: None, status: 0, addrinfo: None };
unsafe { uvll::set_data_for_req(req.handle, &cx) }
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |_, task| {
cx.slot = Some(task);
}
unsafe {
assert!(0 == uvll::uv_getaddrinfo(loop_.native_handle(),
self.native_handle(),
getaddrinfo_cb,
c_node_ptr,
c_service_ptr,
hint_ptr));
}
extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
status: c_int,
res: *uvll::addrinfo) {
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
let err = status_to_maybe_uv_error(status);
let addrinfo = net::UvAddrInfo(res);
let data = req.get_req_data();
(*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err);
unsafe {
uvll::uv_freeaddrinfo(res);
match cx.status {
0 => Ok(accum_addrinfo(cx.addrinfo.get_ref())),
n => Err(UvError(n))
}
}
}
}
fn get_loop(&self) -> Loop {
unsafe {
Loop {
handle: uvll::get_loop_from_fs_req(self.native_handle())
}
}
}
fn install_req_data(&mut self) {
let req = self.native_handle() as *uvll::uv_getaddrinfo_t;
let data = ~RequestData {
getaddrinfo_cb: None
n => Err(UvError(n))
};
unsafe {
let data = transmute::<~RequestData, *c_void>(data);
uvll::set_data_for_req(req, data);
extern fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
status: c_int,
res: *uvll::addrinfo) {
let cx: &mut Ctx = unsafe {
cast::transmute(uvll::get_data_for_req(req))
};
cx.status = status;
cx.addrinfo = Some(Addrinfo { handle: res });
let sched: ~Scheduler = Local::take();
sched.resume_blocked_task_immediately(cx.slot.take_unwrap());
}
}
}
fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
return &mut **data;
}
impl Drop for GetAddrInfoRequest {
fn drop(&mut self) {
unsafe { uvll::free_req(self.handle) }
}
}
fn delete(self) {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
let _data = transmute::<*c_void, ~RequestData>(data);
uvll::set_data_for_req(self.native_handle(), null::<()>());
uvll::free_req(self.native_handle());
}
impl Drop for Addrinfo {
fn drop(&mut self) {
unsafe { uvll::uv_freeaddrinfo(self.handle) }
}
}
@ -184,10 +151,9 @@ fn each_ai_flag(_f: &fn(c_int, ai::Flag)) {
}
// Traverse the addrinfo linked list, producing a vector of Rust socket addresses
pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] {
pub fn accum_addrinfo(addr: &Addrinfo) -> ~[ai::Info] {
unsafe {
let &net::UvAddrInfo(addr) = addr;
let mut addr = addr;
let mut addr = addr.handle;
let mut addrs = ~[];
loop {
@ -235,15 +201,6 @@ pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] {
}
}
impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest {
fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest {
GetAddrInfoRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_getaddrinfo_t {
match self { &GetAddrInfoRequest(ptr) => ptr }
}
}
#[cfg(test)]
mod test {
use Loop;

View File

@ -46,7 +46,7 @@ use ai = std::rt::io::net::addrinfo;
use super::*;
use idle::IdleWatcher;
use net::{UvIpv4SocketAddr, UvIpv6SocketAddr};
use addrinfo::{GetAddrInfoRequest, accum_addrinfo};
use addrinfo::GetAddrInfoRequest;
use pipe::PipeListener;
// XXX we should not be calling uvll functions in here.
@ -351,37 +351,8 @@ impl IoFactory for UvIoFactory {
fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
hint: Option<ai::Hint>) -> Result<~[ai::Info], IoError> {
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<~[ai::Info], IoError>> = &result_cell;
let host_ptr: *Option<&str> = &host;
let servname_ptr: *Option<&str> = &servname;
let hint_ptr: *Option<ai::Hint> = &hint;
let addrinfo_req = GetAddrInfoRequest::new();
let addrinfo_req_cell = Cell::new(addrinfo_req);
do task::unkillable { // FIXME(#8674)
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
let mut addrinfo_req = addrinfo_req_cell.take();
unsafe {
do addrinfo_req.getaddrinfo(self.uv_loop(),
*host_ptr, *servname_ptr,
*hint_ptr) |_, addrinfo, err| {
let res = match err {
None => Ok(accum_addrinfo(addrinfo)),
Some(err) => Err(uv_error_to_io_error(err))
};
(*result_cell_ptr).put_back(res);
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
}
}
addrinfo_req.delete();
assert!(!result_cell.is_empty());
return result_cell.take();
let r = GetAddrInfoRequest::run(self.uv_loop(), host, servname, hint);
r.map_err(uv_error_to_io_error)
}
fn fs_from_raw_fd(&mut self, fd: c_int,