Merge pull request #98963 from RandomShaper/fix_classdb_deadlock

Fix deadlocks related to ClassDB queries about global classes
This commit is contained in:
Thaddeus Crews 2024-11-10 12:12:24 -06:00
commit 323b2d53d7
No known key found for this signature in database
GPG Key ID: 62181B86FE9E5D84
2 changed files with 66 additions and 45 deletions

View File

@ -750,69 +750,87 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName &
} }
bool ClassDB::can_instantiate(const StringName &p_class) { bool ClassDB::can_instantiate(const StringName &p_class) {
OBJTYPE_RLOCK; String script_path;
{
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class); ClassInfo *ti = classes.getptr(p_class);
if (!ti) { if (!ti) {
if (!ScriptServer::is_global_class(p_class)) { if (!ScriptServer::is_global_class(p_class)) {
ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class))); ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class)));
}
script_path = ScriptServer::get_global_class_path(p_class);
goto use_script; // Open the lock for resource loading.
} }
String path = ScriptServer::get_global_class_path(p_class);
Ref<Script> scr = ResourceLoader::load(path);
return scr.is_valid() && scr->is_valid() && !scr->is_abstract();
}
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) { if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
return false; return false;
} }
#endif #endif
return _can_instantiate(ti); return _can_instantiate(ti);
}
use_script:
Ref<Script> scr = ResourceLoader::load(script_path);
return scr.is_valid() && scr->is_valid() && !scr->is_abstract();
} }
bool ClassDB::is_abstract(const StringName &p_class) { bool ClassDB::is_abstract(const StringName &p_class) {
OBJTYPE_RLOCK; String script_path;
{
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class); ClassInfo *ti = classes.getptr(p_class);
if (!ti) { if (!ti) {
if (!ScriptServer::is_global_class(p_class)) { if (!ScriptServer::is_global_class(p_class)) {
ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class))); ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class)));
}
script_path = ScriptServer::get_global_class_path(p_class);
goto use_script; // Open the lock for resource loading.
} }
String path = ScriptServer::get_global_class_path(p_class);
Ref<Script> scr = ResourceLoader::load(path); if (ti->creation_func != nullptr) {
return scr.is_valid() && scr->is_valid() && scr->is_abstract(); return false;
}
if (!ti->gdextension) {
return true;
}
#ifndef DISABLE_DEPRECATED
return ti->gdextension->create_instance2 == nullptr && ti->gdextension->create_instance == nullptr;
#else
return ti->gdextension->create_instance2 == nullptr;
#endif // DISABLE_DEPRECATED
} }
if (ti->creation_func != nullptr) { use_script:
return false; Ref<Script> scr = ResourceLoader::load(script_path);
} return scr.is_valid() && scr->is_valid() && scr->is_abstract();
if (!ti->gdextension) {
return true;
}
#ifndef DISABLE_DEPRECATED
return ti->gdextension->create_instance2 == nullptr && ti->gdextension->create_instance == nullptr;
#else
return ti->gdextension->create_instance2 == nullptr;
#endif // DISABLE_DEPRECATED
} }
bool ClassDB::is_virtual(const StringName &p_class) { bool ClassDB::is_virtual(const StringName &p_class) {
OBJTYPE_RLOCK; String script_path;
{
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class); ClassInfo *ti = classes.getptr(p_class);
if (!ti) { if (!ti) {
if (!ScriptServer::is_global_class(p_class)) { if (!ScriptServer::is_global_class(p_class)) {
ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class))); ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class)));
}
script_path = ScriptServer::get_global_class_path(p_class);
goto use_script; // Open the lock for resource loading.
} }
String path = ScriptServer::get_global_class_path(p_class);
Ref<Script> scr = ResourceLoader::load(path);
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
}
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) { if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
return false; return false;
} }
#endif #endif
return (_can_instantiate(ti) && ti->is_virtual); return (_can_instantiate(ti) && ti->is_virtual);
}
use_script:
Ref<Script> scr = ResourceLoader::load(script_path);
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
} }
void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) { void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) {

View File

@ -512,6 +512,9 @@ void register_scene_types() {
GDREGISTER_CLASS(AnimationNodeStateMachine); GDREGISTER_CLASS(AnimationNodeStateMachine);
GDREGISTER_CLASS(AnimationNodeStateMachinePlayback); GDREGISTER_CLASS(AnimationNodeStateMachinePlayback);
GDREGISTER_INTERNAL_CLASS(AnimationNodeStartState);
GDREGISTER_INTERNAL_CLASS(AnimationNodeEndState);
GDREGISTER_CLASS(AnimationNodeSync); GDREGISTER_CLASS(AnimationNodeSync);
GDREGISTER_CLASS(AnimationNodeStateMachineTransition); GDREGISTER_CLASS(AnimationNodeStateMachineTransition);
GDREGISTER_CLASS(AnimationNodeOutput); GDREGISTER_CLASS(AnimationNodeOutput);