This fixes several issues:
* There was a bug in the cycle detection. It was possible for the cycle
detection to fail because the current thread isn't in the list. Fix
this by just seeing if any of the next threads were already in the
cycle.
* By way of an optimization the thread_waiting_on bookkeeping was done
under the same thread_load_mutex as the cycle detection. But there is
also an early exit after yields. If we exit through the yield the
thread_waiting_on entry is stale and can cause other threads to fail
to do cycle detection.
* When multiple threads end up finishing a resource simultaneously
anyway, probably through cycle detection, there's a small chance that
the original thread finished more-or-less at the same time if the
original thing blocking load completed. We solve this now by letting
only one of the threads do the initial registration.
This fixes several issues in ResourceLoader
* When waiting on resources being loaded on the main thread it is
possible that the resource was waiting on the message queue. Flush
the message queue in this situation. This was an existing bug.
* When re-starting a load for deadlock-prevention reasons, and this
type of resource has nested resources and uses resource changed
connections we end up with references to resourcese being deleted
as duplicates in the dependent task. We now keep a reference to these
resources for the duration of the dependent load task. This closes
the race but does not entirely eliminate it during intial import.
This is an existing bug seemingly specific to TileSetSource but there
might be others.
* When threads are waiting during teardown we ended up deadlocking
because the waiting thread would never end up completing. This is a
bug introduced by f63ab5f
* When a thread loading a resource ends up calling back into the
WorkerThreadPool to wait cooperatively it expects that other threads
complete, or new requests are made, so that work moves forward. If
all OTHER threads end up blocked by the WorkerThreadPool waiting
thread then no forward progress can be made anymore. We now solve
this problem by yielding whenever we are blocked by another task. We
wake up each every task whenever any progress is made to see if
further progress can be made. This is a bug introduced by f63ab5f
* When dependencies get introduced while loading it is possible to form
a dependency cycle. Normally this isn't a problem but when all
threads are already waiting when the cycle is introduced no forward
progress can be made anymore. We now break such cycles. This is a bug
introduced by f63ab5f
When multiple threads try to load the same sub-resource the
ResourceLoader's anti-deadlock protection thinks that the other threads
loading the dependency are old threads blocked on a dependency.
The current thread will then immediately start to load the sub-resource
since they can't wait for it. This can then lead to multiple threads
loading the same resource concurrently.
We fix the problem by recording in the task when loading has ACTUALLY
started, and if so we simply wait.
This is no worse than before, at the point where we are waiting now we
previously re-started the load entirely.
Tested by running the MRP from the below issue (with and without asan
and msan), and loading and running various public and private Godot
projects.
This also fixes a use-after-free on resource_changed_connections when
multiple threads end up running the same import. This is a pre-existing
bug but this code widened the race window.
This also fixes a pre-existing memory leak in load_threaded_request,
when the user calls the function we capture the Ref<LoadToken> but
immediately drop the ref. Causing the refcount to go to 1. Later in
_run_load_task we unreference manually, bringing the refcount to 0. This
then later prevents the Ref<> from memdeleting the LoadToken.
This fixes#118085
This allows removing it from `class_db.h`, significantly reducing the amount of files
that include it transitively.
Also includes some include cleanup in `control.h` and `rich_text_label.h` done while
ensure they don't depend on `callable_mp`.
- Remove part of the "Failed loading resource" message about opening
the project in the editor, as it's sometimes misleading.
- Fix `(expected type: )` appearing at the end of the
"No loader found for resource:" error message.