Skip to content

Commit aa7380f

Browse files
ioquatixk0kubun
authored andcommitted
Fix handling of error/errno in io_internal_wait. (ruby#12961)
[Bug #21195]
1 parent 2efa400 commit aa7380f

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

io.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,8 +1181,14 @@ io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct time
11811181
return -1;
11821182
}
11831183

1184-
errno = error;
1185-
return -1;
1184+
// If there was an error BEFORE we started waiting, return it:
1185+
if (error) {
1186+
errno = error;
1187+
return -1;
1188+
} else {
1189+
// Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1190+
return ready;
1191+
}
11861192
}
11871193

11881194
static VALUE

test/ruby/test_io.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4379,4 +4379,30 @@ def test_stdout_to_closed_pipe
43794379
end
43804380
end
43814381
end
4382+
4383+
def test_blocking_timeout
4384+
assert_separately([], <<~'RUBY')
4385+
IO.pipe do |r, w|
4386+
trap(:INT) do
4387+
w.puts "INT"
4388+
end
4389+
4390+
main = Thread.current
4391+
thread = Thread.new do
4392+
# Wait until the main thread has entered `$stdin.gets`:
4393+
Thread.pass until main.status == 'sleep'
4394+
4395+
# Cause an interrupt while handling `$stdin.gets`:
4396+
Process.kill :INT, $$
4397+
end
4398+
4399+
r.timeout = 1
4400+
assert_equal("INT", r.gets.chomp)
4401+
rescue IO::TimeoutError
4402+
# Ignore - some platforms don't support interrupting `gets`.
4403+
ensure
4404+
thread&.join
4405+
end
4406+
RUBY
4407+
end
43824408
end

0 commit comments

Comments
 (0)