diff options
author | nagachika <nagachika@ruby-lang.org> | 2021-04-24 14:04:04 +0900 |
---|---|---|
committer | nagachika <nagachika@ruby-lang.org> | 2021-04-24 14:04:04 +0900 |
commit | 13f93ad16d3d1ecf96ece229cd4bc5ea294e1a71 (patch) | |
tree | 21bddf7f946238897e120b267b963e6829a7389f | |
parent | 5a9b5b8e953dc36f4f7f7639e8aeaa8132241c79 (diff) |
merge revision(s) 611e711085c7e3984555a79626d025c8b876eced,a9c5c2d614f30a616970245fef3e7ffc151e2ecf: [Backport #17527]
Test incorrect behaviour of `rb_io_wait_readable/writable`.
---
test/fiber/test_io.rb | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
Check errno before invoking scheduler in
`rb_io_wait_readable/writable`.
See <https://bugs.ruby-lang.org/issues/17527> for more details.
---
io.c | 66 +++++++++++++++++++++++++++++++++++-------------------------------
1 file changed, 35 insertions(+), 31 deletions(-)
-rw-r--r-- | io.c | 68 | ||||
-rw-r--r-- | test/fiber/test_io.rb | 35 | ||||
-rw-r--r-- | version.h | 4 |
3 files changed, 74 insertions, 33 deletions
@@ -1306,71 +1306,77 @@ rb_io_from_fd(int fd) int rb_io_wait_readable(int f) { - VALUE scheduler = rb_scheduler_current(); - if (scheduler != Qnil) { - return RTEST( - rb_scheduler_io_wait_readable(scheduler, rb_io_from_fd(f)) - ); - } + VALUE scheduler; io_fd_check_closed(f); + + scheduler = rb_scheduler_current(); switch (errno) { case EINTR: #if defined(ERESTART) case ERESTART: #endif - rb_thread_check_ints(); - return TRUE; + rb_thread_check_ints(); + return TRUE; case EAGAIN: #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif - rb_thread_wait_fd(f); - return TRUE; + if (scheduler != Qnil) { + return RTEST( + rb_scheduler_io_wait_readable(scheduler, rb_io_from_fd(f)) + ); + } else { + rb_thread_wait_fd(f); + } + return TRUE; default: - return FALSE; + return FALSE; } } int rb_io_wait_writable(int f) { - VALUE scheduler = rb_scheduler_current(); - if (scheduler != Qnil) { - return RTEST( - rb_scheduler_io_wait_writable(scheduler, rb_io_from_fd(f)) - ); - } + VALUE scheduler; io_fd_check_closed(f); + + scheduler = rb_scheduler_current(); switch (errno) { case EINTR: #if defined(ERESTART) case ERESTART: #endif - /* - * In old Linux, several special files under /proc and /sys don't handle - * select properly. Thus we need avoid to call if don't use O_NONBLOCK. - * Otherwise, we face nasty hang up. Sigh. - * e.g. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8 - * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8 - * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING(). - * Then rb_thread_check_ints() is enough. - */ - rb_thread_check_ints(); - return TRUE; + /* + * In old Linux, several special files under /proc and /sys don't handle + * select properly. Thus we need avoid to call if don't use O_NONBLOCK. + * Otherwise, we face nasty hang up. Sigh. + * e.g. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8 + * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8 + * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING(). + * Then rb_thread_check_ints() is enough. + */ + rb_thread_check_ints(); + return TRUE; case EAGAIN: #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif - rb_thread_fd_writable(f); - return TRUE; + if (scheduler != Qnil) { + return RTEST( + rb_scheduler_io_wait_writable(scheduler, rb_io_from_fd(f)) + ); + } else { + rb_thread_fd_writable(f); + } + return TRUE; default: - return FALSE; + return FALSE; } } diff --git a/test/fiber/test_io.rb b/test/fiber/test_io.rb index f01cc3af1b..fafda7c310 100644 --- a/test/fiber/test_io.rb +++ b/test/fiber/test_io.rb @@ -62,4 +62,39 @@ class TestFiberIO < Test::Unit::TestCase end end.each(&:join) end + + def test_epipe_on_read + skip "UNIXSocket is not defined!" unless defined?(UNIXSocket) + + i, o = UNIXSocket.pair + + unless i.nonblock? && o.nonblock? + i.close + o.close + skip "I/O is not non-blocking!" + end + + error = nil + + thread = Thread.new do + scheduler = Scheduler.new + Fiber.set_scheduler scheduler + + Fiber.schedule do + begin + i.close + o.write(MESSAGE) + rescue => error + # Saved into error. + end + end + end + + thread.join + + i.close + o.close + + assert_kind_of Errno::EPIPE, error + end end @@ -12,11 +12,11 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 2 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 71 +#define RUBY_PATCHLEVEL 72 #define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_MONTH 4 -#define RUBY_RELEASE_DAY 18 +#define RUBY_RELEASE_DAY 24 #include "ruby/version.h" |