Skip to content

Commit 8c559fc

Browse files
committed
Resource loader: Detect another nature of cyclic loads
1 parent d705613 commit 8c559fc

File tree

2 files changed

+15
-10
lines changed

2 files changed

+15
-10
lines changed

core/io/resource_loader.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -643,13 +643,12 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
643643
// the token anymore so it's released.
644644
load_task_ptr->load_token->reference();
645645

646+
load_task_ptr->thread_id = Thread::get_caller_id();
646647
if (p_thread_mode == LOAD_THREAD_FROM_CURRENT) {
647648
// The current thread may happen to be a thread from the pool.
648649
WorkerThreadPool::TaskID tid = WorkerThreadPool::get_singleton()->get_caller_task_id();
649650
if (tid != WorkerThreadPool::INVALID_TASK_ID) {
650651
load_task_ptr->task_id = tid;
651-
} else {
652-
load_task_ptr->thread_id = Thread::get_caller_id();
653652
}
654653
} else {
655654
load_task_ptr->task_id = WorkerThreadPool::get_singleton()->add_native_task(&ResourceLoader::_run_load_task, load_task_ptr);
@@ -803,12 +802,18 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
803802
ThreadLoadTask &load_task = thread_load_tasks[p_load_token.local_path];
804803

805804
if (load_task.status == THREAD_LOAD_IN_PROGRESS) {
806-
DEV_ASSERT((load_task.task_id == 0) != (load_task.thread_id == 0));
807-
808-
if ((load_task.task_id != 0 && load_task.task_id == WorkerThreadPool::get_singleton()->get_caller_task_id()) ||
809-
(load_task.thread_id != 0 && load_task.thread_id == Thread::get_caller_id())) {
810-
// Load is in progress, but it's precisely this thread the one in charge.
811-
// That means this is a cyclic load.
805+
if (load_task.thread_id == Thread::get_caller_id()) {
806+
// Load is in progress, but it's precisely this thread the one in charge,
807+
// which means this is a cyclic load.
808+
// There are two different cases of this:
809+
// 1. There is an actual cyclic dependency between resources, which is not allowed.
810+
// (In this case, the segment of stack frames belonging to this root load has
811+
// two tasks to load the same resource.)
812+
// 2. There's some resource format loader that exceptionally allows cyclic loads;
813+
// for instance, GDScript's preload.
814+
// (In a case like this, there is an ongoing load task for a given resource
815+
// in the stack, but not necessarily belonging to the same root load. We must
816+
// still detect it and the component supporting that should handle the situation.)
812817
if (r_error) {
813818
*r_error = ERR_BUSY;
814819
}

core/io/resource_loader.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ class ResourceLoader {
174174
static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(const String &path);
175175

176176
struct ThreadLoadTask {
177-
WorkerThreadPool::TaskID task_id = 0; // Used if run on a worker thread from the pool.
178-
Thread::ID thread_id = 0; // Used if running on an user thread (e.g., simple non-threaded load).
177+
Thread::ID thread_id = 0;
178+
WorkerThreadPool::TaskID task_id = 0; // Non-zero if run on a worker thread from the pool.
179179
bool awaited = false; // If it's in the pool, this helps not awaiting from more than one dependent thread.
180180
ConditionVariable *cond_var = nullptr; // In not in the worker pool or already awaiting, this is used as a secondary awaiting mechanism.
181181
uint32_t awaiters_count = 0;

0 commit comments

Comments
 (0)