Fix vanilla bug causing integrated server saving from 2 threads concurrently after a crash

This commit is contained in:
Player 2014-04-09 22:18:44 +02:00
parent c7d887f078
commit 09ff49fe58
3 changed files with 112 additions and 18 deletions

View file

@ -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;

View file

@ -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()
{

View file

@ -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<SaveHandler> handlerSet = Sets.newSetFromMap(new MapMaker().weakKeys().<SaveHandler,Boolean>makeMap());
private WeakReference<SaveHandler> 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()