summaryrefslogtreecommitdiff
path: root/modules/mono
diff options
context:
space:
mode:
authorIgnacio Etcheverry <ignalfonsore@gmail.com>2018-10-06 23:00:18 +0200
committerIgnacio Etcheverry <ignalfonsore@gmail.com>2018-10-06 23:00:18 +0200
commitb63e518ce9685a2f7a681af023c8b4a190d55d88 (patch)
treec53ead656ac31d6a7429ec82b8e446106584035b /modules/mono
parenta41cf404a9013db6aed56d6ed9b051c2a4948bff (diff)
Mono: Fix crash on NodePath/RID disposal during Godot shutdown
Diffstat (limited to 'modules/mono')
-rw-r--r--modules/mono/glue/nodepath_glue.cpp2
-rw-r--r--modules/mono/glue/rid_glue.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp87
-rw-r--r--modules/mono/mono_gd/gd_mono.h7
4 files changed, 17 insertions, 81 deletions
diff --git a/modules/mono/glue/nodepath_glue.cpp b/modules/mono/glue/nodepath_glue.cpp
index 4b7648a4f9..422d73104d 100644
--- a/modules/mono/glue/nodepath_glue.cpp
+++ b/modules/mono/glue/nodepath_glue.cpp
@@ -40,7 +40,7 @@ NodePath *godot_icall_NodePath_Ctor(MonoString *p_path) {
void godot_icall_NodePath_Dtor(NodePath *p_ptr) {
ERR_FAIL_NULL(p_ptr);
- _GodotSharp::get_singleton()->queue_dispose(p_ptr);
+ memdelete(p_ptr);
}
MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) {
diff --git a/modules/mono/glue/rid_glue.cpp b/modules/mono/glue/rid_glue.cpp
index 5d66b8aa6f..6c002b5b9d 100644
--- a/modules/mono/glue/rid_glue.cpp
+++ b/modules/mono/glue/rid_glue.cpp
@@ -45,7 +45,7 @@ RID *godot_icall_RID_Ctor(Object *p_from) {
void godot_icall_RID_Dtor(RID *p_ptr) {
ERR_FAIL_NULL(p_ptr);
- _GodotSharp::get_singleton()->queue_dispose(p_ptr);
+ memdelete(p_ptr);
}
uint32_t godot_icall_RID_get_id(RID *p_ptr) {
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index bf5455de16..0c4433112d 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -671,14 +671,18 @@ Error GDMono::_unload_scripts_domain() {
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);
+ finalizing_scripts_domain = true;
+
+ if (!mono_domain_finalize(scripts_domain, 2000)) {
+ ERR_PRINT("Mono: Domain finalization timeout");
+ }
+
+ finalizing_scripts_domain = false;
mono_gc_collect(mono_gc_max_generation());
@@ -696,8 +700,6 @@ Error GDMono::_unload_scripts_domain() {
MonoDomain *domain = scripts_domain;
scripts_domain = NULL;
- _GodotSharp::get_singleton()->_dispose_callback();
-
MonoException *exc = NULL;
mono_domain_try_unload(domain, (MonoObject **)&exc);
@@ -800,7 +802,9 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
mono_domain_set(root_domain, true);
mono_gc_collect(mono_gc_max_generation());
- mono_domain_finalize(p_domain, 2000);
+ if (!mono_domain_finalize(p_domain, 2000)) {
+ ERR_PRINT("Mono: Domain finalization timeout");
+ }
mono_gc_collect(mono_gc_max_generation());
_domain_assemblies_cleanup(mono_domain_get_id(p_domain));
@@ -875,6 +879,7 @@ GDMono::GDMono() {
gdmono_log = memnew(GDMonoLog);
runtime_initialized = false;
+ finalizing_scripts_domain = false;
root_domain = NULL;
scripts_domain = NULL;
@@ -941,29 +946,6 @@ GDMono::~GDMono() {
_GodotSharp *_GodotSharp::singleton = NULL;
-void _GodotSharp::_dispose_callback() {
-
-#ifndef NO_THREADS
- queue_mutex->lock();
-#endif
-
- for (List<NodePath *>::Element *E = np_delete_queue.front(); E; E = E->next()) {
- memdelete(E->get());
- }
-
- for (List<RID *>::Element *E = rid_delete_queue.front(); E; E = E->next()) {
- memdelete(E->get());
- }
-
- np_delete_queue.clear();
- rid_delete_queue.clear();
- queue_empty = true;
-
-#ifndef NO_THREADS
- queue_mutex->unlock();
-#endif
-}
-
void _GodotSharp::attach_thread() {
GDMonoUtils::attach_current_thread();
@@ -1012,6 +994,8 @@ bool _GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {
if (!p_domain)
return true;
+ if (p_domain == SCRIPTS_DOMAIN && GDMono::get_singleton()->is_finalizing_scripts_domain())
+ return true;
return mono_domain_is_unloading(p_domain);
}
@@ -1025,49 +1009,6 @@ 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() && !is_domain_finalizing_for_unload(SCRIPTS_DOMAIN)) {
- memdelete(p_node_path);
- } else {
-#ifndef NO_THREADS
- queue_mutex->lock();
-#endif
-
- ENQUEUE_FOR_DISPOSAL(np_delete_queue, p_node_path);
-
-#ifndef NO_THREADS
- queue_mutex->unlock();
-#endif
- }
-}
-
-void _GodotSharp::queue_dispose(RID *p_rid) {
-
- if (GDMonoUtils::is_main_thread() && !is_domain_finalizing_for_unload(SCRIPTS_DOMAIN)) {
- memdelete(p_rid);
- } else {
-#ifndef NO_THREADS
- queue_mutex->lock();
-#endif
-
- ENQUEUE_FOR_DISPOSAL(rid_delete_queue, p_rid);
-
-#ifndef NO_THREADS
- queue_mutex->unlock();
-#endif
- }
-}
-
void _GodotSharp::_bind_methods() {
ClassDB::bind_method(D_METHOD("attach_thread"), &_GodotSharp::attach_thread);
@@ -1080,8 +1021,6 @@ void _GodotSharp::_bind_methods() {
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);
}
_GodotSharp::_GodotSharp() {
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 97c2252f7c..745dcc34eb 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -172,6 +172,8 @@ public:
_FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized && !mono_runtime_is_shutting_down() /* stays true after shutdown finished */; }
+ _FORCE_INLINE_ bool is_finalizing_scripts_domain() { return finalizing_scripts_domain; }
+
_FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
#ifdef TOOLS_ENABLED
_FORCE_INLINE_ MonoDomain *get_tools_domain() { return tools_domain; }
@@ -260,8 +262,6 @@ class _GodotSharp : public Object {
friend class GDMono;
- void _dispose_callback();
-
bool _is_domain_finalizing_for_unload(int32_t p_domain_id);
List<NodePath *> np_delete_queue;
@@ -295,9 +295,6 @@ public:
bool is_runtime_shutting_down();
bool is_runtime_initialized();
- void queue_dispose(NodePath *p_node_path);
- void queue_dispose(RID *p_rid);
-
_GodotSharp();
~_GodotSharp();
};