summaryrefslogtreecommitdiffstats
path: root/core/io/resource_loader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/io/resource_loader.cpp')
-rw-r--r--core/io/resource_loader.cpp35
1 files changed, 27 insertions, 8 deletions
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index f852e8d382..c68191554c 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -476,9 +476,6 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
if (run_on_current_thread) {
load_task_ptr->thread_id = Thread::get_caller_id();
- if (must_not_register) {
- load_token->res_if_unregistered = load_task_ptr->resource;
- }
} else {
load_task_ptr->task_id = WorkerThreadPool::get_singleton()->add_native_task(&ResourceLoader::_thread_load_function, load_task_ptr);
}
@@ -486,6 +483,9 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
if (run_on_current_thread) {
_thread_load_function(load_task_ptr);
+ if (must_not_register) {
+ load_token->res_if_unregistered = load_task_ptr->resource;
+ }
}
return load_token;
@@ -613,14 +613,33 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
return Ref<Resource>();
}
- if (load_task.task_id != 0 && !load_task.awaited) {
- // Loading thread is in the worker pool and still not awaited.
+ if (load_task.task_id != 0) {
+ // Loading thread is in the worker pool.
load_task.awaited = true;
thread_load_mutex.unlock();
- WorkerThreadPool::get_singleton()->wait_for_task_completion(load_task.task_id);
- thread_load_mutex.lock();
+ Error err = WorkerThreadPool::get_singleton()->wait_for_task_completion(load_task.task_id);
+ if (err == ERR_BUSY) {
+ // The WorkerThreadPool has scheduled tasks in a way that the current load depends on
+ // another one in a lower stack frame. Restart such load here. When the stack is eventually
+ // unrolled, the original load will have been notified to go on.
+#ifdef DEV_ENABLED
+ print_verbose("ResourceLoader: Load task happened to wait on another one deep in the call stack. Attempting to avoid deadlock by re-issuing the load now.");
+#endif
+ // CACHE_MODE_IGNORE is needed because, otherwise, the new request would just see there's
+ // an ongoing load for that resource and wait for it again. This value forces a new load.
+ Ref<ResourceLoader::LoadToken> token = _load_start(load_task.local_path, load_task.type_hint, LOAD_THREAD_DISTRIBUTE, ResourceFormatLoader::CACHE_MODE_IGNORE);
+ Ref<Resource> resource = _load_complete(*token.ptr(), &err);
+ if (r_error) {
+ *r_error = err;
+ }
+ thread_load_mutex.lock();
+ return resource;
+ } else {
+ DEV_ASSERT(err == OK);
+ thread_load_mutex.lock();
+ }
} else {
- // Loading thread is main or user thread, or in the worker pool, but already awaited by some other thread.
+ // Loading thread is main or user thread.
if (!load_task.cond_var) {
load_task.cond_var = memnew(ConditionVariable);
}