* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48361 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
6ccf3d68c2
commit
fd9f6bde95
18
ChangeLog
18
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>
|
Mon Nov 10 17:24:34 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* ext/etc/etc.c (etc_getlogin): set login name encoding properly.
|
* ext/etc/etc.c (etc_getlogin): set login name encoding properly.
|
||||||
|
@ -79,6 +79,9 @@ rb_io_nonblock_set(VALUE io, VALUE nb)
|
|||||||
{
|
{
|
||||||
rb_io_t *fptr;
|
rb_io_t *fptr;
|
||||||
GetOpenFile(io, fptr);
|
GetOpenFile(io, fptr);
|
||||||
|
if (RTEST(nb))
|
||||||
|
rb_io_set_nonblock(fptr);
|
||||||
|
else
|
||||||
io_nonblock_set(fptr->fd, io_nonblock_mode(fptr->fd), RTEST(nb));
|
io_nonblock_set(fptr->fd, io_nonblock_mode(fptr->fd), RTEST(nb));
|
||||||
return io;
|
return io;
|
||||||
}
|
}
|
||||||
|
@ -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 rb_pid_t rb_w32_uaspawn_flags(int, const char *, char *const *, DWORD);
|
||||||
extern int kill(int, int);
|
extern int kill(int, int);
|
||||||
extern int fcntl(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_getpid(void);
|
||||||
extern rb_pid_t rb_w32_getppid(void);
|
extern rb_pid_t rb_w32_getppid(void);
|
||||||
#if !defined(__BORLANDC__)
|
#if !defined(__BORLANDC__)
|
||||||
|
6
io.c
6
io.c
@ -2474,6 +2474,11 @@ read_all(rb_io_t *fptr, long siz, VALUE str)
|
|||||||
void
|
void
|
||||||
rb_io_set_nonblock(rb_io_t *fptr)
|
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;
|
int oflags;
|
||||||
#ifdef F_GETFL
|
#ifdef F_GETFL
|
||||||
oflags = fcntl(fptr->fd, 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);
|
rb_sys_fail_path(fptr->pathv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1259,7 +1259,6 @@ class TestIO < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_write_nonblock
|
def test_write_nonblock
|
||||||
skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
|
||||||
pipe(proc do |w|
|
pipe(proc do |w|
|
||||||
w.write_nonblock(1)
|
w.write_nonblock(1)
|
||||||
w.close
|
w.close
|
||||||
@ -1269,7 +1268,6 @@ class TestIO < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_read_nonblock_with_not_empty_buffer
|
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|
|
with_pipe {|r, w|
|
||||||
w.write "foob"
|
w.write "foob"
|
||||||
w.close
|
w.close
|
||||||
@ -1279,7 +1277,6 @@ class TestIO < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_write_nonblock_simple_no_exceptions
|
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|
|
pipe(proc do |w|
|
||||||
w.write_nonblock('1', exception: false)
|
w.write_nonblock('1', exception: false)
|
||||||
w.close
|
w.close
|
||||||
@ -1290,7 +1287,6 @@ class TestIO < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_read_nonblock_error
|
def test_read_nonblock_error
|
||||||
return if !have_nonblock?
|
return if !have_nonblock?
|
||||||
skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
|
||||||
with_pipe {|r, w|
|
with_pipe {|r, w|
|
||||||
begin
|
begin
|
||||||
r.read_nonblock 4096
|
r.read_nonblock 4096
|
||||||
@ -1310,7 +1306,6 @@ class TestIO < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_read_nonblock_no_exceptions
|
def test_read_nonblock_no_exceptions
|
||||||
return if !have_nonblock?
|
return if !have_nonblock?
|
||||||
skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
|
||||||
with_pipe {|r, w|
|
with_pipe {|r, w|
|
||||||
assert_equal :wait_readable, r.read_nonblock(4096, exception: false)
|
assert_equal :wait_readable, r.read_nonblock(4096, exception: false)
|
||||||
w.puts "HI!"
|
w.puts "HI!"
|
||||||
@ -1322,7 +1317,6 @@ class TestIO < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_read_nonblock_with_buffer_no_exceptions
|
def test_read_nonblock_with_buffer_no_exceptions
|
||||||
return if !have_nonblock?
|
return if !have_nonblock?
|
||||||
skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
|
||||||
with_pipe {|r, w|
|
with_pipe {|r, w|
|
||||||
assert_equal :wait_readable, r.read_nonblock(4096, "", exception: false)
|
assert_equal :wait_readable, r.read_nonblock(4096, "", exception: false)
|
||||||
w.puts "HI!"
|
w.puts "HI!"
|
||||||
@ -1337,7 +1331,6 @@ class TestIO < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_write_nonblock_error
|
def test_write_nonblock_error
|
||||||
return if !have_nonblock?
|
return if !have_nonblock?
|
||||||
skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
|
||||||
with_pipe {|r, w|
|
with_pipe {|r, w|
|
||||||
begin
|
begin
|
||||||
loop {
|
loop {
|
||||||
@ -1351,7 +1344,6 @@ class TestIO < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_write_nonblock_no_exceptions
|
def test_write_nonblock_no_exceptions
|
||||||
return if !have_nonblock?
|
return if !have_nonblock?
|
||||||
skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
|
||||||
with_pipe {|r, w|
|
with_pipe {|r, w|
|
||||||
loop {
|
loop {
|
||||||
ret = w.write_nonblock("a"*100000, exception: false)
|
ret = w.write_nonblock("a"*100000, exception: false)
|
||||||
@ -2643,7 +2635,6 @@ End
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_cross_thread_close_fd
|
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|
|
with_pipe do |r,w|
|
||||||
read_thread = Thread.new do
|
read_thread = Thread.new do
|
||||||
begin
|
begin
|
||||||
@ -2932,7 +2923,6 @@ End
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_readpartial_locktmp
|
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]'
|
bug6099 = '[ruby-dev:45297]'
|
||||||
buf = " " * 100
|
buf = " " * 100
|
||||||
data = "a" * 100
|
data = "a" * 100
|
||||||
|
@ -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
|
#ifndef WNOHANG
|
||||||
#define WNOHANG -1
|
#define WNOHANG -1
|
||||||
#endif
|
#endif
|
||||||
@ -6354,7 +6381,18 @@ rb_w32_read(int fd, void *buf, size_t size)
|
|||||||
|
|
||||||
if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, pol)) {
|
if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, pol)) {
|
||||||
err = GetLastError();
|
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 (pol) CloseHandle(ol.hEvent);
|
||||||
if (err == ERROR_ACCESS_DENIED)
|
if (err == ERROR_ACCESS_DENIED)
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
@ -6517,6 +6555,10 @@ rb_w32_write(int fd, const void *buf, size_t size)
|
|||||||
if (size > 0)
|
if (size > 0)
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = -1;
|
||||||
|
errno = EWOULDBLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
|
MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user