From 51dee044c1cb079a463118c5113ae9fdf96e463e Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 30 Mar 2025 12:11:59 +0900 Subject: [PATCH] merge revision(s) 5f77f9bea61fb4cc8447a76e191fdfb28f076862: [Backport #21195] Fix handling of `error`/`errno` in `io_internal_wait`. (#12961) [Bug #21195] --- io.c | 10 ++++++++-- test/ruby/test_io.rb | 26 ++++++++++++++++++++++++++ version.h | 2 +- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/io.c b/io.c index 7f23656049..b4b262b6ac 100644 --- a/io.c +++ b/io.c @@ -1156,8 +1156,14 @@ io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct time return -1; } - errno = error; - return -1; + // If there was an error BEFORE we started waiting, return it: + if (error) { + errno = error; + return -1; + } else { + // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want: + return ready; + } } static VALUE diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 16de2e8a76..760279ca3d 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -4297,4 +4297,30 @@ __END__ end end end + + def test_blocking_timeout + assert_separately([], <<~'RUBY') + IO.pipe do |r, w| + trap(:INT) do + w.puts "INT" + end + + main = Thread.current + thread = Thread.new do + # Wait until the main thread has entered `$stdin.gets`: + Thread.pass until main.status == 'sleep' + + # Cause an interrupt while handling `$stdin.gets`: + Process.kill :INT, $$ + end + + r.timeout = 1 + assert_equal("INT", r.gets.chomp) + rescue IO::TimeoutError + # Ignore - some platforms don't support interrupting `gets`. + ensure + thread&.join + end + RUBY + end end diff --git a/version.h b/version.h index b9f9eee68d..31b5671956 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 138 +#define RUBY_PATCHLEVEL 139 #include "ruby/version.h" #include "ruby/internal/abi.h"