Skip to content

Commit 62eb3e6

Browse files
committed
[GR-41105] Fix IO#{wait,wait_readable,wait_writable} with a timeout > INT_MAX seconds
* poll(2) only accepts an int as timeout which represents milliseconds, so that's only about 24.86 days. * ppoll() takes a struct timespec, but that does not seem available on macOS, and it might be slower due to the sigmask handling.
1 parent e9f3da4 commit 62eb3e6

File tree

3 files changed

+13
-6
lines changed

3 files changed

+13
-6
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Bug fixes:
1717
* Disallow the marshaling of polyglot exceptions since we can't properly reconstruct them (@nirvdrum).
1818
* Fix `String#split` missing a value in its return array when called with a pattern of `" "` and a _limit_ value > 0 on a string with trailing whitespace where the limit hasn't been met (@nirvdrum).
1919
* Fix `Kernel#sleep` and `Mutex#sleep` for durations smaller than 1 millisecond (#2716, @eregon).
20+
* Fix `IO#{wait,wait_readable,wait_writable}` with a timeout > INT_MAX seconds (@eregon).
2021

2122
Compatibility:
2223

lib/truffle/io/wait.rb

+2-3
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,11 @@ def ready?
1717
Truffle::IOOperations.poll(self, Truffle::IOOperations::POLLIN, 0)
1818
end
1919

20-
def wait(timeout = nil)
20+
def wait_readable(timeout = nil)
2121
ensure_open_and_readable
2222
Truffle::IOOperations.poll(self, Truffle::IOOperations::POLLIN, timeout) ? self : nil
2323
end
24-
25-
alias_method :wait_readable, :wait
24+
alias_method :wait, :wait_readable
2625

2726
def wait_writable(timeout = nil)
2827
ensure_open_and_writable

src/main/ruby/truffleruby/core/truffle/io_operations.rb

+10-3
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,16 @@ def self.poll(io, event_mask, timeout)
212212
raise ArgumentError, 'timeout must be positive' if timeout < 0
213213

214214
# Milliseconds, rounded down
215-
timeout = remaining_timeout = (timeout * 1_000).to_i
215+
timeout_ms = Primitive.rb_to_int((timeout * 1_000).to_i)
216+
while timeout_ms > 2147483647 # INT_MAX
217+
timeout_ms -= 2147483000
218+
ret = poll(io, event_mask, 2147483)
219+
return ret unless ret == false
220+
end
221+
222+
remaining_timeout = timeout_ms
216223
start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
217-
deadline = start + timeout
224+
deadline = start + timeout_ms
218225
else
219226
remaining_timeout = -1
220227
end
@@ -225,7 +232,7 @@ def self.poll(io, event_mask, timeout)
225232
if primitive_result < 0
226233
errno = Errno.errno
227234
if errno == Errno::EINTR::Errno
228-
if timeout
235+
if timeout_ms
229236
# Update timeout
230237
now = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
231238
if now >= deadline

0 commit comments

Comments
 (0)