From 242e82f25bc4762e62200c9c300ce02e0b99138f Mon Sep 17 00:00:00 2001 From: Aikar Date: Sat, 17 Mar 2018 14:59:03 -0400 Subject: [PATCH] Fix more issues with async scheduler and cancelling pending task was a race condition, so do need to use the head/parsePending logic still --- .../0275-Improved-Async-Task-Scheduler.patch | 82 +++++++++---------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/Spigot-Server-Patches/0275-Improved-Async-Task-Scheduler.patch b/Spigot-Server-Patches/0275-Improved-Async-Task-Scheduler.patch index bdc534596..a45eb5897 100644 --- a/Spigot-Server-Patches/0275-Improved-Async-Task-Scheduler.patch +++ b/Spigot-Server-Patches/0275-Improved-Async-Task-Scheduler.patch @@ -1,4 +1,4 @@ -From a02abf4be83eadada6f4e91795711a06cee84905 Mon Sep 17 00:00:00 2001 +From 8b8705c3506d9120a1e0fffd272a4c31d9be2abb Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 16 Mar 2018 22:59:43 -0400 Subject: [PATCH] Improved Async Task Scheduler @@ -38,10 +38,10 @@ queue if a plugin schedules lots of asynchronous tasks. diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java new file mode 100644 -index 000000000..cf5aada2f +index 000000000..83575a44d --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java -@@ -0,0 +1,161 @@ +@@ -0,0 +1,128 @@ +/* + * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License + * @@ -70,7 +70,6 @@ index 000000000..cf5aada2f +import com.destroystokyo.paper.ServerSchedulerReportingWrapper; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.bukkit.plugin.Plugin; -+import org.bukkit.scheduler.BukkitTask; + +import java.util.ArrayList; +import java.util.Iterator; @@ -93,6 +92,7 @@ index 000000000..cf5aada2f + } + + private synchronized void removeTask(int taskId) { ++ parsePending(); + this.pending.removeIf((task) -> { + if (task.getTaskId() == taskId) { + task.cancel0(); @@ -109,6 +109,7 @@ index 000000000..cf5aada2f + } + + private synchronized void runTasks(int currentTick) { ++ parsePending(); + while (!this.pending.isEmpty() && this.pending.peek().getNextRun() <= currentTick) { + CraftTask task = this.pending.remove(); + if (executeTask(task)) { @@ -118,6 +119,7 @@ index 000000000..cf5aada2f + temp.add(task); + } + } ++ parsePending(); + } + this.pending.addAll(temp); + temp.clear(); @@ -127,11 +129,10 @@ index 000000000..cf5aada2f + protected CraftTask handle(CraftTask task, final long delay) { + if (task.getPeriod() == -1L && delay == 0L) { + executeTask(task); ++ return task; + } else { -+ task.setNextRun(this.currentTick + delay); -+ this.management.execute(() -> this.addTask(task)); ++ return super.handle(task, delay); + } -+ return task; + } + + private boolean executeTask(CraftTask task) { @@ -143,12 +144,9 @@ index 000000000..cf5aada2f + return false; + } + -+ private synchronized void addTask(CraftTask task) { -+ this.pending.add(task); -+ } -+ + @Override + public synchronized void cancelTasks(Plugin plugin) { ++ parsePending(); + for (Iterator iterator = this.pending.iterator(); iterator.hasNext(); ) { + CraftTask task = iterator.next(); + if (task.getTaskId() != -1 && (plugin == null || task.getOwner().equals(plugin))) { @@ -163,37 +161,6 @@ index 000000000..cf5aada2f + cancelTasks(null); + } + -+ @Override -+ public synchronized List getPendingTasks() { -+ ArrayList list = new ArrayList<>(); -+ for (CraftTask task : this.runners.values()) { -+ if (isValid(task)) { -+ list.add(task); -+ } -+ } -+ for (CraftTask task : this.pending) { -+ if (isValid(task) && !list.contains(task)) { -+ list.add(task); -+ } -+ } -+ -+ return list; -+ } -+ -+ @Override -+ public synchronized boolean isQueued(int taskId) { -+ CraftTask runningTask = this.runners.get(taskId); -+ if (runningTask != null && isValid(runningTask)) { -+ return true; -+ } -+ for (CraftTask task : this.pending) { -+ if (task.getTaskId() == taskId) { -+ return isValid(task); // The task will run -+ } -+ } -+ return false; -+ } -+ + /** + * Task is not cancelled + * @param runningTask @@ -204,7 +171,7 @@ index 000000000..cf5aada2f + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -index e47f4cca2..c3cb9e6d2 100644 +index e47f4cca2..8de7026f7 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java @@ -15,7 +15,6 @@ import java.util.concurrent.atomic.AtomicReference; @@ -378,6 +345,15 @@ index e47f4cca2..c3cb9e6d2 100644 // We don't need to parse pending // (async tasks must live with race-conditions if they attempt to cancel between these few lines of code) } +@@ -391,7 +450,7 @@ public class CraftScheduler implements BukkitScheduler { + //debugHead = debugHead.getNextHead(currentTick); // Paper + } + +- private void addTask(final CraftTask task) { ++ protected void addTask(final CraftTask task) { + final AtomicReference tail = this.tail; + CraftTask tailTask = tail.get(); + while (!tail.compareAndSet(tailTask, task)) { @@ -400,7 +459,13 @@ public class CraftScheduler implements BukkitScheduler { tailTask.setNext(task); } @@ -393,6 +369,26 @@ index e47f4cca2..c3cb9e6d2 100644 task.setNextRun(currentTick + delay); addTask(task); return task; +@@ -418,8 +483,8 @@ public class CraftScheduler implements BukkitScheduler { + return ids.incrementAndGet(); + } + +- private void parsePending() { +- MinecraftTimings.bukkitSchedulerPendingTimer.startTiming(); ++ void parsePending() { // Paper ++ if (!this.isAsyncScheduler) MinecraftTimings.bukkitSchedulerPendingTimer.startTiming(); // Paper + CraftTask head = this.head; + CraftTask task = head.getNext(); + CraftTask lastTask = head; +@@ -438,7 +503,7 @@ public class CraftScheduler implements BukkitScheduler { + task.setNext(null); + } + this.head = lastTask; +- MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming(); ++ if (!this.isAsyncScheduler) MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming(); // Paper + } + + private boolean isReady(final int currentTick) { -- 2.16.2