diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index e5fa7145ca65..2040f42bb78d 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -569,6 +569,7 @@ ], "requiresConcealed" : { "java.base" : [ + "jdk.internal.event", "jdk.internal.misc", "jdk.internal.vm.annotation", "jdk.internal.org.objectweb.asm", diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java index 103787588b26..1f7eda4eeb75 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java @@ -25,6 +25,8 @@ package com.oracle.svm.core.posix; +import java.util.function.BooleanSupplier; + import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -47,7 +49,7 @@ import com.oracle.svm.core.posix.headers.Time; import com.oracle.svm.core.sampler.SubstrateSigprofHandler; -@AutomaticallyRegisteredImageSingleton(SubstrateSigprofHandler.class) +@AutomaticallyRegisteredImageSingleton(value = SubstrateSigprofHandler.class, onlyWith = LinuxOnly.class) public class PosixSubstrateSigprofHandler extends SubstrateSigprofHandler { public static final long INTERVAL_S = 0; @@ -134,3 +136,10 @@ protected IsolateThread getThreadLocalKeyValue(UnsignedWord key) { return (IsolateThread) Pthread.pthread_getspecific((Pthread.pthread_key_t) key); } } + +class LinuxOnly implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return Platform.includedIn(Platform.LINUX.class); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrChunkWriter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrChunkWriter.java index e66728803603..1b063b855da2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrChunkWriter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrChunkWriter.java @@ -41,6 +41,7 @@ import com.oracle.svm.core.jfr.traceid.JfrTraceIdEpoch; import com.oracle.svm.core.os.RawFileOperationSupport; import com.oracle.svm.core.sampler.SamplerBuffersAccess; +import com.oracle.svm.core.sampler.SubstrateSigprofHandler; import com.oracle.svm.core.thread.JavaVMOperation; import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.thread.VMOperationControl; @@ -384,8 +385,7 @@ protected void operate() { */ @Uninterruptible(reason = "Prevent pollution of the current thread's thread local JFR buffer.") private void changeEpoch() { - /* Process all unprocessed sampler buffers before changing the epoch. */ - SamplerBuffersAccess.processSamplerBuffers(); + processSamplerBuffers(); // Write unflushed data from the thread local buffers but do *not* reinitialize them // The thread local code will handle space reclamation on their own time @@ -413,6 +413,24 @@ private void changeEpoch() { // Now that the epoch changed, re-register all running threads for the new epoch. SubstrateJVM.getThreadRepo().registerRunningThreads(); } + + /** + * The VM is at a safepoint, so all other threads have a native state. However, the SIGPROF + * handler may still be executed at any time for any thread (including the current thread). + * To prevent races, we need to ensure that there are no threads that execute the SIGPROF + * handler while we are accessing the currently active buffers of other threads. + */ + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + private void processSamplerBuffers() { + SubstrateSigprofHandler.preventThreadsFromEnteringSigProfHandler(); + try { + SubstrateSigprofHandler.waitUntilAllThreadsExitedSignalHandler(); + SamplerBuffersAccess.processActiveBuffers(); + SamplerBuffersAccess.processFullBuffers(); + } finally { + SubstrateSigprofHandler.allowThreadsInSigProfHandler(); + } + } } public long getChunkStartNanos() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java index 3635233cfd5c..01fb89611283 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java @@ -24,18 +24,14 @@ */ package com.oracle.svm.core.jfr; -import java.util.function.BooleanSupplier; - import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.jdk.JDK17OrEarlier; -import com.oracle.svm.util.ReflectionUtil; /** - * The event IDs depend on the metadata.xml and therefore vary between JDK versions. + * This file contains the VM-level events that Native Image supports on all JDK versions. The event + * IDs depend on the JDK version-specific metadata.xml file. */ public final class JfrEvent { public static final JfrEvent ThreadStart = create("jdk.ThreadStart"); @@ -60,7 +56,6 @@ public final class JfrEvent { public static final JfrEvent SafepointEnd = create("jdk.SafepointEnd"); public static final JfrEvent ExecuteVMOperation = create("jdk.ExecuteVMOperation"); public static final JfrEvent JavaMonitorEnter = create("jdk.JavaMonitorEnter"); - public static final JfrEvent ThreadSleep = create("jdk.ThreadSleep", JDK17OrEarlier.class); public static final JfrEvent ThreadPark = create("jdk.ThreadPark"); public static final JfrEvent JavaMonitorWait = create("jdk.JavaMonitorWait"); @@ -68,18 +63,8 @@ public final class JfrEvent { private final String name; @Platforms(Platform.HOSTED_ONLY.class) - private static JfrEvent create(String name) { - return create(name, TargetClass.AlwaysIncluded.class); - } - - @Platforms(Platform.HOSTED_ONLY.class) - private static JfrEvent create(String name, Class onlyWith) { - BooleanSupplier onlyWithProvider = ReflectionUtil.newInstance(onlyWith); - if (onlyWithProvider.getAsBoolean()) { - return new JfrEvent(name); - } else { - return null; - } + public static JfrEvent create(String name) { + return new JfrEvent(name); } @Platforms(Platform.HOSTED_ONLY.class) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java index 405cc7027057..caba4c62be17 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java @@ -49,7 +49,6 @@ import com.sun.management.internal.PlatformMBeanProviderImpl; import jdk.jfr.Configuration; -import jdk.jfr.Event; import jdk.jfr.internal.JVM; import jdk.jfr.internal.jfc.JFC; @@ -59,9 +58,9 @@ * * There are two different kinds of JFR events: *