diff options
author | k0kubun <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-11-18 08:25:48 +0000 |
---|---|---|
committer | k0kubun <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-11-18 08:25:48 +0000 |
commit | fe6974a8fcca42f4f83171097a3bc29fbe0f2f67 (patch) | |
tree | 01f157d468dc018c5765144f344e98a37a584c62 /mjit.c | |
parent | 0a7a5a7ad4da3ec8bed425502f5012908a0e77c8 (diff) |
mjit_worker.c: support MJIT in forked Ruby process
by launching MJIT worker thread in child Ruby process.
See the comment before `mjit_child_after_fork` for details.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65785 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'mjit.c')
-rw-r--r-- | mjit.c | 63 |
1 files changed, 50 insertions, 13 deletions
@@ -496,18 +496,6 @@ init_header_filename(void) return TRUE; } -/* This is called after each fork in the child in to switch off MJIT - engine in the child as it does not inherit MJIT threads. */ -void -mjit_child_after_fork(void) -{ - if (mjit_enabled) { - verbose(3, "Switching off MJIT in a forked child"); - mjit_enabled = FALSE; - } - /* TODO: Should we initiate MJIT in the forked Ruby. */ -} - static enum rb_id_table_iterator_result valid_class_serials_add_i(ID key, VALUE v, void *unused) { @@ -661,6 +649,7 @@ mjit_init(struct mjit_options *opts) verbose(1, "Failure in MJIT header file name initialization\n"); return; } + pch_owner_pid = getpid(); init_list(&unit_queue); init_list(&active_units); @@ -748,6 +737,54 @@ mjit_resume(void) return Qtrue; } +/* Skip calling `clean_object_files` for units which currently exist in the list. */ +static void +skip_cleaning_object_files(struct rb_mjit_unit_list *list) +{ + struct rb_mjit_unit *unit = NULL, *next; + + /* No mutex for list, assuming MJIT worker does not exist yet since it's immediately after fork. */ + list_for_each_safe(&list->head, unit, next, unode) { +#ifndef _MSC_VER /* Actualy mswin does not reach here since it doesn't have fork */ + if (unit->o_file) unit->o_file_inherited_p = TRUE; +#endif + +#if defined(_WIN32) /* mswin doesn't reach here either. This is for MinGW. */ + if (unit->so_file) unit->so_file = NULL; +#endif + } +} + +/* This is called after fork initiated by Ruby's method to launch MJIT worker thread + for child Ruby process. + + In multi-process Ruby applications, child Ruby processes do most of the jobs. + Thus we want child Ruby processes to enqueue ISeqs to MJIT worker's queue and + call the JIT-ed code. + + But unfortunately current MJIT-generated code is process-specific. After the fork, + JIT-ed code created by parent Ruby process cannnot be used in child Ruby process + because the code could rely on inline cache values (ivar's IC, send's CC) which + may vary between processes after fork or embed some process-specific addresses. + + So child Ruby process can't request parent process to JIT an ISeq and use the code. + Instead of that, MJIT worker thread is created for all child Ruby processes, even + while child processes would end up with compiling the same ISeqs. + */ +void +mjit_child_after_fork(void) +{ + if (!mjit_enabled) + return; + + /* Let parent process delete the already-compiled object files. + This must be done before starting MJIT worker on child process. */ + skip_cleaning_object_files(&active_units); + + /* MJIT worker thread is not inherited on fork. Start it for this child process. */ + start_worker(); +} + /* Finish the threads processing units and creating PCH, finalize and free MJIT data. It should be called last during MJIT life. */ @@ -781,7 +818,7 @@ mjit_finish(void) rb_native_cond_destroy(&mjit_gc_wakeup); #ifndef _MSC_VER /* mswin has prebuilt precompiled header */ - if (!mjit_opts.save_temps) + if (!mjit_opts.save_temps && getpid() == pch_owner_pid) remove_file(pch_file); xfree(header_file); header_file = NULL; |