diff --git a/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java b/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java index 72938bbb5b..cb6dc22969 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java @@ -28,7 +28,7 @@ public class CraftCrashReport implements Callable { for (Map.Entry entry : Thread.getAllStackTraces().entrySet()) { value.append(' ').append(entry.getKey().getState().name()).append(' ').append(entry.getKey().getName()).append(": ").append(Arrays.toString(entry.getValue())).append(','); } - value.append('}'); + value.append("}\n ").append(Bukkit.getScheduler().toString()); } catch (Throwable t) { value.append("\n Failed to handle CraftCrashReport:\n"); PrintWriter writer = new PrintWriter(value); diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncDebugger.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncDebugger.java new file mode 100644 index 0000000000..2899bacf57 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncDebugger.java @@ -0,0 +1,37 @@ +package org.bukkit.craftbukkit.scheduler; + +import org.bukkit.plugin.Plugin; + + +class CraftAsyncDebugger { + private CraftAsyncDebugger next = null; + private final int expiry; + private final Plugin plugin; + private final Class clazz; + + CraftAsyncDebugger(final int expiry, final Plugin plugin, final Class clazz) { + this.expiry = expiry; + this.plugin = plugin; + this.clazz = clazz; + + } + + final CraftAsyncDebugger getNextHead(final int time) { + CraftAsyncDebugger next, current = this; + while (time > current.expiry && (next = current.next) != null) { + current = next; + } + return current; + } + + final CraftAsyncDebugger setNext(final CraftAsyncDebugger next) { + return this.next = next; + } + + StringBuilder debugTo(final StringBuilder string) { + for (CraftAsyncDebugger next = this; next != null; next = next.next) { + string.append(plugin.getDescription().getName()).append(':').append(clazz.getName()).append('@').append(expiry).append(','); + } + return string; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java index 6b70a78bc1..f2dbfbadd6 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java @@ -71,6 +71,13 @@ public class CraftScheduler implements BukkitScheduler { private final ConcurrentHashMap runners = new ConcurrentHashMap(); private volatile int currentTick = -1; private final Executor executor = Executors.newCachedThreadPool(); + private CraftAsyncDebugger debugHead = new CraftAsyncDebugger(-1, null, null) {@Override StringBuilder debugTo(StringBuilder string) {return string;}}; + private CraftAsyncDebugger debugTail = debugHead; + private static final int RECENT_TICKS; + + static { + RECENT_TICKS = 30; + } public int scheduleSyncDelayedTask(final Plugin plugin, final Runnable task) { return this.scheduleSyncDelayedTask(plugin, task, 0l); @@ -325,6 +332,7 @@ public class CraftScheduler implements BukkitScheduler { } parsePending(); } else { + debugTail = debugTail.setNext(new CraftAsyncDebugger(currentTick + RECENT_TICKS, task.getOwner(), task.getTaskClass())); executor.execute(task); // 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) @@ -339,6 +347,7 @@ public class CraftScheduler implements BukkitScheduler { } pending.addAll(temp); temp.clear(); + debugHead = debugHead.getNextHead(currentTick); } private void addTask(final CraftTask task) { @@ -418,4 +427,12 @@ public class CraftScheduler implements BukkitScheduler { } return true; } + + @Override + public String toString() { + int debugTick = currentTick; + StringBuilder string = new StringBuilder("Recent tasks from ").append(debugTick - RECENT_TICKS).append('-').append(debugTick).append('{'); + debugHead.debugTo(string); + return string.append('}').toString(); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java index 8e56766d2a..cfd6fb45b9 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java @@ -75,4 +75,8 @@ class CraftTask implements BukkitTask, Runnable { void setNext(CraftTask next) { this.next = next; } + + Class getTaskClass() { + return task.getClass(); + } }