aboutsummaryrefslogtreecommitdiffstats
path: root/io.c
diff options
context:
space:
mode:
authorKJ Tsanaktsidis <ktsanaktsidis@zendesk.com>2023-06-01 16:37:18 +0800
committerGitHub <noreply@github.com>2023-06-01 17:37:18 +0900
commitedee9b6a12ac846d7b3de2d704e170bf28178cb3 (patch)
treef0b4af6454d65cc42eb22f58073691bfbd8667e3 /io.c
parentd8f333491e4c26df7ca577f40d7708d5aedf764f (diff)
downloadruby-edee9b6a12ac846d7b3de2d704e170bf28178cb3.tar.gz
Use a real Ruby mutex in rb_io_close_wait_list (#7884)
Because a thread calling IO#close now blocks in a native condvar wait, it's possible for there to be _no_ threads left to actually handle incoming signals/ubf calls/etc. This manifested as failing tests on Solaris 10 (SPARC), because: * One thread called IO#close, which sent a SIGVTALRM to the other thread to interrupt it, and then waited on the condvar to be notified that the reading thread was done. * One thread was calling IO#read, but it hadn't yet reached the actual call to select(2) when the SIGVTALRM arrived, so it never unblocked itself. This results in a deadlock. The fix is to use a real Ruby mutex for the close lock; that way, the closing thread goes into sigwait-sleep and can keep trying to interrupt the select(2) thread. See the discussion in: https://github.com/ruby/ruby/pull/7865/
Diffstat (limited to 'io.c')
-rw-r--r--io.c10
1 files changed, 1 insertions, 9 deletions
diff --git a/io.c b/io.c
index b99041fbd1..e4df1a5ed5 100644
--- a/io.c
+++ b/io.c
@@ -5423,14 +5423,6 @@ maygvl_fclose(FILE *file, int keepgvl)
static void free_io_buffer(rb_io_buffer_t *buf);
static void clear_codeconv(rb_io_t *fptr);
-static void*
-call_close_wait_nogvl(void *arg)
-{
- struct rb_io_close_wait_list *busy = (struct rb_io_close_wait_list *)arg;
- rb_notify_fd_close_wait(busy);
- return NULL;
-}
-
static void
fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
struct rb_io_close_wait_list *busy)
@@ -5476,7 +5468,7 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
// Ensure waiting_fd users do not hit EBADF.
if (busy) {
// Wait for them to exit before we call close().
- (void)rb_thread_call_without_gvl(call_close_wait_nogvl, busy, RUBY_UBF_IO, 0);
+ rb_notify_fd_close_wait(busy);
}
// Disable for now.