diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index bc70088d6ab..be6f1451e36 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -450,6 +450,16 @@ static void validate_thread_id_array(typeArrayHandle ids_ah, TRAPS) { } } +// Returns true if the JavaThread's Java object is a platform thread +static bool is_platform_thread(JavaThread* jt) { + if (jt != nullptr) { + oop thread_obj = jt->threadObj(); + return (thread_obj != nullptr) && !thread_obj->is_a(vmClasses::BoundVirtualThread_klass()); + } else { + return false; + } +} + #if INCLUDE_MANAGEMENT static void validate_thread_info_array(objArrayHandle infoArray_h, TRAPS) { @@ -462,6 +472,11 @@ static void validate_thread_info_array(objArrayHandle infoArray_h, TRAPS) { } } +// Returns true if the ThreadSnapshot's Java object is a platform thread +static bool is_platform_thread(ThreadSnapshot* ts) { + oop thread_obj = ts->threadObj(); + return (thread_obj != nullptr) && !thread_obj->is_a(vmClasses::BoundVirtualThread_klass()); +} static MemoryManager* get_memory_manager_from_jobject(jobject obj, TRAPS) { if (obj == nullptr) { @@ -1044,7 +1059,7 @@ static void do_thread_dump(ThreadDumpResult* dump_result, for (int i = 0; i < num_threads; i++) { jlong tid = ids_ah->long_at(i); JavaThread* jt = tlh.list()->find_JavaThread_from_java_tid(tid); - oop thread_obj = (jt != nullptr ? jt->threadObj() : (oop)nullptr); + oop thread_obj = is_platform_thread(jt) ? jt->threadObj() : (oop)nullptr; instanceHandle threadObj_h(THREAD, (instanceOop) thread_obj); thread_handle_array->append(threadObj_h); } @@ -1145,8 +1160,8 @@ JVM_ENTRY(jint, jmm_GetThreadInfo(JNIEnv *env, jlongArray ids, jint maxDepth, jo // For each thread, create an java/lang/management/ThreadInfo object // and fill with the thread information - if (ts->threadObj() == nullptr) { - // if the thread does not exist or now it is terminated, set threadinfo to null + if (!is_platform_thread(ts)) { + // if the thread does not exist, has terminated, or is a virtual thread, then set threadinfo to null infoArray_h->obj_at_put(index, nullptr); continue; } @@ -1211,8 +1226,8 @@ JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboo int index = 0; for (ThreadSnapshot* ts = dump_result.snapshots(); ts != nullptr; ts = ts->next(), index++) { - if (ts->threadObj() == nullptr) { - // if the thread does not exist or now it is terminated, set threadinfo to null + if (!is_platform_thread(ts)) { + // if the thread does not exist, has terminated, or is a virtual thread, then set threadinfo to null result_h->obj_at_put(index, nullptr); continue; } @@ -1408,7 +1423,7 @@ JVM_ENTRY(jlong, jmm_GetThreadCpuTime(JNIEnv *env, jlong thread_id)) } else { ThreadsListHandle tlh; java_thread = tlh.list()->find_JavaThread_from_java_tid(thread_id); - if (java_thread != nullptr) { + if (is_platform_thread(java_thread)) { return os::thread_cpu_time((Thread*) java_thread); } } @@ -2101,8 +2116,7 @@ JVM_ENTRY(jlong, jmm_GetOneThreadAllocatedMemory(JNIEnv *env, jlong thread_id)) ThreadsListHandle tlh; JavaThread* java_thread = tlh.list()->find_JavaThread_from_java_tid(thread_id); - - if (java_thread != nullptr) { + if (is_platform_thread(java_thread)) { return java_thread->cooked_allocated_bytes(); } return -1; @@ -2141,7 +2155,7 @@ JVM_ENTRY(void, jmm_GetThreadAllocatedMemory(JNIEnv *env, jlongArray ids, ThreadsListHandle tlh; for (int i = 0; i < num_threads; i++) { JavaThread* java_thread = tlh.list()->find_JavaThread_from_java_tid(ids_ah->long_at(i)); - if (java_thread != nullptr) { + if (is_platform_thread(java_thread)) { sizeArray_h->long_at_put(i, java_thread->cooked_allocated_bytes()); } } @@ -2169,11 +2183,8 @@ JVM_ENTRY(jlong, jmm_GetThreadCpuTimeWithKind(JNIEnv *env, jlong thread_id, jboo } else { ThreadsListHandle tlh; java_thread = tlh.list()->find_JavaThread_from_java_tid(thread_id); - if (java_thread != nullptr) { - oop thread_obj = java_thread->threadObj(); - if (thread_obj != nullptr && !thread_obj->is_a(vmClasses::BaseVirtualThread_klass())) { - return os::thread_cpu_time((Thread*) java_thread, user_sys_cpu_time != 0); - } + if (is_platform_thread(java_thread)) { + return os::thread_cpu_time((Thread*) java_thread, user_sys_cpu_time != 0); } } return -1; @@ -2215,7 +2226,7 @@ JVM_ENTRY(void, jmm_GetThreadCpuTimesWithKind(JNIEnv *env, jlongArray ids, ThreadsListHandle tlh; for (int i = 0; i < num_threads; i++) { JavaThread* java_thread = tlh.list()->find_JavaThread_from_java_tid(ids_ah->long_at(i)); - if (java_thread != nullptr) { + if (is_platform_thread(java_thread)) { timeArray_h->long_at_put(i, os::thread_cpu_time((Thread*)java_thread, user_sys_cpu_time != 0)); } diff --git a/src/java.management/share/classes/java/lang/management/ThreadInfo.java b/src/java.management/share/classes/java/lang/management/ThreadInfo.java index 0038d2a1c29..9701e1ae0d8 100644 --- a/src/java.management/share/classes/java/lang/management/ThreadInfo.java +++ b/src/java.management/share/classes/java/lang/management/ThreadInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,7 +92,6 @@ import sun.management.ThreadInfoCompositeData; */ public class ThreadInfo { - private boolean virtual; // accessed by ThreadImpl private String threadName; private long threadId; private long blockedTime; @@ -224,7 +223,6 @@ public class ThreadInfo { StackTraceElement[] stackTrace, MonitorInfo[] lockedMonitors, LockInfo[] lockedSynchronizers) { - this.virtual = t.isVirtual(); this.threadId = t.threadId(); this.threadName = t.getName(); this.threadState = ManagementFactoryHelper.toThreadState(state); diff --git a/src/java.management/share/classes/java/lang/management/ThreadMXBean.java b/src/java.management/share/classes/java/lang/management/ThreadMXBean.java index 0fdfb9573fc..52437adc6b3 100644 --- a/src/java.management/share/classes/java/lang/management/ThreadMXBean.java +++ b/src/java.management/share/classes/java/lang/management/ThreadMXBean.java @@ -65,17 +65,16 @@ import java.util.Map; * of thread IDs as the input parameter and return per-thread information. * *
* The {@link #isThreadCpuTimeSupported} method can be used to determine * if a Java virtual machine supports measuring of the CPU time for any - * thread. The {@link #isCurrentThreadCpuTimeSupported} method can - * be used to determine if a Java virtual machine supports measuring of - * the CPU time for the current thread. - * A Java virtual machine implementation that supports CPU time measurement - * for any thread will also support that for the current thread. + * platform thread. The {@link #isCurrentThreadCpuTimeSupported()} method + * can be used to determine if a Java virtual machine supports measuring of + * the CPU time with the {@link #getCurrentThreadCpuTime()} and + * {@link #getCurrentThreadUserTime()} methods from a platform thread. * *
The CPU time provided by this interface has nanosecond precision
* but not necessarily nanosecond accuracy.
@@ -411,8 +410,9 @@ public interface ThreadMXBean extends PlatformManagedObject {
* {@link #getThreadCpuTime getThreadCpuTime}(Thread.currentThread().threadId());
*
*
- * @return the total CPU time for the current thread if CPU time
- * measurement is enabled; {@code -1} otherwise.
+ * @return the total CPU time for the current thread if the current
+ * thread is a platform thread and if CPU time measurement is enabled;
+ * {@code -1} otherwise.
*
* @throws UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for
@@ -438,8 +438,9 @@ public interface ThreadMXBean extends PlatformManagedObject {
* {@link #getThreadUserTime getThreadUserTime}(Thread.currentThread().threadId());
*
*
- * @return the user-level CPU time for the current thread if CPU time
- * measurement is enabled; {@code -1} otherwise.
+ * @return the user-level CPU time for the current thread if the current
+ * thread is a platform thread and if CPU time measurement is enabled;
+ * {@code -1} otherwise.
*
* @throws UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for
@@ -472,8 +473,8 @@ public interface ThreadMXBean extends PlatformManagedObject {
* where CPU time measurement starts.
*
* @param id the thread ID of a thread
- * @return the total CPU time for a thread of the specified ID
- * if the thread of the specified ID exists, the thread is alive,
+ * @return the total CPU time for a thread of the specified ID if the
+ * thread of the specified ID is a platform thread, the thread is alive,
* and CPU time measurement is enabled;
* {@code -1} otherwise.
*
@@ -507,8 +508,8 @@ public interface ThreadMXBean extends PlatformManagedObject {
* where CPU time measurement starts.
*
* @param id the thread ID of a thread
- * @return the user-level CPU time for a thread of the specified ID
- * if the thread of the specified ID exists, the thread is alive,
+ * @return the user-level CPU time for a thread of the specified ID if the
+ * thread of the specified ID is a platform thread, the thread is alive,
* and CPU time measurement is enabled;
* {@code -1} otherwise.
*
@@ -526,29 +527,31 @@ public interface ThreadMXBean extends PlatformManagedObject {
/**
* Tests if the Java virtual machine implementation supports CPU time
- * measurement for any thread.
+ * measurement for any platform thread.
* A Java virtual machine implementation that supports CPU time
- * measurement for any thread will also support CPU time
- * measurement for the current thread.
+ * measurement for any platform thread will also support CPU time
+ * measurement for the current thread, when the current thread is a
+ * platform thread.
*
* @return
* {@code true}
* if the Java virtual machine supports CPU time
- * measurement for any thread;
+ * measurement for any platform thread;
* {@code false} otherwise.
*/
public boolean isThreadCpuTimeSupported();
/**
- * Tests if the Java virtual machine supports CPU time
- * measurement for the current thread.
+ * Tests if the Java virtual machine supports CPU time measurement from
+ * a platform thread with the {@link #getCurrentThreadCpuTime()} and
+ * {@link #getCurrentThreadUserTime()} methods.
* This method returns {@code true} if {@link #isThreadCpuTimeSupported}
* returns {@code true}.
*
* @return
* {@code true}
- * if the Java virtual machine supports CPU time
- * measurement for current thread;
+ * if the Java virtual machine supports CPU time measurement
+ * of the current platform thread;
* {@code false} otherwise.
*/
public boolean isCurrentThreadCpuTimeSupported();
diff --git a/src/java.management/share/classes/sun/management/ThreadImpl.java b/src/java.management/share/classes/sun/management/ThreadImpl.java
index 90cc8f3d1c4..cd34f4378a5 100644
--- a/src/java.management/share/classes/sun/management/ThreadImpl.java
+++ b/src/java.management/share/classes/sun/management/ThreadImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@ import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.stream.Stream;
import javax.management.ObjectName;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -130,7 +131,7 @@ public class ThreadImpl implements ThreadMXBean {
public long[] getAllThreadIds() {
Util.checkMonitorAccess();
Thread[] threads = getThreads();
- return platformThreadIds(threads);
+ return threadIds(threads);
}
@Override
@@ -141,12 +142,7 @@ public class ThreadImpl implements ThreadMXBean {
@Override
public ThreadInfo getThreadInfo(long id, int maxDepth) {
long[] ids = new long[] { id };
- ThreadInfo ti = getThreadInfo(ids, maxDepth)[0];
- if (ti == null || Util.isVirtual(ti)) {
- return null;
- } else {
- return ti;
- }
+ return getThreadInfo(ids, maxDepth)[0];
}
@Override
@@ -190,7 +186,6 @@ public class ThreadImpl implements ThreadMXBean {
} else {
getThreadInfo1(ids, maxDepth, infos);
}
- nullVirtualThreads(infos);
return infos;
}
@@ -220,10 +215,6 @@ public class ThreadImpl implements ThreadMXBean {
}
private boolean verifyCurrentThreadCpuTime() {
- // check if Thread CPU time measurement is supported.
- if (Thread.currentThread().isVirtual()) {
- throw new UnsupportedOperationException("Not supported by virtual threads");
- }
if (!isCurrentThreadCpuTimeSupported()) {
throw new UnsupportedOperationException(
"Current thread CPU time measurement is not supported.");
@@ -233,7 +224,7 @@ public class ThreadImpl implements ThreadMXBean {
@Override
public long getCurrentThreadCpuTime() {
- if (verifyCurrentThreadCpuTime()) {
+ if (verifyCurrentThreadCpuTime() && !Thread.currentThread().isVirtual()) {
return getThreadTotalCpuTime0(0);
}
return -1;
@@ -283,11 +274,7 @@ public class ThreadImpl implements ThreadMXBean {
long id = ids[0];
Thread thread = Thread.currentThread();
if (id == thread.threadId()) {
- if (thread.isVirtual()) {
- times[0] = -1;
- } else {
- times[0] = getThreadTotalCpuTime0(0);
- }
+ times[0] = thread.isVirtual() ? -1L : getThreadTotalCpuTime0(0);
} else {
times[0] = getThreadTotalCpuTime0(id);
}
@@ -300,7 +287,7 @@ public class ThreadImpl implements ThreadMXBean {
@Override
public long getCurrentThreadUserTime() {
- if (verifyCurrentThreadCpuTime()) {
+ if (verifyCurrentThreadCpuTime() && !Thread.currentThread().isVirtual()) {
return getThreadUserCpuTime0(0);
}
return -1;
@@ -326,11 +313,7 @@ public class ThreadImpl implements ThreadMXBean {
long id = ids[0];
Thread thread = Thread.currentThread();
if (id == thread.threadId()) {
- if (thread.isVirtual()) {
- times[0] = -1;
- } else {
- times[0] = getThreadUserCpuTime0(0);
- }
+ times[0] = thread.isVirtual() ? -1L : getThreadTotalCpuTime0(0);
} else {
times[0] = getThreadUserCpuTime0(id);
}
@@ -376,11 +359,7 @@ public class ThreadImpl implements ThreadMXBean {
if (verified) {
Thread thread = Thread.currentThread();
if (id == thread.threadId()) {
- if (thread.isVirtual()) {
- return -1L;
- } else {
- return getThreadAllocatedMemory0(0);
- }
+ return thread.isVirtual() ? -1L : getThreadAllocatedMemory0(0);
} else {
return getThreadAllocatedMemory0(id);
}
@@ -431,19 +410,16 @@ public class ThreadImpl implements ThreadMXBean {
* of threads is empty.
*/
private long[] threadsToIds(Thread[] threads) {
- if (threads != null) {
- long[] tids = platformThreadIds(threads);
- if (tids.length > 0) {
- return tids;
- }
+ if (threads != null && threads.length > 0) {
+ return threadIds(threads);
+ } else {
+ return null;
}
- return null;
}
@Override
public long[] findMonitorDeadlockedThreads() {
Util.checkMonitorAccess();
-
Thread[] threads = findMonitorDeadlockedThreads0();
return threadsToIds(threads);
}
@@ -496,12 +472,10 @@ public class ThreadImpl implements ThreadMXBean {
public ThreadInfo[] getThreadInfo(long[] ids,
boolean lockedMonitors,
boolean lockedSynchronizers) {
- ThreadInfo[] infos = dumpThreads0(ids, lockedMonitors, lockedSynchronizers,
- Integer.MAX_VALUE);
- nullVirtualThreads(infos);
- return infos;
+ return dumpThreads0(ids, lockedMonitors, lockedSynchronizers, Integer.MAX_VALUE);
}
+ @Override
public ThreadInfo[] getThreadInfo(long[] ids,
boolean lockedMonitors,
boolean lockedSynchronizers,
@@ -516,19 +490,16 @@ public class ThreadImpl implements ThreadMXBean {
if (ids.length == 0) return new ThreadInfo[0];
verifyDumpThreads(lockedMonitors, lockedSynchronizers);
- ThreadInfo[] infos = dumpThreads0(ids, lockedMonitors, lockedSynchronizers, maxDepth);
- nullVirtualThreads(infos);
- return infos;
+ return dumpThreads0(ids, lockedMonitors, lockedSynchronizers, maxDepth);
}
@Override
public ThreadInfo[] dumpAllThreads(boolean lockedMonitors,
boolean lockedSynchronizers) {
- ThreadInfo[] infos = dumpAllThreads(lockedMonitors, lockedSynchronizers,
- Integer.MAX_VALUE);
- return platformThreads(infos);
+ return dumpAllThreads(lockedMonitors, lockedSynchronizers, Integer.MAX_VALUE);
}
+ @Override
public ThreadInfo[] dumpAllThreads(boolean lockedMonitors,
boolean lockedSynchronizers,
int maxDepth) {
@@ -538,7 +509,9 @@ public class ThreadImpl implements ThreadMXBean {
}
verifyDumpThreads(lockedMonitors, lockedSynchronizers);
ThreadInfo[] infos = dumpThreads0(null, lockedMonitors, lockedSynchronizers, maxDepth);
- return platformThreads(infos);
+ return Arrays.stream(infos)
+ .filter(ti -> ti != null)
+ .toArray(ThreadInfo[]::new);
}
// VM support where maxDepth == -1 to request entire stack dump
@@ -572,34 +545,11 @@ public class ThreadImpl implements ThreadMXBean {
}
/**
- * Returns the thread identifiers of the platform threads in the given array.
+ * Returns the thread identifiers of the threads in the given array.
*/
- private static long[] platformThreadIds(Thread[] threads) {
+ private static long[] threadIds(Thread[] threads) {
return Stream.of(threads)
- .filter(t -> !t.isVirtual())
.mapToLong(Thread::threadId)
.toArray();
}
-
- /**
- * Returns the ThreadInfo objects from the given array that correspond to platform
- * threads.
- */
- private ThreadInfo[] platformThreads(ThreadInfo[] infos) {
- return Stream.of(infos)
- .filter(ti -> !Util.isVirtual(ti))
- .toArray(ThreadInfo[]::new);
- }
-
- /**
- * Set the elements of the given array to null if they correspond to a virtual thread.
- */
- private static void nullVirtualThreads(ThreadInfo[] infos) {
- for (int i = 0; i < infos.length; i++) {
- ThreadInfo ti = infos[i];
- if (ti != null && Util.isVirtual(ti)) {
- infos[i] = null;
- }
- }
- }
}
diff --git a/src/java.management/share/classes/sun/management/Util.java b/src/java.management/share/classes/sun/management/Util.java
index 80bad1e1523..e5a25792263 100644
--- a/src/java.management/share/classes/sun/management/Util.java
+++ b/src/java.management/share/classes/sun/management/Util.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,17 +25,11 @@
package sun.management;
-import java.lang.reflect.Field;
import java.lang.management.ManagementPermission;
-import java.lang.management.ThreadInfo;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
import java.util.List;
import javax.management.ObjectName;
import javax.management.MalformedObjectNameException;
-
public class Util {
private Util() {} // there are no instances of this class
@@ -86,31 +80,4 @@ public class Util {
public static void checkControlAccess() throws SecurityException {
checkAccess(controlPermission);
}
-
- /**
- * Returns true if the given ThreadInfo is for a virtual thread.
- */
- public static boolean isVirtual(ThreadInfo threadInfo) {
- try {
- return (boolean) THREADINFO_VIRTUAL.get(threadInfo);
- } catch (Exception e) {
- throw new InternalError(e);
- }
- }
-
- @SuppressWarnings("removal")
- private static Field threadInfoVirtual() {
- PrivilegedExceptionAction