Set uv's custom data before uv_read_start

This is a behavioral difference in libuv between different platforms in
different situations. It turns out that libuv on windows will immediately
allocate a buffer instead of waiting for data to be ready. What this implies is
that we must have our custom data set on the handle before we call
uv_read_start.

I wish I knew of a way to test this, but this relies to being on the windows
platform *and* reading from a true TTY handle which only happens when this is
actually attached to a terminal. I have manually verified this works.

Closes #10645
This commit is contained in:
Alex Crichton 2013-11-24 21:47:13 -08:00
parent 01b5381703
commit 6acf227cc8
1 changed files with 15 additions and 10 deletions

View File

@ -69,22 +69,27 @@ impl StreamWatcher {
// uv_read_stop function
let _f = ForbidUnwind::new("stream read");
let mut rcx = ReadContext {
buf: Some(slice_to_uv_buf(buf)),
result: 0,
task: None,
};
// When reading a TTY stream on windows, libuv will invoke alloc_cb
// immediately as part of the call to alloc_cb. What this means is that
// we must be ready for this to happen (by setting the data in the uv
// handle). In theory this otherwise doesn't need to happen until after
// the read is succesfully started.
unsafe {
uvll::set_data_for_uv_handle(self.handle, &rcx)
}
// Send off the read request, but don't block until we're sure that the
// read request is queued.
match unsafe {
uvll::uv_read_start(self.handle, alloc_cb, read_cb)
} {
0 => {
let mut rcx = ReadContext {
buf: Some(slice_to_uv_buf(buf)),
result: 0,
task: None,
};
do wait_until_woken_after(&mut rcx.task) {
unsafe {
uvll::set_data_for_uv_handle(self.handle, &rcx)
}
}
wait_until_woken_after(&mut rcx.task, || {});
match rcx.result {
n if n < 0 => Err(UvError(n as c_int)),
n => Ok(n as uint),