public final class Safepoint extends Object
When a safepoint is requested, one thread (the master) will acquire a mutex for the duration of
this safepoint operation. The master will set the thread-local variable
Safepoint.safepointRequested of each other thread (the slaves) accordingly.
The slaves occasionally check their thread-local Safepoint.safepointRequested values, and if a
safepoint is pending, they call Safepoint.slowPathSafepointCheck(boolean) to block on the mutex
that the master is holding. Blocking on the mutex (or other native calls) will transition the
slaves to being in native code, via CFunctionSnippets.prologueSnippet().
The master loops waiting for each slave to be in native code. At that point the master will atomically change the thread status of the slave to being at a safepoint. Once a thread is at a safepoint, CFunctionSnippets.epilogueSnippet() will prevent it from returning to Java code.
When all slaves are at the safepoint, the master can execute any VMOperations that have accumulated. When the VMOperation queues are empty, the master will change the status of each slave back to being in native code. Once a slave is back in native code, it might return to Java code, though any slaves that noticed the safepoint request will be blocked on the mutex. Then the master drops the mutex, and the slaves that were blocked on the mutex are free continue their execution.
CFunctionSnippets.epilogueSnippet() tries to do an atomic compare-and-set of the thread status from being in native code to being in Java code. In the usual case (the fast path) that will succeed and the thread will be back running Java code. If, however, the thread was already in native code when the safepoint was requested, it will have missed the request and will not be blocked on the mutex. In that case the atomic compare-and-set fails because the thread state is at a safepoint. The failure will send the thread to the slow path which will block on the mutex.
VMThreads.THREAD_MUTEX is used as the mutex on which slaves block to freeze and is a
natural choice because the master also has to hold that mutex to walk the thread list. Because
the mutex is held from the time the safepoint is initiated until it is complete, new threads can
not be created (or attached) during the safepoint.
ThreadingSupportFeature implements an optional per-thread timer on top of the safepoint
mechanism. For that purpose, a safepoint check is actually implemented as a decrement of
Safepoint.safepointRequested with a zero check that triggers a call to
Safepoint.slowPathSafepointCheck(boolean). If a timer is registered and the slow path determines that that
timer has expired, a timer callback is executed and Safepoint.safepointRequested is reset with a
value that estimates the number of safepoint checks during the intended timer interval. When an
actual safepoint is requested, the master overwrites each slave's Safepoint.safepointRequested
with Safepoint.SafepointRequestValues.ENTER so it becomes 0 on the next decrement. When no timer is
active on a thread, its Safepoint.safepointRequested value is reset to
Safepoint.SafepointRequestValues.RESET. Because Safepoint.safepointRequested still eventually
decrements to 0, threads can very infrequently call Safepoint.slowPathSafepointCheck(boolean) without
cause.
SafepointCheckNode| Modifier and Type | Class and Description |
|---|---|
static class |
Safepoint.Master
Methods for the thread that brings the system to a safepoint.
|
static class |
Safepoint.Options |
static class |
Safepoint.PromptnessException |
static interface |
Safepoint.SafepointRequestValues
Specific values for
Safepoint.safepointRequested. |
static class |
Safepoint.Statistics
Statistics about the progress of a particular safepoint.
|
| Modifier and Type | Field and Description |
|---|---|
static SnippetRuntime.SubstrateForeignCallDescriptor[] |
FOREIGN_CALLS
All foreign calls defined in this class.
|
| Modifier and Type | Method and Description |
|---|---|
static void |
checkSafepointRequested()
Check if a safepoint has been requested, and block if it is requested.
|
protected static VMMutex |
getMutex() |
protected static int |
getSafepointRequested(org.graalvm.nativeimage.IsolateThread vmThread) |
static org.graalvm.word.LocationIdentity |
getThreadLocalSafepointRequestedLocationIdentity()
Returns the memory location identity accessed by
Safepoint.checkSafepointRequested(). |
static long |
getThreadLocalSafepointRequestedOffset() |
static void |
setSafepointRequested(int value) |
static void |
setSafepointRequested(org.graalvm.nativeimage.IsolateThread vmThread,
int value) |
static void |
setSafepointRequestedValueBeforeSafepoint(org.graalvm.nativeimage.IsolateThread vmThread,
int value) |
static void |
transitionNativeToJava()
Transition from native to Java.
|
public static final SnippetRuntime.SubstrateForeignCallDescriptor[] FOREIGN_CALLS
protected static VMMutex getMutex()
public static void setSafepointRequested(org.graalvm.nativeimage.IsolateThread vmThread,
int value)
protected static int getSafepointRequested(org.graalvm.nativeimage.IsolateThread vmThread)
public static void setSafepointRequested(int value)
public static void setSafepointRequestedValueBeforeSafepoint(org.graalvm.nativeimage.IsolateThread vmThread,
int value)
public static org.graalvm.word.LocationIdentity getThreadLocalSafepointRequestedLocationIdentity()
Safepoint.checkSafepointRequested().public static long getThreadLocalSafepointRequestedOffset()
public static void checkSafepointRequested()
public static void transitionNativeToJava()