From 1c5da01dec2bc259b2f6da547dd545e7a80ec188 Mon Sep 17 00:00:00 2001 From: Sotr Date: Sun, 12 Aug 2018 20:53:24 +0800 Subject: [PATCH] [ci skip] Cleanup --- .../utils/ReentrantSpinningDebugLock.java | 30 -- .../utils/thread/OpenExecutionException.java | 7 + .../SuspendableAbstractExecutorService.java | 318 ------------------ .../thread/SuspendableExecutionException.java | 51 --- .../SuspendableExecutorCompletionService.java | 99 +----- .../thread/SuspendableThreadPoolExecutor.java | 291 +--------------- .../server/mixin/core/MixinTimingHandler.java | 6 +- .../java/org/bukkit/plugin/EventExecutor.java | 10 +- 8 files changed, 32 insertions(+), 780 deletions(-) delete mode 100644 sources/src/main/java/io/akarin/api/internal/utils/ReentrantSpinningDebugLock.java create mode 100644 sources/src/main/java/io/akarin/api/internal/utils/thread/OpenExecutionException.java delete mode 100644 sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableAbstractExecutorService.java delete mode 100644 sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableExecutionException.java 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 the type of the given value - * @return a {@code RunnableFuture} which, when run, will run the - * underlying runnable and which, as a {@code Future}, will yield - * the given value as its result and provide for cancellation of - * the underlying task - * @since 1.6 - */ - protected RunnableFuture newTaskFor(Runnable runnable, T value) { - return new FutureTask(runnable, value); - } - - /** - * Returns a {@code RunnableFuture} for the given callable task. - * - * @param callable the callable task being wrapped - * @param the type of the callable's result - * @return a {@code RunnableFuture} which, when run, will call the - * underlying callable and which, as a {@code Future}, will yield - * the callable's result as its result and provide for - * cancellation of the underlying task - * @since 1.6 - */ - protected RunnableFuture newTaskFor(Callable callable) { - return new FutureTask(callable); - } - - /** - * @throws RejectedExecutionException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public Future submit(Runnable task) { - if (task == null) throw new NullPointerException(); - RunnableFuture ftask = newTaskFor(task, null); - execute(ftask); - return ftask; - } - - /** - * @throws RejectedExecutionException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public Future submit(Runnable task, T result) { - if (task == null) throw new NullPointerException(); - RunnableFuture ftask = newTaskFor(task, result); - execute(ftask); - return ftask; - } - - /** - * @throws RejectedExecutionException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public Future submit(Callable task) { - if (task == null) throw new NullPointerException(); - RunnableFuture ftask = newTaskFor(task); - execute(ftask); - return ftask; - } - - /** - * the main mechanics of invokeAny. - */ - private T doInvokeAny(Collection> tasks, - boolean timed, long nanos) - throws InterruptedException, ExecutionException, TimeoutException { - if (tasks == null) - throw new NullPointerException(); - int ntasks = tasks.size(); - if (ntasks == 0) - throw new IllegalArgumentException(); - ArrayList> futures = new ArrayList>(ntasks); - ExecutorCompletionService ecs = - new ExecutorCompletionService(this); - - // For efficiency, especially in executors with limited - // parallelism, check to see if previously submitted tasks are - // done before submitting more of them. This interleaving - // plus the exception mechanics account for messiness of main - // loop. - - try { - // Record exceptions so that if we fail to obtain any - // result, we can throw the last exception we got. - ExecutionException ee = null; - final long deadline = timed ? System.nanoTime() + nanos : 0L; - Iterator> it = tasks.iterator(); - - // Start one task for sure; the rest incrementally - futures.add(ecs.submit(it.next())); - --ntasks; - int active = 1; - - for (;;) { - Future f = ecs.poll(); - if (f == null) { - if (ntasks > 0) { - --ntasks; - futures.add(ecs.submit(it.next())); - ++active; - } - else if (active == 0) - break; - else if (timed) { - f = ecs.poll(nanos, TimeUnit.NANOSECONDS); - if (f == null) - throw new TimeoutException(); - nanos = deadline - System.nanoTime(); - } - else - f = ecs.take(); - } - if (f != null) { - --active; - try { - return f.get(); - } catch (ExecutionException eex) { - ee = eex; - } catch (RuntimeException rex) { - ee = new ExecutionException(rex); - } - } - } - - if (ee == null) - ee = new SuspendableExecutionException(); - throw ee; - - } finally { - for (int i = 0, size = futures.size(); i < size; i++) - futures.get(i).cancel(true); - } - } - - public T invokeAny(Collection> tasks) - throws InterruptedException, ExecutionException { - try { - return doInvokeAny(tasks, false, 0); - } catch (TimeoutException cannotHappen) { - assert false; - return null; - } - } - - public T invokeAny(Collection> tasks, - long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - return doInvokeAny(tasks, true, unit.toNanos(timeout)); - } - - public List> invokeAll(Collection> tasks) - throws InterruptedException { - if (tasks == null) - throw new NullPointerException(); - ArrayList> futures = new ArrayList>(tasks.size()); - boolean done = false; - try { - for (Callable t : tasks) { - RunnableFuture f = newTaskFor(t); - futures.add(f); - execute(f); - } - for (int i = 0, size = futures.size(); i < size; i++) { - Future f = futures.get(i); - if (!f.isDone()) { - try { - f.get(); - } catch (CancellationException ignore) { - } catch (ExecutionException ignore) { - } - } - } - done = true; - return futures; - } finally { - if (!done) - for (int i = 0, size = futures.size(); i < size; i++) - futures.get(i).cancel(true); - } - } - - public List> invokeAll(Collection> tasks, - long timeout, TimeUnit unit) - throws InterruptedException { - if (tasks == null) - throw new NullPointerException(); - long nanos = unit.toNanos(timeout); - ArrayList> futures = new ArrayList>(tasks.size()); - boolean done = false; - try { - for (Callable t : tasks) - futures.add(newTaskFor(t)); - - final long deadline = System.nanoTime() + nanos; - final int size = futures.size(); - - // Interleave time checks and calls to execute in case - // executor doesn't have any/much parallelism. - for (int i = 0; i < size; i++) { - execute((Runnable)futures.get(i)); - nanos = deadline - System.nanoTime(); - if (nanos <= 0L) - return futures; - } - - for (int i = 0; i < size; i++) { - Future f = futures.get(i); - if (!f.isDone()) { - if (nanos <= 0L) - return futures; - try { - f.get(nanos, TimeUnit.NANOSECONDS); - } catch (CancellationException ignore) { - } catch (ExecutionException ignore) { - } catch (TimeoutException toe) { - return futures; - } - nanos = deadline - System.nanoTime(); - } - } - done = true; - return futures; - } finally { - if (!done) - for (int i = 0, size = futures.size(); i < size; i++) - futures.get(i).cancel(true); - } - } - -} diff --git a/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableExecutionException.java b/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableExecutionException.java deleted file mode 100644 index 896689380..000000000 --- a/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableExecutionException.java +++ /dev/null @@ -1,51 +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.concurrent.ExecutionException; - -/** - * Exception thrown when attempting to retrieve the result of a task - * that aborted by throwing an exception. This exception can be - * inspected using the {@link #getCause()} method. - * - * @see Future - * @since 1.5 - * @author Doug Lea - */ -public class SuspendableExecutionException extends ExecutionException { - private static final long serialVersionUID = 7830266012832686185L; -} diff --git a/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableExecutorCompletionService.java b/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableExecutorCompletionService.java index 4456ed5f1..6204d15c8 100644 --- a/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableExecutorCompletionService.java +++ b/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableExecutorCompletionService.java @@ -38,93 +38,22 @@ package io.akarin.api.internal.utils.thread; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; -import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RunnableFuture; import java.util.concurrent.TimeUnit; -/** - * A {@link CompletionService} that uses a supplied {@link Executor} - * to execute tasks. This class arranges that submitted tasks are, - * upon completion, placed on a queue accessible using {@code take}. - * The class is lightweight enough to be suitable for transient use - * when processing groups of tasks. - * - *

- * - * 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 SuspendableExecutorCompletionService implements CompletionService { - private final Executor executor; - private final SuspendableAbstractExecutorService aes; + private final SuspendableThreadPoolExecutor executor; private final BlockingQueue> completionQueue; - public static void suspend(SuspendableExecutorCompletionService service) { - SuspendableThreadPoolExecutor.suspend((SuspendableThreadPoolExecutor) service.executor); + public void suspend() { + executor.suspend(); } - public static void resume(SuspendableExecutorCompletionService service) { - SuspendableThreadPoolExecutor.resume((SuspendableThreadPoolExecutor) service.executor); + public void resume() { + executor.resume(); } /** @@ -140,17 +69,11 @@ public class SuspendableExecutorCompletionService implements CompletionServic } private RunnableFuture newTaskFor(Callable task) { - if (aes == null) - return new FutureTask(task); - else - return aes.newTaskFor(task); + return new FutureTask(task); } private RunnableFuture newTaskFor(Runnable task, V result) { - if (aes == null) - return new FutureTask(task, result); - else - return aes.newTaskFor(task, result); + return new FutureTask(task, result); } /** @@ -161,12 +84,10 @@ public class SuspendableExecutorCompletionService implements CompletionServic * @param executor the executor to use * @throws NullPointerException if executor is {@code null} */ - public SuspendableExecutorCompletionService(Executor executor) { + public SuspendableExecutorCompletionService(SuspendableThreadPoolExecutor executor) { if (executor == null) throw new NullPointerException(); this.executor = executor; - this.aes = (executor instanceof SuspendableAbstractExecutorService) ? - (SuspendableAbstractExecutorService) executor : null; this.completionQueue = new LinkedBlockingQueue>(); } @@ -183,13 +104,11 @@ public class SuspendableExecutorCompletionService implements CompletionServic * them not to be retrievable. * @throws NullPointerException if executor or completionQueue are {@code null} */ - public SuspendableExecutorCompletionService(Executor executor, + public SuspendableExecutorCompletionService(SuspendableThreadPoolExecutor executor, BlockingQueue> completionQueue) { if (executor == null || completionQueue == null) throw new NullPointerException(); this.executor = executor; - this.aes = (executor instanceof SuspendableAbstractExecutorService) ? - (SuspendableAbstractExecutorService) executor : null; this.completionQueue = completionQueue; } diff --git a/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableThreadPoolExecutor.java b/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableThreadPoolExecutor.java index fb1e622a0..317562963 100644 --- a/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableThreadPoolExecutor.java +++ b/sources/src/main/java/io/akarin/api/internal/utils/thread/SuspendableThreadPoolExecutor.java @@ -34,6 +34,7 @@ */ package io.akarin.api.internal.utils.thread; + import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; @@ -48,282 +49,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.*; -/** - * An {@link ExecutorService} that executes each submitted task using - * one of possibly several pooled threads, normally configured - * using {@link Executors} factory methods. - * - *

Thread 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: - * - *

- * - *
Core and maximum pool sizes
- * - *
A {@code ThreadPoolExecutor} will automatically adjust the - * pool size (see {@link #getPoolSize}) - * according to the bounds set by - * corePoolSize (see {@link #getCorePoolSize}) and - * maximumPoolSize (see {@link #getMaximumPoolSize}). - * - * When a new task is submitted in method {@link #execute(Runnable)}, - * and fewer than corePoolSize threads are running, a new thread is - * created to handle the request, even if other worker threads are - * idle. If there are more than corePoolSize but less than - * maximumPoolSize threads running, a new thread will be created only - * if the queue is full. By setting corePoolSize and maximumPoolSize - * the same, you create a fixed-size thread pool. By setting - * maximumPoolSize to an essentially unbounded value such as {@code - * Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary - * number of concurrent tasks. Most typically, core and maximum pool - * sizes are set only upon construction, but they may also be changed - * dynamically using {@link #setCorePoolSize} and {@link - * #setMaximumPoolSize}.
- * - *
On-demand construction
- * - *
By default, even core threads are initially created and - * started only when new tasks arrive, but this can be overridden - * dynamically using method {@link #prestartCoreThread} or {@link - * #prestartAllCoreThreads}. You probably want to prestart threads if - * you construct the pool with a non-empty queue.
- * - *
Creating new threads
- * - *
New threads are created using a {@link ThreadFactory}. If not - * otherwise specified, a {@link Executors#defaultThreadFactory} is - * used, that creates threads to all be in the same {@link - * ThreadGroup} and with the same {@code NORM_PRIORITY} priority and - * non-daemon status. By supplying a different ThreadFactory, you can - * alter the thread's name, thread group, priority, daemon status, - * etc. If a {@code ThreadFactory} fails to create a thread when asked - * by returning null from {@code newThread}, the executor will - * continue, but might not be able to execute any tasks. Threads - * should possess the "modifyThread" {@code RuntimePermission}. If - * worker threads or other threads using the pool do not possess this - * permission, service may be degraded: configuration changes may not - * take effect in a timely manner, and a shutdown pool may remain in a - * state in which termination is possible but not completed.
- * - *
Keep-alive times
- * - *
If the pool currently has more than corePoolSize threads, - * excess threads will be terminated if they have been idle for more - * than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}). - * This provides a means of reducing resource consumption when the - * pool is not being actively used. If the pool becomes more active - * later, new threads will be constructed. This parameter can also be - * changed dynamically using method {@link #setKeepAliveTime(long, - * TimeUnit)}. Using a value of {@code Long.MAX_VALUE} {@link - * TimeUnit#NANOSECONDS} effectively disables idle threads from ever - * terminating prior to shut down. By default, the keep-alive policy - * applies only when there are more than corePoolSize threads. But - * method {@link #allowCoreThreadTimeOut(boolean)} can be used to - * apply this time-out policy to core threads as well, so long as the - * keepAliveTime value is non-zero.
- * - *
Queuing
- * - *
Any {@link BlockingQueue} may be used to transfer and hold - * submitted tasks. The use of this queue interacts with pool sizing: - * - *
    - * - *
  • If fewer than corePoolSize threads are running, the Executor - * always prefers adding a new thread - * rather than queuing.
  • - * - *
  • If corePoolSize or more threads are running, the Executor - * always prefers queuing a request rather than adding a new - * thread.
  • - * - *
  • If a request cannot be queued, a new thread is created unless - * this would exceed maximumPoolSize, in which case, the task will be - * rejected.
  • - * - *
- * - * There are three general strategies for queuing: - *
    - * - *
  1. Direct handoffs. A good default choice for a work - * queue is a {@link SynchronousQueue} that hands off tasks to threads - * without otherwise holding them. Here, an attempt to queue a task - * will fail if no threads are immediately available to run it, so a - * new thread will be constructed. This policy avoids lockups when - * handling sets of requests that might have internal dependencies. - * Direct handoffs generally require unbounded maximumPoolSizes to - * avoid rejection of new submitted tasks. This in turn admits the - * possibility of unbounded thread growth when commands continue to - * arrive on average faster than they can be processed.
  2. - * - *
  3. Unbounded queues. Using an unbounded queue (for - * example a {@link LinkedBlockingQueue} without a predefined - * capacity) will cause new tasks to wait in the queue when all - * corePoolSize threads are busy. Thus, no more than corePoolSize - * threads will ever be created. (And the value of the maximumPoolSize - * therefore doesn't have any effect.) This may be appropriate when - * each task is completely independent of others, so tasks cannot - * affect each others execution; for example, in a web page server. - * While this style of queuing can be useful in smoothing out - * transient bursts of requests, it admits the possibility of - * unbounded work queue growth when commands continue to arrive on - * average faster than they can be processed.
  4. - * - *
  5. Bounded queues. A bounded queue (for example, an - * {@link ArrayBlockingQueue}) helps prevent resource exhaustion when - * used with finite maximumPoolSizes, but can be more difficult to - * tune and control. Queue sizes and maximum pool sizes may be traded - * off for each other: Using large queues and small pools minimizes - * CPU usage, OS resources, and context-switching overhead, but can - * lead to artificially low throughput. If tasks frequently block (for - * example if they are I/O bound), a system may be able to schedule - * time for more threads than you otherwise allow. Use of small queues - * generally requires larger pool sizes, which keeps CPUs busier but - * may encounter unacceptable scheduling overhead, which also - * decreases throughput.
  6. - * - *
- * - *
- * - *
Rejected tasks
- * - *
New tasks submitted in method {@link #execute(Runnable)} will be - * rejected when the Executor has been shut down, and also when - * the Executor uses finite bounds for both maximum threads and work queue - * capacity, and is saturated. In either case, the {@code execute} method - * invokes the {@link - * RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor)} - * method of its {@link RejectedExecutionHandler}. Four predefined handler - * policies are provided: - * - *
    - * - *
  1. In the default {@link SuspendableThreadPoolExecutor.AbortPolicy}, the - * handler throws a runtime {@link RejectedExecutionException} upon - * rejection.
  2. - * - *
  3. In {@link SuspendableThreadPoolExecutor.CallerRunsPolicy}, the thread - * that invokes {@code execute} itself runs the task. This provides a - * simple feedback control mechanism that will slow down the rate that - * new tasks are submitted.
  4. - * - *
  5. In {@link SuspendableThreadPoolExecutor.DiscardPolicy}, a task that - * cannot be executed is simply dropped.
  6. - * - *
  7. In {@link SuspendableThreadPoolExecutor.DiscardOldestPolicy}, if the - * executor is not shut down, the task at the head of the work queue - * is dropped, and then execution is retried (which can fail again, - * causing this to be repeated.)
  8. - * - *
- * - * It is possible to define and use other kinds of {@link - * RejectedExecutionHandler} classes. Doing so requires some care - * especially when policies are designed to work only under particular - * capacity or queuing policies.
- * - *
Hook methods
- * - *
This class provides {@code protected} overridable - * {@link #beforeExecute(Thread, Runnable)} and - * {@link #afterExecute(Runnable, Throwable)} methods that are called - * before and after execution of each task. These can be used to - * manipulate the execution environment; for example, reinitializing - * ThreadLocals, gathering statistics, or adding log entries. - * Additionally, method {@link #terminated} can be overridden to perform - * any special processing that needs to be done once the Executor has - * fully terminated. - * - *

If hook or callback methods throw exceptions, internal worker - * threads may in turn fail and abruptly terminate.

- * - *
Queue maintenance
- * - *
Method {@link #getQueue()} allows access to the work queue - * for purposes of monitoring and debugging. Use of this method for - * any other purpose is strongly discouraged. Two supplied methods, - * {@link #remove(Runnable)} and {@link #purge} are available to - * assist in storage reclamation when large numbers of queued tasks - * become cancelled.
- * - *
Finalization
- * - *
A pool that is no longer referenced in a program AND - * has no remaining threads will be {@code shutdown} automatically. If - * you would like to ensure that unreferenced pools are reclaimed even - * if users forget to call {@link #shutdown}, then you must arrange - * that unused threads eventually die, by setting appropriate - * keep-alive times, using a lower bound of zero core threads and/or - * setting {@link #allowCoreThreadTimeOut(boolean)}.
- * - *
- * - *

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);