Ensures thread safety, hopefully fixes GH-80
This commit is contained in:
@@ -3,11 +3,15 @@ package co.aikar.timings;
|
||||
public class ThreadAssertion {
|
||||
private static boolean mainThread;
|
||||
|
||||
public static boolean isMainThread() {
|
||||
public static boolean is() {
|
||||
return mainThread;
|
||||
}
|
||||
|
||||
static boolean setMainThread(boolean is) {
|
||||
return mainThread = is;
|
||||
static void start() {
|
||||
mainThread = false;
|
||||
}
|
||||
|
||||
public static void close() {
|
||||
mainThread = false;
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,6 @@ class TimingHandler implements Timing {
|
||||
private boolean added;
|
||||
private boolean timed;
|
||||
private boolean enabled;
|
||||
private boolean unsafe; // Akarin
|
||||
|
||||
TimingHandler(@Nonnull TimingIdentifier id) { // Akarin - javax.annotation
|
||||
this.identifier = id;
|
||||
@@ -114,7 +113,7 @@ class TimingHandler implements Timing {
|
||||
@Override
|
||||
public Timing startTimingUnsafe() {
|
||||
if (enabled && ++timingDepth == 1) {
|
||||
unsafe = true;
|
||||
ThreadAssertion.close();
|
||||
// Akarin end
|
||||
start = System.nanoTime();
|
||||
TIMING_STACK.addLast(this);
|
||||
@@ -124,11 +123,11 @@ class TimingHandler implements Timing {
|
||||
// Akarin start
|
||||
@Override
|
||||
public Timing startTiming(boolean assertThread) {
|
||||
if (enabled && (ThreadAssertion.isMainThread() || Bukkit.isPrimaryThread()) && ++timingDepth == 1) {
|
||||
if (enabled && (ThreadAssertion.is() || Bukkit.isPrimaryThread()) && ++timingDepth == 1) {
|
||||
start = System.nanoTime();
|
||||
TIMING_STACK.addLast(this);
|
||||
if (assertThread && AkarinGlobalConfig.lazyThreadAssertion)
|
||||
ThreadAssertion.setMainThread(true);
|
||||
ThreadAssertion.start();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -144,13 +143,13 @@ class TimingHandler implements Timing {
|
||||
addDiff(System.nanoTime() - start, TIMING_STACK.peekLast());
|
||||
|
||||
start = 0;
|
||||
unsafe = false;
|
||||
ThreadAssertion.close();
|
||||
}
|
||||
}
|
||||
// Akarin end
|
||||
|
||||
public void stopTiming() {
|
||||
if (enabled && timingDepth > 0 && (ThreadAssertion.isMainThread() || Bukkit.isPrimaryThread()) && --timingDepth == 0 && start != 0) { // Akarin
|
||||
if (enabled && timingDepth > 0 && (ThreadAssertion.is() || Bukkit.isPrimaryThread()) && --timingDepth == 0 && start != 0) { // Akarin
|
||||
TimingHandler last;
|
||||
while ((last = TIMING_STACK.removeLast()) != this) {
|
||||
last.timingDepth = 0;
|
||||
@@ -167,8 +166,7 @@ class TimingHandler implements Timing {
|
||||
start = 0;
|
||||
// Akarin start
|
||||
if (AkarinGlobalConfig.lazyThreadAssertion)
|
||||
ThreadAssertion.setMainThread(false);
|
||||
unsafe = false;
|
||||
ThreadAssertion.close();
|
||||
// Akarin end
|
||||
}
|
||||
}
|
||||
@@ -231,7 +229,7 @@ class TimingHandler implements Timing {
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
if (unsafe) stopTimingUnsafe(); else stopTimingIfSync(); // Akarin
|
||||
if (ThreadAssertion.is()) stopTimingUnsafe(); else stopTimingIfSync(); // Akarin
|
||||
}
|
||||
|
||||
public boolean isSpecial() {
|
||||
|
||||
@@ -7,18 +7,19 @@ import java.util.concurrent.Future;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import co.aikar.timings.ThreadAssertion;
|
||||
|
||||
public class AkarinAsyncExecutor {
|
||||
private static final ExecutorService singleExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("Akarin Single Async Executor Thread - %1$d").build());
|
||||
private static final ExecutorService asyncExecutor = Executors.newFixedThreadPool(getNThreads(), new ThreadFactoryBuilder().setNameFormat("Akarin Async Executor Thread - %1$d").build());
|
||||
|
||||
private static int getNThreads(){
|
||||
int processors = Runtime.getRuntime().availableProcessors() / 2;
|
||||
|
||||
if (processors < 2)
|
||||
return 2;
|
||||
if (processors > 8)
|
||||
return 8;
|
||||
return processors;
|
||||
private static int getNThreads() {
|
||||
int processors = Runtime.getRuntime().availableProcessors() / 2;
|
||||
if (processors < 2)
|
||||
return 2;
|
||||
if (processors > 8)
|
||||
return 8;
|
||||
return processors;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,6 +27,7 @@ public class AkarinAsyncExecutor {
|
||||
* @param run
|
||||
*/
|
||||
public static void scheduleSingleAsyncTask(Runnable run) {
|
||||
ThreadAssertion.close();
|
||||
singleExecutor.execute(run);
|
||||
}
|
||||
|
||||
@@ -34,6 +36,7 @@ public class AkarinAsyncExecutor {
|
||||
* @param run
|
||||
*/
|
||||
public static void scheduleAsyncTask(Runnable run) {
|
||||
ThreadAssertion.close();
|
||||
asyncExecutor.execute(run);
|
||||
}
|
||||
|
||||
@@ -43,6 +46,7 @@ public class AkarinAsyncExecutor {
|
||||
* @return
|
||||
*/
|
||||
public static <V> Future<V> scheduleSingleAsyncTask(Callable<V> run) {
|
||||
ThreadAssertion.close();
|
||||
return singleExecutor.submit(run);
|
||||
}
|
||||
|
||||
@@ -51,6 +55,7 @@ public class AkarinAsyncExecutor {
|
||||
* @param run
|
||||
*/
|
||||
public static <V> Future<V> scheduleAsyncTask(Callable<V> run) {
|
||||
ThreadAssertion.close();
|
||||
return asyncExecutor.submit(run);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import com.destroystokyo.paper.profile.CraftPlayerProfile;
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
|
||||
|
||||
import co.aikar.timings.ThreadAssertion;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
@@ -200,6 +202,7 @@ public class LoginListener implements PacketLoginInListener, ITickable {
|
||||
authenticatorPool.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ThreadAssertion.close(); // Akarin
|
||||
try {
|
||||
initUUID();
|
||||
new LoginHandler().fireEvents();
|
||||
@@ -228,6 +231,7 @@ public class LoginListener implements PacketLoginInListener, ITickable {
|
||||
// Paper start - Cache authenticator threads
|
||||
authenticatorPool.execute(new Runnable() {
|
||||
public void run() {
|
||||
ThreadAssertion.close(); // Akarin
|
||||
GameProfile gameprofile = LoginListener.this.i;
|
||||
|
||||
try {
|
||||
@@ -358,6 +362,7 @@ public class LoginListener implements PacketLoginInListener, ITickable {
|
||||
|
||||
// Proceed with login
|
||||
authenticatorPool.execute(() -> {
|
||||
ThreadAssertion.close(); // Akarin
|
||||
try {
|
||||
new LoginHandler().fireEvents();
|
||||
} catch (Exception ex) {
|
||||
|
||||
@@ -51,7 +51,7 @@ public final class MCUtil {
|
||||
}
|
||||
|
||||
public static boolean isMainThread() {
|
||||
return ThreadAssertion.isMainThread() && MinecraftServer.getServer().isMainThread(); // Akarin
|
||||
return ThreadAssertion.is() && MinecraftServer.getServer().isMainThread(); // Akarin
|
||||
}
|
||||
|
||||
private static class DelayedRunnable implements Runnable {
|
||||
@@ -118,7 +118,7 @@ public final class MCUtil {
|
||||
* @return
|
||||
*/
|
||||
public static void ensureMain(String reason, Runnable run) {
|
||||
if (/*AsyncCatcher.enabled &&*/ !ThreadAssertion.isMainThread() && Thread.currentThread() != MinecraftServer.getServer().primaryThread) { // Akarin
|
||||
if (/*AsyncCatcher.enabled &&*/ !ThreadAssertion.is() && Thread.currentThread() != MinecraftServer.getServer().primaryThread) { // Akarin
|
||||
if (reason != null) {
|
||||
new IllegalStateException("Asynchronous " + reason + "!").printStackTrace();
|
||||
}
|
||||
@@ -143,7 +143,7 @@ public final class MCUtil {
|
||||
* @return
|
||||
*/
|
||||
public static <T> T ensureMain(String reason, Supplier<T> run) {
|
||||
if (/*AsyncCatcher.enabled &&*/ !ThreadAssertion.isMainThread() && Thread.currentThread() != MinecraftServer.getServer().primaryThread) { // Akarin
|
||||
if (/*AsyncCatcher.enabled &&*/ !ThreadAssertion.is() && Thread.currentThread() != MinecraftServer.getServer().primaryThread) { // Akarin
|
||||
if (reason != null) {
|
||||
new IllegalStateException("Asynchronous " + reason + "! Blocking thread until it returns ").printStackTrace();
|
||||
}
|
||||
@@ -287,6 +287,7 @@ public final class MCUtil {
|
||||
* @param run
|
||||
*/
|
||||
public static void scheduleAsyncTask(Runnable run) {
|
||||
ThreadAssertion.close(); // Akarin
|
||||
asyncExecutor.execute(run);
|
||||
}
|
||||
|
||||
|
||||
@@ -1728,7 +1728,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
|
||||
}
|
||||
|
||||
public boolean isMainThread() {
|
||||
return ThreadAssertion.isMainThread() || Thread.currentThread() == this.serverThread; // Akarin
|
||||
return ThreadAssertion.is() || Thread.currentThread() == this.serverThread; // Akarin
|
||||
}
|
||||
|
||||
public int aw() {
|
||||
|
||||
@@ -1742,7 +1742,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
||||
|
||||
if (!async && s.startsWith("/")) {
|
||||
// Paper Start
|
||||
if (!org.spigotmc.AsyncCatcher.shuttingDown && !ThreadAssertion.isMainThread() && !org.bukkit.Bukkit.isPrimaryThread()) {
|
||||
if (!org.spigotmc.AsyncCatcher.shuttingDown && !ThreadAssertion.is() && !org.bukkit.Bukkit.isPrimaryThread()) {
|
||||
final String fCommandLine = s;
|
||||
MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Command Dispatched Async: " + fCommandLine); // Akarin
|
||||
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());
|
||||
|
||||
@@ -710,7 +710,7 @@ public final class CraftServer implements Server {
|
||||
//org.spigotmc.AsyncCatcher.catchOp( "command dispatch" ); // Spigot // Akarin
|
||||
|
||||
// Paper Start
|
||||
if (!org.spigotmc.AsyncCatcher.shuttingDown && !ThreadAssertion.isMainThread() && !Bukkit.isPrimaryThread()) { // Akarin
|
||||
if (!org.spigotmc.AsyncCatcher.shuttingDown && !ThreadAssertion.is() && !Bukkit.isPrimaryThread()) { // Akarin
|
||||
final CommandSender fSender = sender;
|
||||
final String fCommandLine = commandLine;
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Command Dispatched Async: " + commandLine);
|
||||
@@ -1724,7 +1724,7 @@ public final class CraftServer implements Server {
|
||||
|
||||
@Override
|
||||
public boolean isPrimaryThread() {
|
||||
return ThreadAssertion.isMainThread() || Thread.currentThread().equals(console.primaryThread);
|
||||
return ThreadAssertion.is() || Thread.currentThread().equals(console.primaryThread);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,7 +11,7 @@ public class AsyncCatcher
|
||||
|
||||
public static void catchOp(String reason)
|
||||
{
|
||||
if ( enabled && !ThreadAssertion.isMainThread() && Thread.currentThread() != MinecraftServer.getServer().primaryThread )
|
||||
if ( enabled && !ThreadAssertion.is() && Thread.currentThread() != MinecraftServer.getServer().primaryThread )
|
||||
{
|
||||
throw new IllegalStateException( "Asynchronous " + reason + "!" );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user