-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Make waiting_fd
behaviour per-IO.
#13127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors the “waiting_fd” behavior so that waiting and blocking operations are managed per‑IO rather than via a global list. Key changes include:
- Removing the global waiting_fd list initialization and associated memory‐size functions (e.g. in vm_core.h and vm.c).
- Replacing the waiting_fd structure and its helper functions in thread.c with per‑IO blocking operation nodes.
- Eliminating the thread_fd close test file, consistent with the new per‑IO design.
Reviewed Changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
File | Description |
---|---|
vm_core.h | Removed initialization of the global waiting_fds list. |
vm.c | Removed calls to rb_vm_memsize_waiting_fds in memory size reporting. |
thread.c | Commented out and removed waiting_fd structures/functions in favor of per‑IO nodes. |
test/-ext-/thread_fd/test_thread_fd_close.rb | Removed outdated test file no longer applicable under the new design. |
io.c | Updated blocking call APIs to accept an IO pointer instead of a raw file descriptor. |
internal/* | Updated function declarations and struct fields to reflect per‑IO blocking operations. |
Files not reviewed (1)
- ext/-test-/thread_fd/depend: Language not supported
Comments suppressed due to low confidence (2)
vm.c:3229
- Verify that the new per‑IO blocking operations are correctly accounted for in the overall memory size calculations now that the global waiting_fd memory size contribution has been removed.
- rb_vm_memsize_waiting_fds(&vm->waiting_fds) +
test/-ext-/thread_fd/test_thread_fd_close.rb:1
- The removal of the thread_fd close test file reduces test coverage for FD closing behavior; please ensure that the per‑IO waiting/blocking operations introduced in this PR are adequately covered by other tests.
Entire file removed
9cba6ac
to
5d85916
Compare
aa93db0
to
a0aa5d2
Compare
This comment has been minimized.
This comment has been minimized.
0ce6a12
to
bf8fd7d
Compare
bf8fd7d
to
cbc4843
Compare
cbc4843
to
3d742b1
Compare
thread.c
Outdated
if (rb_notify_fd_close(fd, &busy)) { | ||
rb_notify_fd_close_wait(&busy); | ||
} | ||
/* No-op */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We found only one practical example in gems:
https://github.com/vitoshalabs/ruby-pcap/blob/master/ext/pcap/Pcap.c#L149
https://gist.github.com/ko1/81aa42d1bee240a8d8f8d431d165e0c0
not sure we need to consider about that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your investigation.
From your linked example, is it safe to call the current implementation of rb_thread_fd_close
from within GC?
I think a better solution is to take a reference to an auto close IO instance. It is an easy fix and then the code can be updated to use rb_io_wait
etc.
As an interim solution, what about issuing a warning and adding documentation about how to fix it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplified code (as I understand):
io1 = open(...)
io2 = IO.for_fd(io1.fileno) # https://github.com/vitoshalabs/ruby-pcap/blob/master/ext/pcap/Pcap.c#L455C94-L455C95
# maybe io2 is used
io2.read...
rb_notify_fd_close_wait(io1.fileno) # wait for closing interrupting io2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using RUBY_IO_MODE_EXTERNAL
and rb_io_close
is a much better model for us to expose as a public interface:
io1 = open(...)
io2 = IO.for_fd(io1.fileno, FMODE_EXTERNAL)
# maybe io2 is used
io2.read...
rb_io_close(io2)
I've updated the documentation to recommend this.
402685f
to
cbe7c95
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request refactors how waiting file descriptors are managed by removing the global waiting_fds list and transitioning to per-IO blocking operation mechanisms. Key changes include eliminating waiting_fds initialization and related memsize computations, overhauling thread and IO blocking logic in thread.c and io.c, and updating tests and deprecated extensions accordingly.
Reviewed Changes
Copilot reviewed 12 out of 14 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
vm_core.h | Removes the initialization of the global waiting_fds list to support a per-IO approach. |
vm.c | Eliminates the waiting_fds memsize function and its usage in the overall VM memsize calculation. |
thread.c | Removes the waiting_fd structure and associated functions, replacing them with a new blocking operation release. |
test/ruby/test_io.rb | Adjusts the range in a loop to properly limit file descriptor usage. |
io.c | Updates finalization logic by removing the busy parameter and replacing calls with the new IO close-wait functions. |
internal/thread.h & internal/io.h | Remove deprecated APIs and type definitions related to waiting_fd. |
test/-ext-/thread_fd/* & ext/-test-/thread_fd/extconf.rb | Remove deprecated thread_fd extension tests and associated build files. |
Files not reviewed (2)
- common.mk: Language not supported
- ext/-test-/thread_fd/depend: Language not supported
Comments suppressed due to low confidence (5)
vm_core.h:1870
- The removal of the waiting_fds initialization appears intentional for per-IO handling. Please verify that all parts of the codebase referencing waiting_fds have been updated to use the new per-IO blocking operations.
ccan_list_head_init(&vm->waiting_fds);
vm.c:3196
- The removal of the rb_vm_memsize_waiting_fds declaration and its usage in the memsize calculation must be coordinated with the new per-IO mechanism. Confirm that the overall memsize reporting remains accurate after these changes.
size_t rb_vm_memsize_waiting_fds(struct ccan_list_head *waiting_fds); // thread.c
thread.c:151
- The waiting_fd structure and its associated functions have been removed in favor of a new blocking operation approach. Please ensure that the new mechanism (using rb_io_blocking_operation_release and related logic) correctly handles concurrency and interrupt processing.
struct waiting_fd {
test/ruby/test_io.rb:3829
- Changing the range from (0..fd_setsize+1) to (0...fd_setsize) ensures that file descriptors do not exceed the set size. Confirm that this correction aligns with the intended limits of the fd set.
(0...fd_setsize).map {|i|
io.c:5520
- The updated fptr_finalize_flush signature (removing the busy parameter) reflects the new IO close logic. Verify that the new function correctly waits for blocking operations to complete before closing the IO and that all call sites are updated accordingly.
fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
345c156
to
c6d1db9
Compare
@ko1 requested the following changes:
|
6fbf43e
to
8993485
Compare
@ioquatix I think this change is causing segmentation fault in my nightly CI run against ruby head: https://github.com/sass-contrib/sass-embedded-host-ruby/actions/runs/15010437636/job/42178042427 To summarize the use case: sass-embedded spawns the dart-sass child process and communicates with child process’ stdio. When parent ruby process is forked, the stdio file descriptors of the child process are duplicated. However, because this gem does not support share the child process across multiple parent process, I need to close the stdio file descriptors in the forked ruby process. Right now it crashes when closing the duplicated file descriptors right after fork in the forked ruby process. |
Thanks for your report, I will take a look. |
I was able to reproduce the issue, I'll work on a fix. |
Okay, I found the root cause of the issue. |
Here is the reproduction: r, w = IO.pipe
thread = Thread.new do
r.read
end
Thread.pass until thread.status == "sleep"
fork do
r.close
end
w.close
Process.wait
thread.join |
Proposed fix: #13343 |
See #5384 for full context.