瀏覽代碼

ResourceLoader: Add last resort life-time insurance for tokens

(cherry picked from commit ccd470d33c49e28d5be3ca258da4f2ce950949db)
Pedro J. Estébanez 1 年之前
父節點
當前提交
ea651a150b
共有 1 個文件被更改,包括 10 次插入0 次删除
  1. 10 0
      core/io/resource_loader.cpp

+ 10 - 0
core/io/resource_loader.cpp

@@ -317,6 +317,7 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
 }
 
 // This implementation must allow re-entrancy for a task that started awaiting in a deeper stack frame.
+// The load task token must be manually re-referenced before this is called, which includes threaded runs.
 void ResourceLoader::_run_load_task(void *p_userdata) {
 	ThreadLoadTask &load_task = *(ThreadLoadTask *)p_userdata;
 
@@ -447,6 +448,9 @@ void ResourceLoader::_run_load_task(void *p_userdata) {
 		}
 	}
 
+	// It's safe now to let the task go in case no one else was grabbing the token.
+	load_task.load_token->unreference();
+
 	if (unlock_pending) {
 		thread_load_mutex.unlock();
 	}
@@ -597,6 +601,11 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path,
 			}
 		}
 
+		// It's important to keep the token alive because until the load completes,
+		// which includes before the thread start, it may happen that no one is grabbing
+		// the token anymore so it's released.
+		load_task_ptr->load_token->reference();
+
 		if (p_thread_mode == LOAD_THREAD_FROM_CURRENT) {
 			// The current thread may happen to be a thread from the pool.
 			WorkerThreadPool::TaskID tid = WorkerThreadPool::get_singleton()->get_caller_task_id();
@@ -781,6 +790,7 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
 					// resource loading that means that the task to wait for can be restarted here to break the
 					// cycle, with as much recursion into this process as needed.
 					// When the stack is eventually unrolled, the original load will have been notified to go on.
+					load_task.load_token->reference();
 					_run_load_task(&load_task);
 				}