فهرست منبع

Make resource loader cycle checker work on a per-thread basis.
This removes editor errors saying cycles existed when the thumbnailer was running.

Juan Linietsky 6 سال پیش
والد
کامیت
1f9c54bd55
2فایلهای تغییر یافته به همراه51 افزوده شده و 9 حذف شده
  1. 33 7
      core/io/resource_loader.cpp
  2. 18 2
      core/io/resource_loader.h

+ 33 - 7
core/io/resource_loader.cpp

@@ -55,7 +55,7 @@ Error ResourceInteractiveLoader::wait() {
 
 ResourceInteractiveLoader::~ResourceInteractiveLoader() {
 	if (path_loading != String()) {
-		ResourceLoader::_remove_from_loading_map(path_loading);
+		ResourceLoader::_remove_from_loading_map_and_thread(path_loading, path_loading_thread);
 	}
 }
 
@@ -293,10 +293,14 @@ bool ResourceLoader::_add_to_loading_map(const String &p_path) {
 		loading_map_mutex->lock();
 	}
 
-	if (loading_map.has(p_path)) {
+	LoadingMapKey key;
+	key.path = p_path;
+	key.thread = Thread::get_caller_id();
+
+	if (loading_map.has(key)) {
 		success = false;
 	} else {
-		loading_map[p_path] = true;
+		loading_map[key] = true;
 		success = true;
 	}
 
@@ -312,7 +316,27 @@ void ResourceLoader::_remove_from_loading_map(const String &p_path) {
 		loading_map_mutex->lock();
 	}
 
-	loading_map.erase(p_path);
+	LoadingMapKey key;
+	key.path = p_path;
+	key.thread = Thread::get_caller_id();
+
+	loading_map.erase(key);
+
+	if (loading_map_mutex) {
+		loading_map_mutex->unlock();
+	}
+}
+
+void ResourceLoader::_remove_from_loading_map_and_thread(const String &p_path, Thread::ID p_thread) {
+	if (loading_map_mutex) {
+		loading_map_mutex->lock();
+	}
+
+	LoadingMapKey key;
+	key.path = p_path;
+	key.thread = p_thread;
+
+	loading_map.erase(key);
 
 	if (loading_map_mutex) {
 		loading_map_mutex->unlock();
@@ -471,6 +495,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
 
 			ril->resource = res_cached;
 			ril->path_loading = local_path;
+			ril->path_loading_thread = Thread::get_caller_id();
 			return ril;
 		}
 	}
@@ -499,6 +524,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
 		if (!p_no_cache) {
 			ril->set_local_path(local_path);
 			ril->path_loading = local_path;
+			ril->path_loading_thread = Thread::get_caller_id();
 		}
 
 		if (xl_remapped)
@@ -919,7 +945,7 @@ void ResourceLoader::remove_custom_loaders() {
 }
 
 Mutex *ResourceLoader::loading_map_mutex = NULL;
-HashMap<String, int> ResourceLoader::loading_map;
+HashMap<ResourceLoader::LoadingMapKey, int, ResourceLoader::LoadingMapKeyHasher> ResourceLoader::loading_map;
 
 void ResourceLoader::initialize() {
 #ifndef NO_THREADS
@@ -929,9 +955,9 @@ void ResourceLoader::initialize() {
 
 void ResourceLoader::finalize() {
 #ifndef NO_THREADS
-	const String *K = NULL;
+	const LoadingMapKey *K = NULL;
 	while ((K = loading_map.next(K))) {
-		ERR_PRINTS("Exited while resource is being loaded: " + *K);
+		ERR_PRINTS("Exited while resource is being loaded: " + K->path);
 	}
 	loading_map.clear();
 	memdelete(loading_map_mutex);

+ 18 - 2
core/io/resource_loader.h

@@ -31,8 +31,8 @@
 #ifndef RESOURCE_LOADER_H
 #define RESOURCE_LOADER_H
 
+#include "core/os/thread.h"
 #include "core/resource.h"
-
 /**
 	@author Juan Linietsky <[email protected]>
 */
@@ -42,6 +42,7 @@ class ResourceInteractiveLoader : public Reference {
 	GDCLASS(ResourceInteractiveLoader, Reference);
 	friend class ResourceLoader;
 	String path_loading;
+	Thread::ID path_loading_thread;
 
 protected:
 	static void _bind_methods();
@@ -121,10 +122,25 @@ class ResourceLoader {
 
 	static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path);
 	static Mutex *loading_map_mutex;
-	static HashMap<String, int> loading_map;
+
+	//used to track paths being loaded in a thread, avoids cyclic recursion
+	struct LoadingMapKey {
+		String path;
+		Thread::ID thread;
+		bool operator==(const LoadingMapKey &p_key) const {
+			return (thread == p_key.thread && path == p_key.path);
+		}
+	};
+	struct LoadingMapKeyHasher {
+
+		static _FORCE_INLINE_ uint32_t hash(const LoadingMapKey &p_key) { return p_key.path.hash() + HashMapHasherDefault::hash(p_key.thread); }
+	};
+
+	static HashMap<LoadingMapKey, int, LoadingMapKeyHasher> loading_map;
 
 	static bool _add_to_loading_map(const String &p_path);
 	static void _remove_from_loading_map(const String &p_path);
+	static void _remove_from_loading_map_and_thread(const String &p_path, Thread::ID p_thread);
 
 public:
 	static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL);