diff --git a/src/win/pipe.c b/src/win/pipe.c index 1fe253d1..1ba2568c 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1194,8 +1194,16 @@ int uv_pipe_read_start(uv_pipe_t* handle, /* If reading was stopped and then started again, there could still be a read * request pending. */ - if (!(handle->flags & UV_HANDLE_READ_PENDING)) + if (!(handle->flags & UV_HANDLE_READ_PENDING)) { + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + handle->read_req.event_handle == NULL) { + handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL); + if (handle->read_req.event_handle == NULL) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } uv_pipe_queue_read(loop, handle); + } return 0; } diff --git a/test/test-list.h b/test/test-list.h index 50aaed46..23bd2eb1 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -60,6 +60,7 @@ TEST_DECLARE (tty_composing_character) TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) +TEST_DECLARE (stdio_emulate_iocp) TEST_DECLARE (ip6_pton) TEST_DECLARE (connect_unspecified) TEST_DECLARE (ipc_heavy_traffic_deadlock_bug) @@ -550,6 +551,7 @@ TASK_LIST_START TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) TEST_ENTRY (stdio_over_pipes) + TEST_ENTRY (stdio_emulate_iocp) TEST_ENTRY (ip6_pton) TEST_ENTRY (connect_unspecified) TEST_ENTRY (ipc_heavy_traffic_deadlock_bug) diff --git a/test/test-stdio-over-pipes.c b/test/test-stdio-over-pipes.c index a130ff6a..1aed4712 100644 --- a/test/test-stdio-over-pipes.c +++ b/test/test-stdio-over-pipes.c @@ -94,7 +94,7 @@ static void after_write(uv_write_t* req, int status) { } -static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) { +static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* rdbuf) { uv_write_t* req; uv_buf_t wrbuf; int r; @@ -103,11 +103,11 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) { if (nread > 0) { output_used += nread; - if (output_used == 12) { + if (output_used % 12 == 0) { ASSERT(memcmp("hello world\n", output, 12) == 0); - wrbuf = uv_buf_init(output, output_used); + wrbuf = uv_buf_init(output, 12); req = malloc(sizeof(*req)); - r = uv_write(req, (uv_stream_t*)&in, &wrbuf, 1, after_write); + r = uv_write(req, (uv_stream_t*) &in, &wrbuf, 1, after_write); ASSERT(r == 0); } } @@ -116,10 +116,10 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) { } -TEST_IMPL(stdio_over_pipes) { +static void test_stdio_over_pipes(int overlapped) { int r; uv_process_t process; - uv_stdio_container_t stdio[2]; + uv_stdio_container_t stdio[3]; loop = uv_default_loop(); @@ -129,11 +129,15 @@ TEST_IMPL(stdio_over_pipes) { uv_pipe_init(loop, &in, 0); options.stdio = stdio; - options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; - options.stdio[0].data.stream = (uv_stream_t*)∈ - options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - options.stdio[1].data.stream = (uv_stream_t*)&out; - options.stdio_count = 2; + options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | + (overlapped ? UV_OVERLAPPED_PIPE : 0); + options.stdio[0].data.stream = (uv_stream_t*) ∈ + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE | + (overlapped ? UV_OVERLAPPED_PIPE : 0); + options.stdio[1].data.stream = (uv_stream_t*) &out; + options.stdio[2].flags = UV_INHERIT_FD; + options.stdio[2].data.fd = 2; + options.stdio_count = 3; r = uv_spawn(loop, &process, &options); ASSERT(r == 0); @@ -145,13 +149,22 @@ TEST_IMPL(stdio_over_pipes) { ASSERT(r == 0); ASSERT(on_read_cb_called > 1); - ASSERT(after_write_cb_called == 1); + ASSERT(after_write_cb_called == 2); ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 3); - ASSERT(memcmp("hello world\n", output, 12) == 0); - ASSERT(output_used == 12); + ASSERT(memcmp("hello world\nhello world\n", output, 24) == 0); + ASSERT(output_used == 24); MAKE_VALGRIND_HAPPY(); +} + +TEST_IMPL(stdio_over_pipes) { + test_stdio_over_pipes(0); + return 0; +} + +TEST_IMPL(stdio_emulate_iocp) { + test_stdio_over_pipes(1); return 0; } @@ -160,18 +173,19 @@ TEST_IMPL(stdio_over_pipes) { static int on_pipe_read_called; static int after_write_called; -static uv_pipe_t stdin_pipe; -static uv_pipe_t stdout_pipe; +static uv_pipe_t stdin_pipe1; +static uv_pipe_t stdout_pipe1; +static uv_pipe_t stdin_pipe2; +static uv_pipe_t stdout_pipe2; -static void on_pipe_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { +static void on_pipe_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) { ASSERT(nread > 0); ASSERT(memcmp("hello world\n", buf->base, nread) == 0); on_pipe_read_called++; free(buf->base); - uv_close((uv_handle_t*)&stdin_pipe, close_cb); - uv_close((uv_handle_t*)&stdout_pipe, close_cb); + uv_read_stop(pipe); } @@ -204,52 +218,81 @@ int stdio_over_pipes_helper(void) { uv_write_t write_req[ARRAY_SIZE(buffers)]; uv_buf_t buf[ARRAY_SIZE(buffers)]; unsigned int i; + int j; int r; uv_loop_t* loop = uv_default_loop(); ASSERT(UV_NAMED_PIPE == uv_guess_handle(0)); ASSERT(UV_NAMED_PIPE == uv_guess_handle(1)); - r = uv_pipe_init(loop, &stdin_pipe, 0); + r = uv_pipe_init(loop, &stdin_pipe1, 0); ASSERT(r == 0); - r = uv_pipe_init(loop, &stdout_pipe, 0); + r = uv_pipe_init(loop, &stdout_pipe1, 0); + ASSERT(r == 0); + r = uv_pipe_init(loop, &stdin_pipe2, 0); + ASSERT(r == 0); + r = uv_pipe_init(loop, &stdout_pipe2, 0); ASSERT(r == 0); - uv_pipe_open(&stdin_pipe, 0); - uv_pipe_open(&stdout_pipe, 1); + uv_pipe_open(&stdin_pipe1, 0); + uv_pipe_open(&stdout_pipe1, 1); + uv_pipe_open(&stdin_pipe2, 0); + uv_pipe_open(&stdout_pipe2, 1); - /* Unref both stdio handles to make sure that all writes complete. */ - uv_unref((uv_handle_t*)&stdin_pipe); - uv_unref((uv_handle_t*)&stdout_pipe); + for (j = 0; j < 2; j++) { + /* Unref both stdio handles to make sure that all writes complete. */ + uv_unref((uv_handle_t*) &stdin_pipe1); + uv_unref((uv_handle_t*) &stdout_pipe1); + uv_unref((uv_handle_t*) &stdin_pipe2); + uv_unref((uv_handle_t*) &stdout_pipe2); - for (i = 0; i < ARRAY_SIZE(buffers); i++) { - buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i])); - } + for (i = 0; i < ARRAY_SIZE(buffers); i++) { + buf[i] = uv_buf_init((char*) buffers[i], strlen(buffers[i])); + } - for (i = 0; i < ARRAY_SIZE(buffers); i++) { - r = uv_write(&write_req[i], (uv_stream_t*)&stdout_pipe, &buf[i], 1, - after_pipe_write); + for (i = 0; i < ARRAY_SIZE(buffers); i++) { + r = uv_write(&write_req[i], + (uv_stream_t*) (j == 0 ? &stdout_pipe1 : &stdout_pipe2), + &buf[i], + 1, + after_pipe_write); + ASSERT(r == 0); + } + + notify_parent_process(); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(after_write_called == 7 * (j + 1)); + ASSERT(on_pipe_read_called == j); + ASSERT(close_cb_called == 0); + + uv_ref((uv_handle_t*) &stdout_pipe1); + uv_ref((uv_handle_t*) &stdin_pipe1); + uv_ref((uv_handle_t*) &stdout_pipe2); + uv_ref((uv_handle_t*) &stdin_pipe2); + + r = uv_read_start((uv_stream_t*) (j == 0 ? &stdin_pipe1 : &stdin_pipe2), + on_read_alloc, + on_pipe_read); ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(after_write_called == 7 * (j + 1)); + ASSERT(on_pipe_read_called == j + 1); + ASSERT(close_cb_called == 0); } - notify_parent_process(); - uv_run(loop, UV_RUN_DEFAULT); - - ASSERT(after_write_called == 7); - ASSERT(on_pipe_read_called == 0); - ASSERT(close_cb_called == 0); - - uv_ref((uv_handle_t*)&stdout_pipe); - uv_ref((uv_handle_t*)&stdin_pipe); - - r = uv_read_start((uv_stream_t*)&stdin_pipe, on_read_alloc, on_pipe_read); - ASSERT(r == 0); + uv_close((uv_handle_t*)&stdin_pipe1, close_cb); + uv_close((uv_handle_t*)&stdout_pipe1, close_cb); + uv_close((uv_handle_t*)&stdin_pipe2, close_cb); + uv_close((uv_handle_t*)&stdout_pipe2, close_cb); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(after_write_called == 7); - ASSERT(on_pipe_read_called == 1); - ASSERT(close_cb_called == 2); + ASSERT(after_write_called == 14); + ASSERT(on_pipe_read_called == 2); + ASSERT(close_cb_called == 4); MAKE_VALGRIND_HAPPY(); return 0;