diff options
author | Benoit Daloze <eregontp@gmail.com> | 2020-09-17 15:15:43 +0200 |
---|---|---|
committer | Benoit Daloze <eregontp@gmail.com> | 2020-09-17 15:15:43 +0200 |
commit | 264889ec3d3d38fc1fd23c4fb48402f1367a8deb (patch) | |
tree | 17c72384804dc42aa85a417c9a721fdba90431d9 | |
parent | deffb630210e35da146c3cee5972fb405b0f00b5 (diff) | |
download | ruby-264889ec3d3d38fc1fd23c4fb48402f1367a8deb.tar.gz |
Fix Mutex#unlock with a scheduler and thread contention
* It would hit "[BUG] unexpected THREAD_STOPPED" before.
-rw-r--r-- | test/fiber/test_mutex.rb | 23 | ||||
-rw-r--r-- | thread_sync.c | 26 |
2 files changed, 36 insertions, 13 deletions
diff --git a/test/fiber/test_mutex.rb b/test/fiber/test_mutex.rb index baec559a70..a70c6992ab 100644 --- a/test/fiber/test_mutex.rb +++ b/test/fiber/test_mutex.rb @@ -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 diff --git a/thread_sync.c b/thread_sync.c index 741bff6160..10ff9c49b1 100644 --- a/thread_sync.c +++ b/thread_sync.c @@ -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) { |