summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2021-07-25 13:38:05 +0900
committernagachika <nagachika@ruby-lang.org>2021-07-25 13:49:53 +0900
commit95dc88c88869541dd0eccafd14924d78c8d7f427 (patch)
treef4ad43fffd779545d16d7d47106a25c341633eb5
parentdc7ad0287eff6e11c2d0f71d2a02e56fe172a0da (diff)
partially merge revision(s) 5f69a7f60467fa58c2f998daffab43e118bff36c: [Backport #17666]
Co-authored-by: Samuel Williams <@ioquatix> https://github.com/nagachika/ruby/pull/1/commits/2cee515f024f3295945f312cb6b052f972f9c93d
-rw-r--r--cont.c5
-rw-r--r--internal/cont.h1
-rw-r--r--test/fiber/test_thread.rb45
-rw-r--r--thread.c2
-rw-r--r--thread_sync.c4
-rw-r--r--version.h2
6 files changed, 55 insertions, 4 deletions
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