freeze dump: print lock details

This way it is clear who is holding the lock and probably causing the thread lock by not unlocking/releasing it again
This commit is contained in:
Moritz Zwerger 2025-02-06 18:43:29 +01:00
parent c1bcfbe982
commit e077192eb2
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
2 changed files with 34 additions and 4 deletions

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
* Copyright (C) 2020-2025 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -14,6 +14,10 @@
package de.bixilon.minosoft.terminal.commands
import de.bixilon.minosoft.commands.nodes.LiteralNode
import de.bixilon.minosoft.data.text.BaseComponent
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.data.text.events.click.OpenFileClickEvent
import de.bixilon.minosoft.data.text.formatting.color.ChatColors
import de.bixilon.minosoft.util.crash.freeze.FreezeDumpUtil
object DumpCommand : Command {
@ -24,7 +28,7 @@ object DumpCommand : Command {
stack.print.print("§4Failed to create freeze dump!")
stack.print.print(it.dump)
} else {
stack.print.print("§4Freeze dump created and saved at §e${it.path}!")
stack.print.print(BaseComponent(TextComponent("Freeze dump created and saved at ").color(ChatColors.DARK_RED), TextComponent(it.path).color(ChatColors.YELLOW).clickEvent(OpenFileClickEvent(it.path))))
}
}
}),

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
* Copyright (C) 2020-2025 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -13,12 +13,16 @@
package de.bixilon.minosoft.util.crash.freeze
import de.bixilon.kutil.concurrent.lock.RWLock
import de.bixilon.kutil.concurrent.lock.locks.reentrant.ReentrantRWLock
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
import de.bixilon.kutil.concurrent.pool.ThreadPool
import de.bixilon.kutil.concurrent.pool.runnable.ThreadPoolRunnable
import de.bixilon.kutil.file.FileUtil.slashPath
import de.bixilon.kutil.reflection.ReflectionUtil.field
import de.bixilon.kutil.reflection.ReflectionUtil.getFieldOrNull
import de.bixilon.kutil.time.TimeUtil
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
import de.bixilon.minosoft.terminal.RunConfiguration
import java.io.FileOutputStream
import java.lang.management.ManagementFactory
@ -49,6 +53,9 @@ object FreezeDumpUtil {
builder.append("-- Pool --")
builder.appendLine()
builder.append(createThreadPoolDump())
builder.append("-- Locks --")
builder.appendLine()
builder.append(createLockDump())
val dump = builder.toString()
@ -77,7 +84,7 @@ object FreezeDumpUtil {
val dump = StringBuffer(System.lineSeparator())
val threadMXBean = ManagementFactory.getThreadMXBean()
for (threadInfo in threadMXBean.dumpAllThreads(true, true)) {
dump.append(threadInfo.toString())
dump.append(threadInfo.toString()) // TODO: threadInfo.toString() is limited to 8 frames!
}
return dump
@ -90,4 +97,23 @@ object FreezeDumpUtil {
return queue.toString()
}
private fun RWLock.owner() = when (this) {
is ReentrantRWLock -> owner()
else -> "unknown"
}
private fun ReentrantRWLock.owner() = this::class.java.getFieldOrNull("lock")?.field?.get<Any>(this).toString()
private fun createLockDump(): String {
val dump = StringBuffer()
for (session in PlaySession.collectSessions()) {
dump.appendLine()
dump.append("#${session.id}\n")
dump.append(" world: ${session.world.lock.owner()}\n")
dump.append(" entities: ${session.world.entities.lock.owner()}\n")
}
return dump.toString()
}
}