Make resource loader cycle checker work on a per-thread basis.

This removes editor errors saying cycles existed when the thumbnailer was running.
This commit is contained in:
Juan Linietsky 2019-02-16 17:38:09 -03:00
parent 0a563bfab1
commit 1f9c54bd55
2 changed files with 51 additions and 9 deletions

View file

@ -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);

View file

@ -31,8 +31,8 @@
#ifndef RESOURCE_LOADER_H
#define RESOURCE_LOADER_H
#include "core/os/thread.h"
#include "core/resource.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@ -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);