diff --git a/mono/metadata/threads-types.h b/mono/metadata/threads-types.h index e512630942d4..2814818714aa 100644 --- a/mono/metadata/threads-types.h +++ b/mono/metadata/threads-types.h @@ -275,4 +275,7 @@ mono_thread_internal_describe (MonoInternalThread *internal, GString *str); gboolean mono_thread_internal_is_current (MonoInternalThread *internal); +gboolean +mono_threads_is_current_thread_in_protected_block (void); + #endif /* _MONO_METADATA_THREADS_TYPES_H_ */ diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index 8fe4816619cd..e3edcd2cc05e 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -253,6 +253,14 @@ mono_thread_get_abort_prot_block_count (MonoInternalThread *thread) return (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT; } +gboolean +mono_threads_is_current_thread_in_protected_block (void) +{ + MonoInternalThread *thread = mono_thread_internal_current (); + + return mono_thread_get_abort_prot_block_count (thread) > 0; +} + void mono_threads_begin_abort_protected_block (void) { diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 5f6bbd6dce46..b48d5ae7e0a3 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -1832,8 +1832,15 @@ typedef struct { MonoCoopMutex lock; } JitCompilationData; +/* +Timeout, in millisecounds, that we wait other threads to finish JITing. +This value can't be too small or we won't see enough methods being reused and it can't be too big to cause massive stalls due to unforseable circunstances. +*/ +#define MAX_JIT_TIMEOUT_MS 1000 + + static JitCompilationData compilation_data; -static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups; +static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups_or_timeouts; static void mini_jit_init_job_control (void) @@ -1898,7 +1905,7 @@ wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain) mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited); mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple); mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload); - mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups); + mono_counters_register ("JIT compile spurious wakeups or timeouts", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups_or_timeouts); inited = TRUE; } @@ -1915,9 +1922,14 @@ wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain) unlock_compilation_data (); return FALSE; - } else if (jit_tls->active_jit_methods > 0) { + } else if (jit_tls->active_jit_methods > 0 || mono_threads_is_current_thread_in_protected_block ()) { //We can't suspend the current thread if it's already JITing a method. //Dependency management is too compilated and we want to get rid of this anyways. + + //We can't suspend the current thread if it's running a protected block (such as a cctor) + //We can't rely only on JIT nesting as cctor's can be run from outside the JIT. + + //Finally, he hit a timeout or spurious wakeup. We're better off just giving up and keep recompiling ++entry->compilation_count; ++jit_methods_multiple; ++jit_tls->active_jit_methods; @@ -1937,7 +1949,7 @@ wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain) ++entry->threads_waiting; g_assert (entry->has_cond); - mono_coop_cond_wait (&entry->cond, &compilation_data.lock); + mono_coop_cond_timedwait (&entry->cond, &compilation_data.lock, MAX_JIT_TIMEOUT_MS); --entry->threads_waiting; if (entry->done) { @@ -1945,7 +1957,17 @@ wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain) unlock_compilation_data (); return TRUE; } else { - ++jit_spurious_wakeups; + //We hit the timeout or a spurious wakeup, fallback to JITing + g_assert (entry->ref_count > 1); + unref_jit_entry (entry); + ++jit_spurious_wakeups_or_timeouts; + + ++entry->compilation_count; + ++jit_methods_multiple; + ++jit_tls->active_jit_methods; + + unlock_compilation_data (); + return FALSE; } } }