From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 23 Oct 2018 23:14:38 -0400
Subject: [PATCH] Improve Server Thread Pool and Thread Priorities

Use a simple executor since Fork join is a much more complex pool
type and we are not using its capabilities.

Set thread priorities so main thread has above normal priority over
server threads

Allow usage of a single thread executor by not using ForkJoin so single core CPU's.

diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index aea9e169f9a11378c176c0cc3ee5a0d59e6a4c38..354109e5f7a8e1b0895e12002951a4bd3bf7dd0c 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -175,6 +175,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
         S s0 = function.apply(thread); // CraftBukkit - decompile error
 
         atomicreference.set(s0);
+        thread.setPriority(Thread.NORM_PRIORITY+2); // Paper - boost priority
         thread.start();
         return s0;
     }
diff --git a/src/main/java/net/minecraft/server/ServerWorkerThread.java b/src/main/java/net/minecraft/server/ServerWorkerThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c4c4171baf18a58667e3882e47fc23293d4fc1c
--- /dev/null
+++ b/src/main/java/net/minecraft/server/ServerWorkerThread.java
@@ -0,0 +1,13 @@
+package net.minecraft.server;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ServerWorkerThread extends Thread {
+    private static final AtomicInteger threadId = new AtomicInteger(1);
+    public ServerWorkerThread(Runnable target, String poolName, int prioritityModifier) {
+        super(target, "Worker-" + poolName + "-" + threadId.getAndIncrement());
+        setPriority(Thread.NORM_PRIORITY+prioritityModifier); // Deprioritize over main
+        this.setDaemon(true);
+        this.setUncaughtExceptionHandler(SystemUtils::onThreadError);
+    }
+}
diff --git a/src/main/java/net/minecraft/server/SystemUtils.java b/src/main/java/net/minecraft/server/SystemUtils.java
index cc14e4b4609fa7013df666181c0e02a53970c123..1fe1df445ba56b2f176ee25502a774aa0a7bd00b 100644
--- a/src/main/java/net/minecraft/server/SystemUtils.java
+++ b/src/main/java/net/minecraft/server/SystemUtils.java
@@ -48,8 +48,8 @@ import org.apache.logging.log4j.Logger;
 public class SystemUtils {
 
     private static final AtomicInteger c = new AtomicInteger(1);
-    private static final ExecutorService d = a("Bootstrap");
-    private static final ExecutorService e = a("Main");
+    private static final ExecutorService d = a("Bootstrap", -2); // Paper - add -2 priority
+    private static final ExecutorService e = a("Main", -1); // Paper - add -1 priority
     private static final ExecutorService f = n();
     public static LongSupplier a = System::nanoTime;
     public static final UUID b = new UUID(0L, 0L); public static final UUID getNullUUID() {return b;} // Paper OBFHELPER
@@ -79,15 +79,18 @@ public class SystemUtils {
         return Instant.now().toEpochMilli();
     }
 
-    private static ExecutorService a(String s) {
-        int i = MathHelper.clamp(Runtime.getRuntime().availableProcessors() - 1, 1, 7);
-        Object object;
+    private static ExecutorService a(String s, int priorityModifier) { // Paper - add priority
+        // Paper start - use simpler thread pool that allows 1 thread
+        int i = Math.min(8, Math.max(Runtime.getRuntime().availableProcessors() - 2, 1));
+        i = Integer.getInteger("Paper.WorkerThreadCount", i);
+        ExecutorService object;
 
         if (i <= 0) {
             object = MoreExecutors.newDirectExecutorService();
         } else {
-            object = new ForkJoinPool(i, (forkjoinpool) -> {
-                ForkJoinWorkerThread forkjoinworkerthread = new ForkJoinWorkerThread(forkjoinpool) {
+            object = new java.util.concurrent.ThreadPoolExecutor(i, i,0L, TimeUnit.MILLISECONDS, new java.util.concurrent.LinkedBlockingQueue<Runnable>(), target -> new ServerWorkerThread(target, s, priorityModifier));
+        }
+        /*
                     protected void onTermination(Throwable throwable) {
                         if (throwable != null) {
                             SystemUtils.LOGGER.warn("{} died", this.getName(), throwable);
@@ -103,6 +106,7 @@ public class SystemUtils {
                 return forkjoinworkerthread;
             }, SystemUtils::a, true);
         }
+        }*/ // Paper end
 
         return (ExecutorService) object;
     }
@@ -151,6 +155,7 @@ public class SystemUtils {
         });
     }
 
+    public static void onThreadError(Thread thread, Throwable throwable) { a(thread, throwable); } // Paper - OBFHELPER
     private static void a(Thread thread, Throwable throwable) {
         c(throwable);
         if (throwable instanceof CompletionException) {
