ruby-changes:36280
From: usa <ko1@a...>
Date: Mon, 10 Nov 2014 19:42:34 +0900 (JST)
Subject: [ruby-changes:36280] usa:r48361 (trunk): * win32/win32.c, include/win32/win32.h (rb_w32_set_nonblock): new
usa 2014-11-10 19:42:19 +0900 (Mon, 10 Nov 2014) New Revision: 48361 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=48361 Log: * 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. Modified files: trunk/ChangeLog trunk/ext/io/nonblock/nonblock.c trunk/include/ruby/win32.h trunk/io.c trunk/test/ruby/test_io.rb trunk/win32/win32.c Index: include/ruby/win32.h =================================================================== --- include/ruby/win32.h (revision 48360) +++ include/ruby/win32.h (revision 48361) @@ -327,6 +327,7 @@ extern rb_pid_t rb_w32_uaspawn(int, cons https://github.com/ruby/ruby/blob/trunk/include/ruby/win32.h#L327 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__) Index: ChangeLog =================================================================== --- ChangeLog (revision 48360) +++ ChangeLog (revision 48361) @@ -1,3 +1,21 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Mon Nov 10 19:37:09 2014 NAKAMURA Usaku <usa@r...> + + * 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@r...> * ext/etc/etc.c (etc_getlogin): set login name encoding properly. Index: io.c =================================================================== --- io.c (revision 48360) +++ io.c (revision 48361) @@ -2474,6 +2474,11 @@ read_all(rb_io_t *fptr, long siz, VALUE https://github.com/ruby/ruby/blob/trunk/io.c#L2474 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) https://github.com/ruby/ruby/blob/trunk/io.c#L2494 rb_sys_fail_path(fptr->pathv); } } +#endif } void Index: win32/win32.c =================================================================== --- win32/win32.c (revision 48360) +++ win32/win32.c (revision 48361) @@ -4122,6 +4122,33 @@ fcntl(int fd, int cmd, ...) https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L4122 } } +/* 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 si https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L6381 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, si https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L6555 if (size > 0) goto retry; } + if (ret == 0) { + ret = -1; + errno = EWOULDBLOCK; + } MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); Index: ext/io/nonblock/nonblock.c =================================================================== --- ext/io/nonblock/nonblock.c (revision 48360) +++ ext/io/nonblock/nonblock.c (revision 48361) @@ -79,7 +79,10 @@ rb_io_nonblock_set(VALUE io, VALUE nb) https://github.com/ruby/ruby/blob/trunk/ext/io/nonblock/nonblock.c#L79 { 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; } Index: test/ruby/test_io.rb =================================================================== --- test/ruby/test_io.rb (revision 48360) +++ test/ruby/test_io.rb (revision 48361) @@ -1259,7 +1259,6 @@ class TestIO < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1259 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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1268 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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1277 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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1287 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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1306 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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1317 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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1331 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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1344 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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L2635 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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L2923 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/