From 66871c5a06d723f8350935ced1e88d8cc929d809 Mon Sep 17 00:00:00 2001 From: KJ Tsanaktsidis Date: Sun, 21 May 2023 22:29:16 +1000 Subject: Fix busy-loop when waiting for file descriptors to close When one thread is closing a file descriptor whilst another thread is concurrently reading it, we need to wait for the reading thread to be done with it to prevent a potential EBADF (or, worse, file descriptor reuse). At the moment, that is done by keeping a list of threads still using the file descriptor in io_close_fptr. It then continually calls rb_thread_schedule() in fptr_finalize_flush until said list is empty. That busy-looping seems to behave rather poorly on some OS's, particulary FreeBSD. It can cause the TestIO#test_race_gets_and_close test to fail (even with its very long 200 second timeout) because the closing thread starves out the using thread. To fix that, I introduce the concept of struct rb_io_close_wait_list; a list of threads still using a file descriptor that we want to close. We call `rb_notify_fd_close` to let the thread scheduler know we're closing a FD, which fills the list with threads. Then, we call rb_notify_fd_close_wait which will block the thread until all of the still-using threads are done. This is implemented with a condition variable sleep, so no busy-looping is required. --- common.mk | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'common.mk') diff --git a/common.mk b/common.mk index 1e9349d464..ec13d25ca2 100644 --- a/common.mk +++ b/common.mk @@ -6576,6 +6576,10 @@ explicit_bzero.$(OBJEXT): {$(VPATH)}internal/config.h explicit_bzero.$(OBJEXT): {$(VPATH)}internal/dllexport.h explicit_bzero.$(OBJEXT): {$(VPATH)}internal/has/attribute.h explicit_bzero.$(OBJEXT): {$(VPATH)}missing.h +file.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h +file.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h +file.$(OBJEXT): $(CCAN_DIR)/list/list.h +file.$(OBJEXT): $(CCAN_DIR)/str/str.h file.$(OBJEXT): $(hdrdir)/ruby/ruby.h file.$(OBJEXT): $(top_srcdir)/internal/array.h file.$(OBJEXT): $(top_srcdir)/internal/class.h @@ -6773,6 +6777,7 @@ file.$(OBJEXT): {$(VPATH)}shape.h file.$(OBJEXT): {$(VPATH)}st.h file.$(OBJEXT): {$(VPATH)}subst.h file.$(OBJEXT): {$(VPATH)}thread.h +file.$(OBJEXT): {$(VPATH)}thread_native.h file.$(OBJEXT): {$(VPATH)}util.h gc.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h gc.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h @@ -7810,6 +7815,10 @@ io.$(OBJEXT): {$(VPATH)}thread_native.h io.$(OBJEXT): {$(VPATH)}util.h io.$(OBJEXT): {$(VPATH)}vm_core.h io.$(OBJEXT): {$(VPATH)}vm_opts.h +io_buffer.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h +io_buffer.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h +io_buffer.$(OBJEXT): $(CCAN_DIR)/list/list.h +io_buffer.$(OBJEXT): $(CCAN_DIR)/str/str.h io_buffer.$(OBJEXT): $(hdrdir)/ruby/ruby.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/array.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/bignum.h @@ -7995,6 +8004,7 @@ io_buffer.$(OBJEXT): {$(VPATH)}onigmo.h io_buffer.$(OBJEXT): {$(VPATH)}oniguruma.h io_buffer.$(OBJEXT): {$(VPATH)}st.h io_buffer.$(OBJEXT): {$(VPATH)}subst.h +io_buffer.$(OBJEXT): {$(VPATH)}thread_native.h iseq.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h iseq.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h iseq.$(OBJEXT): $(CCAN_DIR)/list/list.h -- cgit v1.2.3