2021-06-11 14:02:28 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 12 Apr 2020 15:50:48 -0400
Subject: [PATCH] Improved Watchdog Support
Forced Watchdog Crash support and Improve Async Shutdown
If the request to shut down the server is received while we are in
a watchdog hang, immediately treat it as a crash and begin the shutdown
process. Shutdown process is now improved to also shutdown cleanly when
not using restart scripts either.
If a server is deadlocked, a server owner can send SIGUP (or any other signal
the JVM understands to shut down as it currently does) and the watchdog
will no longer need to wait until the full timeout, allowing you to trigger
a close process and try to shut the server down gracefully, saving player and
world data.
Previously there was no way to trigger this outside of waiting for a full watchdog
timeout, which may be set to a really long time...
Additionally, fix everything to do with shutting the server down asynchronously.
Previously, nearly everything about the process was fragile and unsafe. Main might
not have actually been frozen, and might still be manipulating state.
Or, some reuest might ask main to do something in the shutdown but main is dead.
Or worse, other things might start closing down items such as the Console or Thread Pool
before we are fully shutdown.
This change tries to resolve all of these issues by moving everything into the stop
method and guaranteeing only one thread is stopping the server.
We then issue Thread Death to the main thread of another thread initiates the stop process.
We have to ensure Thread Death propagates correctly though to stop main completely.
This is to ensure that if main isn't truely stuck, it's not manipulating state we are trying to save.
This also moves all plugins who register "delayed init" tasks to occur just before "Done" so they
are properly accounted for and wont trip watchdog on init.
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
2023-02-13 18:52:27 +01:00
index 6aaed8e8bf8c721fc834da5c76ac72a4c3e92458..4b002e8b75d117b726b0de274a76d3596fce015b 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
@@ -92,7 +92,12 @@ public class Metrics {
* Starts the Scheduler which submits our data every 30 minutes.
*/
private void startSubmitting() {
- final Runnable submitTask = this::submitData;
+ final Runnable submitTask = () -> {
+ if (MinecraftServer.getServer().hasStopped()) {
+ return;
+ }
+ submitData();
+ };
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution of requests on the
// bStats backend. To circumvent this problem, we introduce some randomness into the initial and second delay.
2024-07-29 17:10:53 +02:00
diff --git a/src/main/java/io/papermc/paper/util/LogManagerShutdownThread.java b/src/main/java/io/papermc/paper/util/LogManagerShutdownThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..183e141d0c13190c6905dc4510d891992afef878
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/LogManagerShutdownThread.java
@@ -0,0 +1,26 @@
+package io.papermc.paper.util;
+
+public class LogManagerShutdownThread extends Thread {
+
+ static LogManagerShutdownThread INSTANCE = new LogManagerShutdownThread();
+ public static final void hook() {
+ if (INSTANCE == null) {
+ throw new IllegalStateException("Cannot re-hook after being unhooked");
+ }
+ Runtime.getRuntime().addShutdownHook(INSTANCE);
+ }
+
+ public static final void unhook() {
+ Runtime.getRuntime().removeShutdownHook(INSTANCE);
+ INSTANCE = null;
+ }
+
+ private LogManagerShutdownThread() {
+ super("Log4j2 Shutdown Thread");
+ }
+
+ @Override
+ public void run() {
+ org.apache.logging.log4j.LogManager.shutdown();
+ }
+}
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java
2024-06-17 13:36:43 +02:00
index 589a8bf75be6ccc59f1e5dd5d8d9afed41c4772d..b24265573fdef5d9a964bcd76146f34542c420cf 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/CrashReport.java
+++ b/src/main/java/net/minecraft/CrashReport.java
2024-06-17 13:36:43 +02:00
@@ -237,6 +237,7 @@ public class CrashReport {
2021-06-11 14:02:28 +02:00
}
public static CrashReport forThrowable(Throwable cause, String title) {
+ if (cause instanceof ThreadDeath) com.destroystokyo.paper.util.SneakyThrow.sneaky(cause); // Paper
while (cause instanceof CompletionException && cause.getCause() != null) {
cause = cause.getCause();
}
2024-07-29 17:10:53 +02:00
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
2024-10-26 03:13:48 +02:00
index e114e687f2f4503546687fd6792226a643af8793..90ca25c4aaf92a5639839a7cdaee2ffcdb75efa7 100644
2024-07-29 17:10:53 +02:00
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -77,6 +77,7 @@ public class Main {
@DontObfuscate
public static void main(final OptionSet optionset) { // CraftBukkit - replaces main(String[] astring)
+ io.papermc.paper.util.LogManagerShutdownThread.hook(); // Paper
SharedConstants.tryDetectVersion();
/* CraftBukkit start - Replace everything
OptionParser optionparser = new OptionParser();
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
2024-10-26 03:13:48 +02:00
index 0b095c559c6a95ba2d9d7717d527cc2d8b7b6354..79f3dc4f53dce892c4756b0850352e0ca2eb95a6 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
2024-10-26 03:13:48 +02:00
@@ -318,7 +318,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2021-06-14 03:06:38 +02:00
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
2021-06-11 14:02:28 +02:00
public int autosavePeriod;
2024-06-17 13:36:43 +02:00
// Paper - don't store the vanilla dispatcher
2021-06-11 14:02:28 +02:00
- private boolean forceTicks;
2024-06-17 13:36:43 +02:00
+ public boolean forceTicks; // Paper - Improved watchdog support
2021-06-11 14:02:28 +02:00
// CraftBukkit end
// Spigot start
public static final int TPS = 20;
2024-10-26 03:13:48 +02:00
@@ -330,6 +330,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2024-09-19 16:36:07 +02:00
public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files
2024-01-23 12:06:27 +01:00
public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
2021-06-11 14:02:28 +02:00
+ public volatile Thread shutdownThread; // Paper
+ public volatile boolean abnormalExit = false; // Paper
+
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
AtomicReference<S> atomicreference = new AtomicReference();
2024-07-17 19:24:53 +02:00
Thread thread = new ca.spottedleaf.moonrise.common.util.TickThread(() -> { // Paper - rewrite chunk system
2024-10-26 03:13:48 +02:00
@@ -504,6 +507,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2024-07-29 17:10:53 +02:00
}
*/
// Paper end
+ io.papermc.paper.util.LogManagerShutdownThread.unhook(); // Paper
Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));
// CraftBukkit end
this.paperConfigurations = services.paperConfigurations(); // Paper - add paper configuration files
2024-10-26 03:13:48 +02:00
@@ -1020,6 +1024,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2021-06-11 14:02:28 +02:00
// CraftBukkit start
private boolean hasStopped = false;
2024-01-23 12:06:27 +01:00
private boolean hasLoggedStop = false; // Paper - Debugging
2021-06-11 14:02:28 +02:00
+ public volatile boolean hasFullyShutdown = false; // Paper
private final Object stopLock = new Object();
public final boolean hasStopped() {
2021-06-14 03:06:38 +02:00
synchronized (this.stopLock) {
2024-10-26 03:13:48 +02:00
@@ -1035,6 +1040,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2021-06-14 03:06:38 +02:00
this.hasStopped = true;
2021-06-11 14:02:28 +02:00
}
2024-01-23 12:06:27 +01:00
if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
2021-06-11 14:02:28 +02:00
+ // Paper start - kill main thread, and kill it hard
+ shutdownThread = Thread.currentThread();
+ org.spigotmc.WatchdogThread.doStop(); // Paper
+ // Paper end
// CraftBukkit end
2022-06-08 06:22:42 +02:00
if (this.metricsRecorder.isRecording()) {
this.cancelRecordingMetrics();
2024-10-26 03:13:48 +02:00
@@ -1116,6 +1125,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
ca.spottedleaf.moonrise.common.util.MoonriseCommon.haltExecutors();
2021-06-11 14:02:28 +02:00
}
2024-10-26 03:13:48 +02:00
// Paper end - rewrite chunk system
+ // Paper start - Improved watchdog support - move final shutdown items here
2024-06-17 13:36:43 +02:00
+ Util.shutdownExecutors();
2021-06-11 14:02:28 +02:00
+ try {
+ net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
2024-06-17 13:36:43 +02:00
+ } catch (final Exception ignored) {
2021-06-11 14:02:28 +02:00
+ }
2024-01-23 12:06:27 +01:00
+ io.papermc.paper.log.CustomLogManager.forceReset(); // Paper - Reset loggers after shutdown
2021-06-11 14:02:28 +02:00
+ this.onServerExit();
2024-10-26 03:13:48 +02:00
+ // Paper end - Improved watchdog support - move final shutdown items here
2021-06-11 14:02:28 +02:00
}
public String getLocalIp() {
2024-10-26 03:13:48 +02:00
@@ -1210,6 +1228,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2021-06-11 14:02:28 +02:00
protected void runServer() {
try {
+ long serverStartTime = Util.getNanos(); // Paper
2022-06-08 06:22:42 +02:00
if (!this.initServer()) {
throw new IllegalStateException("Failed to initialize server");
}
2024-10-26 03:13:48 +02:00
@@ -1219,6 +1238,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2023-03-14 20:54:57 +01:00
this.status = this.buildServerStatus();
2021-06-11 14:02:28 +02:00
2022-06-08 06:22:42 +02:00
// Spigot start
2024-07-19 21:36:09 +02:00
+ // Paper start - Improved Watchdog Support
2022-06-08 06:22:42 +02:00
+ LOGGER.info("Running delayed init tasks");
2024-10-26 03:13:48 +02:00
+ this.server.getScheduler().mainThreadHeartbeat(); // run all 1 tick delay tasks during init,
2022-06-08 06:22:42 +02:00
+ // this is going to be the first thing the tick process does anyways, so move done and run it after
+ // everything is init before watchdog tick.
+ // anything at 3+ won't be caught here but also will trip watchdog....
+ // tasks are default scheduled at -1 + delay, and first tick will tick at 1
2024-07-19 00:33:14 +02:00
+ final long actualDoneTimeMs = System.currentTimeMillis() - org.bukkit.craftbukkit.Main.BOOT_TIME.toEpochMilli(); // Paper - Add total time
2024-07-19 21:36:09 +02:00
+ LOGGER.info("Done ({})! For help, type \"help\"", String.format(java.util.Locale.ROOT, "%.3fs", actualDoneTimeMs / 1000.00D)); // Paper - Add total time
+ org.spigotmc.WatchdogThread.tick();
+ // Paper end - Improved Watchdog Support
2022-06-08 06:22:42 +02:00
org.spigotmc.WatchdogThread.hasStarted = true; // Paper
2023-10-27 01:34:58 +02:00
Arrays.fill( this.recentTps, 20 );
2024-01-25 10:54:46 +01:00
// Paper start - further improve server tick loop
2024-10-26 03:13:48 +02:00
@@ -1339,6 +1369,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2023-12-05 23:55:31 +01:00
JvmProfiler.INSTANCE.onServerTick(this.smoothedTickTimeMillis);
2021-06-11 14:02:28 +02:00
}
2024-10-26 03:13:48 +02:00
} catch (Throwable throwable2) {
2021-06-11 14:02:28 +02:00
+ // Paper start
2024-10-26 03:13:48 +02:00
+ if (throwable2 instanceof ThreadDeath) {
+ MinecraftServer.LOGGER.error("Main thread terminated by WatchDog due to hard crash", throwable2);
2021-06-11 14:02:28 +02:00
+ return;
+ }
+ // Paper end
2024-10-26 03:13:48 +02:00
MinecraftServer.LOGGER.error("Encountered an unexpected exception", throwable2);
CrashReport crashreport = MinecraftServer.constructOrExtractCrashReport(throwable2);
2024-01-14 10:46:04 +01:00
2024-10-26 03:13:48 +02:00
@@ -1363,15 +1399,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2022-06-08 06:22:42 +02:00
this.services.profileCache().clearExecutor();
2021-11-24 12:06:34 +01:00
}
2021-06-11 14:02:28 +02:00
- org.spigotmc.WatchdogThread.doStop(); // Spigot
+ //org.spigotmc.WatchdogThread.doStop(); // Spigot // Paper - move into stop
// CraftBukkit start - Restore terminal to original settings
try {
- net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
+ //net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Move into stop
} catch (Exception ignored) {
}
// CraftBukkit end
2024-01-23 12:06:27 +01:00
- io.papermc.paper.log.CustomLogManager.forceReset(); // Paper - Reset loggers after shutdown
2021-06-11 14:02:28 +02:00
- this.onServerExit();
2024-01-23 12:06:27 +01:00
+ //io.papermc.paper.log.CustomLogManager.forceReset(); // Paper - Reset loggers after shutdown
2021-11-24 12:06:34 +01:00
+ //this.onServerExit(); // Paper - moved into stop
2021-06-11 14:02:28 +02:00
}
}
2024-10-26 03:13:48 +02:00
@@ -1502,6 +1538,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2021-06-11 14:02:28 +02:00
@Override
public TickTask wrapRunnable(Runnable runnable) {
+ // Paper start - anything that does try to post to main during watchdog crash, run on watchdog
+ if (this.hasStopped && Thread.currentThread().equals(shutdownThread)) {
+ runnable.run();
+ runnable = () -> {};
+ }
+ // Paper end
return new TickTask(this.tickCount, runnable);
}
2024-10-26 03:13:48 +02:00
@@ -2353,7 +2395,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.resources.managers.updateStaticRegistryTags();
this.resources.managers.getRecipeManager().finalizeRecipeLoading(this.worldData.enabledFeatures());
2024-04-26 17:33:00 +02:00
this.potionBrewing = this.potionBrewing.reload(this.worldData.enabledFeatures()); // Paper - Custom Potion Mixes
2021-06-11 14:02:28 +02:00
- this.getPlayerList().saveAll();
2022-06-16 22:59:53 +02:00
+ // Paper start
+ if (Thread.currentThread() != this.serverThread) {
+ return;
+ }
2024-04-25 13:02:27 +02:00
+ // this.getPlayerList().saveAll(); // Paper - we don't need to save everything, just advancements // TODO Move this to a different patch
2022-06-16 22:59:53 +02:00
+ for (ServerPlayer player : this.getPlayerList().getPlayers()) {
+ player.getAdvancements().save();
+ }
+ // Paper end
2021-06-11 14:02:28 +02:00
this.getPlayerList().reloadResources();
2022-03-01 06:43:03 +01:00
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary());
2022-06-08 06:22:42 +02:00
this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager);
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
2024-10-26 03:13:48 +02:00
index 3ed19896a0e06fe834953e6450f23abdc805a6cc..7a79541db29cc47c844d617fc8a4360f61c73372 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
2024-10-26 03:13:48 +02:00
@@ -327,7 +327,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
2021-06-11 14:02:28 +02:00
long j = Util.getNanos() - i;
String s = String.format(Locale.ROOT, "%.3fs", (double) j / 1.0E9D);
- DedicatedServer.LOGGER.info("Done ({})! For help, type \"help\"", s);
2024-07-19 21:36:09 +02:00
+ DedicatedServer.LOGGER.info("Done preparing level \"{}\" ({})", this.getLevelIdName(), s); // Paper - clarify startup log messages & add total time
2021-06-11 14:02:28 +02:00
if (dedicatedserverproperties.announcePlayerAchievements != null) {
Updated Upstream (Bukkit/CraftBukkit) (#10242)
* Updated Upstream (Bukkit/CraftBukkit)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing
Bukkit Changes:
a6a9d2a4 Remove some old ApiStatus.Experimental annotations
be72314c SPIGOT-7300, PR-829: Add new DamageSource API providing enhanced information about entity damage
b252cf05 SPIGOT-7576, PR-970: Add methods in MushroomCow to change stew effects
b1c689bd PR-902: Add Server#isLoggingIPs to get log-ips configuration
08f86d1c PR-971: Add Player methods for client-side potion effects
2e3024a9 PR-963: Add API for in-world structures
a23292a7 SPIGOT-7530, PR-948: Improve Resource Pack API with new 1.20.3 functionality
1851857b SPIGOT-3071, PR-969: Add entity spawn method with spawn reason
cde4c52a SPIGOT-5553, PR-964: Add EntityKnockbackEvent
CraftBukkit Changes:
38fd4bd50 Fix accidentally renamed internal damage method
80f0ce4be SPIGOT-7300, PR-1180: Add new DamageSource API providing enhanced information about entity damage
7e43f3b16 SPIGOT-7581: Fix typo in BlockMushroom
ea14b7d90 SPIGOT-7576, PR-1347: Add methods in MushroomCow to change stew effects
4c687f243 PR-1259: Add Server#isLoggingIPs to get log-ips configuration
22a541a29 Improve support for per-world game rules
cb7dccce2 PR-1348: Add Player methods for client-side potion effects
b8d6109f0 PR-1335: Add API for in-world structures
4398a1b5b SPIGOT-7577: Make CraftWindCharge#explode discard the entity
e74107678 Fix Crafter maximum stack size
0bb0f4f6a SPIGOT-7530, PR-1314: Improve Resource Pack API with new 1.20.3 functionality
4949f556d SPIGOT-3071, PR-1345: Add entity spawn method with spawn reason
20ac73ca2 PR-1353: Fix Structure#place not working as documented with 0 palette
3c1b77871 SPIGOT-6911, PR-1349: Change max book length in CraftMetaBook
333701839 SPIGOT-7572: Bee nests generated without bees
f48f4174c SPIGOT-5553, PR-1336: Add EntityKnockbackEvent
2024-02-11 22:28:00 +01:00
((GameRules.BooleanValue) this.getGameRules().getRule(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)).set(dedicatedserverproperties.announcePlayerAchievements, this.overworld()); // CraftBukkit - per-world
2021-06-11 14:02:28 +02:00
}
2024-10-26 03:13:48 +02:00
@@ -444,7 +444,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
2023-06-09 07:25:23 +02:00
// this.remoteStatusListener.stop(); // Paper - don't wait for remote connections
2021-06-11 14:02:28 +02:00
}
- System.exit(0); // CraftBukkit
+ hasFullyShutdown = true; // Paper
+ System.exit(this.abnormalExit ? 70 : 0); // CraftBukkit // Paper
}
@Override
2024-10-26 03:13:48 +02:00
@@ -824,7 +825,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
2021-06-11 14:02:28 +02:00
@Override
public void stopServer() {
super.stopServer();
- Util.shutdownExecutors();
2021-11-24 12:06:34 +01:00
+ //Util.shutdownExecutors(); // Paper - moved into super
SkullBlockEntity.clear();
2021-06-11 14:02:28 +02:00
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
2024-10-26 03:13:48 +02:00
index bbefb529607d1cffe8917b883389494a8fa126c0..511e7254d938733aca508efd5de82e61678c7620 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
2024-10-26 03:13:48 +02:00
@@ -554,7 +554,7 @@ public abstract class PlayerList {
2021-06-14 03:06:38 +02:00
this.cserver.getPluginManager().callEvent(playerQuitEvent);
2021-06-11 14:02:28 +02:00
entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
- entityplayer.doTick(); // SPIGOT-924
+ if (server.isSameThread()) entityplayer.doTick(); // SPIGOT-924 // Paper - don't tick during emergency shutdowns (Watchdog)
// CraftBukkit end
2024-01-23 14:34:17 +01:00
// Paper start - Configurable player collision; Remove from collideRule team if needed
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
2024-10-26 03:13:48 +02:00
index d6e942aca1bcc769c390504a4119d6619872c4d4..9b706276dc5b5f55b966c5472c6c4e864342b916 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
+++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
2024-10-26 03:13:48 +02:00
@@ -168,6 +168,6 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
public static boolean isNonRecoverable(Throwable exception) {
return exception instanceof ReportedException reportedException
? isNonRecoverable(reportedException.getCause())
- : exception instanceof OutOfMemoryError || exception instanceof StackOverflowError;
+ : exception instanceof OutOfMemoryError || exception instanceof StackOverflowError || exception instanceof ThreadDeath; // Paper
2024-04-12 21:14:06 +02:00
}
2024-10-26 03:13:48 +02:00
}
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
2024-10-26 03:13:48 +02:00
index bb2d3ba2065b6bf67af24a8630ac2d58169fe783..044985030607bc20a61666dee7dd2659ae4553b5 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
2024-10-26 03:13:48 +02:00
@@ -1495,6 +1495,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
2021-06-11 14:02:28 +02:00
try {
tickConsumer.accept(entity);
} catch (Throwable throwable) {
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
2024-01-24 11:45:17 +01:00
// Paper start - Prevent block entity and entity crashes
2023-06-08 00:41:25 +02:00
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
2021-06-21 10:09:18 +02:00
MinecraftServer.LOGGER.error(msg, throwable);
2021-06-14 03:06:38 +02:00
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
2024-10-26 03:13:48 +02:00
index e03d57f58a9f962cd429e8851fb3f35f3491e2c0..1313ac2ff9f1b9fccab54b0c200b9dfa7a4edd00 100644
2021-06-14 03:06:38 +02:00
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
2024-10-26 03:13:48 +02:00
@@ -1081,6 +1081,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
2021-06-14 03:06:38 +02:00
gameprofilerfiller.pop();
} catch (Throwable throwable) {
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
2024-01-24 11:45:17 +01:00
// Paper start - Prevent block entity and entity crashes
2021-06-21 10:09:18 +02:00
final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
2023-09-17 00:54:33 +02:00
index c6e8441e299f477ddb22c1ce2618710763978f1a..e8e93538dfd71de86515d9405f728db1631e949a 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
2023-09-17 00:54:33 +02:00
@@ -12,11 +12,27 @@ public class ServerShutdownThread extends Thread {
2021-06-11 14:02:28 +02:00
@Override
public void run() {
try {
+ // Paper start - try to shutdown on main
+ server.safeShutdown(false, false);
+ for (int i = 1000; i > 0 && !server.hasStopped(); i -= 100) {
+ Thread.sleep(100);
+ }
+ if (server.hasStopped()) {
+ while (!server.hasFullyShutdown) Thread.sleep(1000);
+ return;
+ }
+ // Looks stalled, close async
org.spigotmc.AsyncCatcher.enabled = false; // Spigot
+ server.forceTicks = true;
2021-06-14 03:06:38 +02:00
this.server.close();
2021-06-11 14:02:28 +02:00
+ while (!server.hasFullyShutdown) Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ // Paper end
} finally {
2022-06-12 02:59:24 +02:00
+ org.apache.logging.log4j.LogManager.shutdown(); // Paper
2021-06-11 14:02:28 +02:00
try {
- net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
+ //net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Move into stop
} catch (Exception e) {
}
}
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
2024-07-11 21:09:15 +02:00
index 39e56b95aaafbcd8ebe68fdefaace83702e9510d..3ba27955548a26367a87d6b87c3c61beb299dfb9 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/spigotmc/RestartCommand.java
+++ b/src/main/java/org/spigotmc/RestartCommand.java
2024-06-17 13:36:43 +02:00
@@ -139,7 +139,7 @@ public class RestartCommand extends Command
2021-06-11 14:02:28 +02:00
// Paper end
// Paper start - copied from above and modified to return if the hook registered
- private static boolean addShutdownHook(String restartScript)
2024-06-17 13:36:43 +02:00
+ public static boolean addShutdownHook(String restartScript) // Paper
2021-06-11 14:02:28 +02:00
{
String[] split = restartScript.split( " " );
if ( split.length > 0 && new File( split[0] ).isFile() )
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
2024-07-17 19:24:53 +02:00
index 529df2a41dd93d6e1505053bd04032dbf0cdaa31..c9e17225bc52fe5e7b2dc0908db225a86c6e94d1 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
2022-06-09 10:51:45 +02:00
@@ -11,6 +11,7 @@ import org.bukkit.Bukkit;
2024-07-17 19:24:53 +02:00
public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThread // Paper - rewrite chunk system
2021-06-11 14:02:28 +02:00
{
2024-06-17 13:36:43 +02:00
+ public static final boolean DISABLE_WATCHDOG = Boolean.getBoolean("disable.watchdog"); // Paper - Improved watchdog support
2021-06-11 14:02:28 +02:00
private static WatchdogThread instance;
private long timeoutTime;
private boolean restart;
2024-07-17 19:24:53 +02:00
@@ -39,6 +40,7 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
2021-06-11 14:02:28 +02:00
{
2021-06-14 03:06:38 +02:00
if ( WatchdogThread.instance == null )
2021-06-11 14:02:28 +02:00
{
+ if (timeoutTime <= 0) timeoutTime = 300; // Paper
2021-06-14 03:06:38 +02:00
WatchdogThread.instance = new WatchdogThread( timeoutTime * 1000L, restart );
WatchdogThread.instance.start();
2021-06-11 14:02:28 +02:00
} else
2024-07-17 19:24:53 +02:00
@@ -70,12 +72,13 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
2021-06-11 14:02:28 +02:00
// Paper start
Logger log = Bukkit.getServer().getLogger();
2021-06-14 03:06:38 +02:00
long currentTime = WatchdogThread.monotonicMillis();
- if ( this.lastTick != 0 && this.timeoutTime > 0 && currentTime > this.lastTick + this.earlyWarningEvery && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
2021-06-11 14:02:28 +02:00
+ MinecraftServer server = MinecraftServer.getServer();
2021-06-14 03:06:38 +02:00
+ if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.hasStarted && (!server.isRunning() || (currentTime > this.lastTick + this.earlyWarningEvery && !DISABLE_WATCHDOG) )) // Paper - add property to disable
2021-06-11 14:02:28 +02:00
{
- boolean isLongTimeout = currentTime > lastTick + timeoutTime;
+ boolean isLongTimeout = currentTime > lastTick + timeoutTime || (!server.isRunning() && !server.hasStopped() && currentTime > lastTick + 1000);
// Don't spam early warning dumps
if ( !isLongTimeout && (earlyWarningEvery <= 0 || !hasStarted || currentTime < lastEarlyWarning + earlyWarningEvery || currentTime < lastTick + earlyWarningDelay)) continue;
- if ( !isLongTimeout && MinecraftServer.getServer().hasStopped()) continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
+ if ( !isLongTimeout && server.hasStopped()) continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
lastEarlyWarning = currentTime;
if (isLongTimeout) {
// Paper end
2024-07-17 19:24:53 +02:00
@@ -136,9 +139,24 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
2021-06-11 14:02:28 +02:00
if ( isLongTimeout )
{
2021-06-14 03:06:38 +02:00
- if ( this.restart && !MinecraftServer.getServer().hasStopped() )
2021-06-11 14:02:28 +02:00
+ if ( !server.hasStopped() )
{
- RestartCommand.restart();
+ AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
+ server.forceTicks = true;
+ if (restart) {
+ RestartCommand.addShutdownHook( SpigotConfig.restartScript );
+ }
+ // try one last chance to safe shutdown on main incase it 'comes back'
+ server.abnormalExit = true;
+ server.safeShutdown(false, restart);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ if (!server.hasStopped()) {
+ server.close();
+ }
}
break;
} // Paper end
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
2024-04-25 13:02:27 +02:00
index 637d64da9938e51a97338b9253b43889585c67bb..d2a75850af9c6ad2aca66a5f994f1b587d73eac4 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/resources/log4j2.xml
+++ b/src/main/resources/log4j2.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
2024-04-25 13:02:27 +02:00
-<Configuration status="WARN">
+<Configuration status="WARN" shutdownHook="disable">
2021-06-11 14:02:28 +02:00
<Appenders>
<Queue name="ServerGuiConsole">
2024-04-25 13:02:27 +02:00
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg{nolookups}%n" />