Skip to content

Commit 515532b

Browse files
committed
GH-501 logical value for java.lang.VirtualThread added
1 parent 25a5992 commit 515532b

File tree

1 file changed

+119
-2
lines changed

1 file changed

+119
-2
lines changed

visualvm/libs.profiler/profiler.heapwalker/src/org/graalvm/visualvm/lib/profiler/heapwalk/details/jdk/ThreadDetailsProvider.java

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package org.graalvm.visualvm.lib.profiler.heapwalk.details.jdk;
2626

27+
import java.util.Locale;
2728
import org.graalvm.visualvm.lib.jfluid.heap.Instance;
2829
import org.graalvm.visualvm.lib.profiler.heapwalk.details.spi.DetailsProvider;
2930
import org.graalvm.visualvm.lib.profiler.heapwalk.details.spi.DetailsUtils;
@@ -32,16 +33,132 @@
3233
/**
3334
*
3435
* @author Jiri Sedlacek
36+
* @author Tomas Hurka
3537
*/
3638
@ServiceProvider(service=DetailsProvider.class)
3739
public final class ThreadDetailsProvider extends DetailsProvider.Basic {
40+
private static final String VIRTUAL_THREAD_MASK = "java.lang.VirtualThread"; // NOI18N
3841

3942
public ThreadDetailsProvider() {
40-
super(Thread.class.getName() + "+", ThreadGroup.class.getName() + "+"); // NOI18N
43+
super(Thread.class.getName() + "+", ThreadGroup.class.getName() + "+",
44+
VIRTUAL_THREAD_MASK);
4145
}
4246

4347
public String getDetailsString(String className, Instance instance) {
44-
return DetailsUtils.getInstanceFieldString(instance, "name"); // NOI18N
48+
switch (className) {
49+
case VIRTUAL_THREAD_MASK:
50+
StringBuilder sb = new StringBuilder("[#"); // NOI18N
51+
sb.append(instance.getValueOfField("tid")); // NOI18N
52+
String name = DetailsUtils.getInstanceFieldString(instance, "name"); // NOI18N
53+
if (!name.isEmpty()) {
54+
sb.append(","); // NOI18N
55+
sb.append(name);
56+
}
57+
sb.append("]/"); // NOI18N
58+
Instance carrier = (Instance) instance.getValueOfField("carrierThread"); // NOI18N
59+
if (carrier != null) {
60+
// include the carrier thread state and name when mounted
61+
Instance holder = (Instance) carrier.getValueOfField("holder"); // NOI18N
62+
Integer threadStatus = (Integer)holder.getValueOfField("threadStatus"); // NOI18N
63+
String stateAsString = toThreadState(threadStatus.intValue()).toString();
64+
sb.append(stateAsString.toLowerCase(Locale.ROOT));
65+
sb.append('@');
66+
sb.append(DetailsUtils.getInstanceString(carrier));
67+
}
68+
// include virtual thread state when not mounted
69+
if (carrier == null) {
70+
String stateAsString = getThreadState(instance);
71+
sb.append(stateAsString.toLowerCase(Locale.ROOT));
72+
}
73+
return sb.toString();
74+
default:
75+
return DetailsUtils.getInstanceFieldString(instance, "name"); // NOI18N
76+
}
4577
}
4678

79+
/** taken from sun.misc.VM
80+
*
81+
* Returns Thread.State for the given threadStatus
82+
*/
83+
public static Thread.State toThreadState(int threadStatus) {
84+
if ((threadStatus & JVMTI_THREAD_STATE_RUNNABLE) != 0) {
85+
return Thread.State.RUNNABLE;
86+
} else if ((threadStatus & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) != 0) {
87+
return Thread.State.BLOCKED;
88+
} else if ((threadStatus & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) != 0) {
89+
return Thread.State.WAITING;
90+
} else if ((threadStatus & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) != 0) {
91+
return Thread.State.TIMED_WAITING;
92+
} else if ((threadStatus & JVMTI_THREAD_STATE_TERMINATED) != 0) {
93+
return Thread.State.TERMINATED;
94+
} else if ((threadStatus & JVMTI_THREAD_STATE_ALIVE) == 0) {
95+
return Thread.State.NEW;
96+
} else {
97+
return Thread.State.RUNNABLE;
98+
}
99+
}
100+
101+
/* The threadStatus field is set by the VM at state transition
102+
* in the hotspot implementation. Its value is set according to
103+
* the JVM TI specification GetThreadState function.
104+
*/
105+
private final static int JVMTI_THREAD_STATE_ALIVE = 0x0001;
106+
private final static int JVMTI_THREAD_STATE_TERMINATED = 0x0002;
107+
private final static int JVMTI_THREAD_STATE_RUNNABLE = 0x0004;
108+
private final static int JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER = 0x0400;
109+
private final static int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010;
110+
private final static int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020;
111+
112+
private String getThreadState(Instance virtualThread) {
113+
Integer state = (Integer)virtualThread.getValueOfField("state");
114+
switch (state) {
115+
case NEW: return "new"; // NOI18N
116+
case STARTED: return "started"; //NOI18N
117+
case RUNNABLE: return "runnable"; // runnable-unmounted
118+
case RUNNING: return "running"; // runnable-mounted
119+
case PARKING: return "parking";
120+
case PARKED: return "parked"; // unmounted
121+
case PINNED: return "pinned"; // mounted
122+
case YIELDING: return "yelding"; // Thread.yield
123+
case TERMINATED: return "terminated"; // final state
124+
default: return "unknown"; // NOI18N
125+
}
126+
}
127+
128+
/*
129+
* Virtual thread state and transitions:
130+
*
131+
* NEW -> STARTED // Thread.start
132+
* STARTED -> TERMINATED // failed to start
133+
* STARTED -> RUNNING // first run
134+
*
135+
* RUNNING -> PARKING // Thread attempts to park
136+
* PARKING -> PARKED // cont.yield successful, thread is parked
137+
* PARKING -> PINNED // cont.yield failed, thread is pinned
138+
*
139+
* PARKED -> RUNNABLE // unpark or interrupted
140+
* PINNED -> RUNNABLE // unpark or interrupted
141+
*
142+
* RUNNABLE -> RUNNING // continue execution
143+
*
144+
* RUNNING -> YIELDING // Thread.yield
145+
* YIELDING -> RUNNABLE // yield successful
146+
* YIELDING -> RUNNING // yield failed
147+
*
148+
* RUNNING -> TERMINATED // done
149+
*/
150+
private static final int NEW = 0;
151+
private static final int STARTED = 1;
152+
private static final int RUNNABLE = 2; // runnable-unmounted
153+
private static final int RUNNING = 3; // runnable-mounted
154+
private static final int PARKING = 4;
155+
private static final int PARKED = 5; // unmounted
156+
private static final int PINNED = 6; // mounted
157+
private static final int YIELDING = 7; // Thread.yield
158+
private static final int TERMINATED = 99; // final state
159+
160+
// can be suspended from scheduling when unmounted
161+
private static final int SUSPENDED = 1 << 8;
162+
private static final int RUNNABLE_SUSPENDED = (RUNNABLE | SUSPENDED);
163+
private static final int PARKED_SUSPENDED = (PARKED | SUSPENDED);
47164
}

0 commit comments

Comments
 (0)