[threads] Switch foreign threads to GC Safe in mono_thread_detach (#20435)
* [test] Invoke from foreign threads then try to GC and shutdown
Even if the non-Mono threads that once called Mono are looping or deadlocked,
they shouldn't prevent us from doing a GC (in hybrid suspend mode) or from
shutting down if they detached from the runtime.
* [tests] update .gitignore
Ignore AOT build artifacts in subdirectories of mono/tests/, too
* [threads] Make mono_thread_attach external only
Runtime should use mono_thread_internal_attach
* [threads] Mark mono_thread_detach external only; switch to GC Safe
Runtime threads should call mono_thread_internal_detach
Addresses https://github.com/mono/mono/issues/20290 and https://github.com/mono/mono/issues/20283
If a foreign thread (that was created outside the runtime) calls
mono_thread_detach, leave it in a preemptively-suspendable state, since we
can't expect it to coop suspend.
Conversely in mono_thread_attach (external only), ensure that we always leave
the thread in GC Unsafe (aka RUNNING) state, for cases like
while (cond) {
t = mono_thread_attach (domain);
<...>
mono_thread_detach (t);
}
* Tests fixup
Delete test that invokes the runtime in a loop forever.
This is just exercising a race between mono_thread_attach and the
runtime shutdown. Instead update the invoke_foreign_thread test to
loop a few times to check that attach/detach loops are ok.
In the deadlock test, wait for the foreign thread to finish calling
the runtime before the test thread returns from native back to managed
to avoid a race between shutdown and the invoke.
* [interp] Set context to null when freeing
If a foreign thread runs this loop
for (...) {
mono_thread_attach;
mono_runtime_invoke;
mono_thread_detach;
}
on the second iteration it will get a ThreadContext that was already freed
during the detach. Set the TLS variable to null before freeing the context.
* [threads] Switch to GC Unsafe before creating managed thread object
For a re-attaching move the thread state transition to happen earlier so that
create_internal_thread_object (which does a managed allocation) is always done
in GC Unsafe mode.
13 files changed: