When the main thread is waiting on a worker thread pool via
WorkerThreadPool::wait_for_group_task_completion() the MessageQueue is no
longer being serviced.
But in ResourceLoader::_load_complete_inner we need to be able to push a
callable onto the MessageQueue and we wait until completion. Effectively
waiting on the main thread to run our code.
If the tasking waiting on completion is in the group the main thread is
waiting for then this can never happen.
We solve this problem by servicing the MessageQueue in the
WorkerThreadPool if main thread is waiting. To avoid busy waiting on the
semaphore we sleep for a very brief time to spare battery without impacting
latency too much in the waiting case.
Allowing this breaks several assumptions in the engine, normally this
doesn't occur but when using the WTP it can occur. For instance during
resource loading the message queue is serviced during tear down.
This means this situation can be created from user code if they do async
resource loading in the `_load` of a resource in the main scene.
This also makes the MainLoop report that it IS iterating during tests as
the tests expect the message queue to be serviced even though no main
loop is running.
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.