From e077192eb2cdae95f8a7d25cd3c0240550a5130b Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Thu, 6 Feb 2025 18:43:29 +0100 Subject: [PATCH] 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 --- .../minosoft/terminal/commands/DumpCommand.kt | 8 +++-- .../util/crash/freeze/FreezeDumpUtil.kt | 30 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/terminal/commands/DumpCommand.kt b/src/main/java/de/bixilon/minosoft/terminal/commands/DumpCommand.kt index 08e4a2206..e65d04728 100644 --- a/src/main/java/de/bixilon/minosoft/terminal/commands/DumpCommand.kt +++ b/src/main/java/de/bixilon/minosoft/terminal/commands/DumpCommand.kt @@ -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)))) } } }), diff --git a/src/main/java/de/bixilon/minosoft/util/crash/freeze/FreezeDumpUtil.kt b/src/main/java/de/bixilon/minosoft/util/crash/freeze/FreezeDumpUtil.kt index 8f2050d01..8e2d3ae4b 100644 --- a/src/main/java/de/bixilon/minosoft/util/crash/freeze/FreezeDumpUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/crash/freeze/FreezeDumpUtil.kt @@ -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(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() + } }