Skip to content

Commit e1721dc

Browse files
Only enable recurring callback support on demand.
1 parent 0a37b5f commit e1721dc

File tree

6 files changed

+44
-10
lines changed

6 files changed

+44
-10
lines changed

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/Threading.java

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -55,13 +55,22 @@ private Threading() {
5555
}
5656

5757
/**
58+
* This method is intended for expert users.
59+
* <p>
5860
* Registers a {@link RecurringCallback callback handler} that is called by the current thread
59-
* approximately at the provided interval. Only one callback can be active per thread. Each
60-
* thread can have its own callback with a different interval (or none at all). No guarantees
61-
* are made about the actual interval. For example, when the thread is waiting for a lock or
62-
* executing native code, no callback can be done. Exceptions that are thrown during the
63-
* execution of the callback are caught and ignored, unless they are thrown via a call to
64-
* {@link RecurringCallbackAccess#throwException(Throwable)}.
61+
* approximately at the provided interval. This functionality is only supported if the native
62+
* binary is built with {@code -H:+SupportRecurringCallback}. Note that only carefully crafted,
63+
* uninterruptible code can be executed safely in a recurring callback. Executing any other code
64+
* can result in deadlocks or crashes.
65+
* <p>
66+
* Only one callback can be active per thread. Each thread can have its own callback with a
67+
* different interval (or none at all). No guarantees are made about the actual interval. For
68+
* example, when the thread is waiting for a lock or executing native code, no callback can be
69+
* done.
70+
* <p>
71+
* Exceptions that are thrown during the execution of the callback and that are not caught in
72+
* the callback are ignored. {@link RecurringCallbackAccess#throwException} can be used to
73+
* explicitly throw an exception that is not ignored.
6574
* <p>
6675
* Specifying {@code null} for {@code callback} clears the current thread's callback (in which
6776
* case, the values of {@code interval} and {@code unit} are ignored).

substratevm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This changelog summarizes major changes to GraalVM Native Image.
1414
* (GR-58659) (GR-58660) Support for FFM API ("Panama") has been added for darwin-aarch64 and linux-aarch64.
1515
* (GR-49525) Introduced `--future-defaults=[all|<options>|none]` that enables options that are planned to become defaults in future releases. The enabled options are:
1616
1. `run-time-initialized-jdk` shifts away from build-time initialization of the JDK, instead initializing most of it at run time. This transition is gradual, with individual components of the JDK becoming run-time initialized in each release. This process should complete with JDK 29 when this option should not be needed anymore. Unless you store classes from the JDK in the image heap, this option should not affect you. In case this option breaks your build, follow the suggestions in the error messages.
17+
* (GR-63494) Recurring callback support is no longer enabled by default. If this feature is needed, please specify `-H:+SupportRecurringCallback` at image build-time.
1718

1819
## GraalVM for JDK 24 (Internal Version 24.2.0)
1920
* (GR-59717) Added `DuringSetupAccess.registerObjectReachabilityHandler` to allow registering a callback that is executed when an object of a specified type is marked as reachable during heap scanning.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/BuildPhaseProvider.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
public final class BuildPhaseProvider {
3535

3636
private boolean featureRegistrationFinished;
37+
private boolean setupFinished;
3738
private boolean analysisFinished;
3839
private boolean hostedUniverseBuilt;
3940
private boolean readyForCompilation;
@@ -60,6 +61,14 @@ public static boolean isFeatureRegistrationFinished() {
6061
return ImageSingletons.contains(BuildPhaseProvider.class) && singleton().featureRegistrationFinished;
6162
}
6263

64+
public static void markSetupFinished() {
65+
singleton().setupFinished = true;
66+
}
67+
68+
public static boolean isSetupFinished() {
69+
return ImageSingletons.contains(BuildPhaseProvider.class) && singleton().setupFinished;
70+
}
71+
6372
public static void markAnalysisFinished() {
6473
singleton().analysisFinished = true;
6574
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/sampler/JfrRecurringCallbackExecutionSampler.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,24 @@
5454
import com.oracle.svm.core.thread.VMThreads;
5555
import com.oracle.svm.core.util.TimeUtils;
5656

57+
import jdk.graal.compiler.api.replacements.Fold;
58+
5759
public final class JfrRecurringCallbackExecutionSampler extends AbstractJfrExecutionSampler {
5860
private static final ExecutionSampleCallback CALLBACK = new ExecutionSampleCallback();
5961

6062
@Platforms(Platform.HOSTED_ONLY.class)
6163
JfrRecurringCallbackExecutionSampler() {
6264
}
6365

66+
@Fold
67+
public static boolean isPresent() {
68+
if (ImageSingletons.contains(JfrExecutionSampler.class)) {
69+
JfrExecutionSampler sampler = ImageSingletons.lookup(JfrExecutionSampler.class);
70+
return sampler instanceof JfrRecurringCallbackExecutionSampler;
71+
}
72+
return false;
73+
}
74+
6475
@Override
6576
protected void startSampling() {
6677
assert VMOperation.isInProgressAtSafepoint();

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/RecurringCallbackSupport.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@
3434
import org.graalvm.nativeimage.Threading.RecurringCallback;
3535
import org.graalvm.nativeimage.Threading.RecurringCallbackAccess;
3636

37+
import com.oracle.svm.core.BuildPhaseProvider;
3738
import com.oracle.svm.core.Uninterruptible;
3839
import com.oracle.svm.core.heap.RestrictHeapAccess;
3940
import com.oracle.svm.core.jdk.UninterruptibleUtils;
41+
import com.oracle.svm.core.jfr.sampler.JfrRecurringCallbackExecutionSampler;
4042
import com.oracle.svm.core.option.HostedOptionKey;
4143
import com.oracle.svm.core.threadlocal.FastThreadLocalFactory;
4244
import com.oracle.svm.core.threadlocal.FastThreadLocalInt;
@@ -65,7 +67,7 @@ public static class Options {
6567

6668
public static class ConcealedOptions {
6769
@Option(help = "Support a per-thread timer that is called at a specific interval.") //
68-
public static final HostedOptionKey<Boolean> SupportRecurringCallback = new HostedOptionKey<>(true);
70+
public static final HostedOptionKey<Boolean> SupportRecurringCallback = new HostedOptionKey<>(false);
6971
}
7072

7173
/**
@@ -78,7 +80,8 @@ public static class ConcealedOptions {
7880

7981
@Fold
8082
public static boolean isEnabled() {
81-
return ConcealedOptions.SupportRecurringCallback.getValue();
83+
VMError.guarantee(BuildPhaseProvider.isSetupFinished(), "JfrRecurringCallbackExecutionSampler.isPresent() must not be called too early");
84+
return ConcealedOptions.SupportRecurringCallback.getValue() || JfrRecurringCallbackExecutionSampler.isPresent();
8285
}
8386

8487
public static RecurringCallbackTimer createCallbackTimer(long intervalNanos, RecurringCallback callback) {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
import java.util.function.BooleanSupplier;
5454
import java.util.function.Function;
5555

56-
import com.oracle.svm.core.FutureDefaultsOptions;
5756
import org.graalvm.collections.EconomicSet;
5857
import org.graalvm.collections.Pair;
5958
import org.graalvm.nativeimage.ImageInfo;
@@ -121,6 +120,7 @@
121120
import com.oracle.svm.core.BuildArtifacts;
122121
import com.oracle.svm.core.BuildPhaseProvider;
123122
import com.oracle.svm.core.ClassLoaderSupport;
123+
import com.oracle.svm.core.FutureDefaultsOptions;
124124
import com.oracle.svm.core.JavaMainWrapper.JavaMainSupport;
125125
import com.oracle.svm.core.LinkerInvocation;
126126
import com.oracle.svm.core.MissingRegistrationSupport;
@@ -1086,6 +1086,7 @@ protected void setupNativeImage(String imageName, OptionValues options, Map<Meth
10861086
FeatureImpl.DuringSetupAccessImpl config = new FeatureImpl.DuringSetupAccessImpl(featureHandler, loader, bb, debug);
10871087
featureHandler.forEachFeature(feature -> feature.duringSetup(config));
10881088
}
1089+
BuildPhaseProvider.markSetupFinished();
10891090

10901091
if (ImageLayerBuildingSupport.buildingExtensionLayer()) {
10911092
Heap.getHeap().setStartOffset(HostedImageLayerBuildingSupport.singleton().getLoader().getImageHeapSize());

0 commit comments

Comments
 (0)