8303242: ThreadMXBean issues with virtual threads
Reviewed-by: mchung, pchilanomate
This commit is contained in:
parent
5b2e2e4695
commit
629a9053f0
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -65,17 +65,16 @@ import java.util.Map;
|
||||
* of thread IDs as the input parameter and return per-thread information.
|
||||
*
|
||||
* <h2>Thread CPU time</h2>
|
||||
* A Java virtual machine implementation may support measuring
|
||||
* the CPU time for the current thread, for any thread, or for no threads.
|
||||
* A Java virtual machine implementation may support measuring the CPU time
|
||||
* for the current platform thread, for any platform thread, or for no threads.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p> 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());
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @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());
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Field> pa = () -> {
|
||||
Field f = ThreadInfo.class.getDeclaredField("virtual");
|
||||
f.setAccessible(true);
|
||||
return f;
|
||||
};
|
||||
try {
|
||||
return AccessController.doPrivileged(pa);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Field THREADINFO_VIRTUAL = threadInfoVirtual();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 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
|
||||
@ -53,9 +53,8 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
|
||||
* @param ids an array of thread IDs.
|
||||
* @return an array of long values, each of which is the amount of CPU
|
||||
* time the thread whose ID is in the corresponding element of the input
|
||||
* array of IDs has used,
|
||||
* if the thread of a specified ID exists, the thread is alive,
|
||||
* and CPU time measurement is enabled;
|
||||
* array of IDs has used, if the thread of a specified ID is a platform
|
||||
* thread, the thread is alive, and CPU time measurement is enabled;
|
||||
* {@code -1} otherwise.
|
||||
*
|
||||
* @throws NullPointerException if {@code ids} is {@code null}
|
||||
@ -87,9 +86,8 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
|
||||
* @param ids an array of thread IDs.
|
||||
* @return an array of long values, each of which is the amount of user
|
||||
* mode CPU time the thread whose ID is in the corresponding element of
|
||||
* the input array of IDs has used,
|
||||
* if the thread of a specified ID exists, the thread is alive,
|
||||
* and CPU time measurement is enabled;
|
||||
* the input array of IDs has used, if the thread of a specified ID is a
|
||||
* platform thread, the thread is alive, and CPU time measurement is enabled;
|
||||
* {@code -1} otherwise.
|
||||
*
|
||||
* @throws NullPointerException if {@code ids} is {@code null}
|
||||
@ -161,10 +159,9 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
|
||||
*
|
||||
* @param id the thread ID of a thread
|
||||
* @return an approximation of the total memory allocated, in bytes, in
|
||||
* heap memory for the thread with the specified ID
|
||||
* if the thread with the specified ID exists, the thread is alive,
|
||||
* and thread memory allocation measurement is enabled;
|
||||
* {@code -1} otherwise.
|
||||
* heap memory for the thread with the specified ID if the thread with the
|
||||
* specified ID is a platform thread, the thread is alive, and thread memory
|
||||
* allocation measurement is enabled; {@code -1} otherwise.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code id} {@code <=} {@code 0}.
|
||||
* @throws UnsupportedOperationException if the Java virtual
|
||||
|
169
test/jdk/com/sun/management/ThreadMXBean/VirtualThreads.java
Normal file
169
test/jdk/com/sun/management/ThreadMXBean/VirtualThreads.java
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test id=default
|
||||
* @bug 8284161 8303242
|
||||
* @summary Test com.sun.management.ThreadMXBean with virtual threads
|
||||
* @enablePreview
|
||||
* @library /test/lib
|
||||
* @run junit/othervm VirtualThreads
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test id=no-vmcontinuations
|
||||
* @requires vm.continuations
|
||||
* @enablePreview
|
||||
* @library /test/lib
|
||||
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations VirtualThreads
|
||||
*/
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import com.sun.management.ThreadMXBean;
|
||||
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assumptions.*;
|
||||
|
||||
public class VirtualThreads {
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean::getCurrentThreadAllocatedBytes() returns -1 when
|
||||
* invoked from a virtual thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetCurrentThreadAllocatedBytes() throws Exception {
|
||||
ThreadMXBean bean = ManagementFactory.getPlatformMXBean(ThreadMXBean.class);
|
||||
assumeTrue(bean.isThreadAllocatedMemorySupported(),
|
||||
"Thread memory allocation measurement not supported");
|
||||
|
||||
VThreadRunner.run(() -> {
|
||||
assertEquals(-1L, bean.getCurrentThreadAllocatedBytes());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadAllocatedBytes(long) returns -1 when invoked
|
||||
* with the thread ID of a virtual thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadAllocatedBytes1() {
|
||||
ThreadMXBean bean = ManagementFactory.getPlatformMXBean(ThreadMXBean.class);
|
||||
assumeTrue(bean.isThreadAllocatedMemorySupported(),
|
||||
"Thread memory allocation measurement not supported");
|
||||
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long allocated = bean.getThreadAllocatedBytes(vthread.threadId());
|
||||
assertEquals(-1L, allocated);
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadAllocatedBytes(long) returns -1 when invoked
|
||||
* by a virtual thread with its own thread id.
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadAllocatedBytes2() throws Exception {
|
||||
ThreadMXBean bean = ManagementFactory.getPlatformMXBean(ThreadMXBean.class);
|
||||
assumeTrue(bean.isThreadAllocatedMemorySupported(),
|
||||
"Thread memory allocation measurement not supported");
|
||||
|
||||
VThreadRunner.run(() -> {
|
||||
long tid = Thread.currentThread().threadId();
|
||||
long allocated = bean.getThreadAllocatedBytes(tid);
|
||||
assertEquals(-1L, allocated);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadAllocatedBytes(long[]) returns -1 for
|
||||
* elements that correspond to a virtual thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadAllocatedBytes3() {
|
||||
ThreadMXBean bean = ManagementFactory.getPlatformMXBean(ThreadMXBean.class);
|
||||
assumeTrue(bean.isThreadAllocatedMemorySupported(),
|
||||
"Thread memory allocation measurement not supported");
|
||||
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long tid0 = Thread.currentThread().threadId();
|
||||
long tid1 = vthread.threadId();
|
||||
long[] tids = new long[] { tid0, tid1 };
|
||||
long[] allocated = bean.getThreadAllocatedBytes(tids);
|
||||
assertTrue(allocated[0] >= 0L);
|
||||
assertEquals(-1L, allocated[1]);
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadCpuTime(long[]) returns -1 for
|
||||
* elements that correspond to a virtual thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadCpuTime() {
|
||||
ThreadMXBean bean = ManagementFactory.getPlatformMXBean(ThreadMXBean.class);
|
||||
assumeTrue(bean.isThreadCpuTimeSupported(), "Thread CPU time measurement not supported");
|
||||
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long tid0 = Thread.currentThread().threadId();
|
||||
long tid1 = vthread.threadId();
|
||||
long[] tids = new long[] { tid0, tid1 };
|
||||
long[] cpuTimes = bean.getThreadCpuTime(tids);
|
||||
assertTrue(cpuTimes[0] >= 0L);
|
||||
assertEquals(-1L, cpuTimes[1]);
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadUserTime(long[])returns -1 for
|
||||
* elements that correspond to a virtual thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadUserTime() {
|
||||
ThreadMXBean bean = ManagementFactory.getPlatformMXBean(ThreadMXBean.class);
|
||||
assumeTrue(bean.isThreadCpuTimeSupported(), "Thread CPU time measurement not supported");
|
||||
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long tid0 = Thread.currentThread().threadId();
|
||||
long tid1 = vthread.threadId();
|
||||
long[] tids = new long[] { tid0, tid1 };
|
||||
long[] userTimes = bean.getThreadUserTime(tids);
|
||||
assertTrue(userTimes[0] >= 0L);
|
||||
assertEquals(-1L, userTimes[1]);
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
}
|
||||
}
|
@ -23,10 +23,11 @@
|
||||
|
||||
/**
|
||||
* @test id=default
|
||||
* @bug 8284161 8290562
|
||||
* @bug 8284161 8290562 8303242
|
||||
* @summary Test java.lang.management.ThreadMXBean with virtual threads
|
||||
* @enablePreview
|
||||
* @modules java.base/java.lang:+open java.management
|
||||
* @library /test/lib
|
||||
* @run junit/othervm VirtualThreads
|
||||
*/
|
||||
|
||||
@ -35,6 +36,7 @@
|
||||
* @requires vm.continuations
|
||||
* @enablePreview
|
||||
* @modules java.base/java.lang:+open java.management
|
||||
* @library /test/lib
|
||||
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations VirtualThreads
|
||||
*/
|
||||
|
||||
@ -45,24 +47,52 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.channels.Selector;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assumptions.*;
|
||||
|
||||
public class VirtualThreads {
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean::getAllThreadsIds does not include thread ids for
|
||||
* virtual threads.
|
||||
* Test that ThreadMXBean.dumpAllThreads does not include virtual threads.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, Integer.MAX_VALUE})
|
||||
void testDumpAllThreads(int maxDepth) {
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
|
||||
ThreadInfo[] infos = bean.dumpAllThreads(false, false, maxDepth);
|
||||
Set<Long> tids = Arrays.stream(infos)
|
||||
.map(ThreadInfo::getThreadId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// current thread should be included
|
||||
assertTrue(tids.contains(Thread.currentThread().threadId()));
|
||||
|
||||
// virtual thread should not be included
|
||||
assertFalse(tids.contains(vthread.threadId()));
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean::getAllThreadsIds does not include virtual threads.
|
||||
*/
|
||||
@Test
|
||||
void testGetAllThreadIds() throws Exception {
|
||||
void testGetAllThreadIds() {
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long[] tids = ManagementFactory.getThreadMXBean().getAllThreadIds();
|
||||
@ -80,39 +110,83 @@ public class VirtualThreads {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadInfo(long) returns null for a virtual thread.
|
||||
* Test that ThreadMXBean.getThreadInfo(long, maxDepth) returns null for a virtual
|
||||
* thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadInfo1() throws Exception {
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, Integer.MAX_VALUE})
|
||||
void testGetThreadInfo1(int maxDepth) {
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long tid = vthread.threadId();
|
||||
ThreadInfo info = ManagementFactory.getThreadMXBean().getThreadInfo(tid);
|
||||
assertTrue(info == null);
|
||||
ThreadInfo info = ManagementFactory.getThreadMXBean().getThreadInfo(tid, maxDepth);
|
||||
assertNull(info);
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadInfo(long) returns null when invoked by a virtual
|
||||
* thread with its own thread id.
|
||||
* Test that ThreadMXBean.getThreadInfo(long, maxDepth) returns null when invoked
|
||||
* by a virtual thread with its own thread id.
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadInfo2() throws Exception {
|
||||
runInVirtualThread(() -> {
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, Integer.MAX_VALUE})
|
||||
void testGetThreadInfo2(int maxDepth) throws Exception {
|
||||
VThreadRunner.run(() -> {
|
||||
long tid = Thread.currentThread().threadId();
|
||||
ThreadInfo info = ManagementFactory.getThreadMXBean().getThreadInfo(tid);
|
||||
assertTrue(info == null);
|
||||
ThreadInfo info = ManagementFactory.getThreadMXBean().getThreadInfo(tid, maxDepth);
|
||||
assertNull(info);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadInfo(long[], maxDepth) returns a null ThreadInfo
|
||||
* for elements that correspond to a virtual thread.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, Integer.MAX_VALUE})
|
||||
void testGetThreadInfo3(int maxDepth) {
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long tid0 = Thread.currentThread().threadId();
|
||||
long tid1 = vthread.threadId();
|
||||
long[] tids = new long[] { tid0, tid1 };
|
||||
ThreadInfo[] infos = ManagementFactory.getThreadMXBean().getThreadInfo(tids, maxDepth);
|
||||
assertEquals(tid0, infos[0].getThreadId());
|
||||
assertNull(infos[1]);
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadInfo(long[], boolean, boolean, maxDepth) returns
|
||||
* a null ThreadInfo for elements that correspond to a virtual thread.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, Integer.MAX_VALUE})
|
||||
void testGetThreadInfo4(int maxDepth) {
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long tid0 = Thread.currentThread().threadId();
|
||||
long tid1 = vthread.threadId();
|
||||
long[] tids = new long[] { tid0, tid1 };
|
||||
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
|
||||
ThreadInfo[] infos = bean.getThreadInfo(tids, false, false, maxDepth);
|
||||
assertEquals(tid0, infos[0].getThreadId());
|
||||
assertNull(infos[1]);
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ThreadMXBean.getThreadInfo(long) with the thread id of a carrier thread.
|
||||
* The stack frames of the virtual thread should not be returned.
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadInfo3() throws Exception {
|
||||
void testGetThreadInfoCarrierThread() throws Exception {
|
||||
assumeTrue(supportsCustomScheduler(), "No support for custom schedulers");
|
||||
try (ExecutorService pool = Executors.newFixedThreadPool(1)) {
|
||||
var carrierRef = new AtomicReference<Thread>();
|
||||
@ -146,40 +220,24 @@ public class VirtualThreads {
|
||||
assertFalse(contains(stack, "java.nio.channels.Selector"));
|
||||
|
||||
// carrier should not be holding any monitors
|
||||
assertTrue(info.getLockedMonitors().length == 0);
|
||||
assertEquals(0, info.getLockedMonitors().length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadInfo(long[]) returns a null ThreadInfo for
|
||||
* elements that correspond to a virtual thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadInfo4() throws Exception {
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long tid0 = Thread.currentThread().threadId();
|
||||
long tid1 = vthread.threadId();
|
||||
long[] tids = new long[] { tid0, tid1 };
|
||||
ThreadInfo[] infos = ManagementFactory.getThreadMXBean().getThreadInfo(tids);
|
||||
assertTrue(infos[0].getThreadId() == tid0);
|
||||
assertTrue(infos[1] == null);
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean.getThreadCpuTime(long) returns -1 for a virtual thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadCpuTime1() {
|
||||
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
|
||||
assumeTrue(bean.isThreadCpuTimeSupported(), "Thread CPU time measurement not supported");
|
||||
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long tid = vthread.threadId();
|
||||
long cpuTime = ManagementFactory.getThreadMXBean().getThreadCpuTime(tid);
|
||||
assertTrue(cpuTime == -1L);
|
||||
long cpuTime = bean.getThreadCpuTime(tid);
|
||||
assertEquals(-1L, cpuTime);
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
@ -191,10 +249,13 @@ public class VirtualThreads {
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadCpuTime2() throws Exception {
|
||||
runInVirtualThread(() -> {
|
||||
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
|
||||
assumeTrue(bean.isThreadCpuTimeSupported(), "Thread CPU time measurement not supported");
|
||||
|
||||
VThreadRunner.run(() -> {
|
||||
long tid = Thread.currentThread().threadId();
|
||||
long cpuTime = ManagementFactory.getThreadMXBean().getThreadCpuTime(tid);
|
||||
assertTrue(cpuTime == -1L);
|
||||
long cpuTime = bean.getThreadCpuTime(tid);
|
||||
assertEquals(-1L, cpuTime);
|
||||
});
|
||||
}
|
||||
|
||||
@ -203,11 +264,14 @@ public class VirtualThreads {
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadUserTime1() {
|
||||
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
|
||||
assumeTrue(bean.isThreadCpuTimeSupported(), "Thread CPU time measurement not supported");
|
||||
|
||||
Thread vthread = Thread.startVirtualThread(LockSupport::park);
|
||||
try {
|
||||
long tid = vthread.threadId();
|
||||
long userTime = ManagementFactory.getThreadMXBean().getThreadUserTime(tid);
|
||||
assertTrue(userTime == -1L);
|
||||
assertEquals(-1L, userTime);
|
||||
} finally {
|
||||
LockSupport.unpark(vthread);
|
||||
}
|
||||
@ -219,73 +283,61 @@ public class VirtualThreads {
|
||||
*/
|
||||
@Test
|
||||
void testGetThreadUserTime2() throws Exception {
|
||||
runInVirtualThread(() -> {
|
||||
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
|
||||
assumeTrue(bean.isThreadCpuTimeSupported(), "Thread CPU time measurement not supported");
|
||||
|
||||
VThreadRunner.run(() -> {
|
||||
long tid = Thread.currentThread().threadId();
|
||||
long userTime = ManagementFactory.getThreadMXBean().getThreadUserTime(tid);
|
||||
assertTrue(userTime == -1L);
|
||||
assertEquals(-1L, userTime);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean::getCurrentThreadCpuTime throws UOE when invoked
|
||||
* on a virtual thread.
|
||||
* Test that ThreadMXBean::isCurrentThreadCpuTimeSupported returns true when
|
||||
* CPU time measurement for the current thread is supported.
|
||||
*/
|
||||
@Test
|
||||
void testIsCurrentThreadCpuTimeSupported() throws Exception {
|
||||
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
|
||||
assumeTrue(bean.isCurrentThreadCpuTimeSupported(),
|
||||
"Thread CPU time measurement for the current thread not supported");
|
||||
|
||||
VThreadRunner.run(() -> {
|
||||
assertTrue(bean.isCurrentThreadCpuTimeSupported());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean::getCurrentThreadCpuTime returns -1 when invoked
|
||||
* from a virtual thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetCurrentThreadCpuTime() throws Exception {
|
||||
runInVirtualThread(() -> {
|
||||
assertThrows(UnsupportedOperationException.class,
|
||||
() -> ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime());
|
||||
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
|
||||
assumeTrue(bean.isCurrentThreadCpuTimeSupported(),
|
||||
"Thread CPU time measurement for the current thread not supported");
|
||||
|
||||
VThreadRunner.run(() -> {
|
||||
assertEquals(-1L, bean.getCurrentThreadCpuTime());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean::getCurrentThreadUserTime throws UOE when
|
||||
* invoked on a virtual thread.
|
||||
* Test that ThreadMXBean::getCurrentThreadUserTime returns -1 when invoked
|
||||
* from a virtual thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetCurrentThreadUserTime() throws Exception {
|
||||
runInVirtualThread(() -> {
|
||||
assertThrows(UnsupportedOperationException.class,
|
||||
() -> ManagementFactory.getThreadMXBean().getCurrentThreadUserTime());
|
||||
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
|
||||
assumeTrue(bean.isCurrentThreadCpuTimeSupported(),
|
||||
"Thread CPU time measurement for the current thread not supported");
|
||||
|
||||
VThreadRunner.run(() -> {
|
||||
assertEquals(-1L, bean.getCurrentThreadUserTime());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ThreadMXBean::getCurrentThreadAllocatedBytes returns -1 when
|
||||
* invoked on a virtual thread.
|
||||
*/
|
||||
@Test
|
||||
void testGetCurrentThreadAllocatedBytes() throws Exception {
|
||||
runInVirtualThread(() -> {
|
||||
long allocated = ManagementFactory.getPlatformMXBean(com.sun.management.ThreadMXBean.class)
|
||||
.getCurrentThreadAllocatedBytes();
|
||||
assertTrue(allocated == -1L);
|
||||
});
|
||||
}
|
||||
|
||||
interface ThrowingRunnable {
|
||||
void run() throws Exception;
|
||||
}
|
||||
|
||||
private static void runInVirtualThread(ThrowingRunnable task) throws Exception {
|
||||
AtomicReference<Exception> exc = new AtomicReference<>();
|
||||
Runnable target = () -> {
|
||||
try {
|
||||
task.run();
|
||||
} catch (Error e) {
|
||||
exc.set(new RuntimeException(e));
|
||||
} catch (Exception e) {
|
||||
exc.set(e);
|
||||
}
|
||||
};
|
||||
Thread thread = Thread.ofVirtual().start(target);
|
||||
thread.join();
|
||||
Exception e = exc.get();
|
||||
if (e != null) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean contains(StackTraceElement[] stack, String className) {
|
||||
return Arrays.stream(stack)
|
||||
.map(StackTraceElement::getClassName)
|
||||
|
Loading…
Reference in New Issue
Block a user