Skip to content

Commit 4b70dbe

Browse files
Replace setitimer with timer_create method. Implement isHidden entry in JfrMethod.
1 parent 1cc8448 commit 4b70dbe

File tree

15 files changed

+447
-93
lines changed

15 files changed

+447
-93
lines changed

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

Lines changed: 36 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,11 @@
3232

3333
import org.graalvm.nativeimage.ImageSingletons;
3434
import org.graalvm.nativeimage.Platform;
35-
import org.graalvm.nativeimage.Platforms;
3635
import org.graalvm.nativeimage.c.function.CEntryPoint;
3736
import org.graalvm.nativeimage.c.function.CEntryPointLiteral;
3837
import org.graalvm.nativeimage.c.function.CodePointer;
3938
import org.graalvm.nativeimage.hosted.Feature;
4039
import org.graalvm.word.Pointer;
41-
import org.graalvm.word.WordFactory;
4240

4341
import com.oracle.svm.core.IsolateListenerSupport;
4442
import com.oracle.svm.core.IsolateListenerSupportFeature;
@@ -48,31 +46,47 @@
4846
import com.oracle.svm.core.c.function.CEntryPointOptions;
4947
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
5048
import com.oracle.svm.core.feature.InternalFeature;
51-
import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue;
5249
import com.oracle.svm.core.heap.RestrictHeapAccess;
5350
import com.oracle.svm.core.jfr.JfrExecutionSamplerSupported;
5451
import com.oracle.svm.core.jfr.JfrFeature;
5552
import com.oracle.svm.core.jfr.sampler.JfrExecutionSampler;
5653
import com.oracle.svm.core.option.HostedOptionKey;
5754
import com.oracle.svm.core.option.SubstrateOptionsParser;
55+
import com.oracle.svm.core.posix.darwin.DarwinSubstrateSigprofHandler;
5856
import com.oracle.svm.core.posix.headers.Signal;
59-
import com.oracle.svm.core.posix.headers.Time;
57+
import com.oracle.svm.core.posix.linux.LinuxSubstrateSigprofHandler;
6058
import com.oracle.svm.core.sampler.SubstrateSigprofHandler;
6159
import com.oracle.svm.core.thread.ThreadListenerSupport;
6260
import com.oracle.svm.core.thread.ThreadListenerSupportFeature;
63-
import com.oracle.svm.core.util.TimeUtils;
6461
import com.oracle.svm.core.util.UserError;
62+
import com.oracle.svm.core.util.VMError;
6563

6664
import jdk.graal.compiler.options.Option;
6765

68-
public final class PosixSubstrateSigprofHandler extends SubstrateSigprofHandler {
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. Both timers can
73+
* interrupt threads that are blocked. This may result in situations where the VM operation changes
74+
* unexpectedly while a thread executes signal handler code:
75+
* <ul>
76+
* <li>Thread A requests a safepoint.
77+
* <li>Thread B is blocked because of the safepoint but the VM did not start executing the VM
78+
* operation yet (i.e., there is no VM operation in progress).
79+
* <li>Thread B receives a SIGPROF signal and starts executing the signal handler.
80+
* <li>The VM reaches a safepoint and thread A starts executing the VM operation.
81+
* <li>Thread B continues executing the signal handler while the VM operation is now suddenly in
82+
* progress.
83+
* </ul>
84+
* </p>
85+
*/
86+
public abstract class PosixSubstrateSigprofHandler extends SubstrateSigprofHandler {
6987
private static final CEntryPointLiteral<Signal.AdvancedSignalDispatcher> advancedSignalDispatcher = CEntryPointLiteral.create(PosixSubstrateSigprofHandler.class,
7088
"dispatch", int.class, Signal.siginfo_t.class, Signal.ucontext_t.class);
7189

72-
@Platforms(Platform.HOSTED_ONLY.class)
73-
public PosixSubstrateSigprofHandler() {
74-
}
75-
7690
@SuppressWarnings("unused")
7791
@CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished)
7892
@CEntryPointOptions(prologue = CEntryPointOptions.NoPrologue.class, epilogue = CEntryPointOptions.NoEpilogue.class)
@@ -87,40 +101,9 @@ private static void dispatch(@SuppressWarnings("unused") int signalNumber, @Supp
87101
}
88102
}
89103

90-
private static void registerSigprofSignal(Signal.AdvancedSignalDispatcher dispatcher) {
91-
PosixUtils.installSignalHandler(Signal.SignalEnum.SIGPROF, dispatcher, Signal.SA_RESTART());
92-
}
93-
94-
@Override
95-
protected void updateInterval() {
96-
updateInterval(TimeUtils.millisToMicros(newIntervalMillis));
97-
}
98-
99-
public static void updateInterval(long us) {
100-
Time.itimerval newValue = UnsafeStackValue.get(Time.itimerval.class);
101-
newValue.it_value().set_tv_sec(us / TimeUtils.microsPerSecond);
102-
newValue.it_value().set_tv_usec(us % TimeUtils.microsPerSecond);
103-
newValue.it_interval().set_tv_sec(us / TimeUtils.microsPerSecond);
104-
newValue.it_interval().set_tv_usec(us % TimeUtils.microsPerSecond);
105-
106-
int status = Time.NoTransitions.setitimer(Time.TimerTypeEnum.ITIMER_PROF, newValue, WordFactory.nullPointer());
107-
PosixUtils.checkStatusIs0(status, "setitimer(which, newValue, oldValue): wrong arguments.");
108-
}
109-
110104
@Override
111105
protected void installSignalHandler() {
112-
registerSigprofSignal(advancedSignalDispatcher.getFunctionPointer());
113-
updateInterval();
114-
}
115-
116-
@Override
117-
protected void uninstallSignalHandler() {
118-
/*
119-
* Only disable the sampling but do not replace the signal handler with the default one
120-
* because a signal might be pending for some thread (the default signal handler would print
121-
* "Profiling timer expired" to the output).
122-
*/
123-
updateInterval(0);
106+
PosixUtils.installSignalHandler(Signal.SignalEnum.SIGPROF, advancedSignalDispatcher.getFunctionPointer(), Signal.SA_RESTART());
124107
}
125108

126109
static boolean isSignalHandlerBasedExecutionSamplerEnabled() {
@@ -159,12 +142,22 @@ public List<Class<? extends Feature>> getRequiredFeatures() {
159142
@Override
160143
public void afterRegistration(AfterRegistrationAccess access) {
161144
if (JfrExecutionSamplerSupported.isSupported() && isSignalHandlerBasedExecutionSamplerEnabled()) {
162-
SubstrateSigprofHandler sampler = new PosixSubstrateSigprofHandler();
145+
SubstrateSigprofHandler sampler = makeNewSigprofHandler();
163146
ImageSingletons.add(JfrExecutionSampler.class, sampler);
164147
ImageSingletons.add(SubstrateSigprofHandler.class, sampler);
165148

166149
ThreadListenerSupport.get().register(sampler);
167150
IsolateListenerSupport.singleton().register(sampler);
168151
}
169152
}
153+
154+
private static SubstrateSigprofHandler makeNewSigprofHandler() {
155+
if (Platform.includedIn(Platform.LINUX.class)) {
156+
return new LinuxSubstrateSigprofHandler();
157+
} else if (Platform.includedIn(Platform.DARWIN.class)) {
158+
return new DarwinSubstrateSigprofHandler();
159+
} else {
160+
throw VMError.shouldNotReachHere("The JFR-based sampler is not supported on this platform.");
161+
}
162+
}
170163
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package com.oracle.svm.core.posix.darwin;
27+
28+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
29+
30+
import org.graalvm.nativeimage.IsolateThread;
31+
import org.graalvm.nativeimage.Platform;
32+
import org.graalvm.nativeimage.Platforms;
33+
import org.graalvm.word.WordFactory;
34+
35+
import com.oracle.svm.core.Uninterruptible;
36+
import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue;
37+
import com.oracle.svm.core.posix.PosixSubstrateSigprofHandler;
38+
import com.oracle.svm.core.posix.PosixUtils;
39+
import com.oracle.svm.core.posix.headers.Time;
40+
import com.oracle.svm.core.util.TimeUtils;
41+
42+
/**
43+
* Darwin supports only global timer from POSIX (see {@link PosixSubstrateSigprofHandler}).
44+
*/
45+
public final class DarwinSubstrateSigprofHandler extends PosixSubstrateSigprofHandler {
46+
47+
@Platforms(Platform.HOSTED_ONLY.class)
48+
public DarwinSubstrateSigprofHandler() {
49+
}
50+
51+
@Override
52+
protected void updateInterval() {
53+
updateInterval(TimeUtils.millisToMicros(newIntervalMillis));
54+
}
55+
56+
private static void updateInterval(long us) {
57+
Time.itimerval newValue = UnsafeStackValue.get(Time.itimerval.class);
58+
newValue.it_value().set_tv_sec(us / TimeUtils.microsPerSecond);
59+
newValue.it_value().set_tv_usec(us % TimeUtils.microsPerSecond);
60+
newValue.it_interval().set_tv_sec(us / TimeUtils.microsPerSecond);
61+
newValue.it_interval().set_tv_usec(us % TimeUtils.microsPerSecond);
62+
63+
int status = Time.NoTransitions.setitimer(Time.TimerTypeEnum.ITIMER_PROF, newValue, WordFactory.nullPointer());
64+
PosixUtils.checkStatusIs0(status, "setitimer(which, newValue, oldValue): wrong arguments.");
65+
}
66+
67+
@Override
68+
protected void installSignalHandler() {
69+
super.installSignalHandler();
70+
updateInterval();
71+
}
72+
73+
@Override
74+
protected void uninstallSignalHandler() {
75+
/* Disable sampling. */
76+
updateInterval(0);
77+
}
78+
79+
@Override
80+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
81+
protected void install0(IsolateThread thread) {
82+
/* The timer is global, so nothing to do here. */
83+
}
84+
85+
@Override
86+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
87+
protected void uninstall0(IsolateThread thread) {
88+
/* The timer is global, so nothing to do here. */
89+
}
90+
}

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Signal.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ public class Signal {
6868
@CConstant
6969
public static native int SIG_SETMASK();
7070

71+
@CConstant
72+
public static native int SIGEV_SIGNAL();
73+
7174
@CFunction
7275
public static native int sigprocmask(int how, sigset_tPointer set, sigset_tPointer oldset);
7376

@@ -179,10 +182,22 @@ public interface sigaction extends PointerBase {
179182
sigset_tPointer sa_mask();
180183
}
181184

185+
@CStruct(addStructKeyword = true)
186+
public interface sigevent extends PointerBase {
187+
@CField
188+
void sigev_notify(int value);
189+
190+
@CField
191+
void sigev_signo(int value);
192+
}
193+
182194
/** Don't call this function directly, see {@link PosixUtils#sigaction}. */
183195
@CFunction
184196
public static native int sigaction(int signum, sigaction act, sigaction oldact);
185197

198+
@CConstant
199+
public static native int SIGPROF();
200+
186201
@CEnum
187202
@CContext(PosixDirectives.class)
188203
public enum SignalEnum {

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,13 @@
2828
import org.graalvm.nativeimage.c.constant.CConstant;
2929
import org.graalvm.nativeimage.c.function.CFunction;
3030
import org.graalvm.nativeimage.c.function.CLibrary;
31+
import org.graalvm.nativeimage.c.struct.CFieldAddress;
32+
import org.graalvm.nativeimage.c.struct.CPointerTo;
33+
import org.graalvm.nativeimage.c.struct.CStruct;
34+
import org.graalvm.word.PointerBase;
3135

3236
import com.oracle.svm.core.posix.headers.PosixDirectives;
37+
import com.oracle.svm.core.posix.headers.Signal;
3338
import com.oracle.svm.core.posix.headers.Time;
3439

3540
// Checkstyle: stop
@@ -39,6 +44,25 @@
3944
*/
4045
@CContext(PosixDirectives.class)
4146
public class LinuxTime extends Time {
47+
48+
@CStruct
49+
public interface timer_t extends PointerBase {
50+
}
51+
52+
@CPointerTo(timer_t.class)
53+
public interface timer_tPointer extends PointerBase {
54+
timer_t read();
55+
}
56+
57+
@CStruct(addStructKeyword = true)
58+
public interface itimerspec extends PointerBase {
59+
@CFieldAddress
60+
Time.timespec it_interval();
61+
62+
@CFieldAddress
63+
Time.timespec it_value();
64+
}
65+
4266
@CConstant
4367
public static native int CLOCK_MONOTONIC();
4468

@@ -50,5 +74,14 @@ public static class NoTransitions {
5074
@CFunction(transition = CFunction.Transition.NO_TRANSITION)
5175
@CLibrary("rt")
5276
public static native int clock_gettime(int clock_id, timespec tp);
77+
78+
@CFunction(transition = CFunction.Transition.NO_TRANSITION)
79+
public static native int timer_create(int clockid, Signal.sigevent sevp, timer_tPointer timerid);
80+
81+
@CFunction(transition = CFunction.Transition.NO_TRANSITION)
82+
public static native int timer_settime(timer_t timerid, int flags, itimerspec newValue, itimerspec oldValue);
83+
84+
@CFunction(transition = CFunction.Transition.NO_TRANSITION)
85+
public static native int timer_delete(timer_t timerid);
5386
}
5487
}

0 commit comments

Comments
 (0)