Skip to content

Adapt Rage's buffered I/O scheduler hooks to Ruby 4.1 #390

Description

Hi — I wanted to share a heads-up about a change to the optional Fiber::Scheduler buffered I/O hooks in Ruby 4.1. It was merged into CRuby's default branch on August 25, 2026.

While checking scheduler implementations against ruby-head, I noticed that lib/rage/fiber_scheduler.rb uses the previous (length, offset) order. The read hook can pause and continue reading, while the write hook passes the whole buffer string together with the old length/offset interpretation, so both paths may behave differently under the new single-transfer contract.

References

Contract change

Hook Ruby 4.0 and earlier Ruby 4.1
io_read io_read(io, buffer, length, offset) io_read(io, buffer, offset, length)
io_write io_write(io, buffer, length, offset) io_write(io, buffer, offset, length)

Under scheduler interface v4, length is a maximum for one operation. Return a short result directly, return 0 for zero length, and on a readiness backend return -EAGAIN instead of waiting or retrying inside the hook.

One possible update for Rage

  • defined?(IO::Buffer::VERSION) && IO::Buffer::VERSION >= 3 could select v4 versus legacy hook definitions.
  • The v4 read path could make one bounded Iodine::Scheduler.read request for at most length bytes, copy a successful result to buffer at the requested buffer offset, and return the string's byte size.
  • One detail worth checking is Iodine's third argument: the current code passes the buffer offset into Iodine::Scheduler.read, but the Ruby hook's offset refers only to the position within IO::Buffer. I may be missing an Iodine-specific convention here.
  • Iodine's would-block result could return -Errno::EAGAIN::Errno directly, without the v4 loop or Fiber.pause retry.
  • The v4 write path could extract exactly buffer.get_string(offset, length) and perform one write, passing a separate I/O offset only if the Iodine API requires one.
  • A zero-length request could return 0 before calling Iodine, while the existing implementation remains available in the older-interface branch.

The public C/native version gate is RUBY_FIBER_SCHEDULER_VERSION >= 4; IO::Buffer::VERSION >= 3 is the corresponding Ruby-level check.

If this reading of the Iodine API is correct, I would be happy to help prepare or test a patch. Useful Ruby-head cases would use different nonzero offset and length values, plus short-transfer, would-block, and zero-length operations. If Ruby 4.1 is not currently in scope, please feel free to close this.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions