Fix usage of libuv for windows

This commit is contained in:
Alex Crichton 2013-11-09 11:02:16 -08:00
parent c5fdd69d3e
commit e38a89d0b0
11 changed files with 89 additions and 42 deletions

2
.gitmodules vendored
View File

@ -4,7 +4,7 @@
branch = master
[submodule "src/libuv"]
path = src/libuv
url = https://github.com/joyent/libuv.git
url = https://github.com/alexcrichton/libuv.git
branch = master
[submodule "src/gyp"]
path = src/gyp

View File

@ -883,6 +883,7 @@ mod test {
}
#[test]
#[ignore(cfg(windows))] // FIXME(#10102) server never sees second packet
fn test_udp_twice() {
let server_addr = next_test_ip4();
let client_addr = next_test_ip4();

View File

@ -251,6 +251,7 @@ mod tests {
use super::super::local_loop;
#[test]
#[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
fn connect_err() {
match PipeWatcher::connect(local_loop(), &"path/to/nowhere".to_c_str()) {
Ok(*) => fail!(),
@ -259,6 +260,7 @@ mod tests {
}
#[test]
#[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
fn bind_err() {
match PipeListener::bind(local_loop(), &"path/to/nowhere".to_c_str()) {
Ok(*) => fail!(),
@ -267,6 +269,7 @@ mod tests {
}
#[test]
#[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
fn bind() {
let p = next_test_unix().to_c_str();
match PipeListener::bind(local_loop(), &p) {
@ -276,6 +279,7 @@ mod tests {
}
#[test] #[should_fail]
#[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
fn bind_fail() {
let p = next_test_unix().to_c_str();
let _w = PipeListener::bind(local_loop(), &p).unwrap();
@ -283,6 +287,7 @@ mod tests {
}
#[test]
#[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
fn connect() {
let path = next_test_unix();
let path2 = path.clone();
@ -308,6 +313,7 @@ mod tests {
}
#[test] #[should_fail]
#[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
fn connect_fail() {
let path = next_test_unix();
let path2 = path.clone();

View File

@ -232,6 +232,6 @@ impl Drop for Process {
fn drop(&mut self) {
let _m = self.fire_homing_missile();
assert!(self.to_wake.is_none());
self.close_async_();
self.close();
}
}

View File

@ -30,26 +30,21 @@ pub struct SignalWatcher {
impl SignalWatcher {
pub fn new(loop_: &mut Loop, signum: Signum,
channel: SharedChan<Signum>) -> Result<~SignalWatcher, UvError> {
let handle = UvHandle::alloc(None::<SignalWatcher>, uvll::UV_SIGNAL);
let s = ~SignalWatcher {
handle: UvHandle::alloc(None::<SignalWatcher>, uvll::UV_SIGNAL),
home: get_handle_to_current_scheduler!(),
channel: channel,
signal: signum,
};
assert_eq!(unsafe {
uvll::uv_signal_init(loop_.handle, handle)
uvll::uv_signal_init(loop_.handle, s.handle)
}, 0);
match unsafe { uvll::uv_signal_start(handle, signal_cb, signum as c_int) } {
0 => {
let s = ~SignalWatcher {
handle: handle,
home: get_handle_to_current_scheduler!(),
channel: channel,
signal: signum,
};
Ok(s.install())
}
n => {
unsafe { uvll::free_handle(handle) }
Err(UvError(n))
}
match unsafe {
uvll::uv_signal_start(s.handle, signal_cb, signum as c_int)
} {
0 => Ok(s.install()),
n => Err(UvError(n)),
}
}

View File

@ -67,12 +67,27 @@ impl UvHandle<uvll::uv_timer_t> for TimerWatcher {
impl RtioTimer for TimerWatcher {
fn sleep(&mut self, msecs: u64) {
let (_m, sched) = self.fire_homing_missile_sched();
// As with all of the below functions, we must be extra careful when
// destroying the previous action. If the previous action was a channel,
// destroying it could invoke a context switch. For these situtations,
// we must temporarily un-home ourselves, then destroy the action, and
// then re-home again.
let missile = self.fire_homing_missile();
self.stop();
let _missile = match util::replace(&mut self.action, None) {
None => missile, // no need to do a homing dance
Some(action) => {
util::ignore(missile); // un-home ourself
util::ignore(action); // destroy the previous action
self.fire_homing_missile() // re-home ourself
}
};
// If the descheduling operation unwinds after the timer has been
// started, then we need to call stop on the timer.
let _f = ForbidUnwind::new("timer");
let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |_sched, task| {
self.action = Some(WakeTask(task));
self.start(msecs, 0);
@ -87,6 +102,7 @@ impl RtioTimer for TimerWatcher {
// of the homing missile
let _prev_action = {
let _m = self.fire_homing_missile();
self.stop();
self.start(msecs, 0);
util::replace(&mut self.action, Some(SendOnce(chan)))
};
@ -97,12 +113,11 @@ impl RtioTimer for TimerWatcher {
fn period(&mut self, msecs: u64) -> Port<()> {
let (port, chan) = stream();
let _m = self.fire_homing_missile();
// similarly to the destructor, we must drop the previous action outside
// of the homing missile
let _prev_action = {
let _m = self.fire_homing_missile();
self.stop();
self.start(msecs, msecs);
util::replace(&mut self.action, Some(SendMany(chan)))
};
@ -236,6 +251,18 @@ mod test {
timer.oneshot(1);
}
#[test]
fn reset_doesnt_switch_tasks2() {
// similar test to the one above.
let mut timer = TimerWatcher::new(local_loop());
let timer_port = Cell::new(timer.period(1000));
do spawn {
timer_port.take().try_recv();
}
timer.sleep(1);
}
#[test]
fn sender_goes_away_oneshot() {

View File

@ -113,6 +113,6 @@ impl HomingIO for TtyWatcher {
impl Drop for TtyWatcher {
fn drop(&mut self) {
let _m = self.fire_homing_missile();
self.close();
self.close_async_();
}
}

View File

@ -47,14 +47,14 @@ pub static UNKNOWN: c_int = -4094;
pub mod errors {
use std::libc::c_int;
pub static EACCES: c_int = -4093;
pub static ECONNREFUSED: c_int = -4079;
pub static ECONNRESET: c_int = -4078;
pub static ENOTCONN: c_int = -4054;
pub static EPIPE: c_int = -4048;
pub static ECONNABORTED: c_int = -4080;
pub static ECANCELED: c_int = -4082;
pub static EBADF: c_int = -4084;
pub static EACCES: c_int = -4092;
pub static ECONNREFUSED: c_int = -4078;
pub static ECONNRESET: c_int = -4077;
pub static ENOTCONN: c_int = -4053;
pub static EPIPE: c_int = -4047;
pub static ECONNABORTED: c_int = -4079;
pub static ECANCELED: c_int = -4081;
pub static EBADF: c_int = -4083;
}
#[cfg(not(windows))]
pub mod errors {
@ -87,19 +87,19 @@ pub static STDIO_WRITABLE_PIPE: c_int = 0x20;
#[cfg(unix)]
pub type uv_buf_len_t = libc::size_t;
#[cfg(windows)]
pub type uv_buf_len_t = u32;
pub type uv_buf_len_t = libc::c_ulong;
// see libuv/include/uv-unix.h
#[cfg(unix)]
pub struct uv_buf_t {
base: *u8,
len: libc::size_t,
len: uv_buf_len_t,
}
// see libuv/include/uv-win.h
#[cfg(windows)]
pub struct uv_buf_t {
len: u32,
len: uv_buf_len_t,
base: *u8,
}
@ -544,7 +544,19 @@ pub unsafe fn guess_handle(handle: c_int) -> c_int {
// uv_support is the result of compiling rust_uv.cpp
//
// Note that this is in a cfg'd block so it doesn't get linked during testing.
// There's a bit of a conundrum when testing in that we're actually assuming
// that the tests are running in a uv loop, but they were created from the
// statically linked uv to the original rustuv crate. When we create the test
// executable, on some platforms if we re-link against uv, it actually creates
// second copies of everything. We obviously don't want this, so instead of
// dying horribly during testing, we allow all of the test rustuv's references
// to get resolved to the original rustuv crate.
#[link_args = "-luv_support -luv"]
#[cfg(not(test))]
extern {}
extern {
fn rust_uv_loop_new() -> *c_void;

View File

@ -33,7 +33,8 @@ use result::{Ok, Err};
use rt::io::buffered::LineBufferedWriter;
use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io,
CloseAsynchronously};
use super::{Reader, Writer, io_error, IoError, OtherIoError};
use super::{Reader, Writer, io_error, IoError, OtherIoError,
standard_error, EndOfFile};
// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
@ -203,6 +204,15 @@ impl Reader for StdReader {
File(ref mut file) => file.read(buf).map(|i| i as uint),
};
match ret {
// When reading a piped stdin, libuv will return 0-length reads when
// stdin reaches EOF. For pretty much all other streams it will
// return an actual EOF error, but apparently for stdin it's a
// little different. Hence, here we convert a 0 length read to an
// end-of-file indicator so the caller knows to stop reading.
Ok(0) => {
io_error::cond.raise(standard_error(EndOfFile));
None
}
Ok(amt) => Some(amt as uint),
Err(e) => {
io_error::cond.raise(e);

View File

@ -142,14 +142,10 @@ mod test {
fn oneshot_twice() {
do run_in_mt_newsched_task {
let mut timer = Timer::new().unwrap();
let port1 = timer.oneshot(100000000000);
let port1 = timer.oneshot(10000);
let port = timer.oneshot(1);
port.recv();
let port1 = Cell::new(port1);
let ret = do task::try {
port1.take().recv();
};
assert!(ret.is_err());
assert_eq!(port1.try_recv(), None);
}
}

@ -1 +1 @@
Subproject commit c6ecf97aafc858c2ad1089fb78da6c586d61d8b6
Subproject commit 7ac7e0248b34732e9963cdb8e31f7e612d23d14b