summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--ext/io/nonblock/nonblock.c5
-rw-r--r--include/ruby/win32.h1
-rw-r--r--io.c6
-rw-r--r--test/ruby/test_io.rb10
-rw-r--r--win32/win32.c44
6 files changed, 72 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index f16eef8c2d..fbc241727f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Mon Nov 10 19:37:09 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c, include/win32/win32.h (rb_w32_set_nonblock): new
+ function to support nonblock-mode of pipes.
+
+ * win32/win32.c (rb_w32_read): nonblock-mode pipe returns ERROR_NO_DATA
+ if there is no data, but also returns it if remote-end is closed.
+
+ * win32/win32.c (rb_w32_write): if cannot to write any data, it may be
+ blocking.
+
+ * io.c (rb_io_set_nonblock): use rb_w32_set_nonblock for Windows.
+
+ * ext/io/nonblock/nonblock.c (rb_io_nonblock_set): use ruby's API when
+ setting nonblock-mode.
+
+ * test/ruby/test_io.rb: test nonblock pipes on Windows.
+
Mon Nov 10 17:24:34 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/etc/etc.c (etc_getlogin): set login name encoding properly.
diff --git a/ext/io/nonblock/nonblock.c b/ext/io/nonblock/nonblock.c
index ccd8728a31..2c5c298126 100644
--- a/ext/io/nonblock/nonblock.c
+++ b/ext/io/nonblock/nonblock.c
@@ -79,7 +79,10 @@ rb_io_nonblock_set(VALUE io, VALUE nb)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
- io_nonblock_set(fptr->fd, io_nonblock_mode(fptr->fd), RTEST(nb));
+ if (RTEST(nb))
+ rb_io_set_nonblock(fptr);
+ else
+ io_nonblock_set(fptr->fd, io_nonblock_mode(fptr->fd), RTEST(nb));
return io;
}
diff --git a/include/ruby/win32.h b/include/ruby/win32.h
index a6996bc95a..4b938626af 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -327,6 +327,7 @@ extern rb_pid_t rb_w32_uaspawn(int, const char *, char *const *);
extern rb_pid_t rb_w32_uaspawn_flags(int, const char *, char *const *, DWORD);
extern int kill(int, int);
extern int fcntl(int, int, ...);
+extern int rb_w32_set_nonblock(int);
extern rb_pid_t rb_w32_getpid(void);
extern rb_pid_t rb_w32_getppid(void);
#if !defined(__BORLANDC__)
diff --git a/io.c b/io.c
index 290e8b1de3..fb6b95da88 100644
--- a/io.c
+++ b/io.c
@@ -2474,6 +2474,11 @@ read_all(rb_io_t *fptr, long siz, VALUE str)
void
rb_io_set_nonblock(rb_io_t *fptr)
{
+#ifdef _WIN32
+ if (rb_w32_set_nonblock(fptr->fd) != 0) {
+ rb_sys_fail_path(fptr->pathv);
+ }
+#else
int oflags;
#ifdef F_GETFL
oflags = fcntl(fptr->fd, F_GETFL);
@@ -2489,6 +2494,7 @@ rb_io_set_nonblock(rb_io_t *fptr)
rb_sys_fail_path(fptr->pathv);
}
}
+#endif
}
void
diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb
index f6fc27b051..af77da2777 100644
--- a/test/ruby/test_io.rb
+++ b/test/ruby/test_io.rb
@@ -1259,7 +1259,6 @@ class TestIO < Test::Unit::TestCase
end
def test_write_nonblock
- skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
pipe(proc do |w|
w.write_nonblock(1)
w.close
@@ -1269,7 +1268,6 @@ class TestIO < Test::Unit::TestCase
end
def test_read_nonblock_with_not_empty_buffer
- skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
w.write "foob"
w.close
@@ -1279,7 +1277,6 @@ class TestIO < Test::Unit::TestCase
end
def test_write_nonblock_simple_no_exceptions
- skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
pipe(proc do |w|
w.write_nonblock('1', exception: false)
w.close
@@ -1290,7 +1287,6 @@ class TestIO < Test::Unit::TestCase
def test_read_nonblock_error
return if !have_nonblock?
- skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
begin
r.read_nonblock 4096
@@ -1310,7 +1306,6 @@ class TestIO < Test::Unit::TestCase
def test_read_nonblock_no_exceptions
return if !have_nonblock?
- skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
assert_equal :wait_readable, r.read_nonblock(4096, exception: false)
w.puts "HI!"
@@ -1322,7 +1317,6 @@ class TestIO < Test::Unit::TestCase
def test_read_nonblock_with_buffer_no_exceptions
return if !have_nonblock?
- skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
assert_equal :wait_readable, r.read_nonblock(4096, "", exception: false)
w.puts "HI!"
@@ -1337,7 +1331,6 @@ class TestIO < Test::Unit::TestCase
def test_write_nonblock_error
return if !have_nonblock?
- skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
begin
loop {
@@ -1351,7 +1344,6 @@ class TestIO < Test::Unit::TestCase
def test_write_nonblock_no_exceptions
return if !have_nonblock?
- skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
loop {
ret = w.write_nonblock("a"*100000, exception: false)
@@ -2643,7 +2635,6 @@ End
end
def test_cross_thread_close_fd
- skip "cross thread close causes hung-up if pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe do |r,w|
read_thread = Thread.new do
begin
@@ -2932,7 +2923,6 @@ End
end
def test_readpartial_locktmp
- skip "nonblocking mode is not supported for pipe on this platform" if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
bug6099 = '[ruby-dev:45297]'
buf = " " * 100
data = "a" * 100
diff --git a/win32/win32.c b/win32/win32.c
index 9f80d3228d..2661641266 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -4122,6 +4122,33 @@ fcntl(int fd, int cmd, ...)
}
}
+/* License: Ruby's */
+int
+rb_w32_set_nonblock(int fd)
+{
+ SOCKET sock = TO_SOCKET(fd);
+ if (is_socket(sock)) {
+ return setfl(sock, O_NONBLOCK);
+ }
+ else if (is_pipe(sock)) {
+ DWORD state;
+ if (!GetNamedPipeHandleState((HANDLE)sock, &state, NULL, NULL, NULL, NULL, 0)) {
+ errno = map_errno(GetLastError());
+ return -1;
+ }
+ state |= PIPE_NOWAIT;
+ if (!SetNamedPipeHandleState((HANDLE)sock, &state, NULL, NULL)) {
+ errno = map_errno(GetLastError());
+ return -1;
+ }
+ return 0;
+ }
+ else {
+ errno = EBADF;
+ return -1;
+ }
+}
+
#ifndef WNOHANG
#define WNOHANG -1
#endif
@@ -6354,7 +6381,18 @@ rb_w32_read(int fd, void *buf, size_t size)
if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, pol)) {
err = GetLastError();
- if (err != ERROR_IO_PENDING) {
+ if (err == ERROR_NO_DATA && (_osfile(fd) & FPIPE)) {
+ DWORD state;
+ if (GetNamedPipeHandleState((HANDLE)_osfhnd(fd), &state, NULL, NULL, NULL, NULL, 0) && (state & PIPE_NOWAIT)) {
+ errno = EWOULDBLOCK;
+ }
+ else {
+ errno = map_errno(err);
+ }
+ MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
+ return -1;
+ }
+ else if (err != ERROR_IO_PENDING) {
if (pol) CloseHandle(ol.hEvent);
if (err == ERROR_ACCESS_DENIED)
errno = EBADF;
@@ -6517,6 +6555,10 @@ rb_w32_write(int fd, const void *buf, size_t size)
if (size > 0)
goto retry;
}
+ if (ret == 0) {
+ ret = -1;
+ errno = EWOULDBLOCK;
+ }
MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));