From 7adc0b103c22863b0c838b7f56cfb49dd7909d5c Mon Sep 17 00:00:00 2001 From: Martijn Muijsers Date: Tue, 31 Jan 2023 01:18:02 +0100 Subject: [PATCH] Use spin locks with easier syntax --- patches/server/0142-Mutex-utility.patch | 51 ++++- patches/server/0145-Base-thread-pool.patch | 10 +- ...unk-worker-tasks-on-base-thread-pool.patch | 190 ++++++++---------- .../0156-Non-blocking-PooledObjects.patch | 30 +-- 4 files changed, 138 insertions(+), 143 deletions(-) diff --git a/patches/server/0142-Mutex-utility.patch b/patches/server/0142-Mutex-utility.patch index cefe6c4..1c906da 100644 --- a/patches/server/0142-Mutex-utility.patch +++ b/patches/server/0142-Mutex-utility.patch @@ -8,10 +8,10 @@ Gale - https://galemc.org diff --git a/src/main/java/org/galemc/gale/concurrent/Mutex.java b/src/main/java/org/galemc/gale/concurrent/Mutex.java new file mode 100644 -index 0000000000000000000000000000000000000000..65ec8cf910575dfa4c5024ec69b3be1ef2634722 +index 0000000000000000000000000000000000000000..e8ab6cd25909a848c1826824a0f04dc593a26be7 --- /dev/null +++ b/src/main/java/org/galemc/gale/concurrent/Mutex.java -@@ -0,0 +1,76 @@ +@@ -0,0 +1,121 @@ +// Gale - mutex utility + +package org.galemc.gale.concurrent; @@ -30,11 +30,13 @@ index 0000000000000000000000000000000000000000..65ec8cf910575dfa4c5024ec69b3be1e + * {@link Lock#tryLock} and {@link Lock#unlock} methods are simply deferred to their usual mutex versions, + * respectively {@link #acquireUninterruptibly}, {@link #acquire}, {@link #tryAcquire} and + * {@link #release}. The {@link Lock#newCondition} method does not have a default implementation. ++ *
++ * This interface extends {@link AutoCloseable}, where {@link #close()} calls {@link #release()}. + * + * @author Martijn Muijsers + */ +@AnyThreadSafe -+public interface Mutex extends Lock { ++public interface Mutex extends Lock, AutoCloseable { + + void acquireUninterruptibly(); + @@ -72,6 +74,49 @@ index 0000000000000000000000000000000000000000..65ec8cf910575dfa4c5024ec69b3be1e + } + + /** ++ * Acquires this mutex in the style of a spin lock: repeatedly calls {@link #tryAcquire()} until successful. ++ */ ++ default void spinLock() { ++ //noinspection StatementWithEmptyBody ++ while (!this.tryAcquire()); ++ } ++ ++ /** ++ * Acquires this mutex with {@link #acquire()}, then returns this instance. ++ *
++ * This can be used in the following way: ++ *

++ * ++ *  try (mutex.withLock()) {
++ *   // code
++ *  } ++ *
++ *

++ * ++ * @return This {@link Mutex}, which implements {@link AutoCloseable}. ++ */ ++ default Mutex withLock() throws InterruptedException { ++ this.acquire(); ++ return this; ++ } ++ ++ /** ++ * Acquires this mutex with {@link #spinLock()}, then returns this instance. ++ * ++ * @return This {@link Mutex}, which implements {@link AutoCloseable}. ++ * @see #withLock() ++ */ ++ default Mutex withSpinLock() { ++ this.spinLock(); ++ return this; ++ } ++ ++ @Override ++ default void close() { ++ this.release(); ++ } ++ ++ /** + * Instantiates a new {@link Mutex}, with the default implementation + * that should be geared towards performance. + */ diff --git a/patches/server/0145-Base-thread-pool.patch b/patches/server/0145-Base-thread-pool.patch index e0c93bd..ab8e247 100644 --- a/patches/server/0145-Base-thread-pool.patch +++ b/patches/server/0145-Base-thread-pool.patch @@ -1851,18 +1851,18 @@ index 78f53ee557276de85f0431ebcb146445b1f4fb92..6176867eea06c53882dcaacfbde0334b return ret; diff --git a/src/main/java/org/galemc/gale/concurrent/Mutex.java b/src/main/java/org/galemc/gale/concurrent/Mutex.java -index 65ec8cf910575dfa4c5024ec69b3be1ef2634722..174c248aa706f6b5f3e248cb7604b44a4d508967 100644 +index e8ab6cd25909a848c1826824a0f04dc593a26be7..fdad4a7a15d4af427e1441dcc3d837faf1189f85 100644 --- a/src/main/java/org/galemc/gale/concurrent/Mutex.java +++ b/src/main/java/org/galemc/gale/concurrent/Mutex.java -@@ -17,7 +17,7 @@ import java.util.concurrent.locks.Lock; - * respectively {@link #acquireUninterruptibly}, {@link #acquire}, {@link #tryAcquire} and - * {@link #release}. The {@link Lock#newCondition} method does not have a default implementation. +@@ -19,7 +19,7 @@ import java.util.concurrent.locks.Lock; + *
+ * This interface extends {@link AutoCloseable}, where {@link #close()} calls {@link #release()}. * - * @author Martijn Muijsers + * @author Martijn Muijsers under AGPL-3.0 */ @AnyThreadSafe - public interface Mutex extends Lock { + public interface Mutex extends Lock, AutoCloseable { diff --git a/src/main/java/org/galemc/gale/concurrent/SemaphoreMutex.java b/src/main/java/org/galemc/gale/concurrent/SemaphoreMutex.java index 2e31501d26b141729c80975e97a23b09653ba3bf..5a454236073dd75ed36d058c0f033c4aada403e3 100644 --- a/src/main/java/org/galemc/gale/concurrent/SemaphoreMutex.java diff --git a/patches/server/0155-Run-chunk-worker-tasks-on-base-thread-pool.patch b/patches/server/0155-Run-chunk-worker-tasks-on-base-thread-pool.patch index 94cf448..18fb121 100644 --- a/patches/server/0155-Run-chunk-worker-tasks-on-base-thread-pool.patch +++ b/patches/server/0155-Run-chunk-worker-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/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedThreadPool.java b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedThreadPool.java -index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9b2567fe0 100644 +index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..2fa56c06ec16817d5e35d5283b8e5a0d0e01d643 100644 --- a/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedThreadPool.java +++ b/src/main/java/ca/spottedleaf/concurrentutil/executor/standard/PrioritisedThreadPool.java @@ -2,11 +2,17 @@ package ca.spottedleaf.concurrentutil.executor.standard; @@ -32,7 +32,7 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiConsumer; -@@ -14,8 +20,9 @@ public final class PrioritisedThreadPool { +@@ -14,13 +20,16 @@ public final class PrioritisedThreadPool { private static final Logger LOGGER = LogUtils.getLogger(); @@ -44,7 +44,14 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 protected final String name; protected final long queueMaxHoldTime; -@@ -46,37 +53,14 @@ public final class PrioritisedThreadPool { + protected final ReferenceOpenHashSet nonShutdownQueues = new ReferenceOpenHashSet<>(); ++ protected final Mutex nonShutdownQueuesLock = Mutex.create(); // Gale - base thread pool - chunk worker task queue - spin lock for pool queues + protected final ReferenceOpenHashSet activeQueues = new ReferenceOpenHashSet<>(); ++ protected final Mutex activeQueuesLock = Mutex.create(); // Gale - base thread pool - chunk worker task queue - spin lock for pool queues + + protected boolean shutdown; + +@@ -46,41 +55,18 @@ public final class PrioritisedThreadPool { } this.name = name; this.queueMaxHoldTime = queueHoldTime; @@ -67,15 +74,16 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 - // now the thread can start - this.threads[i].start(); - } -- } -- -- public Thread[] getThreads() { -- return Arrays.copyOf(this.threads, this.threads.length, Thread[].class); } +- public Thread[] getThreads() { +- return Arrays.copyOf(this.threads, this.threads.length, Thread[].class); +- } +- - public PrioritisedPoolExecutor createExecutor(final String name, final int parallelism) { +- synchronized (this.nonShutdownQueues) { + public PrioritisedPoolExecutor createExecutor(final String name, boolean supportsParallelism) { // Gale - base thread pool - chunk worker task queue - synchronized (this.nonShutdownQueues) { ++ try (var ignored = nonShutdownQueuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues if (this.shutdown) { throw new IllegalStateException("Queue is shutdown: " + this.toString()); } @@ -84,7 +92,12 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 this.nonShutdownQueues.add(ret); -@@ -88,136 +72,24 @@ public final class PrioritisedThreadPool { +- synchronized (this.activeQueues) { ++ try (var ignored2 = this.activeQueuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues + this.activeQueues.add(ret); + } + +@@ -88,136 +74,24 @@ public final class PrioritisedThreadPool { } } @@ -231,7 +244,7 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 } private boolean isAlertedHighPriority() { -@@ -225,21 +97,23 @@ public final class PrioritisedThreadPool { +@@ -225,21 +99,19 @@ public final class PrioritisedThreadPool { } @Override @@ -252,15 +265,11 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 final PrioritisedPoolExecutorImpl queue; // select queue - synchronized (queues) { -+ // Gale start - base thread pool - chunk worker task queue - spin lock for pool queues -+ //noinspection StatementWithEmptyBody -+ while (!queuesLock.tryAcquire()); -+ try { -+ // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues ++ try (var ignored = queuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues queue = queues.pollFirst(); if (queue == null) { // no tasks to execute -@@ -249,7 +123,7 @@ public final class PrioritisedThreadPool { +@@ -249,7 +121,7 @@ public final class PrioritisedThreadPool { queue.schedulingId = ++pool.schedulingIdGenerator; // we own this queue now, so increment the executor count // do we also need to push this queue up for grabs for another executor? @@ -269,18 +278,7 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 // re-add to queues // it's very important this is done in the same synchronised block for polling, as this prevents // us from possibly later adding a queue that should not exist in the set -@@ -261,16 +135,17 @@ public final class PrioritisedThreadPool { - // note: we cannot drain entries from the queue while holding this lock, as it will cause deadlock - // the queue addition holds the per-queue lock first then acquires the lock we have now, but if we - // try to poll now we don't hold the per queue lock but we do hold the global lock... -+ // Gale start - base thread pool - chunk worker task queue - spin lock for pool queues -+ } finally { -+ queuesLock.release(); - } -+ // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues - - // parse tasks as long as we are allowed - final long start = System.nanoTime(); +@@ -268,9 +140,6 @@ public final class PrioritisedThreadPool { final long deadline = start + pool.queueMaxHoldTime; do { try { @@ -290,7 +288,7 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 if (!queue.executeTask()) { // no more tasks, try next queue break; -@@ -279,11 +154,15 @@ public final class PrioritisedThreadPool { +@@ -279,11 +148,11 @@ public final class PrioritisedThreadPool { } catch (final ThreadDeath death) { throw death; // goodbye world... } catch (final Throwable throwable) { @@ -301,24 +299,11 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 + } while (!this.isAlertedHighPriority() && System.nanoTime() <= deadline && BaseThreadActivation.tierInExcessOrdinal > BaseTaskQueueTier.LOW_PRIORITY_ASYNC.ordinal); // Gale - base thread pool - chunk worker task queue - synchronized (queues) { -+ // Gale start - base thread pool - chunk worker task queue - spin lock for pool queues -+ //noinspection StatementWithEmptyBody -+ while (!queuesLock.tryAcquire()); -+ try { -+ // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues ++ try (var ignored = queuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues // decrement executors, we are no longer executing if (queue.isQueued) { queues.remove(queue); -@@ -301,11 +180,21 @@ public final class PrioritisedThreadPool { - queues.add(queue); - queue.isQueued = true; - } -+ // Gale start - base thread pool - chunk worker task queue - spin lock for pool queues -+ } finally { -+ queuesLock.release(); - } -+ // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues - } +@@ -306,6 +175,12 @@ public final class PrioritisedThreadPool { return ret; } @@ -331,7 +316,7 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 } public interface PrioritisedPoolExecutor extends PrioritisedExecutor { -@@ -322,7 +211,7 @@ public final class PrioritisedThreadPool { +@@ -322,7 +197,7 @@ public final class PrioritisedThreadPool { public boolean isActive(); } @@ -340,33 +325,32 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 protected final PrioritisedThreadPool pool; protected final long[] priorityCounts = new long[Priority.TOTAL_SCHEDULABLE_PRIORITIES]; -@@ -369,7 +258,12 @@ public final class PrioritisedThreadPool { +@@ -369,7 +244,10 @@ public final class PrioritisedThreadPool { public void halt() { final PrioritisedThreadPool pool = this.pool; final TreeSet queues = pool.queues; - synchronized (queues) { + // Gale start - base thread pool - chunk worker task queue - spin lock for pool queues + final Mutex queuesLock = pool.queuesLock; -+ //noinspection StatementWithEmptyBody -+ while (!queuesLock.tryAcquire()); -+ try { ++ try (var ignored = queuesLock.withSpinLock()) { + // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues if (this.isHalted) { return; } -@@ -378,7 +272,11 @@ public final class PrioritisedThreadPool { - queues.remove(this); +@@ -379,10 +257,10 @@ public final class PrioritisedThreadPool { this.isQueued = false; } -+ // Gale start - base thread pool - chunk worker task queue - spin lock for pool queues -+ } finally { -+ queuesLock.release(); } -+ // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues - synchronized (pool.nonShutdownQueues) { +- synchronized (pool.nonShutdownQueues) { ++ try (var ignored = pool.nonShutdownQueuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues pool.nonShutdownQueues.remove(this); } -@@ -391,8 +289,13 @@ public final class PrioritisedThreadPool { +- synchronized (pool.activeQueues) { ++ try (var ignored = pool.activeQueuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues + pool.activeQueues.remove(this); + } + } +@@ -391,12 +269,15 @@ public final class PrioritisedThreadPool { public boolean isActive() { final PrioritisedThreadPool pool = this.pool; final TreeSet queues = pool.queues; @@ -374,26 +358,17 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 + final Mutex queuesLock = pool.queuesLock; - synchronized (queues) { -+ //noinspection StatementWithEmptyBody -+ while (!queuesLock.tryAcquire()); -+ try { ++ try (var ignored = queuesLock.withSpinLock()) { + // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues if (this.concurrentExecutors != 0) { return true; } -@@ -401,7 +304,11 @@ public final class PrioritisedThreadPool { +- synchronized (pool.activeQueues) { ++ try (var ignored2 = pool.activeQueuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues + if (pool.activeQueues.contains(this)) { return true; } - } -+ // Gale start - base thread pool - chunk worker task queue - spin lock for pool queues -+ } finally { -+ queuesLock.release(); - } -+ // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues - - return false; - } -@@ -469,8 +376,13 @@ public final class PrioritisedThreadPool { +@@ -469,8 +350,11 @@ public final class PrioritisedThreadPool { final PrioritisedThreadPool pool = this.pool; final TreeSet queues = pool.queues; @@ -401,14 +376,12 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 + final Mutex queuesLock = pool.queuesLock; - synchronized (queues) { -+ //noinspection StatementWithEmptyBody -+ while (!queuesLock.tryAcquire()); -+ try { ++ try (var ignored = queuesLock.withSpinLock()) { + // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues if (!this.isQueued) { // see if we need to be queued if (newPriority != null) { -@@ -478,7 +390,7 @@ public final class PrioritisedThreadPool { +@@ -478,7 +362,7 @@ public final class PrioritisedThreadPool { this.schedulingId = ++pool.schedulingIdGenerator; } this.scheduledPriority = newPriority; // must be updated before queue add @@ -417,19 +390,14 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 shouldNotifyHighPriority = newPriority.isHigherOrEqualPriority(Priority.HIGH); queues.add(this); this.isQueued = true; -@@ -508,7 +420,11 @@ public final class PrioritisedThreadPool { - } else { - executorsWanted = 0; - } -+ // Gale start - base thread pool - chunk worker task queue - spin lock for pool queues -+ } finally { -+ queuesLock.release(); +@@ -511,19 +395,20 @@ public final class PrioritisedThreadPool { } -+ // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues if (newPriority == null && shutdown) { - synchronized (pool.activeQueues) { -@@ -517,13 +433,14 @@ public final class PrioritisedThreadPool { +- synchronized (pool.activeQueues) { ++ try (var ignored = pool.activeQueuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues + pool.activeQueues.remove(this); + } } // Wake up the number of executors we want @@ -449,7 +417,13 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 } } } -@@ -543,9 +460,14 @@ public final class PrioritisedThreadPool { +@@ -538,17 +423,18 @@ public final class PrioritisedThreadPool { + final PrioritisedThreadPool pool = this.pool; + + // remove from active queues +- synchronized (pool.nonShutdownQueues) { ++ try (var ignored = pool.nonShutdownQueuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues + pool.nonShutdownQueues.remove(this); } final TreeSet queues = pool.queues; @@ -457,26 +431,14 @@ index 26fa2caa18a9194e57574a4a7fa9f7a4265740e0..ae335a8ab04f4dc08ca0224a4ee70fa9 // try and shift around our priority - synchronized (queues) { -+ // Gale start - base thread pool - chunk worker task queue - spin lock for pool queues -+ //noinspection StatementWithEmptyBody -+ while (!queuesLock.tryAcquire()); -+ try { -+ // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues ++ try (var ignored = queuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues if (this.scheduledPriority == null) { // no tasks are queued, ensure we aren't in activeQueues - synchronized (pool.activeQueues) { -@@ -571,7 +493,11 @@ public final class PrioritisedThreadPool { - } else { - this.scheduledPriority = Priority.HIGHEST; - } -+ // Gale start - base thread pool - chunk worker task queue - spin lock for pool queues -+ } finally { -+ queuesLock.release(); - } -+ // Gale end - base thread pool - chunk worker task queue - spin lock for pool queues +- synchronized (pool.activeQueues) { ++ try (var ignored2 = pool.activeQueuesLock.withSpinLock()) { // Gale - base thread pool - chunk worker task queue - spin lock for pool queues + pool.activeQueues.remove(this); + } - return ret; - } diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java index f5c15d40094c2ddc6220b0595597d12103fcf425..79ef41d2bb30beee2355d1de3dc99c9e00d929d5 100644 --- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java @@ -532,6 +494,18 @@ index 0019e5eefc4b638526a75dd3706a54033dd9b811..7ed820d2483bf6741a355b062f062a04 this.saveAllChunks(false, true, false, true); // Paper - rewrite chunk system - move closing into here this.isSaving = false; +diff --git a/src/main/java/org/galemc/gale/executor/chunksystem/PrioritisedQueueExecutorThreadAgent.java b/src/main/java/org/galemc/gale/executor/chunksystem/PrioritisedQueueExecutorThreadAgent.java +index 1cd17795c8f8a7a0d111123e662904522a6c8819..a6db8e2ca224410cc36080dbd5e8fe0e34ecabc0 100644 +--- a/src/main/java/org/galemc/gale/executor/chunksystem/PrioritisedQueueExecutorThreadAgent.java ++++ b/src/main/java/org/galemc/gale/executor/chunksystem/PrioritisedQueueExecutorThreadAgent.java +@@ -9,7 +9,6 @@ import org.galemc.gale.executor.queue.BaseTaskQueues; + import org.galemc.gale.executor.thread.BaseThread; + import org.slf4j.Logger; + +- + /** + * This class is a copy of {@link PrioritisedQueueExecutorThread}, with the notable difference + * that it does not extend {@link Thread}, but may be instantiated on its own, as an agent representing diff --git a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java b/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java index 9a908566ccdda9ca77e0f9236f674f17f79e9c40..dc006d9940ef8114a3a3e4860fbc1da0f7c2ee60 100644 --- a/src/main/java/org/galemc/gale/executor/queue/BaseTaskQueueTier.java @@ -571,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..0e2e11b883d8910e97c5700f7f6a7d1b545a6164 +index 0000000000000000000000000000000000000000..c82a83a310b0dffd2dc77256b128d0e58d6df691 --- /dev/null +++ b/src/main/java/org/galemc/gale/executor/queue/ChunkWorkerTaskQueue.java -@@ -0,0 +1,108 @@ +@@ -0,0 +1,104 @@ +// Gale - base thread pool - chunk worker task queue + +package org.galemc.gale.executor.queue; @@ -620,16 +594,12 @@ index 0000000000000000000000000000000000000000..0e2e11b883d8910e97c5700f7f6a7d1b + if (workerThreads == null) { + return false; + } -+ //noinspection StatementWithEmptyBody -+ while (!workerThreads.queuesLock.tryAcquire()); -+ try { ++ try (var ignored = workerThreads.queuesLock.withSpinLock()) { + for (var queue : workerThreads.queues) { + if (queue.hasScheduledUncompletedTasksVolatile()) { + return true; + } + } -+ } finally { -+ workerThreads.queuesLock.release(); + } + return false; + } diff --git a/patches/server/0156-Non-blocking-PooledObjects.patch b/patches/server/0156-Non-blocking-PooledObjects.patch index 0129f0c..1ef0a96 100644 --- a/patches/server/0156-Non-blocking-PooledObjects.patch +++ b/patches/server/0156-Non-blocking-PooledObjects.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/com/destroystokyo/paper/util/pooled/PooledObjects.java b/src/main/java/com/destroystokyo/paper/util/pooled/PooledObjects.java -index a743703502cea333bd4231b6557de50e8eaf81eb..0566757ed94cb2c41ace660ef71c8f99b0335032 100644 +index a743703502cea333bd4231b6557de50e8eaf81eb..5531c681b3547c32f4fc8ec86bb722e1ee653826 100644 --- a/src/main/java/com/destroystokyo/paper/util/pooled/PooledObjects.java +++ b/src/main/java/com/destroystokyo/paper/util/pooled/PooledObjects.java @@ -2,11 +2,18 @@ package com.destroystokyo.paper.util.pooled; @@ -37,41 +37,21 @@ index a743703502cea333bd4231b6557de50e8eaf81eb..0566757ed94cb2c41ace660ef71c8f99 public PooledObjects(final Supplier creator, int maxPoolSize) { this(creator, maxPoolSize, null); -@@ -66,8 +74,16 @@ public final class PooledObjects { +@@ -66,7 +74,7 @@ public final class PooledObjects { public final E acquire() { E value; - synchronized (queue) { -+ // Gale start - non-blocking PooledObjects -+ //noinspection StatementWithEmptyBody -+ while (!this.queueLock.tryAcquire()); -+ try { -+ // Gale end - non-blocking PooledObjects ++ try (var ignored = this.queueLock.withSpinLock()) { // Gale - non-blocking PooledObjects value = this.queue.pollLast(); -+ // Gale start - non-blocking PooledObjects -+ } finally { -+ this.queueLock.release(); -+ // Gale end - non-blocking PooledObjects } return value != null ? value : this.creator.get(); - } -@@ -76,10 +92,18 @@ public final class PooledObjects { +@@ -76,7 +84,7 @@ public final class PooledObjects { if (this.releaser != null) { this.releaser.accept(value); } - synchronized (this.queue) { -+ // Gale start - non-blocking PooledObjects -+ //noinspection StatementWithEmptyBody -+ while (!this.queueLock.tryAcquire()); -+ try { -+ // Gale end - non-blocking PooledObjects ++ try (var ignored = this.queueLock.withSpinLock()) { // Gale - non-blocking PooledObjects if (queue.size() < this.maxPoolSize) { this.queue.addLast(value); } -+ // Gale start - non-blocking PooledObjects -+ } finally { -+ this.queueLock.release(); -+ // Gale end - non-blocking PooledObjects - } - } - }