13
0
geforkt von Mirrors/Paper

Fix more issues with async scheduler and cancelling pending task

was a race condition, so do need to use the head/parsePending logic still
Dieser Commit ist enthalten in:
Aikar 2018-03-17 14:59:03 -04:00
Ursprung 700c900cc3
Commit 0d220393d1

Datei anzeigen

@ -38,7 +38,7 @@ 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 +0,0 @@
@ -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<CraftTask> 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<BukkitTask> getPendingTasks() {
+ ArrayList<BukkitTask> 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
@@ -0,0 +0,0 @@ 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)
}
@@ -0,0 +0,0 @@ public class CraftScheduler implements BukkitScheduler {
//debugHead = debugHead.getNextHead(currentTick); // Paper
}
- private void addTask(final CraftTask task) {
+ protected void addTask(final CraftTask task) {
final AtomicReference<CraftTask> tail = this.tail;
CraftTask tailTask = tail.get();
while (!tail.compareAndSet(tailTask, task)) {
@@ -0,0 +0,0 @@ public class CraftScheduler implements BukkitScheduler {
tailTask.setNext(task);
}
@ -393,4 +369,24 @@ index e47f4cca2..c3cb9e6d2 100644
task.setNextRun(currentTick + delay);
addTask(task);
return task;
@@ -0,0 +0,0 @@ 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;
@@ -0,0 +0,0 @@ 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) {
--