mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
IDEA-384931 [debugger]: Collect the hierarchy of thread containers for virtual threads
GitOrigin-RevId: ea0c34a1f0f0718e0dc534ab738adbbdb308cb17
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1ae9e16a76
commit
0cc3449b3a
+5
-1
@@ -217,7 +217,11 @@ private fun dumpItemDtos(allDumpItems: List<DumpItem>, maxItems: Int): ThreadDum
|
||||
isDeadLocked = it.isDeadLocked,
|
||||
stackTraceIndex = stackTraceIndex,
|
||||
iconToolTipIndex = iconToolTipToIndex[it.iconToolTip]!!.toByte(),
|
||||
firstLine = firstLine)
|
||||
firstLine = firstLine,
|
||||
isContainer = it.isContainer,
|
||||
id = it.id,
|
||||
parentId = it.parentId,
|
||||
)
|
||||
}
|
||||
|
||||
return ThreadDumpWithAwaitingDependencies(items = items,
|
||||
|
||||
@@ -73,7 +73,7 @@ class ThreadDumpAction {
|
||||
@JvmStatic
|
||||
fun buildThreadStates(vmProxy: VirtualMachineProxyImpl): List<ThreadState> {
|
||||
val platformThreads = vmProxy.virtualMachine.allThreads()
|
||||
return buildThreadStates(vmProxy, platformThreads, virtualThreads = emptyList())
|
||||
return buildThreadStates(vmProxy, platformThreads, virtualThreads = emptyList(), emptyList())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@@ -85,7 +85,7 @@ class ThreadDumpAction {
|
||||
@ApiStatus.Internal
|
||||
suspend fun buildThreadDump(context: DebuggerContextImpl, onlyPlatformThreads: Boolean, dumpItemsChannel: SendChannel<List<MergeableDumpItem>>) {
|
||||
suspend fun sendJavaPlatformThreads() {
|
||||
val platformThreads = buildJavaPlatformThreadDump(context).toDumpItems()
|
||||
val platformThreads = toDumpItems(buildJavaPlatformThreadDump())
|
||||
dumpItemsChannel.send(platformThreads)
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ class ThreadDumpAction {
|
||||
}
|
||||
}
|
||||
|
||||
fun buildJavaPlatformThreadDump(context: DebuggerContextImpl): List<ThreadState> {
|
||||
fun buildJavaPlatformThreadDump(): List<ThreadState> {
|
||||
val vm = VirtualMachineProxyImpl.getCurrent()
|
||||
vm.suspend()
|
||||
try {
|
||||
@@ -315,6 +315,7 @@ private fun buildThreadStates(
|
||||
vmProxy: VirtualMachineProxyImpl,
|
||||
platformThreads: List<ThreadReference>,
|
||||
virtualThreads: List<Triple<ThreadReference, String, Long>>,
|
||||
threadContainerRefs: List<ObjectReference>
|
||||
): List<ThreadState> {
|
||||
|
||||
val result = mutableListOf<ThreadState>()
|
||||
@@ -355,21 +356,23 @@ private fun buildThreadStates(
|
||||
val threadName: String
|
||||
val stateString: String
|
||||
val javaThreadStateString: String
|
||||
val threadContainerId: Long?
|
||||
val isVirtual: Boolean
|
||||
val isDaemon: Boolean
|
||||
val tid: Long?
|
||||
val prio: Int?
|
||||
val rawStackTrace: String
|
||||
if (virtualThreadInfo != null) {
|
||||
val nameStateAndStackTrace = splitFirstTwoAndRemainingLines(virtualThreadInfo.first)
|
||||
val nameRaw = nameStateAndStackTrace.first
|
||||
javaThreadStateString = nameStateAndStackTrace.second
|
||||
rawStackTrace = nameStateAndStackTrace.third
|
||||
val lines = virtualThreadInfo.first.lineSequence()
|
||||
val (nameRaw, javaThreadState, threadContainerIdx) = lines.take(3).toList()
|
||||
rawStackTrace = lines.drop(3).joinToString("\n")
|
||||
|
||||
if (javaThreadStateString == Thread.State.TERMINATED.name) return
|
||||
if (javaThreadState == Thread.State.TERMINATED.name) return
|
||||
|
||||
threadName = threadName(nameRaw, threadReference)
|
||||
stateString = javaThreadStateToState(javaThreadStateString)
|
||||
stateString = javaThreadStateToState(javaThreadState)
|
||||
javaThreadStateString = javaThreadState
|
||||
threadContainerId = threadContainerRefs[threadContainerIdx.toInt()].uniqueID()
|
||||
|
||||
tid = virtualThreadInfo.second
|
||||
|
||||
@@ -384,6 +387,7 @@ private fun buildThreadStates(
|
||||
threadName = threadName(threadReference)
|
||||
stateString = threadStatusToState(threadStatus)
|
||||
javaThreadStateString = threadStatusToJavaThreadState(threadStatus)
|
||||
threadContainerId = null // thread container is not provided for platform threads for now
|
||||
|
||||
isVirtual = threadReference is ThreadReferenceImpl && threadReference.isVirtual
|
||||
|
||||
@@ -394,9 +398,11 @@ private fun buildThreadStates(
|
||||
prio = getFieldValue(priorityField, threadReference, holderObj)?.let { (it as IntegerValue).intValue() }
|
||||
tid = getFieldValue(tidField, threadReference, holderObj)?.let { (it as LongValue).longValue() }
|
||||
}
|
||||
|
||||
val threadState = ThreadState(threadName, stateString)
|
||||
threadState.javaThreadState = javaThreadStateString
|
||||
threadState.uniqueId = threadReference.uniqueID()
|
||||
threadState.threadContainerUniqueId = threadContainerId
|
||||
|
||||
nameToThreadMap[threadName] = threadState
|
||||
result += threadState
|
||||
|
||||
@@ -503,6 +509,9 @@ private fun buildThreadStates(
|
||||
processOne(pthread, virtualThreadInfo = null)
|
||||
}
|
||||
|
||||
if (virtualThreads.isNotEmpty()) {
|
||||
require(threadContainerRefs.isNotEmpty()) { "The list of thread container references was not provided for virtual threads." }
|
||||
}
|
||||
virtualThreads.forEach { (vthread, stackTrace, tid) ->
|
||||
processOne(vthread, stackTrace to tid)
|
||||
}
|
||||
@@ -554,13 +563,6 @@ private fun getStackTrace(threadReference: ThreadReference): String {
|
||||
}
|
||||
}
|
||||
|
||||
private fun splitFirstTwoAndRemainingLines(text: String): Triple<String, String, String> {
|
||||
val first = text.lineSequence().first()
|
||||
val second = text.lineSequence().drop(1).first()
|
||||
val remaining = text.lineSequence().drop(2).joinToString("\n")
|
||||
return Triple(first, second, remaining)
|
||||
}
|
||||
|
||||
internal class JavaVirtualThreadsProvider : ThreadDumpItemsProviderFactory() {
|
||||
override fun getProvider(context: DebuggerContextImpl) = object : ThreadDumpItemsProvider {
|
||||
val vm = VirtualMachineProxyImpl.getCurrent()
|
||||
@@ -581,13 +583,12 @@ internal class JavaVirtualThreadsProvider : ThreadDumpItemsProviderFactory() {
|
||||
return (
|
||||
if (!enabled) emptyList()
|
||||
else {
|
||||
val virtualThreads = evaluateAndGetAllVirtualThreads(suspendContext!!)
|
||||
buildThreadStates(vm, platformThreads = emptyList(), virtualThreads).toDumpItems()
|
||||
evaluateAndGetAllVirtualThreadsDumpItems(suspendContext!!)
|
||||
})
|
||||
.also { DebuggerStatistics.logVirtualThreadsDump(context.project, it.size) }
|
||||
}
|
||||
|
||||
private fun evaluateAndGetAllVirtualThreads(suspendContext: SuspendContextImpl): List<Triple<ThreadReference, String, Long>> {
|
||||
private fun evaluateAndGetAllVirtualThreadsDumpItems(suspendContext: SuspendContextImpl): List<MergeableDumpItem> {
|
||||
val evaluationContext = EvaluationContextImpl(suspendContext, suspendContext.frameProxy)
|
||||
|
||||
val lookupImpl = getMethodHandlesImplLookup(evaluationContext)
|
||||
@@ -599,7 +600,7 @@ internal class JavaVirtualThreadsProvider : ThreadDumpItemsProviderFactory() {
|
||||
val evaluated = try {
|
||||
DebuggerUtilsImpl.invokeHelperMethod(
|
||||
evaluationContext,
|
||||
VirtualThreadDumper::class.java, "getAllVirtualThreadsWithStackTraces",
|
||||
VirtualThreadDumper::class.java, "getAllVirtualThreadsWithStackTracesAndContainers",
|
||||
listOf(lookupImpl)
|
||||
)
|
||||
}
|
||||
@@ -609,10 +610,22 @@ internal class JavaVirtualThreadsProvider : ThreadDumpItemsProviderFactory() {
|
||||
}
|
||||
if (evaluated == null) return emptyList()
|
||||
|
||||
val (packedThreadsAndStackTraces, threadIds) = (evaluated as ArrayReference).values.map { (it as ArrayReference).values }
|
||||
val packedThreadsAndStackTraces = ((evaluated as ArrayReference).values[0] as ArrayReference).values
|
||||
val threadIds = (evaluated.values[1] as ArrayReference).values
|
||||
val threadContainerNames = (evaluated.values[2] as ArrayReference).values.map { (it as StringReference).value() }
|
||||
val threadContainerRefs = (evaluated.values[3] as ArrayReference).values.map { it as ObjectReference }
|
||||
val parentContainerOrdinals = (evaluated.values[4] as ArrayReference).values.map { (it as IntegerValue).intValue() }
|
||||
|
||||
require(threadContainerNames.size == threadContainerRefs.size) { "The number of thread container names should be equal the number of thread container references." }
|
||||
require(threadContainerNames.size == parentContainerOrdinals.size) { "The number of thread container names should be equal the number of corresponding parent container ordinals." }
|
||||
|
||||
val threadStates = buildVirtualThreadStates(packedThreadsAndStackTraces, threadIds, threadContainerRefs)
|
||||
return toDumpItems(threadStates, threadContainerNames, threadContainerRefs, parentContainerOrdinals)
|
||||
}
|
||||
|
||||
private fun buildVirtualThreadStates(packedThreadsAndStackTraces: List<Value?>, threadIds: List<Value?>, threadContainerRefs: List<ObjectReference>): List<ThreadState> {
|
||||
ProgressManager.checkCanceled()
|
||||
return buildList {
|
||||
val virtualThreads = buildList {
|
||||
var tidIdx = 0
|
||||
var stIdx = 0
|
||||
while (stIdx < packedThreadsAndStackTraces.size) {
|
||||
@@ -627,6 +640,7 @@ internal class JavaVirtualThreadsProvider : ThreadDumpItemsProviderFactory() {
|
||||
}
|
||||
}
|
||||
}
|
||||
return buildThreadStates(vm, platformThreads = emptyList(), virtualThreads, threadContainerRefs)
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -131,8 +131,14 @@ private class FrontendDumpItem(
|
||||
override val attributes: SimpleTextAttributes get() = attributesCache[itemDto.attributesIndex.toInt().toUInt().toInt()]
|
||||
override val isDeadLocked: Boolean get() = itemDto.isDeadLocked
|
||||
override val awaitingDumpItems: Set<DumpItem> get() = internalAwaitingItems
|
||||
override val isContainer: Boolean get() = itemDto.isContainer
|
||||
override val id: Long get() = itemDto.id
|
||||
override val parentId: Long? get() = itemDto.parentId
|
||||
|
||||
fun setAwaitingItems(items: Set<DumpItem>) {
|
||||
internalAwaitingItems = items
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
"FrontendDumpItem(name=$name)"
|
||||
}
|
||||
|
||||
+3
@@ -87,4 +87,7 @@ data class JavaThreadDumpItemDto(
|
||||
val iconIndex: Byte,
|
||||
val attributesIndex: Byte,
|
||||
val isDeadLocked: Boolean,
|
||||
val isContainer: Boolean,
|
||||
val id: Long,
|
||||
val parentId: Long?,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user