From 12214cb8c77d0a1555d6fb3cd09c1a9215357881 Mon Sep 17 00:00:00 2001 From: Relintai Date: Sat, 8 Feb 2025 11:24:42 +0100 Subject: [PATCH] Fix potential hang on exit due to deadlocks. --- .../library/terrain_library_merger_pcm.cpp | 35 +++++++++++++++++++ .../library/terrain_library_merger_pcm.h | 7 ++++ modules/terraman/world/terrain_world.cpp | 6 ++++ 3 files changed, 48 insertions(+) diff --git a/modules/terraman/library/terrain_library_merger_pcm.cpp b/modules/terraman/library/terrain_library_merger_pcm.cpp index 2d92f522e8..39cf675c93 100644 --- a/modules/terraman/library/terrain_library_merger_pcm.cpp +++ b/modules/terraman/library/terrain_library_merger_pcm.cpp @@ -172,6 +172,11 @@ void TerrainLibraryMergerPCM::_material_cache_get_key(Ref chunk) { continue; } + if (unlikely(_engine_quitting)) { + _material_cache_mutex.unlock(); + return; + } + Ref nms = ms->duplicate(); nms->set_library(Ref(this)); nms->set_id(s); @@ -186,6 +191,11 @@ void TerrainLibraryMergerPCM::_material_cache_get_key(Ref chunk) { continue; } + if (unlikely(_engine_quitting)) { + _material_cache_mutex.unlock(); + return; + } + Ref nm = m->duplicate(); cache->material_add(nm); @@ -359,6 +369,11 @@ void TerrainLibraryMergerPCM::_liquid_material_cache_get_key(Ref c continue; } + if (unlikely(_engine_quitting)) { + _liquid_material_cache_mutex.unlock(); + return; + } + Ref nms = ms->duplicate(); nms->set_library(Ref(this)); nms->set_id(s); @@ -373,6 +388,11 @@ void TerrainLibraryMergerPCM::_liquid_material_cache_get_key(Ref c continue; } + if (unlikely(_engine_quitting)) { + _liquid_material_cache_mutex.unlock(); + return; + } + Ref nm = m->duplicate(); cache->material_add(nm); @@ -560,6 +580,11 @@ void TerrainLibraryMergerPCM::_prop_material_cache_get_key(Ref chu continue; } + if (unlikely(_engine_quitting)) { + _prop_material_cache_mutex.unlock(); + return; + } + Ref nm = m->duplicate(); cache->material_add(nm); @@ -972,6 +997,8 @@ void TerrainLibraryMergerPCM::_setup_material_albedo(const int material_index, c } TerrainLibraryMergerPCM::TerrainLibraryMergerPCM() { + _engine_quitting = false; + _packer.instance(); _packer->set_texture_flags(Texture::FLAG_MIPMAPS | Texture::FLAG_FILTER); @@ -1046,6 +1073,14 @@ bool TerrainLibraryMergerPCM::process_prop_textures(Ref prop) { } #endif +void TerrainLibraryMergerPCM::_notification(int p_what) { + switch (p_what) { + case MainLoop::NOTIFICATION_QUITTING: { + _engine_quitting = true; + } break; + } +} + void TerrainLibraryMergerPCM::_bind_methods() { ClassDB::bind_method(D_METHOD("get_texture_flags"), &TerrainLibraryMergerPCM::get_texture_flags); ClassDB::bind_method(D_METHOD("set_texture_flags", "flags"), &TerrainLibraryMergerPCM::set_texture_flags); diff --git a/modules/terraman/library/terrain_library_merger_pcm.h b/modules/terraman/library/terrain_library_merger_pcm.h index 2ed2cf8f68..e3fd73b402 100644 --- a/modules/terraman/library/terrain_library_merger_pcm.h +++ b/modules/terraman/library/terrain_library_merger_pcm.h @@ -125,6 +125,7 @@ class TerrainLibraryMergerPCM : public TerrainLibrary { bool process_prop_textures(Ref prop); #endif + virtual void _notification(int p_what); static void _bind_methods(); RBMap> _material_cache; @@ -143,6 +144,12 @@ class TerrainLibraryMergerPCM : public TerrainLibrary { Mutex _material_cache_mutex; Mutex _liquid_material_cache_mutex; Mutex _prop_material_cache_mutex; + + // To fix potential deadlock on quit + // (Materials can't be duplicated after the engine started deinitializing itself) + // The notification that sets this should be immediate, the engine will start deinitialization later + // so materials that already started duplicating should be fine + bool _engine_quitting; }; #endif diff --git a/modules/terraman/world/terrain_world.cpp b/modules/terraman/world/terrain_world.cpp index 1eb2aeb4df..0f389851fd 100644 --- a/modules/terraman/world/terrain_world.cpp +++ b/modules/terraman/world/terrain_world.cpp @@ -34,6 +34,7 @@ #include "core/containers/hash_set.h" #include "core/object/message_queue.h" +#include "core/os/main_loop.h" #include "terrain_chunk.h" #include "terrain_structure.h" @@ -1429,6 +1430,11 @@ void TerrainWorld::_notification(int p_what) { } break; } + case MainLoop::NOTIFICATION_QUITTING: { + if (_library.is_valid()) { + _library->notification(MainLoop::NOTIFICATION_QUITTING); + } + } break; } }