Skip to content

PoC: let the event loop decide blocking or non blocking#15685

Closed
ysbaddaden wants to merge 17 commits intocrystal-lang:masterfrom
ysbaddaden:refactor/blocking-behavior-3
Closed

PoC: let the event loop decide blocking or non blocking#15685
ysbaddaden wants to merge 17 commits intocrystal-lang:masterfrom
ysbaddaden:refactor/blocking-behavior-3

Conversation

@ysbaddaden
Copy link
Collaborator

@ysbaddaden ysbaddaden commented Apr 18, 2025

The experimental branch as per my thread in #15652. Not meant to be merged. Multiple smaller PRs shall be extracted.

Overall:

  1. File.open is moved to Crystal::EventLoop (for Add io_uring event loop #15634).

    Extracted as Add Crystal::EventLoop::FileDescriptor#open #15750.

  2. Crystal::EventLoop#open decides to set O_NONBLOCK, FILE_FLAG_OVERLAPPED or WSA_FLAG_OVERLAPPED on the IO objects (for io_uring again).

    Extracted as Crystal::EventLoop::FileDescriptor#open now sets the non/blocking flag #15754.

  3. File: the blocking argument now only has an effect on opening the file:

    Extracted as Let the event loop decide the blocking mode of File #15930 and Detach execution context scheduler from running thread during blocking syscall #15871.

  4. Socket now defaults to blocking: nil:

    • UNIX: still respects an explicit blocking: true, otherwise the event loops set O_NONBLOCK (but io_uring won't set it);
    • WINDOWS: always sets WSA_FLAG_OVERLAPPED (no change);
    • we might consider to deprecate the blocking arg.

    Extracted as Refactor Socket blocking mode #15804.

  5. The behavior of IO::FileDescriptor shouldn't have changed;

  6. IO.pipe now respects the Crystal::EventLoop behavior (expects blocking or nonblocking) unless a blocking value is specified.

    Extracted as Refactor IO.pipe blocking mode #15823.

  7. UNIXSocket.pair now respects the Crystal::EventLoop behavior (expects blocking or nonblocking).

    Extracted into Crystal::EventLoop::FileDescriptor#open now sets the non/blocking flag #15754.

The BREAKING CHANGE is that of undocumented behavior:

  • File: the blocking arg doesn't set #blocking= anymore;
  • Socket: the blocking arg now defaults to nil.

Related to #15634

Actually moves the internal `Crystal::System::File.open` method to be
the responsibility of the event loops, so we can choose to open
asynchronously or non-blocking when the event loop supports it (i.e.
io_uring).
This will be used to determine whether we want to set `O_NONBLOCK` or
`FILE_FLAG_OVERLAPPED` depending on the active event loop backend.

We use it for `IO.pipe` and `IO::FileDescriptor`.
Replaces `Crystal::System::Socket#create_handle` and gives full control
to the event loop backend to set `O_NONBLOCK` or `WSA_FLAG_OVERLAPPED`
as it see fits —which the IOCP event loop already did.
@ysbaddaden ysbaddaden added kind:refactor breaking-change May have breaking effect in some edge cases. Mostly negligible, but still noteworthy. topic:stdlib:runtime labels Apr 18, 2025
@ysbaddaden ysbaddaden self-assigned this Apr 18, 2025
@ysbaddaden
Copy link
Collaborator Author

ysbaddaden commented Jun 2, 2025

Almost everything from the PoC has been extracted & merged.

The only the notable exception is the default blocking behavior for files, and its blocking argument.

@ysbaddaden
Copy link
Collaborator Author

Closing this proof of concept PR. It has been fully extracted into individual pull requests 🎉

@ysbaddaden ysbaddaden closed this Jun 26, 2025
@ysbaddaden ysbaddaden deleted the refactor/blocking-behavior-3 branch June 26, 2025 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change May have breaking effect in some edge cases. Mostly negligible, but still noteworthy. kind:refactor topic:stdlib:runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant