Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { CRASH_COND(p_domain == NULL); String domain_name = mono_domain_get_friendly_name(p_domain); print_verbose("Mono: Unloading domain `" + domain_name + "`..."); if (mono_domain_get() != root_domain) mono_domain_set(root_domain, true); mono_gc_collect(mono_gc_max_generation()); mono_domain_finalize(p_domain, 2000); mono_gc_collect(mono_gc_max_generation()); _domain_assemblies_cleanup(mono_domain_get_id(p_domain)); MonoException *exc = NULL; mono_domain_try_unload(p_domain, (MonoObject **)&exc); if (exc) { ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`"); GDMonoUtils::debug_unhandled_exception(exc); return FAILED; } return OK; }
gint64 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection) { if (forceCollection) mono_gc_collect (mono_gc_max_generation ()); return mono_gc_get_used_size (); }
Error GDMono::_unload_scripts_domain() { ERR_FAIL_NULL_V(scripts_domain, ERR_BUG); if (OS::get_singleton()->is_stdout_verbose()) { OS::get_singleton()->print("Mono: Unloading scripts domain...\n"); } _GodotSharp::get_singleton()->_dispose_callback(); if (mono_domain_get() != root_domain) mono_domain_set(root_domain, true); mono_gc_collect(mono_gc_max_generation()); finalizing_scripts_domain = true; mono_domain_finalize(scripts_domain, 2000); finalizing_scripts_domain = false; mono_gc_collect(mono_gc_max_generation()); _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain)); api_assembly = NULL; project_assembly = NULL; #ifdef TOOLS_ENABLED editor_api_assembly = NULL; #endif MonoDomain *domain = scripts_domain; scripts_domain = NULL; _GodotSharp::get_singleton()->_dispose_callback(); MonoObject *ex = NULL; mono_domain_try_unload(domain, &ex); if (ex) { ERR_PRINT("Exception thrown when unloading scripts domain:"); mono_print_unhandled_exception(ex); return FAILED; } return OK; }
Error GDMono::_unload_scripts_domain() { ERR_FAIL_NULL_V(scripts_domain, ERR_BUG); print_verbose("Mono: Unloading scripts domain..."); _GodotSharp::get_singleton()->_dispose_callback(); if (mono_domain_get() != root_domain) mono_domain_set(root_domain, true); mono_gc_collect(mono_gc_max_generation()); mono_domain_finalize(scripts_domain, 2000); mono_gc_collect(mono_gc_max_generation()); _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain)); core_api_assembly = NULL; project_assembly = NULL; #ifdef TOOLS_ENABLED editor_api_assembly = NULL; #endif core_api_assembly_out_of_sync = false; editor_api_assembly_out_of_sync = false; MonoDomain *domain = scripts_domain; scripts_domain = NULL; _GodotSharp::get_singleton()->_dispose_callback(); MonoException *exc = NULL; mono_domain_try_unload(domain, (MonoObject **)&exc); if (exc) { ERR_PRINT("Exception thrown when unloading scripts domain"); GDMonoUtils::debug_unhandled_exception(exc); return FAILED; } return OK; }
void unload_domain() { MonoDomain* old_domain = mono_domain_get(); if (old_domain && old_domain != mono_get_root_domain()) { if (!mono_domain_set(mono_get_root_domain(), false)) printf_console("Error setting domain\n"); mono_thread_pop_appdomain_ref(); mono_domain_unload(old_domain); } //unloading a domain is also a nice point in time to have the GC run. mono_gc_collect(mono_gc_max_generation()); }
void MonoManager::unloadScriptDomain() { if (mScriptDomain != nullptr) { onDomainUnload(); mono_domain_set(mono_get_root_domain(), false); mono_domain_finalize(mScriptDomain, 2000); MonoObject* exception = nullptr; mono_domain_try_unload(mScriptDomain, &exception); if (exception != nullptr) MonoUtil::throwIfException(exception); mono_gc_collect(mono_gc_max_generation()); mScriptDomain = nullptr; } for (auto& assemblyEntry : mAssemblies) { assemblyEntry.second->unload(); // Metas hold references to various assembly objects that were just deleted, so clear them Vector<ScriptMeta*>& typeMetas = getScriptMetaData()[assemblyEntry.first]; for (auto& entry : typeMetas) { entry->scriptClass = nullptr; entry->thisPtrField = nullptr; } } mAssemblies.clear(); mIsCoreLoaded = false; }
void ves_icall_System_GC_InternalCollect (int generation) { mono_gc_collect (generation); }
gboolean mono_domain_finalize (MonoDomain *domain, guint32 timeout) { DomainFinalizationReq *req; guint32 res; HANDLE done_event; MonoInternalThread *thread = mono_thread_internal_current (); if (mono_thread_internal_current () == gc_thread) /* We are called from inside a finalizer, not much we can do here */ return FALSE; /* * No need to create another thread 'cause the finalizer thread * is still working and will take care of running the finalizers */ #ifndef HAVE_NULL_GC if (gc_disabled) return TRUE; mono_gc_collect (mono_gc_max_generation ()); done_event = CreateEvent (NULL, TRUE, FALSE, NULL); if (done_event == NULL) { return FALSE; } req = g_new0 (DomainFinalizationReq, 1); req->domain = domain; req->done_event = done_event; if (domain == mono_get_root_domain ()) finalizing_root_domain = TRUE; mono_finalizer_lock (); domains_to_finalize = g_slist_append (domains_to_finalize, req); mono_finalizer_unlock (); /* Tell the finalizer thread to finalize this appdomain */ mono_gc_finalize_notify (); if (timeout == -1) timeout = INFINITE; while (TRUE) { res = WaitForSingleObjectEx (done_event, timeout, TRUE); /* printf ("WAIT RES: %d.\n", res); */ if (res == WAIT_IO_COMPLETION) { if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0) return FALSE; } else if (res == WAIT_TIMEOUT) { /* We leak the handle here */ return FALSE; } else { break; } } CloseHandle (done_event); if (domain == mono_get_root_domain ()) { mono_thread_pool_cleanup (); mono_gc_finalize_threadpool_threads (); } return TRUE; #else /* We don't support domain finalization without a GC */ return FALSE; #endif }
gboolean mono_domain_finalize (MonoDomain *domain, guint32 timeout) { DomainFinalizationReq *req; MonoInternalThread *thread = mono_thread_internal_current (); gint res; gboolean ret; gint64 start; #if defined(__native_client__) return FALSE; #endif if (mono_thread_internal_current () == gc_thread) /* We are called from inside a finalizer, not much we can do here */ return FALSE; /* * No need to create another thread 'cause the finalizer thread * is still working and will take care of running the finalizers */ if (gc_disabled) return TRUE; /* We don't support domain finalization without a GC */ if (mono_gc_is_null ()) return FALSE; mono_gc_collect (mono_gc_max_generation ()); req = g_new0 (DomainFinalizationReq, 1); req->ref = 2; req->domain = domain; mono_coop_sem_init (&req->done, 0); if (domain == mono_get_root_domain ()) finalizing_root_domain = TRUE; mono_finalizer_lock (); domains_to_finalize = g_slist_append (domains_to_finalize, req); mono_finalizer_unlock (); /* Tell the finalizer thread to finalize this appdomain */ mono_gc_finalize_notify (); if (timeout == -1) timeout = INFINITE; if (timeout != INFINITE) start = mono_msec_ticks (); ret = TRUE; for (;;) { if (timeout == INFINITE) { res = mono_coop_sem_wait (&req->done, MONO_SEM_FLAGS_ALERTABLE); } else { gint64 elapsed = mono_msec_ticks () - start; if (elapsed >= timeout) { ret = FALSE; break; } res = mono_coop_sem_timedwait (&req->done, timeout - elapsed, MONO_SEM_FLAGS_ALERTABLE); } if (res == MONO_SEM_TIMEDWAIT_RET_SUCCESS) { break; } else if (res == MONO_SEM_TIMEDWAIT_RET_ALERTED) { if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0) { ret = FALSE; break; } } else if (res == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT) { ret = FALSE; break; } else { g_error ("%s: unknown result %d", __func__, res); } } if (!ret) { /* Try removing the req from domains_to_finalize: * - if it's not found: the domain is being finalized, * so we the ref count is already decremented * - if it's found: the domain is not yet being finalized, * so we can safely decrement the ref */ gboolean found; mono_finalizer_lock (); found = g_slist_index (domains_to_finalize, req) != -1; if (found) domains_to_finalize = g_slist_remove (domains_to_finalize, req); mono_finalizer_unlock (); if (found) { /* We have to decrement it wherever we * remove it from domains_to_finalize */ if (InterlockedDecrement (&req->ref) != 1) g_error ("%s: req->ref should be 1, as we are the first one to decrement it", __func__); } goto done; } if (domain == mono_get_root_domain ()) { mono_threadpool_ms_cleanup (); mono_gc_finalize_threadpool_threads (); } done: if (InterlockedDecrement (&req->ref) == 0) { mono_coop_sem_destroy (&req->done); g_free (req); } return ret; }