summaryrefslogtreecommitdiffstats
path: root/modules/mono/mono_gd/gd_mono.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/mono_gd/gd_mono.cpp')
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp120
1 files changed, 59 insertions, 61 deletions
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index f1dbb5c514..833aa23820 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -639,9 +639,7 @@ Error GDMono::_unload_scripts_domain() {
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());
@@ -837,7 +835,6 @@ GDMono::GDMono() {
gdmono_log = memnew(GDMonoLog);
runtime_initialized = false;
- finalizing_scripts_domain = false;
root_domain = NULL;
scripts_domain = NULL;
@@ -866,7 +863,7 @@ GDMono::GDMono() {
GDMono::~GDMono() {
- if (runtime_initialized) {
+ if (is_runtime_initialized()) {
if (scripts_domain) {
@@ -891,8 +888,9 @@ GDMono::~GDMono() {
print_verbose("Mono: Runtime cleanup...");
- runtime_initialized = false;
mono_jit_cleanup(root_domain);
+
+ runtime_initialized = false;
}
if (gdmono_log)
@@ -903,33 +901,12 @@ GDMono::~GDMono() {
_GodotSharp *_GodotSharp::singleton = NULL;
-void _GodotSharp::_dispose_object(Object *p_object) {
-
- if (p_object->get_script_instance()) {
- CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_object->get_script_instance());
- if (cs_instance) {
- cs_instance->mono_object_disposed();
- return;
- }
- }
-
- // Unsafe refcount decrement. The managed instance also counts as a reference.
- // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
- if (Object::cast_to<Reference>(p_object)->unreference()) {
- memdelete(p_object);
- }
-}
-
void _GodotSharp::_dispose_callback() {
#ifndef NO_THREADS
queue_mutex->lock();
#endif
- for (List<Object *>::Element *E = obj_delete_queue.front(); E; E = E->next()) {
- _dispose_object(E->get());
- }
-
for (List<NodePath *>::Element *E = np_delete_queue.front(); E; E = E->next()) {
memdelete(E->get());
}
@@ -938,7 +915,6 @@ void _GodotSharp::_dispose_callback() {
memdelete(E->get());
}
- obj_delete_queue.clear();
np_delete_queue.clear();
rid_delete_queue.clear();
queue_empty = true;
@@ -958,52 +934,69 @@ void _GodotSharp::detach_thread() {
GDMonoUtils::detach_current_thread();
}
-bool _GodotSharp::is_finalizing_domain() {
+int32_t _GodotSharp::get_domain_id() {
- return GDMono::get_singleton()->is_finalizing_scripts_domain();
+ MonoDomain *domain = mono_domain_get();
+ CRASH_COND(!domain); // User must check if runtime is initialized before calling this method
+ return mono_domain_get_id(domain);
}
-bool _GodotSharp::is_domain_loaded() {
+int32_t _GodotSharp::get_scripts_domain_id() {
- return GDMono::get_singleton()->get_scripts_domain() != NULL;
+ MonoDomain *domain = SCRIPTS_DOMAIN;
+ CRASH_COND(!domain); // User must check if scripts domain is loaded before calling this method
+ return mono_domain_get_id(domain);
}
-#define ENQUEUE_FOR_DISPOSAL(m_queue, m_inst) \
- m_queue.push_back(m_inst); \
- if (queue_empty) { \
- queue_empty = false; \
- if (!is_finalizing_domain()) { /* call_deferred may not be safe here */ \
- call_deferred("_dispose_callback"); \
- } \
- }
+bool _GodotSharp::is_scripts_domain_loaded() {
-void _GodotSharp::queue_dispose(MonoObject *p_mono_object, Object *p_object) {
+ return GDMono::get_singleton()->is_runtime_initialized() && SCRIPTS_DOMAIN != NULL;
+}
- if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
- _dispose_object(p_object);
- } else {
-#ifndef NO_THREADS
- queue_mutex->lock();
-#endif
+bool _GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) {
- // This is our last chance to invoke notification predelete (this is being called from the finalizer)
- // We must use the MonoObject* passed by the finalizer, because the weak GC handle target returns NULL at this point
- CSharpInstance *si = CAST_CSHARP_INSTANCE(p_object->get_script_instance());
- if (si) {
- si->call_notification_no_check(p_mono_object, Object::NOTIFICATION_PREDELETE);
- }
+ return is_domain_finalizing_for_unload(p_domain_id);
+}
- ENQUEUE_FOR_DISPOSAL(obj_delete_queue, p_object);
+bool _GodotSharp::is_domain_finalizing_for_unload() {
-#ifndef NO_THREADS
- queue_mutex->unlock();
-#endif
- }
+ return is_domain_finalizing_for_unload(mono_domain_get());
+}
+
+bool _GodotSharp::is_domain_finalizing_for_unload(int32_t p_domain_id) {
+
+ return is_domain_finalizing_for_unload(mono_domain_get_by_id(p_domain_id));
+}
+
+bool _GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {
+
+ if (!p_domain)
+ return true;
+ return mono_domain_is_unloading(p_domain);
+}
+
+bool _GodotSharp::is_runtime_shutting_down() {
+
+ return mono_runtime_is_shutting_down();
+}
+
+bool _GodotSharp::is_runtime_initialized() {
+
+ return GDMono::get_singleton()->is_runtime_initialized();
}
+#define ENQUEUE_FOR_DISPOSAL(m_queue, m_inst) \
+ m_queue.push_back(m_inst); \
+ if (queue_empty) { \
+ queue_empty = false; \
+ if (!is_domain_finalizing_for_unload(SCRIPTS_DOMAIN)) { /* call_deferred may not be safe here */ \
+ call_deferred("_dispose_callback"); \
+ } \
+ }
+
void _GodotSharp::queue_dispose(NodePath *p_node_path) {
- if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
+ if (GDMonoUtils::is_main_thread() && !is_domain_finalizing_for_unload(SCRIPTS_DOMAIN)) {
memdelete(p_node_path);
} else {
#ifndef NO_THREADS
@@ -1020,7 +1013,7 @@ void _GodotSharp::queue_dispose(NodePath *p_node_path) {
void _GodotSharp::queue_dispose(RID *p_rid) {
- if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
+ if (GDMonoUtils::is_main_thread() && !is_domain_finalizing_for_unload(SCRIPTS_DOMAIN)) {
memdelete(p_rid);
} else {
#ifndef NO_THREADS
@@ -1040,8 +1033,13 @@ void _GodotSharp::_bind_methods() {
ClassDB::bind_method(D_METHOD("attach_thread"), &_GodotSharp::attach_thread);
ClassDB::bind_method(D_METHOD("detach_thread"), &_GodotSharp::detach_thread);
- ClassDB::bind_method(D_METHOD("is_finalizing_domain"), &_GodotSharp::is_finalizing_domain);
- ClassDB::bind_method(D_METHOD("is_domain_loaded"), &_GodotSharp::is_domain_loaded);
+ ClassDB::bind_method(D_METHOD("get_domain_id"), &_GodotSharp::get_domain_id);
+ ClassDB::bind_method(D_METHOD("get_scripts_domain_id"), &_GodotSharp::get_scripts_domain_id);
+ ClassDB::bind_method(D_METHOD("is_scripts_domain_loaded"), &_GodotSharp::is_scripts_domain_loaded);
+ ClassDB::bind_method(D_METHOD("is_domain_finalizing_for_unload", "domain_id"), &_GodotSharp::_is_domain_finalizing_for_unload);
+
+ ClassDB::bind_method(D_METHOD("is_runtime_shutting_down"), &_GodotSharp::is_runtime_shutting_down);
+ ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &_GodotSharp::is_runtime_initialized);
ClassDB::bind_method(D_METHOD("_dispose_callback"), &_GodotSharp::_dispose_callback);
}