Fixed some async tasks running synchronously. Fixes BUKKIT-2934

Additionally refactored cancel method to be more object-oriented.
Dieser Commit ist enthalten in:
Wesley Wolfe 2012-11-14 16:47:21 -06:00
Ursprung c2bae0bebb
Commit 092800af26
4 geänderte Dateien mit 37 neuen und 39 gelöschten Zeilen

Datei anzeigen

@ -95,4 +95,12 @@ class CraftAsyncTask extends CraftTask {
LinkedList<BukkitWorker> getWorkers() { LinkedList<BukkitWorker> getWorkers() {
return workers; return workers;
} }
boolean cancel0() {
synchronized (workers) {
// Synchronizing here prevents race condition for a completing task
setPeriod(-2l);
}
return true;
}
} }

Datei anzeigen

@ -96,4 +96,13 @@ class CraftFuture<T> extends CraftTask implements Future<T> {
} }
} }
} }
synchronized boolean cancel0() {
if (getPeriod() != -1l) {
return false;
}
setPeriod(-2l);
notifyAll();
return true;
}
} }

Datei anzeigen

@ -108,7 +108,7 @@ public class CraftScheduler implements BukkitScheduler {
} }
public BukkitTask runTaskLaterAsynchronously(Plugin plugin, Runnable runnable, long delay) { public BukkitTask runTaskLaterAsynchronously(Plugin plugin, Runnable runnable, long delay) {
return runTaskTimer(plugin, runnable, delay, -1l); return runTaskTimerAsynchronously(plugin, runnable, delay, -1l);
} }
public int scheduleSyncRepeatingTask(final Plugin plugin, final Runnable runnable, long delay, long period) { public int scheduleSyncRepeatingTask(final Plugin plugin, final Runnable runnable, long delay, long period) {
@ -158,7 +158,7 @@ public class CraftScheduler implements BukkitScheduler {
} }
CraftTask task = runners.get(taskId); CraftTask task = runners.get(taskId);
if (task != null) { if (task != null) {
cancelTask(task); task.cancel0();
} }
task = new CraftTask( task = new CraftTask(
new Runnable() { new Runnable() {
@ -172,7 +172,7 @@ public class CraftScheduler implements BukkitScheduler {
while (tasks.hasNext()) { while (tasks.hasNext()) {
final CraftTask task = tasks.next(); final CraftTask task = tasks.next();
if (task.getTaskId() == taskId) { if (task.getTaskId() == taskId) {
cancelTask(task); task.cancel0();
tasks.remove(); tasks.remove();
if (task.isSync()) { if (task.isSync()) {
runners.remove(taskId); runners.remove(taskId);
@ -188,7 +188,7 @@ public class CraftScheduler implements BukkitScheduler {
return; return;
} }
if (taskPending.getTaskId() == taskId) { if (taskPending.getTaskId() == taskId) {
cancelTask(taskPending); taskPending.cancel0();
} }
} }
} }
@ -206,7 +206,7 @@ public class CraftScheduler implements BukkitScheduler {
while (tasks.hasNext()) { while (tasks.hasNext()) {
final CraftTask task = tasks.next(); final CraftTask task = tasks.next();
if (task.getOwner().equals(plugin)) { if (task.getOwner().equals(plugin)) {
cancelTask(task); task.cancel0();
tasks.remove(); tasks.remove();
if (task.isSync()) { if (task.isSync()) {
runners.remove(task.getTaskId()); runners.remove(task.getTaskId());
@ -222,12 +222,12 @@ public class CraftScheduler implements BukkitScheduler {
return; return;
} }
if (taskPending.getTaskId() != -1 && taskPending.getOwner().equals(plugin)) { if (taskPending.getTaskId() != -1 && taskPending.getOwner().equals(plugin)) {
cancelTask(taskPending); taskPending.cancel0();
} }
} }
for (CraftTask runner : runners.values()) { for (CraftTask runner : runners.values()) {
if (runner.getOwner().equals(plugin)) { if (runner.getOwner().equals(plugin)) {
cancelTask(runner); runner.cancel0();
} }
} }
} }
@ -239,7 +239,7 @@ public class CraftScheduler implements BukkitScheduler {
Iterator<CraftTask> it = CraftScheduler.this.runners.values().iterator(); Iterator<CraftTask> it = CraftScheduler.this.runners.values().iterator();
while (it.hasNext()) { while (it.hasNext()) {
CraftTask task = it.next(); CraftTask task = it.next();
cancelTask(task); task.cancel0();
if (task.isSync()) { if (task.isSync()) {
it.remove(); it.remove();
} }
@ -253,10 +253,10 @@ public class CraftScheduler implements BukkitScheduler {
if (taskPending == task) { if (taskPending == task) {
break; break;
} }
cancelTask(taskPending); taskPending.cancel0();
} }
for (CraftTask runner : runners.values()) { for (CraftTask runner : runners.values()) {
cancelTask(runner); runner.cancel0();
} }
} }
@ -421,35 +421,6 @@ public class CraftScheduler implements BukkitScheduler {
return !pending.isEmpty() && pending.peek().getNextRun() <= currentTick; return !pending.isEmpty() && pending.peek().getNextRun() <= currentTick;
} }
/**
* This method is important to make sure the code is consistent everywhere.
* Synchronizing is needed for future and async to prevent race conditions,
* main thread or otherwise.
* @return True if cancelled
*/
private boolean cancelTask(final CraftTask task) {
if (task.isSync()) {
if (task instanceof CraftFuture) {
synchronized (task) {
if (task.getPeriod() != -1l) {
return false;
}
// This needs to be set INSIDE of the synchronized block
task.setPeriod(-2l);
task.notifyAll();
}
} else {
task.setPeriod(-2l);
}
} else {
synchronized (((CraftAsyncTask) task).getWorkers()) {
// Synchronizing here prevents race condition for a completing task
task.setPeriod(-2l);
}
}
return true;
}
@Override @Override
public String toString() { public String toString() {
int debugTick = currentTick; int debugTick = currentTick;

Datei anzeigen

@ -84,4 +84,14 @@ class CraftTask implements BukkitTask, Runnable {
public void cancel() { public void cancel() {
Bukkit.getScheduler().cancelTask(id); Bukkit.getScheduler().cancelTask(id);
} }
/**
* This method properly sets the status to cancelled, synchronizing when required.
*
* @return false if it is a craft future task that has already begun execution, true otherwise
*/
boolean cancel0() {
setPeriod(-2l);
return true;
}
} }