Avoid enqueueing the same ISeq twice
by a race condition by multiple Ractors. Atmically incrementing body->total_calls may have its own cost, so for now we intentionally leave the unreliable total_calls. So we allow an ISeq to be never pushed when you use multiple Ractors. However, if you enqueue a single ccan node twice, get_from_list loops infinitely. Thus this patch takes care of such a situation.
This commit is contained in:
parent
791d7d4947
commit
c5e8a49bde
@ -8608,6 +8608,7 @@ mjit.$(OBJEXT): {$(VPATH)}util.h
|
|||||||
mjit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
|
mjit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
|
||||||
mjit.$(OBJEXT): {$(VPATH)}vm_core.h
|
mjit.$(OBJEXT): {$(VPATH)}vm_core.h
|
||||||
mjit.$(OBJEXT): {$(VPATH)}vm_opts.h
|
mjit.$(OBJEXT): {$(VPATH)}vm_opts.h
|
||||||
|
mjit.$(OBJEXT): {$(VPATH)}vm_sync.h
|
||||||
mjit_build_dir.$(OBJEXT): {$(VPATH)}config.h
|
mjit_build_dir.$(OBJEXT): {$(VPATH)}config.h
|
||||||
mjit_build_dir.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
|
mjit_build_dir.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
|
||||||
mjit_build_dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
|
mjit_build_dir.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
|
||||||
|
30
mjit.c
30
mjit.c
@ -23,6 +23,7 @@
|
|||||||
#include "internal/file.h"
|
#include "internal/file.h"
|
||||||
#include "internal/hash.h"
|
#include "internal/hash.h"
|
||||||
#include "internal/warnings.h"
|
#include "internal/warnings.h"
|
||||||
|
#include "vm_sync.h"
|
||||||
|
|
||||||
#include "mjit_worker.c"
|
#include "mjit_worker.c"
|
||||||
|
|
||||||
@ -253,18 +254,28 @@ mjit_target_iseq_p(struct rb_iseq_constant_body *body)
|
|||||||
&& !body->builtin_inline_p;
|
&& !body->builtin_inline_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called from an MJIT worker when worker_p is true.
|
// If recompile_p is true, the call is initiated by mjit_recompile.
|
||||||
|
// This assumes the caller holds CRITICAL_SECTION when recompile_p is true.
|
||||||
static void
|
static void
|
||||||
mjit_add_iseq_to_process(const rb_iseq_t *iseq, const struct rb_mjit_compile_info *compile_info, bool worker_p)
|
mjit_add_iseq_to_process(const rb_iseq_t *iseq, const struct rb_mjit_compile_info *compile_info, bool recompile_p)
|
||||||
{
|
{
|
||||||
if (!mjit_enabled || pch_status == PCH_FAILED)
|
if (!mjit_enabled || pch_status == PCH_FAILED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mjit_target_iseq_p(iseq->body)) {
|
if (!mjit_target_iseq_p(iseq->body)) {
|
||||||
iseq->body->jit_func = (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC; // skip mjit_wait
|
iseq->body->jit_func = (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC; // skip mjit_wait
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!recompile_p) {
|
||||||
|
CRITICAL_SECTION_START(3, "in add_iseq_to_process");
|
||||||
|
|
||||||
|
// This prevents multiple Ractors from enqueueing the same ISeq twice.
|
||||||
|
if (rb_multi_ractor_p() && iseq->body->jit_func != NOT_ADDED_JIT_ISEQ_FUNC) {
|
||||||
|
CRITICAL_SECTION_FINISH(3, "in add_iseq_to_process");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RB_DEBUG_COUNTER_INC(mjit_add_iseq_to_process);
|
RB_DEBUG_COUNTER_INC(mjit_add_iseq_to_process);
|
||||||
iseq->body->jit_func = (mjit_func_t)NOT_READY_JIT_ISEQ_FUNC;
|
iseq->body->jit_func = (mjit_func_t)NOT_READY_JIT_ISEQ_FUNC;
|
||||||
create_unit(iseq);
|
create_unit(iseq);
|
||||||
@ -273,15 +284,12 @@ mjit_add_iseq_to_process(const rb_iseq_t *iseq, const struct rb_mjit_compile_inf
|
|||||||
return;
|
return;
|
||||||
if (compile_info != NULL)
|
if (compile_info != NULL)
|
||||||
iseq->body->jit_unit->compile_info = *compile_info;
|
iseq->body->jit_unit->compile_info = *compile_info;
|
||||||
|
|
||||||
if (!worker_p) {
|
|
||||||
CRITICAL_SECTION_START(3, "in add_iseq_to_process");
|
|
||||||
}
|
|
||||||
add_to_list(iseq->body->jit_unit, &unit_queue);
|
add_to_list(iseq->body->jit_unit, &unit_queue);
|
||||||
if (active_units.length >= mjit_opts.max_cache_size) {
|
if (active_units.length >= mjit_opts.max_cache_size) {
|
||||||
unload_requests++;
|
unload_requests++;
|
||||||
}
|
}
|
||||||
if (!worker_p) {
|
|
||||||
|
if (!recompile_p) {
|
||||||
verbose(3, "Sending wakeup signal to workers in mjit_add_iseq_to_process");
|
verbose(3, "Sending wakeup signal to workers in mjit_add_iseq_to_process");
|
||||||
rb_native_cond_broadcast(&mjit_worker_wakeup);
|
rb_native_cond_broadcast(&mjit_worker_wakeup);
|
||||||
CRITICAL_SECTION_FINISH(3, "in add_iseq_to_process");
|
CRITICAL_SECTION_FINISH(3, "in add_iseq_to_process");
|
||||||
@ -356,9 +364,11 @@ mjit_recompile(const rb_iseq_t *iseq)
|
|||||||
assert(iseq->body->jit_unit != NULL);
|
assert(iseq->body->jit_unit != NULL);
|
||||||
|
|
||||||
if (UNLIKELY(mjit_opts.wait)) {
|
if (UNLIKELY(mjit_opts.wait)) {
|
||||||
|
CRITICAL_SECTION_START(3, "in rb_mjit_recompile_iseq");
|
||||||
remove_from_list(iseq->body->jit_unit, &active_units);
|
remove_from_list(iseq->body->jit_unit, &active_units);
|
||||||
add_to_list(iseq->body->jit_unit, &stale_units);
|
add_to_list(iseq->body->jit_unit, &stale_units);
|
||||||
mjit_add_iseq_to_process(iseq, &iseq->body->jit_unit->compile_info, false);
|
mjit_add_iseq_to_process(iseq, &iseq->body->jit_unit->compile_info, true);
|
||||||
|
CRITICAL_SECTION_FINISH(3, "in rb_mjit_recompile_iseq");
|
||||||
mjit_wait(iseq->body);
|
mjit_wait(iseq->body);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -367,7 +377,7 @@ mjit_recompile(const rb_iseq_t *iseq)
|
|||||||
// It's good to avoid a race condition between mjit_add_iseq_to_process and mjit_compile around jit_unit as well.
|
// It's good to avoid a race condition between mjit_add_iseq_to_process and mjit_compile around jit_unit as well.
|
||||||
CRITICAL_SECTION_START(3, "in rb_mjit_recompile_iseq");
|
CRITICAL_SECTION_START(3, "in rb_mjit_recompile_iseq");
|
||||||
iseq->body->jit_unit->stale_p = true;
|
iseq->body->jit_unit->stale_p = true;
|
||||||
iseq->body->jit_func = (mjit_func_t)NOT_ADDED_JIT_ISEQ_FUNC;
|
iseq->body->jit_func = (mjit_func_t)NOT_READY_JIT_ISEQ_FUNC;
|
||||||
pending_stale_p = true;
|
pending_stale_p = true;
|
||||||
CRITICAL_SECTION_FINISH(3, "in rb_mjit_recompile_iseq");
|
CRITICAL_SECTION_FINISH(3, "in rb_mjit_recompile_iseq");
|
||||||
}
|
}
|
||||||
|
2
mjit.h
2
mjit.h
@ -20,7 +20,7 @@
|
|||||||
// Special address values of a function generated from the
|
// Special address values of a function generated from the
|
||||||
// corresponding iseq by MJIT:
|
// corresponding iseq by MJIT:
|
||||||
enum rb_mjit_iseq_func {
|
enum rb_mjit_iseq_func {
|
||||||
// ISEQ was not queued yet for the machine code generation
|
// ISEQ has never been enqueued to unit_queue yet
|
||||||
NOT_ADDED_JIT_ISEQ_FUNC = 0,
|
NOT_ADDED_JIT_ISEQ_FUNC = 0,
|
||||||
// ISEQ is already queued for the machine code generation but the
|
// ISEQ is already queued for the machine code generation but the
|
||||||
// code is not ready yet for the execution
|
// code is not ready yet for the execution
|
||||||
|
@ -1106,7 +1106,7 @@ load_func_from_so(const char *so_file, const char *funcname, struct rb_mjit_unit
|
|||||||
handle = dlopen(so_file, RTLD_NOW);
|
handle = dlopen(so_file, RTLD_NOW);
|
||||||
if (handle == NULL) {
|
if (handle == NULL) {
|
||||||
mjit_warning("failure in loading code from '%s': %s", so_file, dlerror());
|
mjit_warning("failure in loading code from '%s': %s", so_file, dlerror());
|
||||||
return (void *)NOT_ADDED_JIT_ISEQ_FUNC;
|
return (void *)NOT_COMPILED_JIT_ISEQ_FUNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
func = dlsym(handle, funcname);
|
func = dlsym(handle, funcname);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user