diff --git a/patches/server/0148-Base-thread-pool.patch b/patches/server/0148-Base-thread-pool.patch index f2fea67..c8551b1 100644 --- a/patches/server/0148-Base-thread-pool.patch +++ b/patches/server/0148-Base-thread-pool.patch @@ -2163,7 +2163,7 @@ index 0000000000000000000000000000000000000000..e9d778a078bee6b6f1c21078c445b48f +} diff --git a/src/main/java/org/galemc/gale/executor/MinecraftServerBlockableEventLoop.java b/src/main/java/org/galemc/gale/executor/MinecraftServerBlockableEventLoop.java new file mode 100644 -index 0000000000000000000000000000000000000000..84aa4f8e3f823cedc8cf958663fa2168f29d1d9c +index 0000000000000000000000000000000000000000..2da7a1a787bed2e03039796d56201870548ad0e4 --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/MinecraftServerBlockableEventLoop.java @@ -0,0 +1,187 @@ @@ -2338,7 +2338,7 @@ index 0000000000000000000000000000000000000000..84aa4f8e3f823cedc8cf958663fa2168 + //noinspection NonAtomicOperationOnVolatileField + ++blockingCount; + try { -+ MinecraftServer.serverThread.runTasksUntil(stopCondition, null); ++ MinecraftServer.serverThread.runTasksUntil(null, stopCondition, null); + } finally { + //noinspection NonAtomicOperationOnVolatileField + --blockingCount; @@ -2750,7 +2750,7 @@ index 0000000000000000000000000000000000000000..686e16da8372085196d8f92adb881f82 +} diff --git a/src/main/java/org/galemc/gale/executor/lock/YieldingLock.java b/src/main/java/org/galemc/gale/executor/lock/YieldingLock.java new file mode 100644 -index 0000000000000000000000000000000000000000..799608befb739d051153b5321598ea87b50fd6bd +index 0000000000000000000000000000000000000000..4b40afe88f166491f74f99bab96092d04e77fe02 --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/lock/YieldingLock.java @@ -0,0 +1,202 @@ @@ -2862,7 +2862,7 @@ index 0000000000000000000000000000000000000000..799608befb739d051153b5321598ea87 + return; + } + // Otherwise, we yield to other tasks until the lock can be acquired -+ yieldingThread.yieldUntil(null, this); ++ yieldingThread.yieldUntil(null, null, this); + } + // Increment the YieldingLock count of the current thread + if (this.canBeHeld) { @@ -4190,7 +4190,7 @@ index 0000000000000000000000000000000000000000..fb4f9c047fc71a9a01aa47871254c6a9 +} diff --git a/src/main/java/org/galemc/gale/executor/thread/AbstractYieldingThread.java b/src/main/java/org/galemc/gale/executor/thread/AbstractYieldingThread.java new file mode 100644 -index 0000000000000000000000000000000000000000..24a30760982244fb0d3fa1933751a8286c27014c +index 0000000000000000000000000000000000000000..fd4082f1d8fe558bbaaf3b17da18b361e34c81ed --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/thread/AbstractYieldingThread.java @@ -0,0 +1,147 @@ @@ -4249,7 +4249,7 @@ index 0000000000000000000000000000000000000000..24a30760982244fb0d3fa1933751a828 + + @ThisThreadOnly + @PotentiallyYielding("this method is meant to yield") -+ void yieldUntil(@Nullable BooleanSupplier stopCondition, @Nullable YieldingLock yieldingLock); ++ void yieldUntil(@Nullable Long timeoutTime, @Nullable BooleanSupplier stopCondition, @Nullable YieldingLock yieldingLock); + + /** + * Calls {@link #yieldUntil(BooleanSupplier, YieldingLock)}, but creates a {@link YieldingLock} @@ -4261,7 +4261,7 @@ index 0000000000000000000000000000000000000000..24a30760982244fb0d3fa1933751a828 + */ + @ThisThreadOnly + @PotentiallyYielding("this method is meant to yield") -+ default void yieldUntilFuture(@Nullable BooleanSupplier stopCondition, @NotNull CompletableFuture future, @Nullable Consumer autoCompletingLockConsumer) { ++ default void yieldUntilFuture(@Nullable Long timeoutTime, @Nullable BooleanSupplier stopCondition, @NotNull CompletableFuture future, @Nullable Consumer autoCompletingLockConsumer) { + + /* + Here, we abuse the Lock interface to create a YieldingLock @@ -4317,12 +4317,12 @@ index 0000000000000000000000000000000000000000..24a30760982244fb0d3fa1933751a828 + future.thenRun(autoCompletingLock::unlock); + + // Yield while necessary -+ this.yieldUntil(null, autoCompletingLock); ++ this.yieldUntil(timeoutTime, null, autoCompletingLock); + + } + + @ThisThreadOnly -+ void runTasksUntil(@Nullable BooleanSupplier stopCondition, @Nullable YieldingLock yieldingLock); ++ void runTasksUntil(@Nullable Long timeoutTime, @Nullable BooleanSupplier stopCondition, @Nullable YieldingLock yieldingLock); + + @AnyThreadSafe + @YieldFree @@ -4343,7 +4343,7 @@ index 0000000000000000000000000000000000000000..24a30760982244fb0d3fa1933751a828 +} diff --git a/src/main/java/org/galemc/gale/executor/thread/AssistThread.java b/src/main/java/org/galemc/gale/executor/thread/AssistThread.java new file mode 100644 -index 0000000000000000000000000000000000000000..a5605765f6be0b75e5df5613e8b393b64f88fc3c +index 0000000000000000000000000000000000000000..eab769d7319f26db1f4db9599a3c263c507641bd --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/thread/AssistThread.java @@ -0,0 +1,78 @@ @@ -4392,7 +4392,7 @@ index 0000000000000000000000000000000000000000..a5605765f6be0b75e5df5613e8b393b6 + */ + @ThisThreadOnly + protected void runForever() { -+ this.runTasksUntil(() -> false, null); ++ this.runTasksUntil(null, () -> false, null); + } + + /** @@ -4427,10 +4427,10 @@ index 0000000000000000000000000000000000000000..a5605765f6be0b75e5df5613e8b393b6 +} diff --git a/src/main/java/org/galemc/gale/executor/thread/BaseThread.java b/src/main/java/org/galemc/gale/executor/thread/BaseThread.java new file mode 100644 -index 0000000000000000000000000000000000000000..1c7275dd53e29594d25c63d3df54311a300a08fb +index 0000000000000000000000000000000000000000..17ae524053949073fcdcbccc53327c42ba1903c6 --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/thread/BaseThread.java -@@ -0,0 +1,719 @@ +@@ -0,0 +1,722 @@ +// Gale - base thread pool + +package org.galemc.gale.executor.thread; @@ -4675,14 +4675,14 @@ index 0000000000000000000000000000000000000000..1c7275dd53e29594d25c63d3df54311a + *
+ * Exactly one of {@code stopCondition} and {@code yieldingLock} must be non-null. + */ -+ public final void yieldUntil(@Nullable BooleanSupplier stopCondition, @Nullable YieldingLock yieldingLock) { ++ public final void yieldUntil(@Nullable Long timeoutTime, @Nullable BooleanSupplier stopCondition, @Nullable YieldingLock yieldingLock) { + int oldYieldDepth = this.yieldDepth; + int newYieldDepth = oldYieldDepth + 1; + this.yieldDepth = newYieldDepth; + if (newYieldDepth == maximumYieldDepth) { + this.updateCanStartYieldingTasks(); + } -+ this.runTasksUntil(stopCondition, yieldingLock); ++ this.runTasksUntil(timeoutTime, stopCondition, yieldingLock); + this.yieldDepth = oldYieldDepth; + if (newYieldDepth == maximumYieldDepth) { + this.updateCanStartYieldingTasks(); @@ -4691,7 +4691,8 @@ index 0000000000000000000000000000000000000000..1c7275dd53e29594d25c63d3df54311a + + /** + * This method will keep attempting to find a task to do, and execute it, and if none is found, start waiting -+ * until signalled by {@link BaseThreadPool} or by a {@link YieldingLock}. ++ * until the {@code timeoutTime} is reached (which is compared to {@link System#nanoTime}), ++ * or the thread is signalled by {@link BaseThreadPool} or by a {@link YieldingLock}. + * The loop is broken as soon as the stop condition becomes true, or the given lock is successfully acquired. + *
+ * The above is the same as {@link #yieldUntil}, except it may be called in situations that is not 'yielding', @@ -4704,7 +4705,8 @@ index 0000000000000000000000000000000000000000..1c7275dd53e29594d25c63d3df54311a + */ + @ThisThreadOnly + @PotentiallyYielding("may yield further if an executed task is potentially yielding") -+ public final void runTasksUntil(@Nullable BooleanSupplier stopCondition, @Nullable YieldingLock yieldingLock) { ++ public final void runTasksUntil(@Nullable Long timeoutTime, @Nullable BooleanSupplier stopCondition, @Nullable YieldingLock yieldingLock) { ++ if (TickThread.isTickThread()) MinecraftServer.THREAD_DEBUG_LOGGER.ifPresent(it -> it.info("running tasks until")); + this.isPollingTaskOrCheckingStopCondition = true; + + /* @@ -4798,7 +4800,7 @@ index 0000000000000000000000000000000000000000..1c7275dd53e29594d25c63d3df54311a + or for the given yielding lock to be released. This is the only time we should ever block inside + a potentially yielding procedure. + */ -+ this.waitUntilSignalled(yieldingLock); ++ this.waitUntilSignalled(timeoutTime, yieldingLock); + + } + @@ -4928,12 +4930,13 @@ index 0000000000000000000000000000000000000000..1c7275dd53e29594d25c63d3df54311a + /** + * Starts waiting on something to do. + * ++ * @param timeoutTime The maximum time to wait until (compared to {@link System#nanoTime}). + * @param yieldingLock A {@link YieldingLock} to register with, or null if this thread is not waiting for + * a yielding lock. + */ + @ThisThreadOnly + @PotentiallyBlocking -+ private void waitUntilSignalled(@Nullable YieldingLock yieldingLock) { ++ private void waitUntilSignalled(@Nullable Long timeoutTime, @Nullable YieldingLock yieldingLock) { + + // Remember whether we registered to wait with the lock, to unregister later + // Register this thread with the lock if necessary @@ -4999,57 +5002,57 @@ index 0000000000000000000000000000000000000000..1c7275dd53e29594d25c63d3df54311a + // Wait + try { + -+ /* -+ Check if we should wait with a timeout: this only happens if this thread is the server thread, in -+ which case we do not want to wait past the start of the next tick. -+ */ -+ boolean waitedWithTimeout = false; -+ if (this == MinecraftServer.serverThread) { -+ // -1 indicates to not use a timeout (this value is not later set to any other negative value) -+ long waitForNanos = -1; -+ if (MinecraftServer.isWaitingUntilNextTick) { -+ /* -+ During waiting until the next tick, we wait until the next tick start. -+ If it already passed, we do not have to use a timeout, because we will be notified -+ when the stop condition becomes true. -+ */ -+ waitForNanos = MinecraftServer.nextTickStartNanoTime - System.nanoTime(); -+ if (waitForNanos < 0) { -+ waitForNanos = -1; -+ } -+ } else if (MinecraftServer.SERVER.isOversleep) { -+ /* -+ During this phase, MinecraftServer#mayHaveDelayedTasks() is checked, and we may not -+ be notified when it changes. Therefore, if the next tick start has not passed, we will -+ wait until then, but if it has, we wait for a short interval to make sure we keep -+ checking the stop condition (but not for longer than until the last time we can be -+ executing extra delayed tasks). -+ */ -+ waitForNanos = MinecraftServer.nextTickStartNanoTime - System.nanoTime(); -+ if (waitForNanos < 0) { -+ waitForNanos = Math.min(Math.max(0, MinecraftServer.delayedTasksMaxNextTickNanoTime - System.nanoTime()), SERVER_THREAD_WAIT_NANOS_DURING_OVERSLEEP_WITH_DELAYED_TASKS); -+ } -+ } -+ if (waitForNanos >= 0) { -+ // Set the last signal reason to null in case the timeout elapses without a signal -+ this.lastSignalReason = null; -+ // Wait, but at most for the determined time -+ waitedWithTimeout = true; -+ // Skip if the time is too short -+ if (waitForNanos >= SERVER_THREAD_WAIT_NANOS_MINIMUM) { -+ //noinspection ResultOfMethodCallIgnored -+ this.waitCondition.await(waitForNanos, TimeUnit.NANOSECONDS); ++ // -1 indicates to not use a timeout (this value is not later set to any other negative value) ++ long waitForNanos = -1; ++ if (timeoutTime != null) { ++ waitForNanos = Math.max(timeoutTime - System.nanoTime(), SERVER_THREAD_WAIT_NANOS_MINIMUM); ++ } else { ++ /* ++ Check if we should wait with a tick-based timeout: ++ this only happens if this thread is the server thread, in ++ which case we do not want to wait past the start of the next tick. ++ */ ++ if (this == MinecraftServer.serverThread) { ++ if (MinecraftServer.isWaitingUntilNextTick) { ++ /* ++ During waiting until the next tick, we wait until the next tick start. ++ If it already passed, we do not have to use a timeout, because we will be notified ++ when the stop condition becomes true. ++ */ ++ waitForNanos = MinecraftServer.nextTickStartNanoTime - System.nanoTime(); ++ if (waitForNanos < 0) { ++ waitForNanos = -1; ++ } ++ } else if (MinecraftServer.SERVER.isOversleep) { ++ /* ++ During this phase, MinecraftServer#mayHaveDelayedTasks() is checked, and we may not ++ be notified when it changes. Therefore, if the next tick start has not passed, we will ++ wait until then, but if it has, we wait for a short interval to make sure we keep ++ checking the stop condition (but not for longer than until the last time we can be ++ executing extra delayed tasks). ++ */ ++ waitForNanos = MinecraftServer.nextTickStartNanoTime - System.nanoTime(); ++ if (waitForNanos < 0) { ++ waitForNanos = Math.min(Math.max(0, MinecraftServer.delayedTasksMaxNextTickNanoTime - System.nanoTime()), SERVER_THREAD_WAIT_NANOS_DURING_OVERSLEEP_WITH_DELAYED_TASKS); ++ } + } + } + } -+ -+ /* -+ If we did not wait with a timeout, wait indefinitely. If this thread is the server thread, -+ and the intended start time of the next tick has already passed, but the stop condition to stop -+ running tasks is still not true, this thread must be signalled when a change in conditions causes -+ the stop condition to become true. -+ */ -+ if (!waitedWithTimeout) { ++ if (waitForNanos >= 0) { ++ // Set the last signal reason to null in case the timeout elapses without a signal ++ this.lastSignalReason = null; ++ // Skip if the time is too short ++ if (waitForNanos >= SERVER_THREAD_WAIT_NANOS_MINIMUM) { ++ //noinspection ResultOfMethodCallIgnored ++ this.waitCondition.await(waitForNanos, TimeUnit.NANOSECONDS); ++ } ++ } else { ++ /* ++ If we did not wait with a timeout, wait indefinitely. If this thread is the server thread, ++ and the intended start time of the next tick has already passed, but the stop condition to stop ++ running tasks is still not true, this thread must be signalled when a change in conditions causes ++ the stop condition to become true. ++ */ + this.waitCondition.await(); + } + @@ -5301,7 +5304,7 @@ index 0000000000000000000000000000000000000000..a73aafc64dc60b57e2e5a91565e1aff6 +} diff --git a/src/main/java/org/galemc/gale/executor/thread/deferral/ServerThreadDeferral.java b/src/main/java/org/galemc/gale/executor/thread/deferral/ServerThreadDeferral.java new file mode 100644 -index 0000000000000000000000000000000000000000..57f672f9f81aeb6ce0ef44fa47db80602b03a5d4 +index 0000000000000000000000000000000000000000..8c4855c931ccc285768eabcff9d1f2b752d45bf6 --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/thread/deferral/ServerThreadDeferral.java @@ -0,0 +1,151 @@ @@ -5399,7 +5402,7 @@ index 0000000000000000000000000000000000000000..57f672f9f81aeb6ce0ef44fa47db8060 + } + yieldingThread.signal(null); + }, span); -+ yieldingThread.yieldUntil(future::isDone, null); ++ yieldingThread.yieldUntil(null, future::isDone, null); + return future.getNow(null); + } else { + // Block until the task completes diff --git a/patches/server/0152-Run-async-executor-tasks-on-base-thread-pool.patch b/patches/server/0152-Run-async-executor-tasks-on-base-thread-pool.patch index dd90a7b..cf49500 100644 --- a/patches/server/0152-Run-async-executor-tasks-on-base-thread-pool.patch +++ b/patches/server/0152-Run-async-executor-tasks-on-base-thread-pool.patch @@ -27,7 +27,7 @@ index 4b8da38db72d7ebc2d498ec3d711d3b30911096c..80f9e70d5c4330e079feccc9a4b1b595 1, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index fe2892e20dcb0b76d30b81bca7a13e29a1c45723..313d45dae086ac7c1bd0dd71540020c18a9e5d86 100644 +index fe2892e20dcb0b76d30b81bca7a13e29a1c45723..c2930cc38d02fb62cf7b1a8bdde53753cb4bc64e 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1081,9 +1081,6 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop @@ -47,7 +47,7 @@ index fe2892e20dcb0b76d30b81bca7a13e29a1c45723..313d45dae086ac7c1bd0dd71540020c1 + // Gale start - base thread pool - remove Paper async executor + long startTime = Util.getMillis(); + LOGGER.info("Waiting 30 seconds for asynchronous tasks to finish..."); -+ serverThread.runTasksUntil(() -> Util.getMillis() - startTime >= 30 || !BaseTaskQueues.scheduledAsync.hasTasks(), null); // Paper ++ serverThread.runTasksUntil(null, () -> Util.getMillis() - startTime >= 30 || !BaseTaskQueues.scheduledAsync.hasTasks(), null); // Paper + LOGGER.info("Shutting down IO executor..."); + // Gale end - base thread pool - remove Paper async executor Util.shutdownExecutors(); // Paper diff --git a/patches/server/0158-Run-chunk-cache-tasks-on-base-thread-pool.patch b/patches/server/0158-Run-chunk-cache-tasks-on-base-thread-pool.patch index 9cb2be8..13c15dc 100644 --- a/patches/server/0158-Run-chunk-cache-tasks-on-base-thread-pool.patch +++ b/patches/server/0158-Run-chunk-cache-tasks-on-base-thread-pool.patch @@ -7,7 +7,7 @@ License: AGPL-3.0 (https://www.gnu.org/licenses/agpl-3.0.html) Gale - https://galemc.org diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 83a57b9bc59063ed8299f98bc33e14b57f2ea0de..f1aaf1cae3335f7c7340104cfd6dbc3dd62f6ab3 100644 +index 83a57b9bc59063ed8299f98bc33e14b57f2ea0de..5187fd95577afa4ddf4544206ec6bb467bcdce81 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -11,7 +11,6 @@ import java.util.Collections; @@ -44,26 +44,23 @@ index 83a57b9bc59063ed8299f98bc33e14b57f2ea0de..f1aaf1cae3335f7c7340104cfd6dbc3d } else { completablefuture = CompletableFuture.supplyAsync(() -> { return this.getChunkFutureMainThread(chunkX, chunkZ, leastStatus, create); -@@ -973,6 +973,18 @@ public class ServerChunkCache extends ChunkSource { +@@ -973,6 +973,15 @@ public class ServerChunkCache extends ChunkSource { public final class MainThreadExecutor extends BlockableEventLoop { + // Gale start - base thread pool -+ private static volatile boolean chunkWorkerTasksWereCompletedSinceLastDoChunkCacheTasksInYield; -+ public static @Nullable YieldingLock yieldingLockToNotifyForNewChunkCacheTasks; -+ -+ public static void notifyOfCompletedChunkWorkerTasks() { -+ if (yieldingLockToNotifyForNewChunkCacheTasks != null) { -+ chunkWorkerTasksWereCompletedSinceLastDoChunkCacheTasksInYield = true; -+ yieldingLockToNotifyForNewChunkCacheTasks.unlock(); -+ } -+ } ++ /** ++ * The time interval for the server thread to yield when this executor is performing ++ * a {@link #managedYield} but failed to perform any other tasks from this executor itself. ++ */ ++ private static final long MANAGED_YIELD_TIMEOUT_TIME = 50_000L; ++ private static @Nullable YieldingLock yieldingLockToNotifyForNewChunkCacheTasks; + // Gale end - base thread pool + MainThreadExecutor(Level world) { super("Chunk source main thread executor for " + world.dimension().location()); } -@@ -1002,6 +1014,40 @@ public class ServerChunkCache extends ChunkSource { +@@ -1002,6 +1011,40 @@ public class ServerChunkCache extends ChunkSource { super.doRunTask(task); } @@ -89,8 +86,8 @@ index 83a57b9bc59063ed8299f98bc33e14b57f2ea0de..f1aaf1cae3335f7c7340104cfd6dbc3d + var currentThread = AbstractYieldingThread.currentYieldingThread(); + while (!future.isDone()) { + if (!this.pollTask()) { -+ currentThread.yieldUntilFuture(() -> this.hasPendingTasks() || chunkWorkerTasksWereCompletedSinceLastDoChunkCacheTasksInYield, future, autoCompletingLock -> yieldingLockToNotifyForNewChunkCacheTasks = autoCompletingLock); -+ chunkWorkerTasksWereCompletedSinceLastDoChunkCacheTasksInYield = false; ++ long timeoutTime = System.nanoTime() + MANAGED_YIELD_TIMEOUT_TIME; ++ currentThread.yieldUntilFuture(timeoutTime, () -> this.hasPendingTasks(), future, autoCompletingLock -> yieldingLockToNotifyForNewChunkCacheTasks = autoCompletingLock); + } + } + yieldingLockToNotifyForNewChunkCacheTasks = null; diff --git a/patches/server/0161-Run-chunk-worker-tasks-on-base-thread-pool.patch b/patches/server/0161-Run-chunk-worker-tasks-on-base-thread-pool.patch index 1156455..845f598 100644 --- a/patches/server/0161-Run-chunk-worker-tasks-on-base-thread-pool.patch +++ b/patches/server/0161-Run-chunk-worker-tasks-on-base-thread-pool.patch @@ -480,7 +480,7 @@ index f5c15d40094c2ddc6220b0595597d12103fcf425..79ef41d2bb30beee2355d1de3dc99c9e } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 313d45dae086ac7c1bd0dd71540020c18a9e5d86..c14b593bd450d244209d17b637fe7c03a1f746f4 100644 +index c2930cc38d02fb62cf7b1a8bdde53753cb4bc64e..29c86b4ee9b147a7645f6577ce22b7a2e6f0b213 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1070,6 +1070,10 @@ public abstract class MinecraftServer extends MinecraftServerBlockableEventLoop @@ -489,7 +489,7 @@ index 313d45dae086ac7c1bd0dd71540020c18a9e5d86..c14b593bd450d244209d17b637fe7c03 + // Gale start - base thread pool - chunk worker task queue + LOGGER.info("Waiting for chunk worker tasks to finish..."); -+ serverThread.runTasksUntil(() -> !BaseTaskQueues.chunkWorker.hasTasks(), null); ++ serverThread.runTasksUntil(null, () -> !BaseTaskQueues.chunkWorker.hasTasks(), null); + // Gale end - base thread pool - chunk worker task queue this.saveAllChunks(false, true, false, true); // Paper - rewrite chunk system - move closing into here @@ -545,10 +545,10 @@ index ed3ccf2e64539363a7be2d507c68c40b5913f75c..a12250e5aaed02995b7bf09a8018a93f } diff --git a/src/main/java/org/galemc/gale/executor/queue/ChunkWorkerTaskQueue.java b/src/main/java/org/galemc/gale/executor/queue/ChunkWorkerTaskQueue.java new file mode 100644 -index 0000000000000000000000000000000000000000..221f9e6f10c56c92e00fc8f41e09a977a7ed9e76 +index 0000000000000000000000000000000000000000..9c36119b03ba9a20dc6994ef2d2704ebe9cc4800 --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/queue/ChunkWorkerTaskQueue.java -@@ -0,0 +1,106 @@ +@@ -0,0 +1,103 @@ +// Gale - base thread pool - chunk worker task queue + +package org.galemc.gale.executor.queue; @@ -621,11 +621,8 @@ index 0000000000000000000000000000000000000000..221f9e6f10c56c92e00fc8f41e09a977 + return () -> { + var workerAgent = currentThread.getChunkWorkerAgent(); + ChunkTaskScheduler.workerThreads.activeThreads.add(workerAgent); -+ boolean performedTasks = workerAgent.pollTasks(); ++ workerAgent.pollTasks(); + ChunkTaskScheduler.workerThreads.activeThreads.remove(workerAgent); -+ if (performedTasks) { -+ ServerChunkCache.MainThreadExecutor.notifyOfCompletedChunkWorkerTasks(); -+ } + }; + } + @@ -656,7 +653,7 @@ index 0000000000000000000000000000000000000000..221f9e6f10c56c92e00fc8f41e09a977 + +} diff --git a/src/main/java/org/galemc/gale/executor/thread/BaseThread.java b/src/main/java/org/galemc/gale/executor/thread/BaseThread.java -index 1c7275dd53e29594d25c63d3df54311a300a08fb..00a52c8c21ebfa95cfd3e6e9d9d76c5789ea6d83 100644 +index 17ae524053949073fcdcbccc53327c42ba1903c6..a01ce790927ff79071c582ca84d64207fd850dfa 100644 --- a/src/main/java/org/galemc/gale/executor/thread/BaseThread.java +++ b/src/main/java/org/galemc/gale/executor/thread/BaseThread.java @@ -2,6 +2,8 @@ @@ -676,7 +673,7 @@ index 1c7275dd53e29594d25c63d3df54311a300a08fb..00a52c8c21ebfa95cfd3e6e9d9d76c57 import org.jetbrains.annotations.Nullable; import java.util.concurrent.TimeUnit; -@@ -696,6 +699,20 @@ public abstract class BaseThread extends Thread implements AbstractYieldingThrea +@@ -699,6 +702,20 @@ public abstract class BaseThread extends Thread implements AbstractYieldingThrea } }