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(int, 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 to 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.
A safepoint check is implemented as a check of Safepoint.safepointRequested
<= 0, which, if true,
triggers a call to Safepoint.slowPathSafepointCheck(int, boolean)
. ThreadingSupportFeature
implements an
optional per-thread timer on top of the safepoint mechanism. If that timer feature is
supported in the image, each
safepoint check decrements Safepoint.safepointRequested
before the comparison, which will cause it
to periodically enter the slow path. If a timer is registered and the slow path determines that
that timer has expired, the 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 does an arithmetic negation of each slave's
Safepoint.safepointRequested
value to make it enter the slow path on the next safepoint check.
When no timer is active on a thread, its Safepoint.safepointRequested
value is reset to
Safepoint.THREAD_REQUEST_RESET
. Because Safepoint.safepointRequested
still eventually
decrements to 0, threads can very infrequently call Safepoint.slowPathSafepointCheck(int, 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.Statistics
Statistics about the progress of a particular safepoint.
|
Modifier and Type | Field and Description |
---|---|
static SnippetRuntime.SubstrateForeignCallDescriptor |
ENTER_SLOW_PATH_SAFEPOINT_CHECK |
static SnippetRuntime.SubstrateForeignCallDescriptor[] |
FOREIGN_CALLS
All foreign calls defined in this class.
|
Modifier and Type | Method and Description |
---|---|
static org.graalvm.word.LocationIdentity |
getThreadLocalSafepointRequestedLocationIdentity()
Returns the memory location identity for
Safepoint.safepointRequested . |
static long |
getThreadLocalSafepointRequestedOffset() |
static void |
slowTransitionNativeToVM() |
static void |
transitionJavaToVM()
Transition from Java to VM state.
|
static void |
transitionNativeToJava()
Transition from native to Java.
|
static void |
transitionVMToJava()
Transition from VM state to Java.
|
static void |
transitionVMToNative() |
static boolean |
tryFastTransitionNativeToVM() |
public static final SnippetRuntime.SubstrateForeignCallDescriptor ENTER_SLOW_PATH_SAFEPOINT_CHECK
public static final SnippetRuntime.SubstrateForeignCallDescriptor[] FOREIGN_CALLS
public static org.graalvm.word.LocationIdentity getThreadLocalSafepointRequestedLocationIdentity()
Safepoint.safepointRequested
.public static long getThreadLocalSafepointRequestedOffset()
public static void transitionNativeToJava()
public static boolean tryFastTransitionNativeToVM()
public static void slowTransitionNativeToVM()
public static void transitionVMToJava()
public static void transitionJavaToVM()
public static void transitionVMToNative()