* [mono] Reduce domain lock usage.
* Avoid double locking the loader+domain lock, its not needed.
* Use the mem manager lock and the loader lock in a few places instead of
the domain lock.
* Use lock free code in mono_jit_runtime_invoke ().
* Avoid locking around mono_jit_info_table_add (), it does locking itself.
* [mono] Internalize access to MonoMemoryManager.mp to memory-manager.c.
Also add a separate non-coop lock to protect it, since its accessed
very frequently.
* Use a separate lock for each memory manager.
* Remove the domain lock.
gboolean
mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
{
- gboolean res;
- MonoMemoryManager *memory_manager = mono_mem_manager_get_ambient ();
-
- mono_mem_manager_lock (memory_manager);
- res = mono_mempool_contains_addr (memory_manager->mp, vtable_slot);
- mono_mem_manager_unlock (memory_manager);
- return res;
+ return mono_mem_manager_mp_contains_addr (mono_mem_manager_get_ambient (), vtable_slot);
}
gboolean
struct _MonoDomain {
/*
- * This lock must never be taken before the loader lock,
- * i.e. if both are taken by the same thread, the loader lock
- * must taken first.
- */
- MonoCoopMutex lock;
-
- /*
* keep all the managed objects close to each other for the precise GC
* For the Boehm GC we additionally keep close also other GC-tracked pointers.
*/
typedef MonoDomain* (*MonoLoadFunc) (const char *filename, const char *runtime_version);
-void mono_domain_lock (MonoDomain *domain);
-void mono_domain_unlock (MonoDomain *domain);
-
void
mono_install_runtime_load (MonoLoadFunc func);
domain->domain_assemblies = NULL;
- mono_coop_mutex_init_recursive (&domain->lock);
-
mono_coop_mutex_init_recursive (&domain->assemblies_lock);
mono_appdomains_lock ();
return current_runtime;
}
-void
-mono_domain_lock (MonoDomain *domain)
-{
- mono_locks_coop_acquire (&domain->lock, DomainLock);
-}
-
-void
-mono_domain_unlock (MonoDomain *domain)
-{
- mono_locks_coop_release (&domain->lock, DomainLock);
-}
-
GPtrArray*
mono_domain_get_assemblies (MonoDomain *domain)
{
};
struct _MonoMemoryManager {
- MonoDomain *domain;
// Whether the MemoryManager can be unloaded on netcore; should only be set at creation
gboolean collectible;
// Whether this is a singleton or generic MemoryManager
// Currently unused, we take the domain lock instead
MonoCoopMutex lock;
- MonoMemPool *mp;
+ // Private, don't access directly
+ MonoMemPool *_mp;
MonoCodeManager *code_mp;
LockFreeMempool *lock_free_mp;
+ // Protects access to _mp
+ // Non-coop, non-recursive
+ mono_mutex_t mp_mutex;
+
GPtrArray *class_vtable_array;
GHashTable *generic_virtual_cases;
mono_mem_manager_alloc (MonoMemoryManager *memory_manager, guint size);
void *
-mono_mem_manager_alloc_nolock (MonoMemoryManager *memory_manager, guint size);
-
-void *
mono_mem_manager_alloc0 (MonoMemoryManager *memory_manager, guint size);
-void *
-mono_mem_manager_alloc0_nolock (MonoMemoryManager *memory_manager, guint size);
-
gpointer
mono_mem_manager_alloc0_lock_free (MonoMemoryManager *memory_manager, guint size);
void
mono_mem_manager_free_debug_info (MonoMemoryManager *memory_manager);
+gboolean
+mono_mem_manager_mp_contains_addr (MonoMemoryManager *memory_manager, gpointer addr);
+
G_END_DECLS
#endif
InvalidLock = 0,
LoaderLock,
ImageDataLock,
- DomainLock,
DomainAssembliesLock,
DomainJitCodeHashLock,
IcallLock,
{
MonoDomain *domain = mono_get_root_domain ();
- memory_manager->domain = domain;
memory_manager->freeing = FALSE;
mono_coop_mutex_init_recursive (&memory_manager->lock);
+ mono_os_mutex_init (&memory_manager->mp_mutex);
- memory_manager->mp = mono_mempool_new ();
+ memory_manager->_mp = mono_mempool_new ();
memory_manager->code_mp = mono_code_manager_new ();
memory_manager->lock_free_mp = lock_free_mempool_new ();
mono_coop_mutex_destroy (&memory_manager->lock);
if (debug_unload) {
- mono_mempool_invalidate (memory_manager->mp);
+ mono_mempool_invalidate (memory_manager->_mp);
mono_code_manager_invalidate (memory_manager->code_mp);
} else {
#ifndef DISABLE_PERFCOUNTERS
/* FIXME: use an explicit subtraction method as soon as it's available */
- mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, -1 * mono_mempool_get_allocated (memory_manager->mp));
+ mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, -1 * mono_mempool_get_allocated (memory_manager->_mp));
#endif
- mono_mempool_destroy (memory_manager->mp);
- memory_manager->mp = NULL;
+ mono_mempool_destroy (memory_manager->_mp);
+ memory_manager->_mp = NULL;
mono_code_manager_destroy (memory_manager->code_mp);
memory_manager->code_mp = NULL;
}
void
mono_mem_manager_lock (MonoMemoryManager *memory_manager)
{
- //mono_coop_mutex_lock (&memory_manager->lock);
- mono_domain_lock (memory_manager->domain);
+ mono_coop_mutex_lock (&memory_manager->lock);
}
void
mono_mem_manager_unlock (MonoMemoryManager *memory_manager)
{
- //mono_coop_mutex_unlock (&memory_manager->lock);
- mono_domain_unlock (memory_manager->domain);
+ mono_coop_mutex_unlock (&memory_manager->lock);
}
-void *
-mono_mem_manager_alloc (MonoMemoryManager *memory_manager, guint size)
+static inline void
+alloc_lock (MonoMemoryManager *memory_manager)
{
- void *res;
-
- mono_mem_manager_lock (memory_manager);
- res = mono_mem_manager_alloc_nolock (memory_manager, size);
- mono_mem_manager_unlock (memory_manager);
-
- return res;
+ mono_os_mutex_lock (&memory_manager->mp_mutex);
}
-void *
-mono_mem_manager_alloc_nolock (MonoMemoryManager *memory_manager, guint size)
+static inline void
+alloc_unlock (MonoMemoryManager *memory_manager)
{
-#ifndef DISABLE_PERFCOUNTERS
- mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
-#endif
- return mono_mempool_alloc (memory_manager->mp, size);
+ mono_os_mutex_unlock (&memory_manager->mp_mutex);
}
void *
-mono_mem_manager_alloc0 (MonoMemoryManager *memory_manager, guint size)
+mono_mem_manager_alloc (MonoMemoryManager *memory_manager, guint size)
{
void *res;
- mono_mem_manager_lock (memory_manager);
- res = mono_mem_manager_alloc0_nolock (memory_manager, size);
- mono_mem_manager_unlock (memory_manager);
+ alloc_lock (memory_manager);
+#ifndef DISABLE_PERFCOUNTERS
+ mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
+#endif
+ res = mono_mempool_alloc (memory_manager->_mp, size);
+ alloc_unlock (memory_manager);
return res;
}
void *
-mono_mem_manager_alloc0_nolock (MonoMemoryManager *memory_manager, guint size)
+mono_mem_manager_alloc0 (MonoMemoryManager *memory_manager, guint size)
{
+ void *res;
+
+ alloc_lock (memory_manager);
#ifndef DISABLE_PERFCOUNTERS
mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
#endif
- return mono_mempool_alloc0 (memory_manager->mp, size);
+ res = mono_mempool_alloc0 (memory_manager->_mp, size);
+ alloc_unlock (memory_manager);
+
+ return res;
}
char*
{
char *res;
- mono_mem_manager_lock (memory_manager);
- res = mono_mempool_strdup (memory_manager->mp, s);
- mono_mem_manager_unlock (memory_manager);
+ alloc_lock (memory_manager);
+ res = mono_mempool_strdup (memory_manager->_mp, s);
+ alloc_unlock (memory_manager);
+
+ return res;
+}
+
+gboolean
+mono_mem_manager_mp_contains_addr (MonoMemoryManager *memory_manager, gpointer addr)
+{
+ gboolean res;
+ alloc_lock (memory_manager);
+ res = mono_mempool_contains_addr (memory_manager->_mp, addr);
+ alloc_unlock (memory_manager);
return res;
}
get_generic_virtual_entries (MonoMemoryManager *mem_manager, gpointer *vtable_slot);
/*
- * LOCKING: requires the loader and domain locks.
+ * LOCKING: assume the loader lock is held
*
*/
static void
{
MONO_REQ_GC_NEUTRAL_MODE;
+ mono_loader_lock ();
build_imt_slots (klass, vt, imt, extra_interfaces, -1);
+ mono_loader_unlock ();
}
/**
* Fill the given \p imt_slot in the IMT table of \p vtable with
* a trampoline or a trampoline for the case of collisions.
* This is part of the internal mono API.
- * LOCKING: Take the domain lock.
+ * LOCKING: Take the loader lock.
*/
void
mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
* Update and heck needs to ahppen inside the proper domain lock, as all
* the changes made to a MonoVTable.
*/
- mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
- mono_domain_lock (vtable->domain);
+ mono_loader_lock ();
/* we change the slot only if it wasn't changed from the generic imt trampoline already */
if (!callbacks.imt_entry_inited (vtable, imt_slot))
build_imt_slots (vtable->klass, vtable, imt, NULL, imt_slot);
- mono_domain_unlock (vtable->domain);
mono_loader_unlock ();
}
GenericVirtualCase *list;
MonoImtBuilderEntry *entries;
- MonoDomain *domain = mono_get_root_domain ();
- mono_domain_lock (domain);
+ mono_mem_manager_lock (mem_manager);
if (!mem_manager->generic_virtual_cases)
mem_manager->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
entries = entry;
}
- mono_domain_unlock (domain);
+ mono_mem_manager_unlock (mem_manager);
/* FIXME: Leaking memory ? */
return entries;
GenericVirtualCase *gvc, *list;
MonoImtBuilderEntry *entries;
GPtrArray *sorted;
- MonoDomain *domain = mono_get_root_domain ();
MonoMemoryManager *mem_manager = m_class_get_mem_manager (vtable->klass);
- mono_domain_lock (domain);
+ mono_loader_lock ();
+
+ mono_mem_manager_lock (mem_manager);
if (!mem_manager->generic_virtual_cases)
mem_manager->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
num_added++;
}
+ mono_mem_manager_unlock (mem_manager);
+
if (++gvc->count == THUNK_THRESHOLD) {
gpointer *old_thunk = (void **)*vtable_slot;
gpointer vtable_trampoline = NULL;
}
}
- mono_domain_unlock (domain);
+ mono_loader_unlock ();
}
static MonoVTable *mono_class_create_runtime_vtable (MonoClass *klass, MonoError *error);
MonoReflectionTypeHandle vt_type = mono_type_get_object_handle (m_class_get_byval_arg (klass), error);
vt->type = MONO_HANDLE_RAW (vt_type);
if (!is_ok (error)) {
- mono_domain_unlock (domain);
mono_loader_unlock ();
MONO_PROFILER_RAISE (vtable_failed, (vt));
goto return_null;
reflection_setup_internal_class (ref_tb, error);
mono_error_assert_ok (error);
- MonoDomain *domain = MONO_HANDLE_DOMAIN (ref_tb);
MonoType *type = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoReflectionType, ref_tb), type);
MonoClass *klass = mono_class_from_mono_type_internal (type);
MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, ref_tb, cattrs);
mono_save_custom_attrs (klass->image, klass, MONO_HANDLE_RAW (cattrs)); /* FIXME use handles */
- /*
- * we need to lock the domain because the lock will be taken inside
- * So, we need to keep the locking order correct.
- */
mono_loader_lock ();
- mono_domain_lock (domain);
+
if (klass->wastypebuilder) {
- mono_domain_unlock (domain);
mono_loader_unlock ();
return mono_type_get_object_handle (m_class_get_byval_arg (klass), error);
goto_if_nok (error, failure);
}
- mono_domain_unlock (domain);
mono_loader_unlock ();
if (klass->enumtype && !mono_class_is_valid_enum (klass)) {
failure:
mono_class_set_type_load_failure (klass, "TypeBuilder could not create runtime class due to: %s", mono_error_get_message (error));
klass->wastypebuilder = TRUE;
- mono_domain_unlock (domain);
mono_loader_unlock ();
failure_unlocked:
return MONO_HANDLE_CAST (MonoReflectionType, NULL_HANDLE);
InterpMethod *target_imethod;
} InterpVTableEntry;
+static inline GSList*
+g_slist_append_node (GSList *list, GSList *new_list, gpointer data)
+{
+ GSList *last;
+
+ new_list->data = data;
+ new_list->next = NULL;
+
+ if (list) {
+ last = list;
+ while (last->next)
+ last = last->next;
+ last->next = new_list;
+
+ return list;
+ } else
+ return new_list;
+}
+
/* memory manager lock must be held */
static GSList*
append_imethod (MonoMemoryManager *memory_manager, GSList *list, InterpMethod *imethod, InterpMethod *target_imethod)
GSList *ret;
InterpVTableEntry *entry;
- entry = (InterpVTableEntry*) mono_mem_manager_alloc_nolock (memory_manager, sizeof (InterpVTableEntry));
+ entry = (InterpVTableEntry*) mono_mem_manager_alloc0 (memory_manager, sizeof (InterpVTableEntry));
entry->imethod = imethod;
entry->target_imethod = target_imethod;
- ret = g_slist_append_mempool (memory_manager->mp, list, entry);
+ ret = mono_mem_manager_alloc0 (memory_manager, sizeof (GSList));
+ ret = g_slist_append_node (list, ret, entry);
return ret;
}
{
gpointer info;
int i, first_slot, size;
- MonoDomain *domain = mono_get_root_domain ();
MonoClass *klass = class_vtable->klass;
MonoGenericContext *class_context;
MonoRuntimeGenericContextInfoTemplate oti;
class_context = mono_class_is_ginst (klass) ? &mono_class_get_generic_class (klass)->context : NULL;
MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
- mono_domain_lock (domain);
+ mono_mem_manager_lock (jit_mm->mem_manager);
/* First check whether that slot isn't already instantiated.
This might happen because lookup doesn't lock. Allocate
rgctx_index = slot - first_slot + 1 + offset;
info = (MonoRuntimeGenericContext*)rgctx [rgctx_index];
if (info) {
- mono_domain_unlock (domain);
+ mono_mem_manager_unlock (jit_mm->mem_manager);
return info;
}
break;
g_assert (!rgctx [rgctx_index]);
- mono_domain_unlock (domain);
+ mono_mem_manager_unlock (jit_mm->mem_manager);
oti = class_get_rgctx_template_oti (get_shared_class (klass),
method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
*/
/*FIXME We should use CAS here, no need to take a lock.*/
- mono_domain_lock (domain);
+ mono_mem_manager_lock (jit_mm->mem_manager);
/* Check whether the slot hasn't been instantiated in the
meantime. */
rgctx [rgctx_index] = info;
}
- mono_domain_unlock (domain);
+ mono_mem_manager_unlock (jit_mm->mem_manager);
if (do_free)
free_inflated_info (oti.info_type, oti.data);
*exc = NULL;
#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
- MonoDomain *domain = mono_get_root_domain ();
static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL;
if (info->dyn_call_info) {
if (!dyn_runtime_invoke) {
- mono_domain_lock (domain);
-
invoke = mono_marshal_get_runtime_invoke_dynamic ();
- dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
+ RuntimeInvokeDynamicFunction invoke_func = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error);
+ mono_memory_barrier ();
+ dyn_runtime_invoke = invoke_func;
if (!dyn_runtime_invoke && mono_use_interpreter) {
info->use_interp = TRUE;
info->dyn_call_info = NULL;
} else if (!is_ok (error)) {
- mono_domain_unlock (domain);
return NULL;
}
- mono_domain_unlock (domain);
}
}
if (info->dyn_call_info) {
}
if (!cfg->compile_aot && !(flags & JIT_FLAG_DISCARD_RESULTS)) {
- MonoDomain *domain = mono_get_root_domain ();
- mono_domain_lock (domain);
mono_jit_info_table_add (cfg->jit_info);
- mono_domain_unlock (domain);
if (cfg->method->dynamic) {
MonoJitMemoryManager *jit_mm = (MonoJitMemoryManager*)cfg->jit_mm;
MonoException *ex = NULL;
gint64 start;
MonoMethod *prof_method, *shared;
- MonoDomain *target_domain = mono_get_root_domain ();
error_init (error);
shared = NULL;
}
- mono_domain_lock (target_domain);
+ mono_loader_lock ();
if (mono_stats_method_desc && mono_method_desc_full_match (mono_stats_method_desc, method)) {
g_printf ("Printing runtime stats at method: %s\n", mono_method_get_full_name (method));
mono_emit_jit_map (jinfo);
mono_emit_jit_dump (jinfo, code);
#endif
- mono_domain_unlock (target_domain);
+ mono_loader_unlock ();
if (!is_ok (error))
return NULL;