From 95dc88c88869541dd0eccafd14924d78c8d7f427 Mon Sep 17 00:00:00 2001 From: nagachika Date: Sun, 25 Jul 2021 13:38:05 +0900 Subject: [PATCH] partially merge revision(s) 5f69a7f60467fa58c2f998daffab43e118bff36c: [Backport #17666] Co-authored-by: Samuel Williams <@ioquatix> https://github.com/nagachika/ruby/pull/1/commits/2cee515f024f3295945f312cb6b052f972f9c93d --- cont.c | 5 +++++ internal/cont.h | 1 + test/fiber/test_thread.rb | 45 +++++++++++++++++++++++++++++++++++++++ thread.c | 2 +- thread_sync.c | 4 ++-- version.h | 2 +- 6 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 test/fiber/test_thread.rb diff --git a/cont.c b/cont.c index a8250c3273..aad7612b25 100644 --- a/cont.c +++ b/cont.c @@ -1155,6 +1155,11 @@ VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber) return fiber->cont.self; } +unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber) +{ + return fiber->blocking; +} + // This is used for root_fiber because other fibers call cont_init_mjit_cont through cont_new. void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber) diff --git a/internal/cont.h b/internal/cont.h index a365cbe978..9e49dd3c8e 100644 --- a/internal/cont.h +++ b/internal/cont.h @@ -21,5 +21,6 @@ void ruby_register_rollback_func_for_ensure(VALUE (*ensure_func)(VALUE), VALUE ( void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber); VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber); +unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber); #endif /* INTERNAL_CONT_H */ diff --git a/test/fiber/test_thread.rb b/test/fiber/test_thread.rb new file mode 100644 index 0000000000..5fc80f0e6c --- /dev/null +++ b/test/fiber/test_thread.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true +require "test/unit" +require_relative 'scheduler' + +class TestFiberThread < Test::Unit::TestCase + def test_thread_join + thread = Thread.new do + scheduler = Scheduler.new + Fiber.set_scheduler scheduler + + result = nil + Fiber.schedule do + result = Thread.new{:done}.value + end + + scheduler.run + result + end + + assert_equal :done, thread.value + end + + def test_thread_join_blocking + thread = Thread.new do + scheduler = Scheduler.new + Fiber.set_scheduler scheduler + + result = nil + Fiber.schedule do + Fiber.new(blocking: true) do + # This can deadlock if the blocking state is not taken into account: + Thread.new do + sleep(0) + result = :done + end.join + end.resume + end + + scheduler.run + result + end + + assert_equal :done, thread.value + end +end diff --git a/thread.c b/thread.c index 2ee878939b..ec7a9b760f 100644 --- a/thread.c +++ b/thread.c @@ -544,7 +544,7 @@ rb_threadptr_join_list_wakeup(rb_thread_t *thread) while (join_list) { rb_thread_t *target_thread = join_list->thread; - if (target_thread->scheduler != Qnil) { + if (target_thread->scheduler != Qnil && rb_fiberptr_blocking(join_list->fiber) == 0) { rb_scheduler_unblock(target_thread->scheduler, target_thread->self, rb_fiberptr_self(join_list->fiber)); } else { rb_threadptr_interrupt(target_thread); diff --git a/thread_sync.c b/thread_sync.c index 11d77e8e91..26d5e6b686 100644 --- a/thread_sync.c +++ b/thread_sync.c @@ -32,7 +32,7 @@ sync_wakeup(struct list_head *head, long max) if (cur->th->status != THREAD_KILLED) { - if (cur->th->scheduler != Qnil) { + if (cur->th->scheduler != Qnil && rb_fiberptr_blocking(cur->fiber) == 0) { rb_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber)); } else { rb_threadptr_interrupt(cur->th); @@ -437,7 +437,7 @@ rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_fiber_t *fiber) list_for_each_safe(&mutex->waitq, cur, next, node) { list_del_init(&cur->node); - if (cur->th->scheduler != Qnil) { + if (cur->th->scheduler != Qnil && rb_fiberptr_blocking(cur->fiber) == 0) { rb_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber)); goto found; } else { diff --git a/version.h b/version.h index 44776a9df7..72cf6b2a2b 100644 --- a/version.h +++ b/version.h @@ -12,7 +12,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 3 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 113 +#define RUBY_PATCHLEVEL 114 #define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_MONTH 7