… loading happen outside of scanning. This changes all bridges to use the _safe variant of sgen_obj_get_descriptor. Bridge processing happens in the post-scan world, before objects get untagged.
…ied STW is disabled for sgen."
…iminate known races in the process. The new suspend machinery is based around a single word state machine that is manipulated using CAS. This solves the first set of problems with the current approach, the lack of atomicity and the impossibility of doing race free manipulation of protected state. This is specially acute when doing a self suspend. Suspend data must be atomically protected while we prepare to self suspend so a resume request won't race with the current thread putting itself to sleep. This is a classical problem that calls for a mutex/conditional variable pair. Except that all locks in the suspend path must be suspend safe. Wait, WHAT? A Suspend Safe Lock is a primitive that is obstruction free in the face of the kernel suspending a thread either performing a lock operation or waiting on a lock to become available. This, unfortunately, is not possible with pthread_mutex on OSX. The only safe primitive are kernel semaphores, for which doesn't exist conditional variables for. So back to locking and self-suspend. We need a lock because the existing thread state is not atomic but we can't use a mutex/condvar pair so we're left with racy code. Yay! The fix is using CAS over a single variable. Another change was the hardening of the suspend/resume code on posix targets. First we replace a semaphore wait with sigsuspend for async suspend. This is needed since sem_wait is not async-signal safe (yet sem_post is). Second, we now respect interruption requests by having a pair of suspend signals, one with SA_RESTART and one without. Onto the design of the suspension system, a few concepts that are useful looking around. * Self suspend: This is when the thread decides to suspend itself. * Async suspend: This is when a thread decides to suspend another thread. * Suspend Initiator: This the name of a thread that decided to suspend one or more other threads. This is important since all suspending threads will notify it when they are suspended. There can be only one initiator in the system at a given time. * Suspension count: Number of resume calls before a thread is back to running state. There are 7 states that can happen while a thread is runnable: * Running: just running... * (Async|Self) Suspended: Suspended, the difference comes into play when resuming. * (Async|Self) Suspend Requested: Suspend requested, but not completed. See more below for the discussion on why the request state is needed. * Suspend In Progress: Self suspend started saving its state thus async suspend should not modify it. * Suspend Promoted to Async: Async tried to suspend a thread in the middle of a self suspend, it wants to be notified. Now to the suspension protocol and how it happens on a high level view. Suspension starts with a suspend request, which bumps the suspend count by one. This suspend request can be fulfilled either by an async or self suspend action. This is confusing as there's only one initiator but any number of threads can be self suspending. Async suspend then performs a platform specific action such as posix signals that forces a transition on the target. In the case of self suspend, it depends on the thread polling its state and trigger the transition. This works fine except that the suspend state is one huge struct with tons of fields. To control concurrent access to it we use a single initiator in the case of async suspend and we put the thread in a transitional "saving my state" in the case of self suspend. In the case of async suspend, the initiator must wait for all 1+ threads to notify back that they have suspended. Only after that it's possible to know if the async suspend request actually worked or not (we might have hit a dying thread). Together with this, there's an optional implementation of STW in sgen that can use this new machinery. To enable it set the MONO_ENABLE_UNIFIED_SUSPEND env var for now while it gets more testing.
…e GC too. MonoThreads was previously ignoring sgen's in_critical_region, which could lead to a thread suspended inside a gc critical region leading to the GC not been able to STW.
…ate testing to inside MonoThread.
…the null literal.
…emoves the duplicate on io-layer and exports the eglib one.