9
0
mirror of https://github.com/Dreeam-qwq/Gale.git synced 2025-12-27 10:39:12 +00:00

Use timeout instead of notifications after chunk worker task

This commit is contained in:
Martijn Muijsers
2023-02-06 19:18:18 +01:00
parent c8675f646c
commit 8a11cbe4e2
4 changed files with 92 additions and 95 deletions

View File

@@ -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<YieldingLock> autoCompletingLockConsumer) {
+ default void yieldUntilFuture(@Nullable Long timeoutTime, @Nullable BooleanSupplier stopCondition, @NotNull CompletableFuture<?> future, @Nullable Consumer<YieldingLock> 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
+ * <br>
+ * 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.
+ * <br>
+ * 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

View File

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

View File

@@ -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<Runnable> {
+ // 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;

View File

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