mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-06 18:50:51 +01:00
386df52297
5a0150f586ed3eb15fe6f1f596d1a5a7d806f0f9 Fix ITEM_BREAK e6a3911057bd94d8bd7021cbb4923fb84fb106d1 Upstream merge d1cdcf8d4c3639f956474f02ed662517cffbe23e Remove old patch 068df64aeee368377e1673667bffc7a6dcf90554 Rebuild all patches
316 lines
No EOL
12 KiB
Diff
316 lines
No EOL
12 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: md_5 <md_5@live.com.au>
|
|
Date: Tue, 5 Aug 2014 17:20:19 +0100
|
|
Subject: [PATCH] Watchdog Thread.
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/DedicatedServer.java b/src/main/java/net/minecraft/server/DedicatedServer.java
|
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
--- a/src/main/java/net/minecraft/server/DedicatedServer.java
|
|
+++ b/src/main/java/net/minecraft/server/DedicatedServer.java
|
|
@@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
|
|
}
|
|
// CraftBukkit end
|
|
|
|
- if (this.aQ() > 0L) {
|
|
+ if (false && this.aQ() > 0L) { // Spigot - disable
|
|
Thread thread = new Thread(new ThreadWatchdog(this));
|
|
|
|
thread.setName("Server Watchdog");
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -0,0 +0,0 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs
|
|
this.a(crashreport);
|
|
} finally {
|
|
try {
|
|
+ org.spigotmc.WatchdogThread.doStop();
|
|
this.stop();
|
|
this.isStopped = true;
|
|
} catch (Throwable throwable1) {
|
|
@@ -0,0 +0,0 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IAs
|
|
|
|
this.methodProfiler.b();
|
|
this.methodProfiler.b();
|
|
+ org.spigotmc.WatchdogThread.tick(); // Spigot
|
|
SpigotTimings.serverTickTimer.stopTiming(); // Spigot
|
|
org.spigotmc.CustomTimingsHandler.tick(); // Spigot
|
|
}
|
|
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..00000000000000000000000000000000000000000
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/spigotmc/RestartCommand.java
|
|
@@ -0,0 +0,0 @@
|
|
+package org.spigotmc;
|
|
+
|
|
+import java.io.File;
|
|
+import java.util.List;
|
|
+import net.minecraft.server.EntityPlayer;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import org.bukkit.command.Command;
|
|
+import org.bukkit.command.CommandSender;
|
|
+
|
|
+public class RestartCommand extends Command
|
|
+{
|
|
+
|
|
+ public RestartCommand(String name)
|
|
+ {
|
|
+ super( name );
|
|
+ this.description = "Restarts the server";
|
|
+ this.usageMessage = "/restart";
|
|
+ this.setPermission( "bukkit.command.restart" );
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean execute(CommandSender sender, String currentAlias, String[] args)
|
|
+ {
|
|
+ if ( testPermission( sender ) )
|
|
+ {
|
|
+ MinecraftServer.getServer().processQueue.add( new Runnable()
|
|
+ {
|
|
+ @Override
|
|
+ public void run()
|
|
+ {
|
|
+ restart();
|
|
+ }
|
|
+ } );
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ public static void restart()
|
|
+ {
|
|
+ restart( new File( SpigotConfig.restartScript ) );
|
|
+ }
|
|
+
|
|
+ public static void restart(final File script)
|
|
+ {
|
|
+ AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
|
|
+ try
|
|
+ {
|
|
+ if ( script.isFile() )
|
|
+ {
|
|
+ System.out.println( "Attempting to restart with " + SpigotConfig.restartScript );
|
|
+
|
|
+ // Disable Watchdog
|
|
+ WatchdogThread.doStop();
|
|
+
|
|
+ // Kick all players
|
|
+ for ( EntityPlayer p : (List< EntityPlayer>) MinecraftServer.getServer().getPlayerList().players )
|
|
+ {
|
|
+ p.playerConnection.disconnect(SpigotConfig.restartMessage);
|
|
+ }
|
|
+ // Give the socket a chance to send the packets
|
|
+ try
|
|
+ {
|
|
+ Thread.sleep( 100 );
|
|
+ } catch ( InterruptedException ex )
|
|
+ {
|
|
+ }
|
|
+ // Close the socket so we can rebind with the new process
|
|
+ MinecraftServer.getServer().getServerConnection().b();
|
|
+
|
|
+ // Give time for it to kick in
|
|
+ try
|
|
+ {
|
|
+ Thread.sleep( 100 );
|
|
+ } catch ( InterruptedException ex )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ // Actually shutdown
|
|
+ try
|
|
+ {
|
|
+ MinecraftServer.getServer().stop();
|
|
+ } catch ( Throwable t )
|
|
+ {
|
|
+ }
|
|
+
|
|
+ // This will be done AFTER the server has completely halted
|
|
+ Thread shutdownHook = new Thread()
|
|
+ {
|
|
+ @Override
|
|
+ public void run()
|
|
+ {
|
|
+ try
|
|
+ {
|
|
+ String os = System.getProperty( "os.name" ).toLowerCase();
|
|
+ if ( os.contains( "win" ) )
|
|
+ {
|
|
+ Runtime.getRuntime().exec( "cmd /c start " + script.getPath() );
|
|
+ } else
|
|
+ {
|
|
+ Runtime.getRuntime().exec( new String[]
|
|
+ {
|
|
+ "sh", script.getPath()
|
|
+ } );
|
|
+ }
|
|
+ } catch ( Exception e )
|
|
+ {
|
|
+ e.printStackTrace();
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+
|
|
+ shutdownHook.setDaemon( true );
|
|
+ Runtime.getRuntime().addShutdownHook( shutdownHook );
|
|
+ } else
|
|
+ {
|
|
+ System.out.println( "Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server." );
|
|
+ }
|
|
+ System.exit( 0 );
|
|
+ } catch ( Exception ex )
|
|
+ {
|
|
+ ex.printStackTrace();
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
|
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
--- a/src/main/java/org/spigotmc/SpigotConfig.java
|
|
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
|
|
@@ -0,0 +0,0 @@ public class SpigotConfig
|
|
outdatedClientMessage = transform( getString( "messages.outdated-client", outdatedClientMessage ) );
|
|
outdatedServerMessage = transform( getString( "messages.outdated-server", outdatedServerMessage ) );
|
|
}
|
|
+
|
|
+ public static int timeoutTime = 60;
|
|
+ public static boolean restartOnCrash = true;
|
|
+ public static String restartScript = "./start.sh";
|
|
+ public static String restartMessage;
|
|
+ private static void watchdog()
|
|
+ {
|
|
+ timeoutTime = getInt( "settings.timeout-time", timeoutTime );
|
|
+ restartOnCrash = getBoolean( "settings.restart-on-crash", restartOnCrash );
|
|
+ restartScript = getString( "settings.restart-script", restartScript );
|
|
+ restartMessage = transform( getString( "messages.restart", "Server is restarting" ) );
|
|
+ commands.put( "restart", new RestartCommand( "restart" ) );
|
|
+ WatchdogThread.doStart( timeoutTime, restartOnCrash );
|
|
+ }
|
|
}
|
|
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
|
@@ -0,0 +0,0 @@
|
|
+package org.spigotmc;
|
|
+
|
|
+import java.lang.management.ManagementFactory;
|
|
+import java.lang.management.MonitorInfo;
|
|
+import java.lang.management.ThreadInfo;
|
|
+import java.util.logging.Level;
|
|
+import java.util.logging.Logger;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import org.bukkit.Bukkit;
|
|
+
|
|
+public class WatchdogThread extends Thread
|
|
+{
|
|
+
|
|
+ private static WatchdogThread instance;
|
|
+ private final long timeoutTime;
|
|
+ private final boolean restart;
|
|
+ private volatile long lastTick;
|
|
+ private volatile boolean stopping;
|
|
+
|
|
+ private WatchdogThread(long timeoutTime, boolean restart)
|
|
+ {
|
|
+ super( "Spigot Watchdog Thread" );
|
|
+ this.timeoutTime = timeoutTime;
|
|
+ this.restart = restart;
|
|
+ }
|
|
+
|
|
+ public static void doStart(int timeoutTime, boolean restart)
|
|
+ {
|
|
+ if ( instance == null )
|
|
+ {
|
|
+ instance = new WatchdogThread( timeoutTime * 1000L, restart );
|
|
+ instance.start();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static void tick()
|
|
+ {
|
|
+ instance.lastTick = System.currentTimeMillis();
|
|
+ }
|
|
+
|
|
+ public static void doStop()
|
|
+ {
|
|
+ if ( instance != null )
|
|
+ {
|
|
+ instance.stopping = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void run()
|
|
+ {
|
|
+ while ( !stopping )
|
|
+ {
|
|
+ //
|
|
+ if ( lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime )
|
|
+ {
|
|
+ Logger log = Bukkit.getServer().getLogger();
|
|
+ log.log( Level.SEVERE, "The server has stopped responding!" );
|
|
+ log.log( Level.SEVERE, "Please report this to http://www.spigotmc.org/" );
|
|
+ log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" );
|
|
+ log.log( Level.SEVERE, "Spigot version: " + Bukkit.getServer().getVersion() );
|
|
+ //
|
|
+ log.log( Level.SEVERE, "------------------------------" );
|
|
+ log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Spigot!):" );
|
|
+ dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().primaryThread.getId(), Integer.MAX_VALUE ), log );
|
|
+ log.log( Level.SEVERE, "------------------------------" );
|
|
+ //
|
|
+ log.log( Level.SEVERE, "Entire Thread Dump:" );
|
|
+ ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads( true, true );
|
|
+ for ( ThreadInfo thread : threads )
|
|
+ {
|
|
+ dumpThread( thread, log );
|
|
+ }
|
|
+ log.log( Level.SEVERE, "------------------------------" );
|
|
+
|
|
+ if ( restart )
|
|
+ {
|
|
+ RestartCommand.restart();
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ try
|
|
+ {
|
|
+ sleep( 10000 );
|
|
+ } catch ( InterruptedException ex )
|
|
+ {
|
|
+ interrupt();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static void dumpThread(ThreadInfo thread, Logger log)
|
|
+ {
|
|
+ log.log( Level.SEVERE, "------------------------------" );
|
|
+ //
|
|
+ log.log( Level.SEVERE, "Current Thread: " + thread.getThreadName() );
|
|
+ log.log( Level.SEVERE, "\tPID: " + thread.getThreadId()
|
|
+ + " | Suspended: " + thread.isSuspended()
|
|
+ + " | Native: " + thread.isInNative()
|
|
+ + " | State: " + thread.getThreadState() );
|
|
+ if ( thread.getLockedMonitors().length != 0 )
|
|
+ {
|
|
+ log.log( Level.SEVERE, "\tThread is waiting on monitor(s):" );
|
|
+ for ( MonitorInfo monitor : thread.getLockedMonitors() )
|
|
+ {
|
|
+ log.log( Level.SEVERE, "\t\tLocked on:" + monitor.getLockedStackFrame() );
|
|
+ }
|
|
+ }
|
|
+ log.log( Level.SEVERE, "\tStack:" );
|
|
+ //
|
|
+ for ( StackTraceElement stack : thread.getStackTrace() )
|
|
+ {
|
|
+ log.log( Level.SEVERE, "\t\t" + stack );
|
|
+ }
|
|
+ }
|
|
+}
|
|
--
|