summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/fiber/scheduler.rb3
-rw-r--r--test/fiber/test_mutex.rb25
-rw-r--r--thread.c6
-rw-r--r--thread_sync.c10
4 files changed, 35 insertions, 9 deletions
diff --git a/test/fiber/scheduler.rb b/test/fiber/scheduler.rb
index 1e7f60c..f7a773a 100644
--- a/test/fiber/scheduler.rb
+++ b/test/fiber/scheduler.rb
@@ -93,6 +93,7 @@ class Scheduler
end
ensure
@urgent.each(&:close)
+ @urgent = nil
end
def current_time
@@ -139,7 +140,7 @@ class Scheduler
end
if io = @urgent&.last
- @urgent.last.write_nonblock('.')
+ io.write_nonblock('.')
end
end
diff --git a/test/fiber/test_mutex.rb b/test/fiber/test_mutex.rb
index 1f53ae1..baec559 100644
--- a/test/fiber/test_mutex.rb
+++ b/test/fiber/test_mutex.rb
@@ -115,6 +115,31 @@ class TestFiberMutex < Test::Unit::TestCase
assert processed == 3
end
+ def test_queue_pop_waits
+ queue = Queue.new
+ running = false
+
+ thread = Thread.new do
+ scheduler = Scheduler.new
+ Thread.current.scheduler = scheduler
+
+ result = nil
+ Fiber.schedule do
+ result = queue.pop
+ end
+
+ running = true
+ scheduler.run
+ result
+ end
+
+ Thread.pass until running
+ sleep 0.1
+
+ queue << :done
+ assert_equal :done, thread.value
+ end
+
def test_mutex_deadlock
err = /No live threads left. Deadlock\?/
assert_in_out_err %W[-I#{__dir__} -], <<-RUBY, ['in synchronize'], err, success: false
diff --git a/thread.c b/thread.c
index 6b20716..b3b7a69 100644
--- a/thread.c
+++ b/thread.c
@@ -134,7 +134,7 @@ rb_thread_local_storage(VALUE thread)
static void sleep_hrtime(rb_thread_t *, rb_hrtime_t, unsigned int fl);
static void sleep_forever(rb_thread_t *th, unsigned int fl);
-static void rb_thread_sleep_deadly_allow_spurious_wakeup(void);
+static void rb_thread_sleep_deadly_allow_spurious_wakeup(VALUE blocker);
static int rb_threadptr_dead(rb_thread_t *th);
static void rb_check_deadlock(rb_ractor_t *r);
static int rb_threadptr_pending_interrupt_empty_p(const rb_thread_t *th);
@@ -1485,11 +1485,11 @@ rb_thread_sleep_interruptible(void)
}
static void
-rb_thread_sleep_deadly_allow_spurious_wakeup(void)
+rb_thread_sleep_deadly_allow_spurious_wakeup(VALUE blocker)
{
VALUE scheduler = rb_thread_current_scheduler();
if (scheduler != Qnil) {
- rb_scheduler_kernel_sleepv(scheduler, 0, NULL);
+ rb_scheduler_block(scheduler, blocker);
} else {
thread_debug("rb_thread_sleep_deadly_allow_spurious_wakeup\n");
sleep_forever(GET_THREAD(), SLEEP_DEADLOCKABLE);
diff --git a/thread_sync.c b/thread_sync.c
index 5b1e4f2..741bff6 100644
--- a/thread_sync.c
+++ b/thread_sync.c
@@ -483,9 +483,9 @@ rb_mutex_abandon_all(rb_mutex_t *mutexes)
#endif
static VALUE
-rb_mutex_sleep_forever(VALUE time)
+rb_mutex_sleep_forever(VALUE self)
{
- rb_thread_sleep_deadly_allow_spurious_wakeup();
+ rb_thread_sleep_deadly_allow_spurious_wakeup(self);
return Qnil;
}
@@ -516,7 +516,7 @@ rb_mutex_sleep(VALUE self, VALUE timeout)
mutex_lock_uninterruptible(self);
} else {
if (NIL_P(timeout)) {
- rb_ensure(rb_mutex_sleep_forever, Qnil, mutex_lock_uninterruptible, self);
+ rb_ensure(rb_mutex_sleep_forever, self, mutex_lock_uninterruptible, self);
} else {
rb_hrtime_t rel = rb_timeval2hrtime(&t);
rb_ensure(rb_mutex_wait_for, (VALUE)&rel, mutex_lock_uninterruptible, self);
@@ -904,9 +904,9 @@ rb_queue_push(VALUE self, VALUE obj)
}
static VALUE
-queue_sleep(VALUE arg)
+queue_sleep(VALUE self)
{
- rb_thread_sleep_deadly_allow_spurious_wakeup();
+ rb_thread_sleep_deadly_allow_spurious_wakeup(self);
return Qnil;
}