Skip to content

Commit 193cfec

Browse files
Changes according to comments.
1 parent 672b0a4 commit 193cfec

File tree

17 files changed

+241
-190
lines changed

17 files changed

+241
-190
lines changed

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,60 @@
2525

2626
package com.oracle.svm.core.posix;
2727

28+
import static com.oracle.svm.core.posix.PosixSubstrateSigprofHandler.isSignalHandlerBasedExecutionSamplerEnabled;
2829
import static com.oracle.svm.core.posix.PosixSubstrateSigprofHandler.Options.SignalHandlerBasedExecutionSampler;
2930

31+
import java.util.List;
32+
33+
import org.graalvm.nativeimage.ImageSingletons;
3034
import org.graalvm.nativeimage.Platform;
3135
import org.graalvm.nativeimage.c.function.CEntryPoint;
3236
import org.graalvm.nativeimage.c.function.CEntryPointLiteral;
3337
import org.graalvm.nativeimage.c.function.CodePointer;
38+
import org.graalvm.nativeimage.hosted.Feature;
3439
import org.graalvm.word.Pointer;
3540

41+
import com.oracle.svm.core.IsolateListenerSupport;
42+
import com.oracle.svm.core.IsolateListenerSupportFeature;
3643
import com.oracle.svm.core.RegisterDumper;
3744
import com.oracle.svm.core.SubstrateOptions;
3845
import com.oracle.svm.core.Uninterruptible;
3946
import com.oracle.svm.core.c.function.CEntryPointOptions;
47+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
48+
import com.oracle.svm.core.feature.InternalFeature;
4049
import com.oracle.svm.core.heap.RestrictHeapAccess;
50+
import com.oracle.svm.core.jfr.JfrExecutionSamplerSupported;
51+
import com.oracle.svm.core.jfr.JfrFeature;
52+
import com.oracle.svm.core.jfr.sampler.JfrExecutionSampler;
4153
import com.oracle.svm.core.option.HostedOptionKey;
4254
import com.oracle.svm.core.option.SubstrateOptionsParser;
55+
import com.oracle.svm.core.posix.darwin.DarwinSubstrateSigprofHandler;
4356
import com.oracle.svm.core.posix.headers.Signal;
57+
import com.oracle.svm.core.posix.linux.LinuxSubstrateSigprofHandler;
4458
import com.oracle.svm.core.sampler.SubstrateSigprofHandler;
59+
import com.oracle.svm.core.thread.ThreadListenerSupport;
60+
import com.oracle.svm.core.thread.ThreadListenerSupportFeature;
4561
import com.oracle.svm.core.util.UserError;
62+
import com.oracle.svm.core.util.VMError;
4663

4764
import jdk.graal.compiler.options.Option;
4865

66+
/**
67+
* <p>
68+
* This class serves as the core for POSIX-based SIGPROF signal handlers.
69+
* </p>
70+
*
71+
* <p>
72+
* POSIX supports two types of timers: the global timer and per-thread timer. While Linux supports
73+
* both, Darwin only supports the global timer. Consequently, we need to split the implementation
74+
* accordingly (see subclasses).
75+
* </p>
76+
*
77+
* <p>
78+
* Note: The global timer can't interrupt threads that are blocked, while per-thread timer can
79+
* (e.g., threads that are blocked on a monitor or threads that are frozen at a safepoint).
80+
* </p>
81+
*/
4982
public abstract class PosixSubstrateSigprofHandler extends SubstrateSigprofHandler {
5083
private static final CEntryPointLiteral<Signal.AdvancedSignalDispatcher> advancedSignalDispatcher = CEntryPointLiteral.create(PosixSubstrateSigprofHandler.class,
5184
"dispatch", int.class, Signal.siginfo_t.class, Signal.ucontext_t.class);
@@ -94,3 +127,33 @@ static class Options {
94127
public static final HostedOptionKey<Boolean> SignalHandlerBasedExecutionSampler = new HostedOptionKey<>(null, PosixSubstrateSigprofHandler::validateSamplerOption);
95128
}
96129
}
130+
131+
@AutomaticallyRegisteredFeature
132+
class PosixSubstrateSigProfHandlerFeature implements InternalFeature {
133+
@Override
134+
public List<Class<? extends Feature>> getRequiredFeatures() {
135+
return List.of(ThreadListenerSupportFeature.class, IsolateListenerSupportFeature.class, JfrFeature.class);
136+
}
137+
138+
@Override
139+
public void afterRegistration(AfterRegistrationAccess access) {
140+
if (JfrExecutionSamplerSupported.isSupported() && isSignalHandlerBasedExecutionSamplerEnabled()) {
141+
SubstrateSigprofHandler sampler = makeNewSigprofHandler();
142+
ImageSingletons.add(JfrExecutionSampler.class, sampler);
143+
ImageSingletons.add(SubstrateSigprofHandler.class, sampler);
144+
145+
ThreadListenerSupport.get().register(sampler);
146+
IsolateListenerSupport.singleton().register(sampler);
147+
}
148+
}
149+
150+
private static SubstrateSigprofHandler makeNewSigprofHandler() {
151+
if (Platform.includedIn(Platform.LINUX.class)) {
152+
return new LinuxSubstrateSigprofHandler();
153+
} else if (Platform.includedIn(Platform.DARWIN.class)) {
154+
return new DarwinSubstrateSigprofHandler();
155+
} else {
156+
throw VMError.shouldNotReachHere("The JFR-based sampler is not supported on this platform.");
157+
}
158+
}
159+
}

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandlerFeature.java

Lines changed: 0 additions & 65 deletions
This file was deleted.

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinSubstrateSigprofHandler.java

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,24 @@
2525

2626
package com.oracle.svm.core.posix.darwin;
2727

28-
import com.oracle.svm.core.Uninterruptible;
28+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
29+
2930
import org.graalvm.nativeimage.IsolateThread;
3031
import org.graalvm.nativeimage.Platform;
3132
import org.graalvm.nativeimage.Platforms;
3233
import org.graalvm.word.WordFactory;
3334

34-
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
35+
import com.oracle.svm.core.Uninterruptible;
3536
import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue;
3637
import com.oracle.svm.core.posix.PosixSubstrateSigprofHandler;
37-
import com.oracle.svm.core.posix.PosixSubstrateSigprofHandlerFeature;
3838
import com.oracle.svm.core.posix.PosixUtils;
3939
import com.oracle.svm.core.posix.headers.Time;
40-
import com.oracle.svm.core.sampler.SubstrateSigprofHandler;
4140
import com.oracle.svm.core.util.TimeUtils;
4241

43-
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
44-
45-
final class DarwinSubstrateSigprofHandler extends PosixSubstrateSigprofHandler {
42+
public final class DarwinSubstrateSigprofHandler extends PosixSubstrateSigprofHandler {
4643

4744
@Platforms(Platform.HOSTED_ONLY.class)
48-
DarwinSubstrateSigprofHandler() {
45+
public DarwinSubstrateSigprofHandler() {
4946
}
5047

5148
@Override
@@ -72,29 +69,19 @@ protected void installSignalHandler() {
7269

7370
@Override
7471
protected void uninstallSignalHandler() {
75-
/*
76-
* Only disable the sampling but do not replace the signal handler with the default one
77-
* because a signal might be pending for some thread (the default signal handler would print
78-
* "Profiling timer expired" to the output).
79-
*/
72+
/* Disable sampling. */
8073
updateInterval(0);
8174
}
8275

8376
@Override
8477
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
8578
protected void install0(IsolateThread thread) {
79+
/* The timer is global, so nothing to do here. */
8680
}
8781

8882
@Override
8983
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
9084
protected void uninstall0(IsolateThread thread) {
91-
}
92-
}
93-
94-
@AutomaticallyRegisteredFeature
95-
final class DarwinSubstrateSigprofHandlerFeature extends PosixSubstrateSigprofHandlerFeature {
96-
@Override
97-
protected SubstrateSigprofHandler makeNewSigprofHandler() {
98-
return new DarwinSubstrateSigprofHandler();
85+
/* The timer is global, so nothing to do here. */
9986
}
10087
}

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/linux/LinuxTime.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
@CContext(PosixDirectives.class)
4646
public class LinuxTime extends Time {
4747

48-
@CStruct(addStructKeyword = true, isIncomplete = true)
48+
@CStruct
4949
public interface timer_t extends PointerBase {
5050
}
5151

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxSubstrateSigprofHandler.java

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,40 @@
2525

2626
package com.oracle.svm.core.posix.linux;
2727

28+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
29+
30+
import org.graalvm.nativeimage.CurrentIsolate;
2831
import org.graalvm.nativeimage.IsolateThread;
2932
import org.graalvm.nativeimage.Platform;
3033
import org.graalvm.nativeimage.Platforms;
3134
import org.graalvm.nativeimage.StackValue;
3235
import org.graalvm.word.WordFactory;
3336

3437
import com.oracle.svm.core.Uninterruptible;
35-
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3638
import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue;
37-
import com.oracle.svm.core.jfr.JfrThreadLocal;
3839
import com.oracle.svm.core.posix.PosixSubstrateSigprofHandler;
39-
import com.oracle.svm.core.posix.PosixSubstrateSigprofHandlerFeature;
4040
import com.oracle.svm.core.posix.PosixUtils;
4141
import com.oracle.svm.core.posix.headers.Signal;
4242
import com.oracle.svm.core.posix.headers.linux.LinuxTime;
43-
import com.oracle.svm.core.sampler.SubstrateSigprofHandler;
43+
import com.oracle.svm.core.thread.VMOperation;
4444
import com.oracle.svm.core.thread.VMThreads;
45+
import com.oracle.svm.core.threadlocal.FastThreadLocalFactory;
46+
import com.oracle.svm.core.threadlocal.FastThreadLocalWord;
4547
import com.oracle.svm.core.util.TimeUtils;
4648

47-
final class LinuxSubstrateSigprofHandler extends PosixSubstrateSigprofHandler {
49+
public final class LinuxSubstrateSigprofHandler extends PosixSubstrateSigprofHandler {
50+
51+
private static final int INITIAL_SAMPLER_TIMER_ID = -1;
52+
private static final FastThreadLocalWord<LinuxTime.timer_t> samplerTimerId = FastThreadLocalFactory.createWord("LinuxSubstrateSigprofHandler.samplerTimerId");
4853

4954
@Platforms(Platform.HOSTED_ONLY.class)
50-
LinuxSubstrateSigprofHandler() {
55+
public LinuxSubstrateSigprofHandler() {
56+
}
57+
58+
@Override
59+
@Uninterruptible(reason = "Prevent VM operations that modify thread-local execution sampler state.")
60+
public void beforeThreadStart(IsolateThread isolateThread, Thread javaThread) {
61+
setSamplerTimerId(isolateThread, WordFactory.signed(INITIAL_SAMPLER_TIMER_ID));
5162
}
5263

5364
@Override
@@ -60,7 +71,7 @@ protected void updateInterval() {
6071
@Override
6172
@Uninterruptible(reason = "Prevent VM operations that modify thread-local execution sampler state.")
6273
protected void install0(IsolateThread thread) {
63-
assert !JfrThreadLocal.isSamplerTimerSet(thread);
74+
assert !isSamplerTimerSet(thread);
6475

6576
Signal.sigevent sigevent = StackValue.get(Signal.sigevent.class);
6677
sigevent.sigev_notify(Signal.SIGEV_SIGNAL());
@@ -69,28 +80,23 @@ protected void install0(IsolateThread thread) {
6980

7081
int status = LinuxTime.NoTransitions.timer_create(LinuxTime.CLOCK_MONOTONIC(), sigevent, timerPointer);
7182
PosixUtils.checkStatusIs0(status, "timer_create(clockid, sevp, timerid): wrong arguments.");
72-
JfrThreadLocal.setSamplerTimerId(thread, timerPointer.read());
83+
setSamplerTimerId(thread, timerPointer.read());
7384
updateInterval(thread);
7485
}
7586

7687
@Override
7788
@Uninterruptible(reason = "Prevent VM operations that modify thread-local execution sampler state.")
7889
protected void uninstall0(IsolateThread thread) {
79-
assert JfrThreadLocal.isSamplerTimerSet(thread);
90+
assert isSamplerTimerSet(thread);
8091

81-
LinuxTime.timer_t samplerTimerId = (LinuxTime.timer_t) JfrThreadLocal.getSamplerTimerId(thread);
82-
int status = LinuxTime.NoTransitions.timer_delete(samplerTimerId);
92+
int status = LinuxTime.NoTransitions.timer_delete(getSamplerTimerId(thread));
8393
PosixUtils.checkStatusIs0(status, "timer_delete(clockid): wrong arguments.");
84-
JfrThreadLocal.setSamplerTimerId(thread, WordFactory.nullPointer());
85-
}
86-
87-
@Override
88-
protected void uninstallSignalHandler() {
94+
setSamplerTimerId(thread, WordFactory.signed(INITIAL_SAMPLER_TIMER_ID));
8995
}
9096

9197
@Uninterruptible(reason = "Prevent VM operations that modify thread-local execution sampler state.")
9298
private void updateInterval(IsolateThread thread) {
93-
assert JfrThreadLocal.isSamplerTimerSet(thread);
99+
assert isSamplerTimerSet(thread);
94100

95101
long ns = TimeUtils.millisToNanos(newIntervalMillis);
96102
LinuxTime.itimerspec newTimerSpec = UnsafeStackValue.get(LinuxTime.itimerspec.class);
@@ -99,16 +105,24 @@ private void updateInterval(IsolateThread thread) {
99105
newTimerSpec.it_interval().set_tv_sec(ns / TimeUtils.nanosPerSecond);
100106
newTimerSpec.it_interval().set_tv_nsec(ns % TimeUtils.nanosPerSecond);
101107

102-
LinuxTime.timer_t samplerTimerId = (LinuxTime.timer_t) JfrThreadLocal.getSamplerTimerId(thread);
103-
int status = LinuxTime.NoTransitions.timer_settime(samplerTimerId, 0, newTimerSpec, WordFactory.nullPointer());
108+
int status = LinuxTime.NoTransitions.timer_settime(getSamplerTimerId(thread), 0, newTimerSpec, WordFactory.nullPointer());
104109
PosixUtils.checkStatusIs0(status, "timer_settime(timerid, flags, newTimerSpec, oldValue): wrong arguments.");
105110
}
106-
}
107111

108-
@AutomaticallyRegisteredFeature
109-
final class LinuxSubstrateSigprofHandlerFeature extends PosixSubstrateSigprofHandlerFeature {
110-
@Override
111-
protected SubstrateSigprofHandler makeNewSigprofHandler() {
112-
return new LinuxSubstrateSigprofHandler();
112+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
113+
private static boolean isSamplerTimerSet(IsolateThread thread) {
114+
return getSamplerTimerId(thread).notEqual(WordFactory.signed(INITIAL_SAMPLER_TIMER_ID));
115+
}
116+
117+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
118+
private static LinuxTime.timer_t getSamplerTimerId(IsolateThread thread) {
119+
assert CurrentIsolate.getCurrentThread() == thread || VMOperation.isInProgressAtSafepoint();
120+
return samplerTimerId.get(thread);
121+
}
122+
123+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
124+
private static void setSamplerTimerId(IsolateThread thread, LinuxTime.timer_t timerId) {
125+
assert CurrentIsolate.getCurrentThread() == thread || VMOperation.isInProgressAtSafepoint();
126+
samplerTimerId.set(thread, timerId);
113127
}
114128
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,15 @@ public static Object acquireTether(UntetheredCodeInfo info) {
9393
* Do not interact with the tether object during GCs, as the reference might be forwarded
9494
* and therefore not safe to access. Tethering is not needed then, either.
9595
*/
96-
assert VMOperation.isGCInProgress() || ((CodeInfoTether) tether).incrementCount() > 0;
96+
assert info.equal(CodeInfoTable.getImageCodeInfo()) || VMOperation.isGCInProgress() || ((CodeInfoTether) tether).incrementCount() > 0;
9797
return tether;
9898
}
9999

100100
@Uninterruptible(reason = "Called from uninterruptible code.")
101101
@NeverInline("Prevent elimination of object reference in caller.")
102102
public static void releaseTether(UntetheredCodeInfo info, Object tether) {
103103
assert VMOperation.isGCInProgress() || UntetheredCodeInfoAccess.getTetherUnsafe(info) == null || UntetheredCodeInfoAccess.getTetherUnsafe(info) == tether;
104-
assert VMOperation.isGCInProgress() || ((CodeInfoTether) tether).decrementCount() >= 0;
104+
assert info.equal(CodeInfoTable.getImageCodeInfo()) || VMOperation.isGCInProgress() || ((CodeInfoTether) tether).decrementCount() >= 0;
105105
}
106106

107107
/**
@@ -133,7 +133,7 @@ public static CodeInfo convert(UntetheredCodeInfo untetheredInfo) {
133133
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
134134
public static boolean isValid(UntetheredCodeInfo info) {
135135
return SubstrateUtil.HOSTED || !haveAssertions() || VMOperation.isGCInProgress() || UntetheredCodeInfoAccess.getTetherUnsafe(info) == null ||
136-
((CodeInfoTether) UntetheredCodeInfoAccess.getTetherUnsafe(info)).getCount() > 0 || info.equal(CodeInfoTable.getImageCodeInfo());
136+
((CodeInfoTether) UntetheredCodeInfoAccess.getTetherUnsafe(info)).getCount() > 0;
137137
}
138138

139139
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BacktraceDecoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ private int visitFrame(CodePointer ip, CodeInfo tetheredCodeInfo, int oldFramesD
118118
frameInfoCursor.initialize(tetheredCodeInfo, ip, true);
119119
while (frameInfoCursor.advance()) {
120120
FrameInfoQueryResult frameInfo = frameInfoCursor.get();
121-
if (!StackTraceUtils.shouldShowFrame(frameInfo, false, true, false)) {
121+
if (!StackTraceUtils.shouldShowFrame(frameInfo)) {
122122
/* Always ignore the frame. It is an internal frame of the VM. */
123123
continue;
124124
}

0 commit comments

Comments
 (0)