summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2021-04-24 14:04:04 +0900
committernagachika <nagachika@ruby-lang.org>2021-04-24 14:04:04 +0900
commit13f93ad16d3d1ecf96ece229cd4bc5ea294e1a71 (patch)
tree21bddf7f946238897e120b267b963e6829a7389f
parent5a9b5b8e953dc36f4f7f7639e8aeaa8132241c79 (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.c68
-rw-r--r--test/fiber/test_io.rb35
-rw-r--r--version.h4
3 files changed, 74 insertions, 33 deletions
diff --git a/io.c b/io.c
index 48592ac51a..bc31c7bffd 100644
--- a/io.c
+++ b/io.c
@@ -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
diff --git a/version.h b/version.h
index 413340163f..f4cfe79521 100644
--- a/version.h
+++ b/version.h
@@ -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"