[runtime]Provide a consistent view of registered threads during suspend operations.

We previously failed to provide a consistent view of the registered threads set. This
would should up in the following ways:

-New threads would join in between two FOREACH_THREAD passes. The recently joined threads
lead to broken invariants that one loop carried to the other.

-Existing threads would leave during a FOREACH_THREAD. The now defunct threads lead
to code waiting them to ack back and deadlock in the process.

-It was possible to witness an in-progress cleanup. This would show up by
mono_thread_info_current returning null when it should not.

To amend this we provide a a consistent view of all registered threads once the global
suspend lock is acquired. This is done by acquiring that lock when registering/unregistering.

This allows us to remove some of the work-around in the sgen thread registration
code and avoid taking the GC lock.
[sgen]We no longer need joined_stw as new threads can't join once the suspend lock has been acquired.

Since no new thread can join until the collection is over, FOREACH_THREAD won't miss any thread.
[sgen] Force inlining of some perf-critical functions.
[runtime]Add more fast variants of the mono_array functions as those shown up in profiling.
[runtime] Small optimizations and cleanup in ves_icall_System_Array_FastCopy.
[io-layer] Fix a warning.
[sgen]Remove doing_handshake field since the race condition it fixes is now handled by mono-threads.
[runtime]Properly set mono-thread state as when starting/running/shutting down/dead.
[sgen] Kill SgenThreadInfo::thread_is_dying in favor of the thread-info state information.
Add a sgen test for threads joining/leaving at random places.