Fix Mutex#unlock with a scheduler and thread contention

* It would hit "[BUG] unexpected THREAD_STOPPED" before.
This commit is contained in:
Benoit Daloze 2020-09-17 15:15:43 +02:00
Родитель deffb63021
Коммит 264889ec3d
2 изменённых файлов: 36 добавлений и 13 удалений

Просмотреть файл

@ -47,6 +47,29 @@ class TestFiberMutex < Test::Unit::TestCase
thread.join
end
def test_mutex_thread
mutex = Mutex.new
mutex.lock
thread = Thread.new do
scheduler = Scheduler.new
Thread.current.scheduler = scheduler
Fiber.schedule do
mutex.lock
sleep 0.1
mutex.unlock
end
scheduler.run
end
sleep 0.1
mutex.unlock
thread.join
end
def test_condition_variable
mutex = Mutex.new
condition = ConditionVariable.new

Просмотреть файл

@ -402,20 +402,20 @@ rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_fiber_t *fiber)
if (cur->th->scheduler != Qnil) {
rb_scheduler_unblock(cur->th->scheduler, cur->self, rb_fiberptr_self(cur->fiber));
} else {
switch (cur->th->status) {
case THREAD_RUNNABLE: /* from someone else calling Thread#run */
case THREAD_STOPPED_FOREVER: /* likely (rb_mutex_lock) */
rb_threadptr_interrupt(cur->th);
goto found;
case THREAD_STOPPED: /* probably impossible */
rb_bug("unexpected THREAD_STOPPED");
case THREAD_KILLED:
/* not sure about this, possible in exit GC? */
rb_bug("unexpected THREAD_KILLED");
continue;
}
}
switch (cur->th->status) {
case THREAD_RUNNABLE: /* from someone else calling Thread#run */
case THREAD_STOPPED_FOREVER: /* likely (rb_mutex_lock) */
rb_threadptr_interrupt(cur->th);
goto found;
case THREAD_STOPPED: /* probably impossible */
rb_bug("unexpected THREAD_STOPPED");
case THREAD_KILLED:
/* not sure about this, possible in exit GC? */
rb_bug("unexpected THREAD_KILLED");
continue;
}
}
found:
while (*th_mutex != mutex) {