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 extends Callable> 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 extends Callable> 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 extends Callable> tasks)
- throws InterruptedException, ExecutionException {
- try {
- return doInvokeAny(tasks, false, 0);
- } catch (TimeoutException cannotHappen) {
- assert false;
- return null;
- }
- }
-
- public T invokeAny(Collection extends Callable> tasks,
- long timeout, TimeUnit unit)
- throws InterruptedException, ExecutionException, TimeoutException {
- return doInvokeAny(tasks, true, unit.toNanos(timeout));
- }
-
- public List> invokeAll(Collection extends Callable> 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 extends Callable> 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:
- *
- *
- * - 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.
- *
- * - 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.
- *
- * - 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.
- *
- *
- *
- *
- *
- * - 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:
- *
- *
- *
- * - In the default {@link SuspendableThreadPoolExecutor.AbortPolicy}, the
- * handler throws a runtime {@link RejectedExecutionException} upon
- * rejection.
- *
- * - 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.
- *
- * - In {@link SuspendableThreadPoolExecutor.DiscardPolicy}, a task that
- * cannot be executed is simply dropped.
- *
- * - 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.)
- *
- *
- *
- * 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);