[threads] Switch foreign threads to GC Safe in mono_thread_detach (#20435)
commit4dd414b6ca6c772f438fe92b7fa44cd37b6b5047
authorAleksey Kliger (λgeek) <alklig@microsoft.com>
Thu, 8 Oct 2020 14:31:30 +0000 (8 10:31 -0400)
committerGitHub <noreply@github.com>
Thu, 8 Oct 2020 14:31:30 +0000 (8 10:31 -0400)
tree2aed5667f25121d3d29b7ae7030231fd113bbd93
parent22e81d941c00d0106e358bcccae89cb634985174
[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:
mono/metadata/appdomain.c
mono/metadata/cominterop.c
mono/metadata/threads-types.h
mono/metadata/threads.c
mono/metadata/threads.h
mono/mini/interp/interp.c
mono/mini/mini-runtime.c
mono/profiler/aot.c
mono/profiler/log.c
mono/tests/.gitignore
mono/tests/Makefile.am
mono/tests/libtest.c
mono/tests/pinvoke-detach-1.cs [new file with mode: 0644]