@@ -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 != curr_load_task && load_task.thread_id == Thread::get_caller_id ()) {
806+ // Load is in progress, but it's precisely this thread the one in charge,
807+ // and it's not the topmost task in the stack, 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 }
0 commit comments