summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaphfrk <raphfrk@gmail.com>2011-02-02 23:53:04 +0000
committerErik Broes <erikbroes@grum.nl>2011-02-07 01:03:32 +0100
commit9e7991ab528cfc195200e342cd022ab3f63de3f6 (patch)
tree0bbfbafc83376b0e2f2f57c129aae76d0b20f9db
parentb64667cde4ad0281a51fb2738010a80da44862f9 (diff)
downloadcraftbukkit-9e7991ab528cfc195200e342cd022ab3f63de3f6.tar
craftbukkit-9e7991ab528cfc195200e342cd022ab3f63de3f6.tar.gz
craftbukkit-9e7991ab528cfc195200e342cd022ab3f63de3f6.tar.lz
craftbukkit-9e7991ab528cfc195200e342cd022ab3f63de3f6.tar.xz
craftbukkit-9e7991ab528cfc195200e342cd022ab3f63de3f6.zip
Scheduler
-rw-r--r--src/main/java/net/minecraft/server/MinecraftServer.java5
-rw-r--r--src/main/java/org/bukkit/craftbukkit/CraftServer.java7
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java209
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java110
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scheduler/CraftThreadManager.java55
-rw-r--r--src/main/java/org/bukkit/craftbukkit/scheduler/CraftWorker.java82
6 files changed, 468 insertions, 0 deletions
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 5fcff48f..887a68dd 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -17,6 +17,7 @@ import java.net.UnknownHostException;
import joptsimple.OptionSet;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.scheduler.CraftScheduler;
// CraftBukkit end
public class MinecraftServer implements ICommandListener, Runnable {
@@ -275,6 +276,10 @@ public class MinecraftServer implements ICommandListener, Runnable {
this.e.f();
+ // CraftBukkit start
+ ((CraftScheduler) server.getScheduler()).mainThreadHeartbeat(this.h);
+ // CraftBukkit end
+
while (this.e.d()) {
;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 3ebb579c..c2650add 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -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()};
}
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
new file mode 100644
index 00000000..d50a036e
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
@@ -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();
+ }
+
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java
new file mode 100644
index 00000000..2b47cc47
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java
@@ -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();
+ }
+
+
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftThreadManager.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftThreadManager.java
new file mode 100644
index 00000000..8ded4984
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftThreadManager.java
@@ -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();
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftWorker.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftWorker.java
new file mode 100644
index 00000000..2bb9400d
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftWorker.java
@@ -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;
+ }
+
+}