diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c index 5754f9f75046..f39289ad9eb5 100644 --- a/mono/metadata/appdomain.c +++ b/mono/metadata/appdomain.c @@ -3312,9 +3312,13 @@ deregister_reflection_info_roots (MonoDomain *domain) mono_domain_assemblies_unlock (domain); } +extern MonoCoopMutex mono_domain_unload_mutex; + static gsize WINAPI unload_thread_main (void *arg) { + mono_coop_mutex_lock(&mono_domain_unload_mutex); + unload_data *data = (unload_data*)arg; MonoDomain *domain = data->domain; MonoMemoryManager *memory_manager = mono_domain_memory_manager (domain); @@ -3386,6 +3390,7 @@ unload_thread_main (void *arg) result = 0; // success exit: + mono_coop_mutex_unlock(&mono_domain_unload_mutex); mono_atomic_store_release (&data->done, TRUE); unload_data_unref (data); return result; diff --git a/mono/metadata/appdomain.h b/mono/metadata/appdomain.h index 016ddf6bad1c..e76ab2c0adfb 100644 --- a/mono/metadata/appdomain.h +++ b/mono/metadata/appdomain.h @@ -109,6 +109,9 @@ mono_domain_jit_foreach (MonoDomain *domain, MonoJitInfoFunc func, void *user_da MONO_API void mono_domain_foreach (MonoDomainFunc func, void* user_data); +MONO_API void +mono_unity_domain_foreach_locked (MonoDomainFunc func, void* user_data); + MONO_API void mono_domain_assembly_foreach (MonoDomain* domain, MonoDomainAssemblyFunc func, void* user_data); diff --git a/mono/metadata/domain.c b/mono/metadata/domain.c index d544b2df8e21..69d455956b87 100644 --- a/mono/metadata/domain.c +++ b/mono/metadata/domain.c @@ -86,6 +86,12 @@ gboolean mono_dont_free_domains; #define mono_appdomains_unlock() mono_coop_mutex_unlock (&appdomains_mutex) static MonoCoopMutex appdomains_mutex; +/* Lock used to prevent domain enumeration while domains may be unloading. + * This lock must be taken before any other domain-related locks to prevent deadlock. + * See https://github.com/Unity-Technologies/mono/pull/2173 + */ +MonoCoopMutex mono_domain_unload_mutex; + static MonoDomain *mono_root_domain = NULL; /* some statistics */ @@ -559,6 +565,7 @@ mono_init_internal (const char *filename, const char *exe_filename, const char * mono_thread_info_attach (); mono_coop_mutex_init_recursive (&appdomains_mutex); + mono_coop_mutex_init_recursive(&mono_domain_unload_mutex); mono_metadata_init (); mono_images_init (); @@ -925,6 +932,7 @@ mono_cleanup (void) mono_metadata_cleanup (); mono_coop_mutex_destroy (&appdomains_mutex); + mono_coop_mutex_destroy (&mono_domain_unload_mutex); mono_w32process_cleanup (); mono_w32file_cleanup (); @@ -1041,6 +1049,14 @@ mono_domain_foreach (MonoDomainFunc func, gpointer user_data) MONO_EXIT_GC_UNSAFE; } +void +mono_unity_domain_foreach_locked(MonoDomainFunc func, gpointer user_data) +{ + mono_coop_mutex_lock(&mono_domain_unload_mutex); + mono_domain_foreach(func, user_data); + mono_coop_mutex_unlock(&mono_domain_unload_mutex); +} + void mono_domain_ensure_entry_assembly (MonoDomain *domain, MonoAssembly *assembly) { diff --git a/mono/metadata/etw-profiler.c b/mono/metadata/etw-profiler.c index 0039669ab5e8..80d969bac15b 100644 --- a/mono/metadata/etw-profiler.c +++ b/mono/metadata/etw-profiler.c @@ -290,7 +290,7 @@ on_attach () memset (&enumerationData, 0, sizeof (enumerationData)); // Iterate through each domain - mono_domain_foreach (on_enumerate_domain, &enumerationData); + mono_unity_domain_foreach_locked (on_enumerate_domain, &enumerationData); ETW_PROFILER_LOG_ARGS ("Finished enumerating JIT data. Found %d domains, %d assemblies, %d methods", enumerationData.mNumDomains, enumerationData.mNumAssemblies, enumerationData.mNumMethods); }