Paper/CraftBukkit-Patches/0060-Watchdog-Thread.patch

295 lines
11 KiB
Diff
Raw Normal View History

From c746e94351236fc5cc57da30acf90fced3e22fa8 Mon Sep 17 00:00:00 2001
From: md_5 <md_5@live.com.au>
Date: Sat, 23 Feb 2013 12:33:20 +1100
Subject: [PATCH] Watchdog Thread.
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index b082ad2..1e83999 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -485,6 +485,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo
this.a(crashreport);
} finally {
try {
+ org.spigotmc.WatchdogThread.doStop();
this.stop();
this.isStopped = true;
} catch (Throwable throwable1) {
@@ -675,6 +676,7 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo
SpigotTimings.tickablesTimer.stopTiming(); // Spigot
this.methodProfiler.b();
+ org.spigotmc.WatchdogThread.tick(); // Spigot
SpigotTimings.serverTickTimer.stopTiming(); // Spigot
org.spigotmc.CustomTimingsHandler.tick(); // Spigot
}
2013-06-20 11:07:32 +02:00
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
new file mode 100644
2013-12-01 06:17:16 +01:00
index 0000000..a8840c9
2013-06-20 11:07:32 +02:00
--- /dev/null
+++ b/src/main/java/org/spigotmc/RestartCommand.java
2013-12-01 06:17:16 +01:00
@@ -0,0 +1,113 @@
2013-06-20 11:07:32 +02:00
+package org.spigotmc;
+
+import java.io.File;
2013-06-20 11:07:32 +02:00
+import java.util.List;
2013-04-25 01:01:05 +02:00
+import net.minecraft.server.EntityPlayer;
2013-12-01 06:17:16 +01:00
+import net.minecraft.server.IChatBaseComponent;
2013-06-20 11:07:32 +02:00
+import net.minecraft.server.MinecraftServer;
2013-12-01 06:17:16 +01:00
+import net.minecraft.server.PacketPlayOutKickDisconnect;
2013-06-20 11:07:32 +02:00
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
2013-12-01 06:17:16 +01:00
+import org.bukkit.craftbukkit.util.CraftChatMessage;
+
2013-06-20 11:07:32 +02:00
+public class RestartCommand extends Command
+{
+
2013-06-20 11:07:32 +02:00
+ 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 ) )
+ {
+ restart();
+ }
+ return true;
+ }
+
+ public static void restart()
+ {
+ try
+ {
+ final File file = new File( SpigotConfig.restartScript );
+ if ( file.isFile() )
+ {
+ System.out.println( "Attempting to restart with " + SpigotConfig.restartScript );
+
+ // Kick all players
2013-06-20 11:07:32 +02:00
+ for ( EntityPlayer p : (List< EntityPlayer>) MinecraftServer.getServer().getPlayerList().players )
+ {
2013-12-01 06:17:16 +01:00
+ p.playerConnection.disconnect(SpigotConfig.restartMessage);
+ p.playerConnection.networkManager.d();
+ }
+ // Give the socket a chance to send the packets
2013-06-20 11:07:32 +02:00
+ try
+ {
+ Thread.sleep( 100 );
+ } catch ( InterruptedException ex )
+ {
+ }
+ // Close the socket so we can rebind with the new process
2013-12-01 06:17:16 +01:00
+ MinecraftServer.getServer().ag().b();
+
+ // Give time for it to kick in
2013-06-20 11:07:32 +02:00
+ try
+ {
+ Thread.sleep( 100 );
+ } catch ( InterruptedException ex )
+ {
+ }
+
+ // Actually shutdown
2013-06-20 11:07:32 +02:00
+ try
+ {
+ MinecraftServer.getServer().stop();
2013-06-20 11:07:32 +02:00
+ } catch ( Throwable t )
+ {
+ }
+
2013-02-24 01:30:30 +01:00
+ // This will be done AFTER the server has completely halted
2013-06-20 11:07:32 +02:00
+ Thread shutdownHook = new Thread()
+ {
2013-02-24 01:30:30 +01:00
+ @Override
2013-06-20 11:07:32 +02:00
+ public void run()
+ {
+ try
+ {
+ String os = System.getProperty( "os.name" ).toLowerCase();
+ if ( os.contains( "win" ) )
+ {
+ Runtime.getRuntime().exec( "cmd /c start " + file.getPath() );
+ } else
+ {
+ Runtime.getRuntime().exec( new String[]
+ {
+ "sh", file.getPath()
+ } );
2013-02-24 01:30:30 +01:00
+ }
2013-06-20 11:07:32 +02:00
+ } catch ( Exception e )
+ {
2013-02-24 01:30:30 +01:00
+ e.printStackTrace();
+ }
+ }
+ };
+
2013-06-20 11:07:32 +02:00
+ shutdownHook.setDaemon( true );
+ Runtime.getRuntime().addShutdownHook( shutdownHook );
+ } else
+ {
+ System.out.println( "Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server." );
+ }
2013-06-20 11:07:32 +02:00
+ System.exit( 0 );
+ } catch ( Exception ex )
+ {
+ ex.printStackTrace();
+ }
+ }
2013-06-20 11:07:32 +02:00
+}
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
2014-01-22 09:19:39 +01:00
index 8b7c73e..4152452 100644
2013-06-20 11:07:32 +02:00
--- a/src/main/java/org/spigotmc/SpigotConfig.java
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
2014-01-22 09:19:39 +01:00
@@ -167,4 +167,18 @@ public class SpigotConfig
2013-12-01 08:40:51 +01:00
outdatedClientMessage = transform( getString( "messages.outdated-client", outdatedClientMessage ) );
outdatedServerMessage = transform( getString( "messages.outdated-server", outdatedServerMessage ) );
2013-06-20 11:07:32 +02:00
}
+
2013-06-20 11:07:32 +02:00
+ public static int timeoutTime = 60;
+ public static boolean restartOnCrash = true;
+ public static String restartScript = "./start.sh";
2013-10-16 10:38:15 +02:00
+ public static String restartMessage;
2013-06-20 11:07:32 +02:00
+ private static void watchdog()
+ {
+ timeoutTime = getInt( "settings.timeout-time", timeoutTime );
+ restartOnCrash = getBoolean( "settings.restart-on-crash", restartOnCrash );
+ restartScript = getString( "settings.restart-script", restartScript );
2013-10-16 10:38:15 +02:00
+ restartMessage = transform( getString( "messages.restart", "Server is restarting" ) );
+ commands.put( "restart", new RestartCommand( "restart" ) );
2013-06-20 11:07:32 +02:00
+ WatchdogThread.doStart( timeoutTime, restartOnCrash );
+ }
2013-06-20 11:07:32 +02:00
}
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
new file mode 100644
2013-12-23 11:01:45 +01:00
index 0000000..de08ad6
--- /dev/null
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
2013-12-23 11:01:45 +01:00
@@ -0,0 +1,117 @@
+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;
+
2013-06-20 11:07:32 +02:00
+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;
+
2013-06-20 11:07:32 +02:00
+ private WatchdogThread(long timeoutTime, boolean restart)
+ {
+ super( "Spigot Watchdog Thread" );
+ this.timeoutTime = timeoutTime;
+ this.restart = restart;
+ }
+
2013-06-20 11:07:32 +02:00
+ public static void doStart(int timeoutTime, boolean restart)
+ {
+ if ( instance == null )
+ {
+ instance = new WatchdogThread( timeoutTime * 1000L, restart );
+ instance.start();
+ }
+ }
+
2013-06-20 11:07:32 +02:00
+ public static void tick()
+ {
+ instance.lastTick = System.currentTimeMillis();
+ }
+
2013-06-20 11:07:32 +02:00
+ public static void doStop()
+ {
+ if ( instance != null )
+ {
+ instance.stopping = true;
+ }
+ }
+
+ @Override
2013-06-20 11:07:32 +02:00
+ public void run()
+ {
+ while ( !stopping )
+ {
+ //
2013-06-20 11:07:32 +02:00
+ if ( lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime )
+ {
+ Logger log = Bukkit.getServer().getLogger();
2013-06-20 11:07:32 +02:00
+ 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!):" );
2013-08-09 12:34:05 +02:00
+ dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().primaryThread.getId(), Integer.MAX_VALUE ), log );
+ log.log( Level.SEVERE, "------------------------------" );
+ //
+ log.log( Level.SEVERE, "Entire Thread Dump:" );
2013-06-20 11:07:32 +02:00
+ ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads( true, true );
+ for ( ThreadInfo thread : threads )
+ {
+ dumpThread( thread, log );
+ }
2013-06-20 11:07:32 +02:00
+ log.log( Level.SEVERE, "------------------------------" );
+
2013-06-20 11:07:32 +02:00
+ if ( restart )
+ {
+ RestartCommand.restart();
+ }
+ break;
+ }
+
2013-06-20 11:07:32 +02:00
+ try
+ {
+ sleep( 10000 );
+ } catch ( InterruptedException ex )
+ {
+ interrupt();
+ }
+ }
+ }
+
+ private static void dumpThread(ThreadInfo thread, Logger log)
+ {
2013-12-23 11:01:45 +01:00
+ 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 )
+ {
2013-12-23 11:01:45 +01:00
+ log.log( Level.SEVERE, "\tThread is waiting on monitor(s):" );
+ for ( MonitorInfo monitor : thread.getLockedMonitors() )
+ {
2013-12-23 11:01:45 +01:00
+ log.log( Level.SEVERE, "\t\tLocked on:" + monitor.getLockedStackFrame() );
+ }
+ }
2013-12-23 11:01:45 +01:00
+ log.log( Level.SEVERE, "\tStack:" );
+ //
+ for ( StackTraceElement stack : thread.getStackTrace() )
+ {
+ log.log( Level.SEVERE, "\t\t" + stack );
+ }
+ }
+}
--
2013-12-01 04:40:53 +01:00
1.8.3.2