diff --git a/sources/src/main/java/io/akarin/api/internal/utils/ReentrantSpinningDebugLock.java b/sources/src/main/java/io/akarin/api/internal/utils/ReentrantSpinningDebugLock.java deleted file mode 100644 index 4e5c85786..000000000 --- a/sources/src/main/java/io/akarin/api/internal/utils/ReentrantSpinningDebugLock.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.akarin.api.internal.utils; - -import java.util.concurrent.atomic.AtomicBoolean; - -public class ReentrantSpinningDebugLock extends ReentrantSpinningLock { - private final AtomicBoolean singleLock = new AtomicBoolean(false); - private long heldThreadId = 0; - private int reentrantLocks = 0; - public StackTraceElement[] tStackTraceElements; - - public void lock() { - long currentThreadId = Thread.currentThread().getId(); - if (heldThreadId == currentThreadId) { - reentrantLocks++; - } else { - while (!singleLock.compareAndSet(false, true)) ; // In case acquire one lock concurrently - heldThreadId = currentThreadId; - } - tStackTraceElements = Thread.currentThread().getStackTrace(); - } - - public void unlock() { - if (reentrantLocks == 0) { - heldThreadId = 0; - singleLock.set(false); - } else { - --reentrantLocks; - } - } -} diff --git a/sources/src/main/java/io/akarin/api/internal/utils/thread/OpenExecutionException.java b/sources/src/main/java/io/akarin/api/internal/utils/thread/OpenExecutionException.java new file mode 100644 index 000000000..215952436 --- /dev/null +++ b/sources/src/main/java/io/akarin/api/internal/utils/thread/OpenExecutionException.java @@ -0,0 +1,7 @@ +package io.akarin.api.internal.utils.thread; + +import java.util.concurrent.ExecutionException; + +public class OpenExecutionException extends ExecutionException { + private static final long serialVersionUID = 7830266012832686185L; +} diff --git a/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableAbstractExecutorService.java b/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableAbstractExecutorService.java deleted file mode 100644 index fe249187d..000000000 --- a/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableAbstractExecutorService.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - -/* - * - * - * - * - * - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -package io.akarin.api.internal.utils.thread; -import java.util.*; -import java.util.concurrent.AbstractExecutorService; -import java.util.concurrent.Callable; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorCompletionService; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; -import java.util.concurrent.RunnableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** - * Provides default implementations of {@link ExecutorService} - * execution methods. This class implements the {@code submit}, - * {@code invokeAny} and {@code invokeAll} methods using a - * {@link RunnableFuture} returned by {@code newTaskFor}, which defaults - * to the {@link FutureTask} class provided in this package. For example, - * the implementation of {@code submit(Runnable)} creates an - * associated {@code RunnableFuture} that is executed and - * returned. Subclasses may override the {@code newTaskFor} methods - * to return {@code RunnableFuture} implementations other than - * {@code FutureTask}. - * - *
Extension example. Here is a sketch of a class - * that customizes {@link ThreadPoolExecutor} to use - * a {@code CustomTask} class instead of the default {@code FutureTask}: - *
{@code
- * public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
- *
- * static class CustomTask implements RunnableFuture {...}
- *
- * protected RunnableFuture newTaskFor(Callable c) {
- * return new CustomTask(c);
- * }
- * protected RunnableFuture newTaskFor(Runnable r, V v) {
- * return new CustomTask(r, v);
- * }
- * // ... add constructors, etc.
- * }}
- *
- * @since 1.5
- * @author Doug Lea
- */
-public abstract class SuspendableAbstractExecutorService extends AbstractExecutorService implements ExecutorService {
-
- /**
- * Returns a {@code RunnableFuture} for the given runnable and default
- * value.
- *
- * @param runnable the runnable task being wrapped
- * @param value the default value for the returned future
- * @param - * - * Usage Examples. - * - * Suppose you have a set of solvers for a certain problem, each - * returning a value of some type {@code Result}, and would like to - * run them concurrently, processing the results of each of them that - * return a non-null value, in some method {@code use(Result r)}. You - * could write this as: - * - *
{@code
- * void solve(Executor e,
- * Collection> solvers)
- * throws InterruptedException, ExecutionException {
- * CompletionService ecs
- * = new ExecutorCompletionService(e);
- * for (Callable s : solvers)
- * ecs.submit(s);
- * int n = solvers.size();
- * for (int i = 0; i < n; ++i) {
- * Result r = ecs.take().get();
- * if (r != null)
- * use(r);
- * }
- * }}
- *
- * Suppose instead that you would like to use the first non-null result
- * of the set of tasks, ignoring any that encounter exceptions,
- * and cancelling all other tasks when the first one is ready:
- *
- * {@code
- * void solve(Executor e,
- * Collection> solvers)
- * throws InterruptedException {
- * CompletionService ecs
- * = new ExecutorCompletionService(e);
- * int n = solvers.size();
- * List> futures
- * = new ArrayList>(n);
- * Result result = null;
- * try {
- * for (Callable s : solvers)
- * futures.add(ecs.submit(s));
- * for (int i = 0; i < n; ++i) {
- * try {
- * Result r = ecs.take().get();
- * if (r != null) {
- * result = r;
- * break;
- * }
- * } catch (ExecutionException ignore) {}
- * }
- * }
- * finally {
- * for (Future f : futures)
- * f.cancel(true);
- * }
- *
- * if (result != null)
- * use(result);
- * }}
- */
public class SuspendableExecutorCompletionServiceThread pools address two different problems: they usually - * provide improved performance when executing large numbers of - * asynchronous tasks, due to reduced per-task invocation overhead, - * and they provide a means of bounding and managing the resources, - * including threads, consumed when executing a collection of tasks. - * Each {@code ThreadPoolExecutor} also maintains some basic - * statistics, such as the number of completed tasks. - * - *
To be useful across a wide range of contexts, this class - * provides many adjustable parameters and extensibility - * hooks. However, programmers are urged to use the more convenient - * {@link Executors} factory methods {@link - * Executors#newCachedThreadPool} (unbounded thread pool, with - * automatic thread reclamation), {@link Executors#newFixedThreadPool} - * (fixed size thread pool) and {@link - * Executors#newSingleThreadExecutor} (single background thread), that - * preconfigure settings for the most common usage - * scenarios. Otherwise, use the following guide when manually - * configuring and tuning this class: - * - *
If hook or callback methods throw exceptions, internal worker - * threads may in turn fail and abruptly terminate.
Extension example. Most extensions of this class - * override one or more of the protected hook methods. For example, - * here is a subclass that adds a simple pause/resume feature: - * - *
{@code
- * class PausableThreadPoolExecutor extends ThreadPoolExecutor {
- * private boolean isPaused;
- * private ReentrantLock pauseLock = new ReentrantLock();
- * private Condition unpaused = pauseLock.newCondition();
- *
- * public PausableThreadPoolExecutor(...) { super(...); }
- *
- * protected void beforeExecute(Thread t, Runnable r) {
- * super.beforeExecute(t, r);
- * pauseLock.lock();
- * try {
- * while (isPaused) unpaused.await();
- * } catch (InterruptedException ie) {
- * t.interrupt();
- * } finally {
- * pauseLock.unlock();
- * }
- * }
- *
- * public void pause() {
- * pauseLock.lock();
- * try {
- * isPaused = true;
- * } finally {
- * pauseLock.unlock();
- * }
- * }
- *
- * public void resume() {
- * pauseLock.lock();
- * try {
- * isPaused = false;
- * unpaused.signalAll();
- * } finally {
- * pauseLock.unlock();
- * }
- * }
- * }}
- *
- * @since 1.5
- * @author Doug Lea
- */
public class SuspendableThreadPoolExecutor extends ThreadPoolExecutor {
/**
* The main pool control state, ctl, is an atomic integer packing
@@ -398,16 +123,14 @@ public class SuspendableThreadPoolExecutor extends ThreadPoolExecutor {
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
- @SuppressWarnings("deprecation")
- public static void suspend(SuspendableThreadPoolExecutor executor) {
- long currentThread = Thread.currentThread().getId();
- for (Worker worker : executor.workers) if (worker.thread.getId() != currentThread) worker.thread.suspend();
+ public void suspend() {
+ Thread curThread = Thread.currentThread();
+ for (Worker worker : workers) if (worker.thread != curThread) worker.thread.suspend();
}
- @SuppressWarnings("deprecation")
- public static void resume(SuspendableThreadPoolExecutor executor) {
- long currentThread = Thread.currentThread().getId();
- for (Worker worker : executor.workers) if (worker.thread.getId() != currentThread) worker.thread.resume();
+ public void resume() {
+ Thread curThread = Thread.currentThread();
+ for (Worker worker : workers) if (worker.thread != curThread) worker.thread.resume();
}
/*
diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java
index 1ae72ae72..220295249 100644
--- a/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java
+++ b/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java
@@ -18,8 +18,8 @@ import net.minecraft.server.MinecraftServer;
public abstract class MixinTimingHandler implements IMixinTimingHandler {
@Shadow @Final String name;
@Shadow private boolean enabled;
- @Shadow private volatile long start;
- @Shadow private volatile int timingDepth;
+ @Shadow private long start;
+ @Shadow private int timingDepth;
@Shadow abstract void addDiff(long diff);
@Shadow public abstract Timing startTiming();
@@ -47,7 +47,7 @@ public abstract class MixinTimingHandler implements IMixinTimingHandler {
if (!alreadySync) {
Thread curThread = Thread.currentThread();
if (curThread != MinecraftServer.getServer().primaryThread) {
- if (false && !AkarinGlobalConfig.silentAsyncTimings) {
+ if (!AkarinGlobalConfig.silentAsyncTimings) {
Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name);
Thread.dumpStack();
}
diff --git a/sources/src/main/java/org/bukkit/plugin/EventExecutor.java b/sources/src/main/java/org/bukkit/plugin/EventExecutor.java
index c8476a85b..2adef1bb7 100644
--- a/sources/src/main/java/org/bukkit/plugin/EventExecutor.java
+++ b/sources/src/main/java/org/bukkit/plugin/EventExecutor.java
@@ -3,8 +3,6 @@ package org.bukkit.plugin;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.Listener;
-import org.bukkit.event.block.BlockPhysicsEvent;
-
// Paper start
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -22,6 +20,10 @@ import io.akarin.api.internal.Akari;
import io.akarin.api.internal.utils.thread.SuspendableExecutorCompletionService;
// Paper end
+/**
+ * Akarin Changes Note
+ * 1) Suspend for event (safety issue)
+ */
/**
* Interface which defines the class for event call backs to plugins
*/
@@ -71,11 +73,11 @@ public interface EventExecutor {
if (!eventClass.isInstance(event)) return;
try {
Akari.eventSuspendTiming.startTimingIfSync(); // Akarin
- SuspendableExecutorCompletionService.suspend(Akari.STAGE_TICK); // Akarin
+ Akari.STAGE_TICK.suspend(); // Akarin
Akari.eventSuspendTiming.stopTimingIfSync(); // Akarin
asmExecutor.execute(listener, event);
Akari.eventResumeTiming.startTimingIfSync(); // Akarin
- SuspendableExecutorCompletionService.resume(Akari.STAGE_TICK); // Akarin
+ Akari.STAGE_TICK.resume(); // Akarin
Akari.eventResumeTiming.stopTimingIfSync(); // Akarin
} catch (Exception e) {
throw new EventException(e);