9
0
mirror of https://github.com/Dreeam-qwq/Gale.git synced 2025-12-22 00:09:25 +00:00
Files
Gale/patches/server/0148-Watch-for-blocking-base-threads.patch
2023-02-13 20:34:58 +01:00

114 lines
6.3 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martijn Muijsers <martijnmuijsers@live.nl>
Date: Fri, 3 Feb 2023 23:52:49 +0100
Subject: [PATCH] Watch for blocking base threads
License: AGPL-3.0 (https://www.gnu.org/licenses/agpl-3.0.html)
Gale - https://galemc.org
diff --git a/build.gradle.kts b/build.gradle.kts
index 00508c2b7a0aa9ecdd0c8709a559f26de17a0004..e01986477360b1dbe991af6667e726e8ac656246 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -15,6 +15,7 @@ dependencies {
exclude("io.papermc.paper", "paper-api")
}
// Gale end - project setup
+ implementation("io.projectreactor.tools:blockhound:1.0.7.RELEASE") // Gale - base thread pool - watch for blocking base threads
// Paper start
implementation("org.jline:jline-terminal-jansi:3.21.0")
implementation("net.minecrell:terminalconsoleappender:1.3.0")
@@ -169,11 +170,13 @@ fun TaskContainer.registerRunTask(
if (providers.gradleProperty("paper.runDisableWatchdog").getOrElse("false") == "true") {
systemProperty("disable.watchdog", true)
}
+ systemProperty("gale.detect.thread.blocks", true) // Gale - base thread pool - watch for blocking base threads
val memoryGb = providers.gradleProperty("paper.runMemoryGb").getOrElse("2")
val modifiedJvmArgs = jvmArgs ?: arrayListOf()
modifiedJvmArgs.addAll(listOf("-Xms${memoryGb}G", "-Xmx${memoryGb}G"))
modifiedJvmArgs.add("--add-modules=jdk.incubator.vector") // Gale - Pufferfish - SIMD support
+ modifiedJvmArgs.add("-XX:+AllowRedefinitionToAddDeleteMethods") // Gale - base thread pool - watch for blocking base threads
jvmArgs = modifiedJvmArgs
doFirst {
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index fab5d1c1531fa89113bef6d17df8437b0aec4582..95d8715928a0ddccdabcb76090a3b5bdd143c5a5 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -4,18 +4,20 @@ import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
+import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ExceptionCollector;
import net.minecraft.world.level.lighting.LayerLightEventListener;
import net.minecrell.terminalconsole.TerminalConsoleAppender; // Paper
+import org.galemc.gale.executor.thread.BaseThread;
+import org.spigotmc.WatchdogThread;
+import reactor.blockhound.BlockHound;
public class Main {
public static boolean useJline = true;
@@ -48,6 +50,49 @@ public class Main {
// Gale end - include time in startup logs
public static void main(String[] args) {
+ // Gale start - base thread pool - watch for blocking base threads
+ if (Boolean.getBoolean("gale.detect.thread.blocks")) {
+ printlnStartupInfoToSystemOut("Initializing blocking base thread detection...");
+ try {
+ var builder = BlockHound.builder();
+ // Mark base threads as intended to be non-blocking (except the WatchdogThread, which obviously sleeps until needed)
+ builder.nonBlockingThreadPredicate(currentPredicate -> currentPredicate.or(thread -> thread instanceof BaseThread && !(thread instanceof WatchdogThread)));
+ // Set the callback when a base thread blocks
+ builder.blockingMethodCallback(blockingMethod -> {
+ if (MinecraftServer.SERVER == null) {
+ // Allow blocking before the server has finished initializing
+ return;
+ }
+ String message = "A base thread (" + Thread.currentThread() + ") started blocking:";
+ if (MinecraftServer.LOGGER != null) {
+ MinecraftServer.LOGGER.error(message);
+ } else {
+ printlnStartupErrorToSystemOut(message);
+ }
+ new Error(blockingMethod.toString()).printStackTrace();
+ });
+ // Allow busy waiting
+ var blockingMethodsField = builder.getClass().getDeclaredField("blockingMethods");
+ blockingMethodsField.setAccessible(true);
+ Map<String, Map<String, Set<String>>> blockingMethods = (Map<String, Map<String, Set<String>>>) blockingMethodsField.get(builder);
+ Map<String, Set<String>> threadBlockingMethods = blockingMethods.get("java/lang/Thread");
+ threadBlockingMethods.remove("onSpinWait");
+ threadBlockingMethods.remove("yield");
+ // Allow base threads to block in the intended way
+ builder.allowBlockingCallsInside("org.galemc.gale.executor.thread.BaseThread", "waitUntilSignalled");
+ // Allow the ServerThread to block during initialization
+ builder.allowBlockingCallsInside("net.minecraft.server.dedicated.DedicatedServer", "initServer");
+ // Install BlockHound
+ builder.install();
+ printlnStartupInfoToSystemOut("Blocking base thread detection is enabled.");
+ } catch (Exception e) {
+ // BlockHound instrumentation failed, which probably means the needed JVM flag is missing
+ printlnStartupInfoToSystemOut("Blocking base thread detection is disabled.");
+ printlnStartupInfoToSystemOut("When it is enabled, unexpected thread blocks can be automatically resolved to improve performance.");
+ printlnStartupInfoToSystemOut("To enable it, add \"-XX:+AllowRedefinitionToAddDeleteMethods\" to your startup flags, BEFORE the \"-jar\".");
+ }
+ }
+ // Gale end - base thread pool - watch for blocking base threads
// Paper start
final String warnWhenLegacyFormattingDetected = String.join(".", "net", "kyori", "adventure", "text", "warnWhenLegacyFormattingDetected");
if (false && System.getProperty(warnWhenLegacyFormattingDetected) == null) {