Add thread safe relative features

This commit is contained in:
Sotr
2018-06-11 15:56:24 +08:00
parent 7bdc57cb70
commit f89f26e2db
9 changed files with 65 additions and 5 deletions

View File

@@ -133,6 +133,11 @@
<artifactId>mixin</artifactId> <artifactId>mixin</artifactId>
<version>0.7.8-SNAPSHOT</version> <version>0.7.8-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>me.nallar.whocalled</groupId>
<artifactId>WhoCalled</artifactId>
<version>1.1</version>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>
@@ -148,6 +153,10 @@
<id>spongepowered-repo</id> <id>spongepowered-repo</id>
<url>https://repo.spongepowered.org/maven/</url> <url>https://repo.spongepowered.org/maven/</url>
</repository> </repository>
<repository>
<id>nallar-repo</id>
<url>http://repo.nallar.me/</url>
</repository>
</repositories> </repositories>
<pluginRepositories> <pluginRepositories>

View File

@@ -24,6 +24,7 @@
package co.aikar.timings; package co.aikar.timings;
import co.aikar.util.LoadingIntMap; import co.aikar.util.LoadingIntMap;
import io.akarin.api.Akari;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;

View File

@@ -8,12 +8,14 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.entity.Minecart;
import com.google.common.collect.Queues; import com.google.common.collect.Queues;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import co.aikar.timings.Timing; import co.aikar.timings.Timing;
import co.aikar.timings.Timings; import co.aikar.timings.Timings;
import net.minecraft.server.MinecraftServer;
public abstract class Akari { public abstract class Akari {
/** /**
@@ -41,6 +43,12 @@ public abstract class Akari {
*/ */
public static final ExecutorCompletionService<?> STAGE_TICK = new ExecutorCompletionService<>(Executors.newSingleThreadExecutor(Akari.STAGE_FACTORY)); public static final ExecutorCompletionService<?> STAGE_TICK = new ExecutorCompletionService<>(Executors.newSingleThreadExecutor(Akari.STAGE_FACTORY));
public static volatile boolean mayMock;
public static boolean isPrimaryThread() {
return Thread.currentThread().equals(MinecraftServer.getServer().primaryThread);
}
/* /*
* The unsafe * The unsafe
*/ */

View File

@@ -189,6 +189,26 @@ public class AkarinGlobalConfig {
asyncLightingThreads = getInt("core.async-lighting.executor-threads", 2); asyncLightingThreads = getInt("core.async-lighting.executor-threads", 2);
} }
public static boolean enableMockPlugin;
private static void enableMockPlugin() {
enableMockPlugin = getBoolean("core.thread-safe.enable-mock-plugins", false);
}
public static List<String> mockPackageList;
private static void mockPluginList() {
mockPackageList = getList("core.thread-safe.mock-package-name-contains", Lists.newArrayList());
}
public static boolean enableAsyncCatcher;
private static void enableAsyncCatcher() {
enableAsyncCatcher = getBoolean("core.thread-safe.async-catcher.enable", false);
}
public static boolean throwOnAsyncCaught;
private static void throwOnAsyncCaught() {
throwOnAsyncCaught = getBoolean("core.thread-safe.async-catcher.throw-on-caught", true);
}
public static boolean asyncLightingWorkStealing; public static boolean asyncLightingWorkStealing;
private static void asyncLightingWorkStealing() { private static void asyncLightingWorkStealing() {
asyncLightingWorkStealing = getBoolean("core.async-lighting.use-work-stealing", false); asyncLightingWorkStealing = getBoolean("core.async-lighting.use-work-stealing", false);

View File

@@ -7,9 +7,14 @@ import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import io.akarin.server.core.AkarinGlobalConfig;
import me.nallar.whocalled.WhoCalled;
import net.minecraft.server.MinecraftServer;
@Mixin(value = CraftServer.class, remap = false) @Mixin(value = CraftServer.class, remap = false)
public class MixinCraftServer { public class MixinCraftServer {
@Shadow @Final @Mutable private String serverName; @Shadow @Final @Mutable private String serverName;
@Shadow @Final protected MinecraftServer console;
private boolean needApplyServerName = true; private boolean needApplyServerName = true;
@Overwrite @Overwrite
@@ -22,4 +27,18 @@ public class MixinCraftServer {
} }
return serverName; return serverName;
} }
@Overwrite
public boolean isPrimaryThread() {
if (AkarinGlobalConfig.enableMockPlugin) {
// Mock forcely main thread plugins
String callerPackage = WhoCalled.$.getCallingClass().getPackage().getName();
if (callerPackage.startsWith("net.minecraft") || callerPackage.startsWith("org.bukkit") ||
callerPackage.startsWith("co.aikar") || callerPackage.startsWith("io.akarin")) return Thread.currentThread().equals(console.primaryThread);
for (String contains : AkarinGlobalConfig.mockPackageList) {
if (callerPackage.contains(contains)) return true;
}
}
return Thread.currentThread().equals(console.primaryThread);
}
} }

View File

@@ -20,7 +20,7 @@ public class MixinTimingHandler {
@Overwrite @Overwrite
public void stopTimingIfSync() { public void stopTimingIfSync() {
if (Bukkit.isPrimaryThread()) { if (Akari.isPrimaryThread()) { // Akarin
stopTiming(true); // Avoid twice thread check stopTiming(true); // Avoid twice thread check
} }
} }
@@ -38,7 +38,7 @@ public class MixinTimingHandler {
start = 0; start = 0;
return; return;
} else { } else {
if (!sync && !Bukkit.isPrimaryThread()) { if (!sync && !Akari.isPrimaryThread()) { // Akarin
if (AkarinGlobalConfig.silentAsyncTimings) { if (AkarinGlobalConfig.silentAsyncTimings) {
Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name); Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name);
new Throwable().printStackTrace(); new Throwable().printStackTrace();

View File

@@ -45,6 +45,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import io.akarin.api.Akari;
import io.akarin.api.mixin.IMixinChunk; import io.akarin.api.mixin.IMixinChunk;
import io.akarin.api.mixin.IMixinWorldServer; import io.akarin.api.mixin.IMixinWorldServer;
import net.minecraft.server.BlockPosition; import net.minecraft.server.BlockPosition;
@@ -245,7 +246,7 @@ public abstract class MixinChunk implements IMixinChunk {
return; return;
} }
if (Bukkit.isPrimaryThread()) { if (Akari.isPrimaryThread()) { // Akarin
try { try {
this.lightExecutorService.execute(() -> { this.lightExecutorService.execute(() -> {
this.checkLightAsync(neighborChunks); this.checkLightAsync(neighborChunks);

View File

@@ -33,6 +33,7 @@ import org.bukkit.Bukkit;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.akarin.api.Akari;
import io.akarin.api.mixin.IMixinChunk; import io.akarin.api.mixin.IMixinChunk;
import io.akarin.api.mixin.IMixinWorldServer; import io.akarin.api.mixin.IMixinWorldServer;
import io.akarin.server.core.AkarinGlobalConfig; import io.akarin.server.core.AkarinGlobalConfig;
@@ -240,7 +241,7 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
neighbor.setLightUpdateTime(chunk.getWorld().getTime()); neighbor.setLightUpdateTime(chunk.getWorld().getTime());
} }
if (Bukkit.isPrimaryThread()) { if (Akari.isPrimaryThread()) { // Akarin
this.lightExecutorService.execute(() -> { this.lightExecutorService.execute(() -> {
this.checkLightAsync(lightType, pos, chunk, neighbors); this.checkLightAsync(lightType, pos, chunk, neighbors);
}); });

View File

@@ -3,6 +3,7 @@ package net.minecraft.server;
import com.google.common.primitives.Doubles; import com.google.common.primitives.Doubles;
import com.google.common.primitives.Floats; import com.google.common.primitives.Floats;
import io.akarin.api.Akari;
import io.akarin.server.core.AkarinGlobalConfig; import io.akarin.server.core.AkarinGlobalConfig;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.GenericFutureListener;
@@ -1384,7 +1385,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
if (!async && s.startsWith("/")) { if (!async && s.startsWith("/")) {
// Paper Start // Paper Start
if (!org.spigotmc.AsyncCatcher.shuttingDown && !org.bukkit.Bukkit.isPrimaryThread()) { if (!org.spigotmc.AsyncCatcher.shuttingDown && !Akari.isPrimaryThread()) { // Akarin
final String fCommandLine = s; final String fCommandLine = s;
MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Command Dispatched Async: " + fCommandLine); MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Command Dispatched Async: " + fCommandLine);
MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable()); MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());