Class TruffleSafepoint

java.lang.Object
com.oracle.truffle.api.TruffleSafepoint

public abstract class TruffleSafepoint extends Object
Truffle safepoints allow interrupting the guest language execution to execute thread-local actions submitted by a language or tool. A safepoint is a location during the guest language execution where the state is consistent, and other operations can read its state.

Supporting Safepoints in a Language

Safepoints are explicitly polled by invoking the poll(Node) method. Safepoints are polled with relaxed location or with exact location. A poll with a relaxed location is significantly more efficient than a poll with a precise location as the compiler is able to move and combine the poll requests during compilation. A Truffle guest language implementation must ensure that a safepoint is polled repeatedly within a constant time interval. For example, a single arithmetic expression completes within a constant number of CPU cycles. However, a loop that summarizes values over an array uses a non-constant time dependent on the array size. This typically means that safepoints are best polled at the end of loops and at the end of function or method calls to cover recursion. In addition, any guest language code that blocks the execution, like guest language locks, need to use the blocking API to allow polling of safepoints while the thread is waiting.

Truffle's loop node and root node support safepoint polling automatically. No further calls to poll(Node) are therefore necessary. Custom loops or loops behind boundary annotated method calls are expected to be notified by the guest language implementation manually.

Thread local actions optionally incur side-effects. By default side-effects are enabled. A language implementation may disable side-effects temporarily for the current thread using setAllowSideEffects(boolean) method.

Submitting thread local actions

See ThreadLocalAction for details on how to submit actions.

Further information can be found in the safepoint tutorial.

Since:
21.1
See Also:
  • Constructor Details

    • TruffleSafepoint

      protected TruffleSafepoint(com.oracle.truffle.api.impl.Accessor.EngineSupport support)
      Do not extend this class. This class is intended to be implemented by a Truffle runtime implementation.
      Since:
      21.1
  • Method Details

    • poll

      public static void poll(Node location)
      Polls a safepoint at the provided location. This allows to run thread local actions at this location. A Truffle guest language implementation must ensure that a safepoint is polled repeatedly within a constant time interval. See TruffleSafepoint for further details.

      In compiled code calls to this method are removed. Instead the compiler inserts safepoints automatically at loop ends and method exits. In this case the node location is approximated by frame state of method ends and loop exits in the compiler IR. For method ends the parent root node and for loop exits the loop node is passed as location.

      Guest language exceptions may be thrown by this method. If side-effects are allowed then also guest language exceptions may be thrown. Otherwise only internal or thread-death exceptions may be thrown. This method is safe to be used on compiled code paths.

      Example usage with an unbounded loop sum behind a CompilerDirectives.TruffleBoundary.

       @TruffleBoundary
       int sum(int[] array) {
           int sum = 0;
           for (int i = 0; i < array.length; i++) {
               sum += array[i];
      
               TruffleSafepoint.poll();
           }
           return sum;
       }
       
      Parameters:
      location - the location of the poll. Must not be null.
      Since:
      21.1
      See Also:
    • pollHere

      public static void pollHere(Node location)
      Similar to poll(Node) but with exact location. A poll with relaxed location is significantly more efficient than a poll with precise location as the compiler is able to move and combine the poll requests during compilation. This method is safe to be used on compiled code paths.

      Usage example:

       TruffleSafepoint safepoint = TruffleSafepoint.getCurrent();
       boolean prev = safepoint.setAllowSideEffects(false);
       try {
           // criticial section
       } finally {
           safepoint.setAllowSideEffects(prev);
           TruffleSafepoint.pollHere(this);
       }
       
      Parameters:
      location - the location of the poll. Must not be null.
      Since:
      21.1
      See Also:
    • setBlockedWithException

      @Deprecated public <T> void setBlockedWithException(Node location, TruffleSafepoint.Interrupter interrupter, TruffleSafepoint.Interruptible<T> interruptible, T object, Runnable beforeInterrupt, Consumer<Throwable> afterInterrupt)
      Transitions the current thread into a blocked state and calls an interruptible functional method. The blocked state is restored when the interruptible method returns. Setting the blocked state allows safepoint notification while the current thread is blocked. This allows Truffle to interrupt e.g. locks temporarily to perform a thread local action.

      The location> parameter is used poll all pending thread local actions before transition to blocked state.

      The interrupter parameter specifies how the blocked state can be interrupted from another thread. The interrupter allows to interrupt the blocked state from other threads. For most blocking java.util.concurrent primitives the thread interrupter can be used. If the thread will be blocked in native code, other ways of interrupting, like signals may be used by implementing the TruffleSafepoint.Interrupter interface.

      The interruptible parameter provides the method that calls the blocking method which throws InterruptedException on interrupt. In order to avoid allocations of the functional interface a single argument can be provided that is passed to the interface. This is typically the lock or semaphore instance. The implementation of this method is expected to throw an InterruptedException if the TruffleSafepoint.Interrupter.interrupt(Thread) method is invoked for this thread. For most java.util.concurrent primitives this is supported by using the interruptible blocking method variant, for example Lock.lockInterruptibly().

      Since it is common to use this method with method reference syntax e.g. Lock::lockInterruptibly for the interruptible parameter, we implicitlely apply a boundary for the entire method call by default. If the interruptible is called from a compiled code path and the interruptible should get partial evaluated, then TruffleSafepoint.CompiledInterruptible should be used instead of TruffleSafepoint.Interruptible. In this case the parameter must be a partial evaluation constant.

      The beforeInterrupt runnable and afterInterrupt consumer optional parameters allow to run code before and after a thread got interrupted and safepoint events are processed. If null is provided then no action will be performed. Arbitrary code may be executed in this runnable. Note that the blocked state is temporarily reset to its previous state while the afterInterrupt is called.

      If an exception is thrown during the processing of the safepoint, afterInterrupt will receive the throwable as argument, or null if the safepoint successfully completed. This exception will still be thrown after completion of afterInterrupt, unless afterInterrupt throws an exception of its own.

      Multiple recursive invocations of this method is supported. The previous blocked state will be restored when the method completes or fails.

      Example usage:

      Note there is a short-cut method to achieve the same behavior as in this example setBlockedThreadInterruptible(Node, Interruptible, Object).

       Lock lock = new ReentrantLock();
       TruffleSafepoint sp = TruffleSafepoint.getCurrent();
       sp.setBlocked(location, Interrupter.THREAD_INTERRUPT, ReentrantLock::lockInterruptibly, lock, null, null);
       
      Since:
      22.1
      See Also:
    • setBlockedFunction

      public abstract <T, R> R setBlockedFunction(Node location, TruffleSafepoint.Interrupter interrupter, TruffleSafepoint.InterruptibleFunction<T,R> interruptible, T object, Runnable beforeInterrupt, Consumer<Throwable> afterInterrupt)
      Transitions the current thread into a blocked state and calls an interruptible functional method. The blocked state is restored when the interruptible method returns. Setting the blocked state allows safepoint notification while the current thread is blocked. This allows Truffle to interrupt e.g. locks temporarily to perform a thread local action.

      The location> parameter is used poll all pending thread local actions before transition to blocked state.

      The interrupter parameter specifies how the blocked state can be interrupted from another thread. The interrupter allows to interrupt the blocked state from other threads. For most blocking java.util.concurrent primitives the thread interrupter can be used. If the thread will be blocked in native code, other ways of interrupting, like signals may be used by implementing the TruffleSafepoint.Interrupter interface.

      The interruptible parameter provides the method that calls the blocking method which throws InterruptedException on interrupt. In order to avoid allocations of the functional interface a single argument can be provided that is passed to the interface. This is typically the lock or semaphore instance. The implementation of this method is expected to throw an InterruptedException if the TruffleSafepoint.Interrupter.interrupt(Thread) method is invoked for this thread. For most java.util.concurrent primitives this is supported by using the interruptible blocking method variant, for example Lock.lockInterruptibly().

      boundary is applied for the entire interruptible method call by default. If the interruptible is called from a compiled code path and the interruptible should get partial evaluated, then TruffleSafepoint.CompiledInterruptibleFunction should be used instead of TruffleSafepoint.InterruptibleFunction. In this case the parameter must be a partial evaluation constant.

      The beforeInterrupt runnable and afterInterrupt consumer optional parameters allow to run code before and after a thread got interrupted and safepoint events are processed. If null is provided then no action will be performed. Arbitrary code may be executed in this runnable. Note that the blocked state is temporarily reset to its previous state while the afterInterrupt is called.

      If an exception is thrown during the processing of the safepoint, afterInterrupt will receive the throwable as argument, or null if the safepoint successfully completed. This exception will still be thrown after completion of afterInterrupt, unless afterInterrupt throws an exception of its own.

      Multiple recursive invocations of this method is supported. The previous blocked state will be restored when the method completes or fails.

      Example usage:

      Note there is a short-cut method to achieve the same behavior as in this example setBlockedThreadInterruptibleFunction(Node, InterruptibleFunction, Object).

       Queue<Object> queue = new ArrayBlockingQueue<>(10);
       TruffleSafepoint sp = TruffleSafepoint.getCurrent();
       sp.setBlockedFunction(location, Interrupter.THREAD_INTERRUPT, BlockingQueue::take, queue, null, null);
       
      Since:
      23.1
      See Also:
    • setBlocked

      public abstract <T> void setBlocked(Node location, TruffleSafepoint.Interrupter interrupter, TruffleSafepoint.Interruptible<T> interruptible, T object, Runnable beforeInterrupt, Consumer<Throwable> afterInterrupt)
      The same as setBlockedFunction(Node, Interrupter, InterruptibleFunction, Object, Runnable, Consumer). The only difference is that the interruptible functional method does not return anything.
      Since:
      23.1
    • setBlockedThreadInterruptible

      public static <T> void setBlockedThreadInterruptible(Node location, TruffleSafepoint.Interruptible<T> interruptible, T object)
      Short-cut method to allow setting the blocked status for methods that throw InterruptedException and support interrupting using Thread.interrupt().
      Parameters:
      location - the location with which the safepoint should be polled.
      interruptible - the thread interruptable method to use for locking the object
      object - the instance to use the interruptable method with.
      Since:
      21.1
    • setBlockedThreadInterruptibleFunction

      public static <T, R> R setBlockedThreadInterruptibleFunction(Node location, TruffleSafepoint.InterruptibleFunction<T,R> interruptible, T object)
      Short-cut method to allow setting the blocked status for methods that throw InterruptedException and support interrupting using Thread.interrupt().
      Parameters:
      location - the location with which the safepoint should be polled.
      interruptible - the thread interruptable method to use for locking the object
      object - the instance to use the interruptable method with.
      Since:
      23.1
    • setAllowActions

      public abstract boolean setAllowActions(boolean enabled) throws IllegalStateException
      Allows to temporarily delay all thread local actions on the current thread. It is recommended to delay actions only for a constant period of time and while trusted and internal guest code is running. Please consider using setAllowSideEffects(boolean) before using this method. While actions are disabled the value of setAllowSideEffects(boolean) has no effect. When actions are enabled again the value of setAllowSideEffects(boolean) will be interpreted again.

      Currently this method may only be used during context finalization. This could be necessary to free up native resources through guest code when a context is cancelled to avoid resource leakage. Any usage of this method should be subject to a detailed security review to ensure only internal and well-known guest code is executed. Disabling thread local actions may delay thread local actions like exit, cancellation and interruption.

      Example usage:

       TruffleSafepoint sp = TruffleSafepoint.getCurrent();
       boolean prev = sp.setAllowActions(false);
       try {
           // critical section
       } finally {
           sp.setAllowActions(prev);
       }
       
      Throws:
      IllegalStateException - if allow actions can currently not be set, for example outside the scope of a context finalization.
      Since:
      22.1
      See Also:
    • setAllowSideEffects

      public abstract boolean setAllowSideEffects(boolean enabled)
      Allows to temporarily delay side-effecting thread local actions on the current thread. It is recommended to delay side-effecting actions only for a short and constant period of time.

      While side-effecting thread local actions are delayed on this thread, only non-side-effecting thread local actions will be scheduled in this thread. Non-side-effecting thread local actions do not mutate guest objects, run guest code or throw guest exceptions, but they might still throw internal errors.

      Example usage:

       TruffleSafepoint sp = TruffleSafepoint.getCurrent();
       boolean prev = sp.setAllowSideEffects(false);
       try {
           // critical section
       } finally {
           sp.setAllowSideEffects(prev);
       }
       
      Since:
      21.1
    • hasPendingSideEffectingActions

      public abstract boolean hasPendingSideEffectingActions()
      Returns whether there is any pending side-effecting thread local action on this thread, due to being in a critical section using setAllowSideEffects(boolean). When side-effecting actions are allowed, this method always returns false.

      This is useful if the language exposes a way to know if there are any pending side-effecting thread local action due to using setAllowSideEffects(boolean).

      Since:
      21.1
    • getCurrent

      public static TruffleSafepoint getCurrent()
      Returns the current safepoint configuration for the current thread. This method is useful to access configuration methods like setBlocked(Node, Interrupter, Interruptible, Object, Runnable, Consumer) or setAllowSideEffects(boolean).

      Important: The result of this method must not be stored or used on a different thread than the current thread.

      Since:
      21.1