Prechádzať zdrojové kódy

Merge pull request #98963 from RandomShaper/fix_classdb_deadlock

Fix deadlocks related to ClassDB queries about global classes
Thaddeus Crews 10 mesiacov pred
rodič
commit
323b2d53d7
2 zmenil súbory, kde vykonal 64 pridanie a 43 odobranie
  1. 61 43
      core/object/class_db.cpp
  2. 3 0
      scene/register_scene_types.cpp

+ 61 - 43
core/object/class_db.cpp

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

+ 3 - 0
scene/register_scene_types.cpp

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