Skip to content

Commit 22add5c

Browse files
Use putThread to avoid races.
1 parent c1e4ab0 commit 22add5c

File tree

7 files changed

+46
-19
lines changed

7 files changed

+46
-19
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrNativeEventWriter.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,12 +250,14 @@ public static void putThread(JfrNativeEventWriterData data, Thread thread) {
250250
if (thread == null) {
251251
putThread(data, 0L);
252252
} else {
253+
SubstrateJVM.maybeRegisterVirtualThread(thread);
253254
putThread(data, SubstrateJVM.getThreadId(thread));
254255
}
255256
}
256257

257258
@Uninterruptible(reason = "Accesses a native JFR buffer.", callerMustBe = true)
258259
public static void putThread(JfrNativeEventWriterData data, long threadId) {
260+
SubstrateJVM.maybeRegisterVirtualThread(threadId);
259261
putLong(data, threadId);
260262
}
261263

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrThreadRepository.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
package com.oracle.svm.core.jfr;
2626

27+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
28+
2729
import org.graalvm.nativeimage.IsolateThread;
2830
import org.graalvm.nativeimage.Platform;
2931
import org.graalvm.nativeimage.Platforms;
@@ -96,14 +98,33 @@ public void registerRunningThreads() {
9698
}
9799
}
98100

101+
/**
102+
* If this method is called on platform threads, nothing will happen since they are already
103+
* registered eagerly upon starting and at epoch changes.
104+
*/
105+
@Uninterruptible(reason = "Locking without transition requires that the whole critical section is uninterruptible.")
106+
public void registerThread(long threadId) {
107+
if (!SubstrateJVM.get().isRecording()) {
108+
return;
109+
}
110+
111+
registerThread0(threadId, 0, true, null, null);
112+
}
113+
99114
@Uninterruptible(reason = "Locking without transition requires that the whole critical section is uninterruptible.")
100115
public void registerThread(Thread thread) {
101116
if (!SubstrateJVM.get().isRecording()) {
102117
return;
103118
}
104119

105120
long threadId = JavaThreads.getThreadId(thread);
121+
boolean isVirtual = JavaThreads.isVirtual(thread);
122+
long osThreadId = isVirtual ? 0 : threadId;
123+
registerThread0(threadId, osThreadId, isVirtual, thread, thread.getName());
124+
}
106125

126+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
127+
private void registerThread0(long threadId, long osThreadId, boolean isVirtual, Thread thread, String name) {
107128
JfrVisited visitedThread = StackValue.get(JfrVisited.class);
108129
visitedThread.setId(threadId);
109130
visitedThread.setHash(UninterruptibleUtils.Long.hashCode(threadId));
@@ -124,14 +145,12 @@ public void registerThread(Thread thread) {
124145
JfrNativeEventWriterDataAccess.initialize(data, epochData.threadBuffer);
125146

126147
/* Similar to JfrThreadConstant::serialize in HotSpot. */
127-
boolean isVirtual = JavaThreads.isVirtual(thread);
128-
long osThreadId = isVirtual ? 0 : threadId;
129148
long threadGroupId = registerThreadGroup(thread, isVirtual);
130149

131150
JfrNativeEventWriter.putLong(data, threadId);
132-
JfrNativeEventWriter.putString(data, thread.getName()); // OS thread name
151+
JfrNativeEventWriter.putString(data, name); // OS thread name
133152
JfrNativeEventWriter.putLong(data, osThreadId); // OS thread id
134-
JfrNativeEventWriter.putString(data, thread.getName()); // Java thread name
153+
JfrNativeEventWriter.putString(data, name); // Java thread name
135154
JfrNativeEventWriter.putLong(data, threadId); // Java thread id
136155
JfrNativeEventWriter.putLong(data, threadGroupId); // Java thread group
137156
JfrNativeEventWriter.putBoolean(data, isVirtual);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/SubstrateJVM.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,6 @@ public long getStackTraceId(JfrEvent eventType, int skipCount) {
306306
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
307307
public static long getThreadId(Thread thread) {
308308
if (HasJfrSupport.get()) {
309-
maybeRegisterVirtualThread(thread);
310309
return JavaThreads.getThreadId(thread);
311310
}
312311
return 0;
@@ -315,7 +314,6 @@ public static long getThreadId(Thread thread) {
315314
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
316315
public static long getCurrentThreadId() {
317316
if (HasJfrSupport.get()) {
318-
maybeRegisterVirtualThread(Thread.currentThread());
319317
return JavaThreads.getCurrentThreadId();
320318
}
321319
return 0;
@@ -326,7 +324,7 @@ public static long getCurrentThreadId() {
326324
* eagerly when started and at chunk rotations.
327325
*/
328326
@Uninterruptible(reason = "Epoch should not change while checking generation.")
329-
private static void maybeRegisterVirtualThread(Thread thread) {
327+
public static void maybeRegisterVirtualThread(Thread thread) {
330328
// Do quick preliminary checks to avoid global locking unless necessary.
331329
if (JavaThreads.isVirtual(thread)) {
332330
Target_java_lang_VirtualThread tjlv = SubstrateUtil.cast(thread, Target_java_lang_VirtualThread.class);
@@ -338,6 +336,15 @@ private static void maybeRegisterVirtualThread(Thread thread) {
338336
}
339337
}
340338

339+
/**
340+
* {@link SubstrateJVM#maybeRegisterVirtualThread(Thread)} Is preferred over this method since
341+
* it can perform preliminary checks to avoid locking the Thread Repository unnecessarily.
342+
*/
343+
@Uninterruptible(reason = "Epoch should not change while checking generation.")
344+
public static void maybeRegisterVirtualThread(long tid) {
345+
getThreadRepo().registerThread(tid);
346+
}
347+
341348
/**
342349
* See {@link JVM#storeMetadataDescriptor}.
343350
*/

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/ExecutionSampleEvent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public static void writeExecutionSample(long elapsedTicks, long threadId, long s
4141

4242
JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.ExecutionSample);
4343
JfrNativeEventWriter.putLong(data, elapsedTicks);
44-
JfrNativeEventWriter.putLong(data, threadId);
44+
JfrNativeEventWriter.putThread(data, threadId);
4545
JfrNativeEventWriter.putLong(data, stackTraceId);
4646
JfrNativeEventWriter.putLong(data, threadState);
4747
JfrNativeEventWriter.endSmallEvent(data);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorWaitEvent.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@
4040
import jdk.graal.compiler.word.Word;
4141

4242
public class JavaMonitorWaitEvent {
43-
public static void emit(long startTicks, Object obj, long notifier, long timeout, boolean timedOut) {
43+
public static void emit(long startTicks, Object obj, Thread notifier, long timeout, boolean timedOut) {
4444
if (HasJfrSupport.get() && obj != null && !Target_jdk_jfr_internal_JVM_ChunkRotationMonitor.class.equals(obj.getClass()) &&
4545
!Target_jdk_jfr_internal_management_HiddenWait.class.equals(obj.getClass())) {
4646
emit0(startTicks, obj, notifier, timeout, timedOut);
4747
}
4848
}
4949

5050
@Uninterruptible(reason = "Accesses a JFR buffer.")
51-
private static void emit0(long startTicks, Object obj, long notifier, long timeout, boolean timedOut) {
51+
private static void emit0(long startTicks, Object obj, Thread notifier, long timeout, boolean timedOut) {
5252
long duration = JfrTicks.duration(startTicks);
5353
if (JfrEvent.JavaMonitorWait.shouldEmit(duration)) {
5454
JfrNativeEventWriterData data = org.graalvm.nativeimage.StackValue.get(JfrNativeEventWriterData.class);
@@ -60,7 +60,7 @@ private static void emit0(long startTicks, Object obj, long notifier, long timeo
6060
JfrNativeEventWriter.putEventThread(data);
6161
JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.JavaMonitorWait, 0));
6262
JfrNativeEventWriter.putClass(data, obj.getClass());
63-
JfrNativeEventWriter.putLong(data, notifier);
63+
JfrNativeEventWriter.putThread(data, notifier);
6464
JfrNativeEventWriter.putLong(data, timeout);
6565
JfrNativeEventWriter.putBoolean(data, timedOut);
6666
JfrNativeEventWriter.putLong(data, Word.objectToUntrackedPointer(obj).rawValue());

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/ThreadStartEvent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public static void emit(Thread thread) {
4747
JfrNativeEventWriter.putEventThread(data);
4848
JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.ThreadStart, 0));
4949
JfrNativeEventWriter.putThread(data, thread);
50-
JfrNativeEventWriter.putLong(data, JavaThreads.getParentThreadId(thread));
50+
JfrNativeEventWriter.putThread(data, JavaThreads.getParentThreadId(thread));
5151
JfrNativeEventWriter.endSmallEvent(data);
5252
}
5353
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232

3333
import com.oracle.svm.core.Uninterruptible;
3434
import com.oracle.svm.core.jfr.JfrTicks;
35-
import com.oracle.svm.core.jfr.SubstrateJVM;
3635
import com.oracle.svm.core.jfr.events.JavaMonitorWaitEvent;
3736
import com.oracle.svm.core.thread.JavaThreads;
3837
import com.oracle.svm.core.util.BasedOnJDKClass;
@@ -120,7 +119,7 @@ static final class ExclusiveNode extends Node {
120119
@BasedOnJDKClass(value = AbstractQueuedLongSynchronizer.class, innerClass = "ConditionNode")
121120
static final class ConditionNode extends Node {
122121
ConditionNode nextWaiter;
123-
long notifierJfrTid;
122+
Thread notifierJfr;
124123

125124
// see AbstractQueuedLongSynchronizer.ConditionNode.isReleasable()
126125
public boolean isReleasable() {
@@ -457,7 +456,7 @@ private void doSignal(ConditionNode first, boolean all) {
457456
first.nextWaiter = null; // GC assistance
458457
}
459458
if ((first.getAndUnsetStatus(COND) & COND) != 0) {
460-
first.notifierJfrTid = SubstrateJVM.getCurrentThreadId();
459+
first.notifierJfr = Thread.currentThread();
461460
enqueue(first);
462461
if (!all) {
463462
break;
@@ -564,7 +563,7 @@ private ConditionNode newConditionNode() {
564563
public void await(Object obj) throws InterruptedException {
565564
long startTicks = JfrTicks.elapsedTicks();
566565
if (Thread.interrupted()) {
567-
JavaMonitorWaitEvent.emit(startTicks, obj, 0, 0L, false);
566+
JavaMonitorWaitEvent.emit(startTicks, obj, null, 0L, false);
568567
throw new InterruptedException();
569568
}
570569
ConditionNode node = newConditionNode();
@@ -587,7 +586,7 @@ public void await(Object obj) throws InterruptedException {
587586
}
588587
node.clearStatus();
589588
// waiting is done, emit wait event
590-
JavaMonitorWaitEvent.emit(startTicks, obj, node.notifierJfrTid, 0L, false);
589+
JavaMonitorWaitEvent.emit(startTicks, obj, node.notifierJfr, 0L, false);
591590
acquire(node, savedAcquisitions);
592591
if (interrupted) {
593592
if (cancelled) {
@@ -604,7 +603,7 @@ public boolean await(Object obj, long time, TimeUnit unit) throws InterruptedExc
604603
long startTicks = JfrTicks.elapsedTicks();
605604
long nanosTimeout = unit.toNanos(time);
606605
if (Thread.interrupted()) {
607-
JavaMonitorWaitEvent.emit(startTicks, obj, 0, 0L, false);
606+
JavaMonitorWaitEvent.emit(startTicks, obj, null, 0L, false);
608607
throw new InterruptedException();
609608
}
610609
ConditionNode node = newConditionNode();
@@ -627,7 +626,7 @@ public boolean await(Object obj, long time, TimeUnit unit) throws InterruptedExc
627626
}
628627
node.clearStatus();
629628
// waiting is done, emit wait event
630-
JavaMonitorWaitEvent.emit(startTicks, obj, node.notifierJfrTid, time, cancelled);
629+
JavaMonitorWaitEvent.emit(startTicks, obj, node.notifierJfr, time, cancelled);
631630
acquire(node, savedAcquisitions);
632631
if (cancelled) {
633632
unlinkCancelledWaiters(node);

0 commit comments

Comments
 (0)