Skip to content

Commit

Permalink
ResourceLoader: Properly push & pop TLS state on recursive load tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
RandomShaper committed Aug 21, 2024
1 parent 5ca419e commit bd0959e
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 0 deletions.
22 changes: 22 additions & 0 deletions core/io/resource_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,24 @@ void ResourceFormatLoader::_bind_methods() {

///////////////////////////////////

// These are used before and after a wait for a WorkerThreadPool task
// because that can lead to another load started in the same thread,
// something we must treat as a different stack for the purposes
// of tracking nesting.

#define PREPARE_FOR_WTP_WAIT \
int load_nesting_backup = ResourceLoader::load_nesting; \
Vector<String> load_paths_stack_backup = ResourceLoader::load_paths_stack; \
ResourceLoader::load_nesting = 0; \
ResourceLoader::load_paths_stack.clear();

#define RESTORE_AFTER_WTP_WAIT \
DEV_ASSERT(ResourceLoader::load_nesting == 0); \
DEV_ASSERT(ResourceLoader::load_paths_stack.is_empty()); \
ResourceLoader::load_nesting = load_nesting_backup; \
ResourceLoader::load_paths_stack = load_paths_stack_backup; \
load_paths_stack_backup.clear();

// This should be robust enough to be called redundantly without issues.
void ResourceLoader::LoadToken::clear() {
thread_load_mutex.lock();
Expand Down Expand Up @@ -234,7 +252,9 @@ void ResourceLoader::LoadToken::clear() {

// If task is unused, await it here, locally, now the token data is consistent.
if (task_to_await) {
PREPARE_FOR_WTP_WAIT
WorkerThreadPool::get_singleton()->wait_for_task_completion(task_to_await);
RESTORE_AFTER_WTP_WAIT
}
}

Expand Down Expand Up @@ -698,7 +718,9 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
// Loading thread is in the worker pool.
load_task.awaited = true;
thread_load_mutex.unlock();
PREPARE_FOR_WTP_WAIT
wtp_task_err = WorkerThreadPool::get_singleton()->wait_for_task_completion(load_task.task_id);
RESTORE_AFTER_WTP_WAIT
}

if (load_task.status == THREAD_LOAD_IN_PROGRESS) { // If early errored, awaiting would deadlock.
Expand Down
2 changes: 2 additions & 0 deletions core/io/resource_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ typedef Error (*ResourceLoaderImport)(const String &p_path);
typedef void (*ResourceLoadedCallback)(Ref<Resource> p_resource, const String &p_path);

class ResourceLoader {
friend class LoadToken;

enum {
MAX_LOADERS = 64
};
Expand Down

0 comments on commit bd0959e

Please sign in to comment.