Scheduler

By: Raphfrk <raphfrk@gmail.com>
This commit is contained in:
CraftBukkit/Spigot 2011-02-02 23:53:04 +00:00
parent 68f094f38b
commit 622ca3e68c
5 changed files with 463 additions and 0 deletions

View file

@ -16,12 +16,15 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.SimplePluginManager;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.craftbukkit.scheduler.CraftScheduler;
public final class CraftServer implements Server {
private final String serverName = "Craftbukkit";
private final String serverVersion;
private final String protocolVersion = "1.2_01";
private final PluginManager pluginManager = new SimplePluginManager(this);
private final BukkitScheduler scheduler = new CraftScheduler(this);
private final CommandMap commandMap = new SimpleCommandMap(this);
protected final MinecraftServer console;
protected final ServerConfigurationManager server;
@ -145,6 +148,10 @@ public final class CraftServer implements Server {
return pluginManager;
}
public BukkitScheduler getScheduler() {
return scheduler;
}
public World[] getWorlds() {
return new World[]{console.e.getWorld()};
}

View file

@ -0,0 +1,209 @@
package org.bukkit.craftbukkit.scheduler;
import java.util.LinkedList;
import java.util.TreeMap;
import java.util.Iterator;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.plugin.Plugin;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.scheduler.CraftTask;
public class CraftScheduler implements BukkitScheduler, Runnable {
private final CraftServer server;
private final CraftThreadManager craftThreadManager = new CraftThreadManager();
private final LinkedList<Runnable> mainThreadQueue = new LinkedList<Runnable>();
private final TreeMap<CraftTask,Boolean> schedulerQueue = new TreeMap<CraftTask,Boolean>();
private final Object currentTickSync = new Object();
private Long currentTick = 0L;
// This lock locks the mainThreadQueue and the currentTick value
private final Lock mainThreadLock = new ReentrantLock();
public void run() {
while (true) {
boolean stop = false;
long firstTick = -1;
long currentTick = -1;
CraftTask first = null;
do {
synchronized (schedulerQueue) {
first = null;
if (!schedulerQueue.isEmpty()) {
first = schedulerQueue.firstKey();
if (first!=null) {
currentTick = getCurrentTick();
firstTick = first.getExecutionTick();
if (currentTick >= firstTick ) {
schedulerQueue.remove(first);
processTask(first);
if (first.getPeriod()>=0) {
first.updateExecution();
schedulerQueue.put(first, first.isSync());
}
} else {
stop = true;
}
} else {
stop = true;
}
} else {
stop = true;
}
}
} while (!stop);
long sleepTime = 0;
if (first == null) {
sleepTime = 60000L;
} else {
currentTick = getCurrentTick();
sleepTime = (firstTick-currentTick)*50 + 25;
}
if (sleepTime < 50L) {
sleepTime = 50L;
} else if (sleepTime > 60000L) {
sleepTime = 60000L;
}
synchronized (schedulerQueue) {
try {
schedulerQueue.wait(sleepTime);
} catch (InterruptedException ie) {
}
}
}
}
void processTask(CraftTask task) {
if (task.isSync()) {
addToMainThreadQueue(task.getTask());
} else {
craftThreadManager.executeTask(task.getTask(), task.getOwner(), task.getIdNumber());
}
}
public CraftScheduler(CraftServer server) {
this.server = server;
Thread t = new Thread(this);
t.start();
}
// If the main thread cannot obtain the lock, it doesn't wait
public void mainThreadHeartbeat(long currentTick) {
if (mainThreadLock.tryLock()) {
try {
this.currentTick = currentTick;
while (!mainThreadQueue.isEmpty()) {
mainThreadQueue.removeFirst().run();
}
} finally {
mainThreadLock.unlock();
}
}
}
long getCurrentTick() {
mainThreadLock.lock();
long tempTick = 0;
try {
tempTick = currentTick;
} finally {
mainThreadLock.unlock();
}
return tempTick;
}
void addToMainThreadQueue(Runnable task) {
mainThreadLock.lock();
try {
mainThreadQueue.addLast(task);
} finally {
mainThreadLock.unlock();
}
}
public int scheduleSyncDelayedTask(Plugin plugin, Runnable task, long delay) {
return scheduleSyncRepeatingTask(plugin, task, delay, -1);
}
public int scheduleSyncDelayedTask(Plugin plugin, Runnable task) {
return scheduleSyncDelayedTask(plugin, task, 0L);
}
public int scheduleSyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period) {
CraftTask newTask = new CraftTask(plugin, task, true, getCurrentTick()+delay, period);
synchronized (schedulerQueue) {
schedulerQueue.put(newTask, true);
schedulerQueue.notify();
}
return newTask.getIdNumber();
}
public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task, long delay) {
return scheduleAsyncRepeatingTask(plugin, task, delay, -1);
}
public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task) {
return scheduleAsyncDelayedTask(plugin, task, 0L);
}
public int scheduleAsyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period) {
CraftTask newTask = new CraftTask(plugin, task, false, getCurrentTick()+delay, period);
synchronized (schedulerQueue) {
schedulerQueue.put(newTask, false);
schedulerQueue.notify();
}
return newTask.getIdNumber();
}
public void cancelTask(int taskId) {
synchronized (schedulerQueue) {
Iterator<CraftTask> itr = schedulerQueue.keySet().iterator();
while (itr.hasNext()) {
CraftTask current = itr.next();
if (current.getIdNumber() == taskId) {
itr.remove();
}
}
}
craftThreadManager.interruptTask(taskId);
}
public void cancelTasks(Plugin plugin) {
synchronized (schedulerQueue) {
Iterator<CraftTask> itr = schedulerQueue.keySet().iterator();
while (itr.hasNext()) {
CraftTask current = itr.next();
if (current.getOwner().equals(plugin)) {
itr.remove();
}
}
}
craftThreadManager.interruptTask(plugin);
}
public void cancelAllTasks() {
synchronized (schedulerQueue) {
schedulerQueue.clear();
}
craftThreadManager.interruptAllTasks();
}
}

View file

@ -0,0 +1,110 @@
package org.bukkit.craftbukkit.scheduler;
import java.lang.Comparable;
import org.bukkit.plugin.Plugin;
public class CraftTask implements Comparable {
private final Runnable task;
private final boolean syncTask;
private long executionTick;
private final long period;
private final Plugin owner;
private final int idNumber;
private static Integer idCounter = 1;
private static Object idCounterSync = new Object();
CraftTask(Plugin owner, Runnable task, boolean syncTask) {
this(owner, task, syncTask, -1, -1);
}
CraftTask(Plugin owner, Runnable task, boolean syncTask, long executionTick) {
this(owner, task, syncTask, executionTick, -1);
}
CraftTask(Plugin owner, Runnable task, boolean syncTask, long executionTick, long period) {
this.task = task;
this.syncTask = syncTask;
this.executionTick = executionTick;
this.period = period;
this.owner = owner;
this.idNumber = CraftTask.getNextId();
}
static int getNextId() {
synchronized (idCounterSync) {
idCounter++;
return idCounter;
}
}
Runnable getTask() {
return task;
}
boolean isSync() {
return syncTask;
}
long getExecutionTick() {
return executionTick;
}
long getPeriod() {
return period;
}
Plugin getOwner() {
return owner;
}
void updateExecution() {
executionTick += period;
}
int getIdNumber() {
return idNumber;
}
@Override
public int compareTo(Object other) {
if (!(other instanceof CraftTask)) {
return 0;
} else {
CraftTask o = (CraftTask) other;
long timeDiff = executionTick - o.getExecutionTick();
if (timeDiff>0) {
return 1;
} else if (timeDiff<0) {
return -1;
} else {
CraftTask otherCraftTask = (CraftTask) other;
return getIdNumber() - otherCraftTask.getIdNumber();
}
}
}
@Override
public boolean equals( Object other ) {
if (other == null) {
return false;
}
if (!(other instanceof CraftTask)) {
return false;
}
CraftTask otherCraftTask = (CraftTask) other;
return otherCraftTask.getIdNumber() == getIdNumber();
}
@Override
public int hashCode() {
return getIdNumber();
}
}

View file

@ -0,0 +1,55 @@
package org.bukkit.craftbukkit.scheduler;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Iterator;
import org.bukkit.plugin.Plugin;
public class CraftThreadManager {
final HashSet<CraftWorker> workers = new HashSet<CraftWorker>();
void executeTask(Runnable task, Plugin owner, int taskId) {
CraftWorker craftWorker = new CraftWorker(this, task, owner, taskId);
synchronized (workers) {
workers.add(craftWorker);
}
}
void interruptTask(int taskId) {
synchronized (workers) {
Iterator<CraftWorker> itr = workers.iterator();
while (itr.hasNext()) {
CraftWorker craftWorker = itr.next();
if (craftWorker.getTaskId() == taskId) {
craftWorker.interrupt();
}
}
}
}
void interruptTask(Plugin owner) {
synchronized (workers) {
Iterator<CraftWorker> itr = workers.iterator();
while (itr.hasNext()) {
CraftWorker craftWorker = itr.next();
if (craftWorker.getOwner().equals(owner)) {
craftWorker.interrupt();
}
}
}
}
void interruptAllTasks() {
synchronized (workers) {
Iterator<CraftWorker> itr = workers.iterator();
while (itr.hasNext()) {
CraftWorker craftWorker = itr.next();
craftWorker.interrupt();
}
}
}
}

View file

@ -0,0 +1,82 @@
package org.bukkit.craftbukkit.scheduler;
import org.bukkit.plugin.Plugin;
public class CraftWorker implements Runnable {
private static int hashIdCounter = 1;
private static Object hashIdCounterSync = new Object();
private final int hashId;
private final Plugin owner;
private final int taskId;
private final Thread t;
private final CraftThreadManager parent;
private final Runnable task;
CraftWorker(CraftThreadManager parent, Runnable task, Plugin owner, int taskId) {
this.parent = parent;
this.taskId = taskId;
this.task = task;
this.owner = owner;
this.hashId = CraftWorker.getNextHashId();
t = new Thread(this);
t.start();
}
public void run() {
try {
task.run();
} catch (Exception e) {
e.printStackTrace();
}
synchronized (parent.workers) {
parent.workers.remove(this);
}
}
public int getTaskId() {
return taskId;
}
public Plugin getOwner() {
return owner;
}
public void interrupt() {
t.interrupt();
}
private static int getNextHashId() {
synchronized (hashIdCounterSync) {
return hashIdCounter++;
}
}
@Override
public int hashCode() {
return hashId;
}
@Override
public boolean equals( Object other ) {
if (other == null) {
return false;
}
if (!(other instanceof CraftWorker)) {
return false;
}
CraftWorker otherCraftWorker = (CraftWorker) other;
return otherCraftWorker.hashCode() == hashId;
}
}