Make Mutex per-Fiber instead of per-Thread

* Enables Mutex to be used as synchronization between multiple Fibers
  of the same Thread.
* With a Fiber scheduler we can yield to another Fiber on contended
  Mutex#lock instead of blocking the entire thread.
* This also makes the behavior of Mutex consistent across CRuby, JRuby and TruffleRuby.
* [Feature #16792]
This commit is contained in:
Benoit Daloze 2020-09-05 16:26:24 +12:00 committed by Samuel Williams
parent 9e0a48c7a3
commit 178c1b0922
Notes: git 2020-09-14 13:44:37 +09:00
9 changed files with 199 additions and 54 deletions

View file

@ -75,11 +75,13 @@
#include "hrtime.h"
#include "internal.h"
#include "internal/class.h"
#include "internal/cont.h"
#include "internal/error.h"
#include "internal/hash.h"
#include "internal/io.h"
#include "internal/object.h"
#include "internal/proc.h"
#include "internal/scheduler.h"
#include "internal/signal.h"
#include "internal/thread.h"
#include "internal/time.h"
@ -548,7 +550,7 @@ rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th)
/* rb_warn("mutex #<%p> remains to be locked by terminated thread",
(void *)mutexes); */
mutexes = mutex->next_mutex;
err = rb_mutex_unlock_th(mutex, th);
err = rb_mutex_unlock_th(mutex, th, mutex->fiber);
if (err) rb_bug("invalid keeping_mutexes: %s", err);
}
}
@ -5040,7 +5042,7 @@ rb_thread_shield_wait(VALUE self)
if (!mutex) return Qfalse;
m = mutex_ptr(mutex);
if (m->th == GET_THREAD()) return Qnil;
if (m->fiber == GET_EC()->fiber_ptr) return Qnil;
rb_thread_shield_waiting_inc(self);
rb_mutex_lock(mutex);
rb_thread_shield_waiting_dec(self);
@ -5540,7 +5542,7 @@ debug_deadlock_check(rb_ractor_t *r, VALUE msg)
if (th->locking_mutex) {
rb_mutex_t *mutex = mutex_ptr(th->locking_mutex);
rb_str_catf(msg, " mutex:%p cond:%"PRIuSIZE,
(void *)mutex->th, rb_mutex_num_waiting(mutex));
(void *)mutex->fiber, rb_mutex_num_waiting(mutex));
}
{
@ -5574,8 +5576,7 @@ rb_check_deadlock(rb_ractor_t *r)
}
else if (th->locking_mutex) {
rb_mutex_t *mutex = mutex_ptr(th->locking_mutex);
if (mutex->th == th || (!mutex->th && !list_empty(&mutex->waitq))) {
if (mutex->fiber == th->ec->fiber_ptr || (!mutex->fiber && !list_empty(&mutex->waitq))) {
found = 1;
}
}