From 6acf227cc8db09ca25d274918f860849c41df19a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 24 Nov 2013 21:47:13 -0800 Subject: [PATCH] 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 --- src/librustuv/stream.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/librustuv/stream.rs b/src/librustuv/stream.rs index 08b307700c7..47ef26ee9d4 100644 --- a/src/librustuv/stream.rs +++ b/src/librustuv/stream.rs @@ -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),