From 09ff49fe589e88197e9fe341dbbd080d1e08dd4e Mon Sep 17 00:00:00 2001 From: Player Date: Wed, 9 Apr 2014 22:18:44 +0200 Subject: [PATCH] Fix vanilla bug causing integrated server saving from 2 threads concurrently after a crash --- .../net/minecraft/client/Minecraft.java.patch | 47 ++++++++++++---- .../server/MinecraftServer.java.patch | 27 ++++++--- .../cpw/mods/fml/common/FMLCommonHandler.java | 56 +++++++++++++++++++ 3 files changed, 112 insertions(+), 18 deletions(-) diff --git a/fml/patches/minecraft/net/minecraft/client/Minecraft.java.patch b/fml/patches/minecraft/net/minecraft/client/Minecraft.java.patch index 9739784ef8..2857f8514c 100644 --- a/fml/patches/minecraft/net/minecraft/client/Minecraft.java.patch +++ b/fml/patches/minecraft/net/minecraft/client/Minecraft.java.patch @@ -20,7 +20,34 @@ @SideOnly(Side.CLIENT) public class Minecraft implements IPlayerUsage { -@@ -448,7 +454,7 @@ +@@ -333,21 +339,23 @@ + File file2 = new File(file1, "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-client.txt"); + System.out.println(p_71377_1_.func_71502_e()); + ++ int retVal; + if (p_71377_1_.func_71497_f() != null) + { + System.out.println("#@!@# Game crashed! Crash report saved to: #@!@# " + p_71377_1_.func_71497_f()); +- System.exit(-1); ++ retVal = -1; + } + else if (p_71377_1_.func_147149_a(file2)) + { + System.out.println("#@!@# Game crashed! Crash report saved to: #@!@# " + file2.getAbsolutePath()); +- System.exit(-1); ++ retVal = -1; + } + else + { + System.out.println("#@?@# Game crashed! Crash report could not be saved. #@?@#"); +- System.exit(-2); ++ retVal = -2; + } ++ FMLCommonHandler.instance().handleExit(retVal); + } + + public void func_71367_a(String p_71367_1_, int p_71367_2_) +@@ -448,7 +456,7 @@ this.field_110451_am = new SimpleReloadableResourceManager(this.field_110452_an); this.field_135017_as = new LanguageManager(this.field_110452_an, this.field_71474_y.field_74363_ab); this.field_110451_am.func_110542_a(this.field_135017_as); @@ -29,7 +56,7 @@ this.field_71446_o = new TextureManager(this.field_110451_am); this.field_110451_am.func_110542_a(this.field_71446_o); this.field_147127_av = new SoundHandler(this.field_110451_am, this.field_71474_y); -@@ -508,12 +514,13 @@ +@@ -508,12 +516,13 @@ this.field_71446_o.func_130088_a(TextureMap.field_110576_c, new TextureMap(1, "textures/items")); GL11.glViewport(0, 0, this.field_71443_c, this.field_71440_d); this.field_71452_i = new EffectRenderer(this.field_71441_e, this.field_71446_o); @@ -44,7 +71,7 @@ } else { -@@ -527,6 +534,7 @@ +@@ -527,6 +536,7 @@ this.func_71352_k(); } @@ -52,7 +79,7 @@ Display.setVSyncEnabled(this.field_71474_y.field_74352_v); } -@@ -916,9 +924,11 @@ +@@ -916,9 +926,11 @@ if (!this.field_71454_w) { @@ -64,7 +91,7 @@ } GL11.glFlush(); -@@ -1496,6 +1506,8 @@ +@@ -1496,6 +1508,8 @@ --this.field_71467_ac; } @@ -73,7 +100,7 @@ this.field_71424_I.func_76320_a("gui"); if (!this.field_71445_n) -@@ -1646,6 +1658,7 @@ +@@ -1646,6 +1660,7 @@ this.field_71462_r.func_146274_d(); } } @@ -81,7 +108,7 @@ } if (this.field_71429_W > 0) -@@ -1787,6 +1800,7 @@ +@@ -1787,6 +1802,7 @@ } } } @@ -89,7 +116,7 @@ } } -@@ -1978,12 +1992,15 @@ +@@ -1978,12 +1994,15 @@ this.field_71453_ak.func_74428_b(); } @@ -105,7 +132,7 @@ this.func_71403_a((WorldClient)null); System.gc(); ISaveHandler isavehandler = this.field_71469_aa.func_75804_a(p_71371_1_, false); -@@ -2019,6 +2036,12 @@ +@@ -2019,6 +2038,12 @@ while (!this.field_71437_Z.func_71200_ad()) { @@ -118,7 +145,7 @@ String s2 = this.field_71437_Z.func_71195_b_(); if (s2 != null) -@@ -2094,6 +2117,7 @@ +@@ -2094,6 +2119,7 @@ this.field_110448_aq.func_148529_f(); this.func_71351_a((ServerData)null); this.field_71455_al = false; diff --git a/fml/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch b/fml/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch index 94f0a0c80c..008dbf69d9 100644 --- a/fml/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch +++ b/fml/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch @@ -29,25 +29,36 @@ long i = func_130071_aq(); long l = 0L; this.field_147147_p.func_151315_a(new ChatComponentText(this.field_71286_C)); -@@ -425,12 +431,17 @@ +@@ -425,12 +431,20 @@ Thread.sleep(1L); this.field_71296_Q = true; } + FMLCommonHandler.instance().handleServerStopping(); ++ FMLCommonHandler.instance().expectServerStopped(); // has to come before finalTick to avoid race conditions } else { ++ FMLCommonHandler.instance().expectServerStopped(); // has to come before finalTick to avoid race conditions this.func_71228_a((CrashReport)null); } } + catch (StartupQuery.AbortedException e) + { + // ignore silently ++ FMLCommonHandler.instance().expectServerStopped(); // has to come before finalTick to avoid race conditions + } catch (Throwable throwable1) { field_147145_h.error("Encountered an unexpected exception", throwable1); -@@ -471,6 +482,8 @@ +@@ -456,6 +470,7 @@ + field_147145_h.error("We were unable to save this crash report to disk."); + } + ++ FMLCommonHandler.instance().expectServerStopped(); // has to come before finalTick to avoid race conditions + this.func_71228_a(crashreport); + } + finally +@@ -471,6 +486,8 @@ } finally { @@ -56,7 +67,7 @@ this.func_71240_o(); } } -@@ -513,6 +526,7 @@ +@@ -513,6 +530,7 @@ { long i = System.nanoTime(); AxisAlignedBB.func_72332_a().func_72298_a(); @@ -64,7 +75,7 @@ ++this.field_71315_w; if (this.field_71295_T) -@@ -566,6 +580,7 @@ +@@ -566,6 +584,7 @@ this.field_71304_b.func_76319_b(); this.field_71304_b.func_76319_b(); @@ -72,7 +83,7 @@ } public void func_71190_q() -@@ -593,6 +608,7 @@ +@@ -593,6 +612,7 @@ } this.field_71304_b.func_76320_a("tick"); @@ -80,7 +91,7 @@ CrashReport crashreport; try -@@ -617,6 +633,7 @@ +@@ -617,6 +637,7 @@ throw new ReportedException(crashreport); } @@ -88,7 +99,7 @@ this.field_71304_b.func_76319_b(); this.field_71304_b.func_76320_a("tracker"); worldserver.func_73039_n().func_72788_a(); -@@ -648,6 +665,7 @@ +@@ -648,6 +669,7 @@ public void func_71256_s() { @@ -96,7 +107,7 @@ (new Thread("Server thread") { private static final String __OBFID = "CL_00001418"; -@@ -695,7 +713,7 @@ +@@ -695,7 +717,7 @@ public String getServerModName() { diff --git a/fml/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java b/fml/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java index 96fc9a07ad..44d563e019 100644 --- a/fml/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java +++ b/fml/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java @@ -17,6 +17,8 @@ import java.lang.ref.WeakReference; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; @@ -86,6 +88,7 @@ public class FMLCommonHandler private Set handlerSet = Sets.newSetFromMap(new MapMaker().weakKeys().makeMap()); private WeakReference handlerToCheck; private EventBus eventBus = new EventBus(); + private volatile CountDownLatch exitLatch = null; /** * The FML event bus. Subscribe here for FML related events * @@ -428,6 +431,50 @@ public class FMLCommonHandler return sidedDelegate.shouldServerShouldBeKilledQuietly(); } + /** + * Make handleExit() wait for handleServerStopped(). + * + * For internal use only! + */ + public void expectServerStopped() + { + exitLatch = new CountDownLatch(1); + } + + /** + * Delayed System.exit() until the server is actually stopped/done saving. + * + * For internal use only! + * + * @param retVal Exit code for System.exit() + */ + public void handleExit(int retVal) + { + CountDownLatch latch = exitLatch; + + if (latch != null) + { + try + { + FMLLog.info("Waiting for the server to terminate/save."); + if (!latch.await(10, TimeUnit.SECONDS)) + { + FMLLog.warning("The server didn't stop within 10 seconds, exiting anyway."); + } + else + { + FMLLog.info("Server terminated."); + } + } + catch (InterruptedException e) + { + FMLLog.warning("Interrupted wait, exiting."); + } + } + + System.exit(retVal); + } + public void handleServerStopped() { sidedDelegate.serverStopped(); @@ -435,6 +482,15 @@ public class FMLCommonHandler Loader.instance().serverStopped(); // FORCE the internal server to stop: hello optifine workaround! if (server!=null) ObfuscationReflectionHelper.setPrivateValue(MinecraftServer.class, server, false, "field_71316"+"_v", "u", "serverStopped"); + + // allow any pending exit to continue, clear exitLatch + CountDownLatch latch = exitLatch; + + if (latch != null) + { + latch.countDown(); + exitLatch = null; + } } public String getModName()