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
These conflict with `ui_text_completion_replace` (accept autocompletion), but
the latter seems to take precedence if an autocomplete popup is open, so this
still works as expected.
Fixes#119085
This method is used to generate headers for embedding files into the binary
(think about the new `#embed` feature in C23 and C++26).
While the stringification step itself was plenty fast, it then proceeded
to wrap everything using the `textwrap` module. `textwrap` is *very*
slow, as it's apparently optimized for human text.
This patch reimplements the wrapping logic using a simple regex,
resulting in a tremendous speed improvement (~6x), and switches to `map`
for the stringification itself (thanks Rémi!)
It also removes a (practically) unused argument, `initial_indent`.
The generated files are pretty much the same, with a tiny difference in
line length (for some reason the old logic overshot the requested line
length)
When two threads unreference() a RefCounted Object at the same time there's
a potential race.
Thread A sees rc_val == 1, enters the if() block.
Thread B sees rc_val == 0, enters the if() block.
Thread A gets scheduled out, or is simply scheduled on a slower core and
Thread B finishes, returning die = true. Thread B then frees the Object.
Some time during or after ~Object() Thread A wakes up and tries to call
methods on the Object, which is either destroyed or in the process of being
destroyed, leading to a use-after-free.
We fix the problem by counting how many threads are currently inside
the critical section, and blocking returning die = true as long as there are
still other threads potentially alive.
Tested by running with --test and by opening and playing various public and
private Godot projects.
This fixes#115173
Adds implicit conversion from `RequiredResult<T_Other>` to `RequiredParam<T>` (where
`T_Other` derives from `T`). This allows passing a `RequiredResult` directly to a
`RequiredParam` without an intermediate variable.
Also changes `SceneTree::get_root()` to return `RequiredResult<Window>`. It is used in a
conversion as described above.
Why non-null: The root window is created in the `SceneTree` constructor and only set to
null in the destructor, so it is always valid during normal use. The function is no longer
`_FORCE_INLINE_` because `RequiredResult<Window>` requires Window to be a complete type.