Merge pull request #107594 from dsnopek/gdextension-shutdown-order-fix

GDExtension: Always run shutdown callback before deinitializing any levels
This commit is contained in:
Thaddeus Crews
2025-06-18 18:13:52 -05:00
2 changed files with 11 additions and 7 deletions

View File

@ -815,8 +815,12 @@ typedef void (*GDExtensionMainLoopShutdownCallback)();
typedef void (*GDExtensionMainLoopFrameCallback)();
typedef struct {
// Will be called after Godot is started and is fully initialized.
GDExtensionMainLoopStartupCallback startup_func;
// Will be called before Godot is shutdown when it is still fully initialized.
GDExtensionMainLoopShutdownCallback shutdown_func;
// Will be called for each process frame. This will run after all `_process()` methods on Node, and before `ScriptServer::frame()`.
// This is intended to be the equivalent of `ScriptLanguage::frame()` for GDExtension language bindings that don't use the script API.
GDExtensionMainLoopFrameCallback frame_func;
} GDExtensionMainLoopCallbacks;

View File

@ -77,13 +77,6 @@ GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(co
emit_signal("extension_unloading", p_extension);
#endif
if (level >= 0) { // Already initialized up to some level.
// Deinitialize down from current level.
for (int32_t i = level; i >= GDExtension::INITIALIZATION_LEVEL_CORE; i--) {
p_extension->deinitialize_library(GDExtension::InitializationLevel(i));
}
}
if (!shutdown_callback_called) {
// Extension is unloading before the shutdown callback has been called,
// which means the engine hasn't shutdown yet but we want to make sure
@ -93,6 +86,13 @@ GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(co
}
}
if (level >= 0) { // Already initialized up to some level.
// Deinitialize down from current level.
for (int32_t i = level; i >= GDExtension::INITIALIZATION_LEVEL_CORE; i--) {
p_extension->deinitialize_library(GDExtension::InitializationLevel(i));
}
}
for (const KeyValue<String, String> &kv : p_extension->class_icon_paths) {
gdextension_class_icon_paths.erase(kv.key);
}