summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Haller <hallerp@gmail.com>2009-10-20 16:21:29 +0000
committerPhilipp Haller <hallerp@gmail.com>2009-10-20 16:21:29 +0000
commit5a817fdbf7652f5ab18c011eea405363507261fe (patch)
treebdb440a85f00d668f855c9b413baf6f03a3bf90e
parentfeb088b2bc8a3e78d1f8ac32b540b78a5b9c01d6 (diff)
downloadscala-5a817fdbf7652f5ab18c011eea405363507261fe.tar.gz
scala-5a817fdbf7652f5ab18c011eea405363507261fe.tar.bz2
scala-5a817fdbf7652f5ab18c011eea405363507261fe.zip
Do not use ForkJoinPool when running on IBM J9;...
Do not use ForkJoinPool when running on IBM J9; in this case use 1.5 ThreadPoolScheduler.
-rw-r--r--src/actors/scala/actors/Scheduler.scala22
-rw-r--r--src/actors/scala/actors/scheduler/ResizableThreadPoolScheduler.scala189
-rw-r--r--src/actors/scala/actors/threadpool/AbstractCollection.java32
-rw-r--r--src/actors/scala/actors/threadpool/AbstractExecutorService.java292
-rw-r--r--src/actors/scala/actors/threadpool/AbstractQueue.java170
-rw-r--r--src/actors/scala/actors/threadpool/Arrays.java811
-rw-r--r--src/actors/scala/actors/threadpool/AtomicInteger.java210
-rw-r--r--src/actors/scala/actors/threadpool/BlockingQueue.java342
-rw-r--r--src/actors/scala/actors/threadpool/Callable.java35
-rw-r--r--src/actors/scala/actors/threadpool/CancellationException.java34
-rw-r--r--src/actors/scala/actors/threadpool/CompletionService.java97
-rw-r--r--src/actors/scala/actors/threadpool/ExecutionException.java65
-rw-r--r--src/actors/scala/actors/threadpool/Executor.java112
-rw-r--r--src/actors/scala/actors/threadpool/ExecutorCompletionService.java178
-rw-r--r--src/actors/scala/actors/threadpool/ExecutorService.java331
-rw-r--r--src/actors/scala/actors/threadpool/Executors.java667
-rw-r--r--src/actors/scala/actors/threadpool/Future.java142
-rw-r--r--src/actors/scala/actors/threadpool/FutureTask.java310
-rw-r--r--src/actors/scala/actors/threadpool/LinkedBlockingQueue.java751
-rw-r--r--src/actors/scala/actors/threadpool/Perf.java28
-rw-r--r--src/actors/scala/actors/threadpool/Queue.java191
-rw-r--r--src/actors/scala/actors/threadpool/RejectedExecutionException.java62
-rw-r--r--src/actors/scala/actors/threadpool/RejectedExecutionHandler.java34
-rw-r--r--src/actors/scala/actors/threadpool/RunnableFuture.java24
-rw-r--r--src/actors/scala/actors/threadpool/SynchronousQueue.java833
-rw-r--r--src/actors/scala/actors/threadpool/ThreadFactory.java41
-rw-r--r--src/actors/scala/actors/threadpool/ThreadPoolExecutor.java1968
-rw-r--r--src/actors/scala/actors/threadpool/TimeUnit.java407
-rw-r--r--src/actors/scala/actors/threadpool/TimeoutException.java38
-rw-r--r--src/actors/scala/actors/threadpool/helpers/FIFOWaitQueue.java85
-rw-r--r--src/actors/scala/actors/threadpool/helpers/NanoTimer.java29
-rw-r--r--src/actors/scala/actors/threadpool/helpers/ThreadHelpers.java66
-rw-r--r--src/actors/scala/actors/threadpool/helpers/Utils.java343
-rw-r--r--src/actors/scala/actors/threadpool/helpers/WaitQueue.java146
-rw-r--r--src/actors/scala/actors/threadpool/locks/CondVar.java190
-rw-r--r--src/actors/scala/actors/threadpool/locks/Condition.java434
-rw-r--r--src/actors/scala/actors/threadpool/locks/FIFOCondVar.java146
-rw-r--r--src/actors/scala/actors/threadpool/locks/Lock.java328
-rw-r--r--src/actors/scala/actors/threadpool/locks/ReadWriteLock.java104
-rw-r--r--src/actors/scala/actors/threadpool/locks/ReentrantLock.java959
-rw-r--r--src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java1339
41 files changed, 12579 insertions, 6 deletions
diff --git a/src/actors/scala/actors/Scheduler.scala b/src/actors/scala/actors/Scheduler.scala
index 7bc5eb20df..080abbbf41 100644
--- a/src/actors/scala/actors/Scheduler.scala
+++ b/src/actors/scala/actors/Scheduler.scala
@@ -11,7 +11,7 @@
package scala.actors
import java.util.concurrent._
-import scheduler.{DelegatingScheduler, ForkJoinScheduler, DefaultThreadPoolScheduler}
+import scheduler.{DelegatingScheduler, ForkJoinScheduler, ResizableThreadPoolScheduler}
/**
* The <code>Scheduler</code> object is used by <code>Actor</code> to
@@ -24,11 +24,21 @@ object Scheduler extends DelegatingScheduler {
Debug.info("initializing "+this+"...")
def makeNewScheduler: IScheduler = {
- //val s = new DefaultThreadPoolScheduler(false)
- val s = new ForkJoinScheduler
- Debug.info(this+": starting new "+s+" ["+s.getClass+"]")
- s.start()
- s
+ // test on which JVM we are running
+ val jvmVendor = System.getProperty("java.vm.vendor")
+ val sched = if (jvmVendor.indexOf("IBM") != -1) {
+ Debug.info(this+": running on a "+jvmVendor+" JVM")
+ // on IBM J9 1.6 do not use ForkJoinPool
+ val s = new ResizableThreadPoolScheduler(false)
+ s.start()
+ s
+ } else {
+ val s = new ForkJoinScheduler
+ s.start()
+ s
+ }
+ Debug.info(this+": starting new "+sched+" ["+sched.getClass+"]")
+ sched
}
/* Only <code>ForkJoinScheduler</code> implements this method.
diff --git a/src/actors/scala/actors/scheduler/ResizableThreadPoolScheduler.scala b/src/actors/scala/actors/scheduler/ResizableThreadPoolScheduler.scala
new file mode 100644
index 0000000000..3433e51fdc
--- /dev/null
+++ b/src/actors/scala/actors/scheduler/ResizableThreadPoolScheduler.scala
@@ -0,0 +1,189 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2005-2009, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id: ThreadPoolScheduler.scala 18948 2009-10-06 17:30:27Z phaller $
+
+package scala.actors.scheduler
+
+import scala.actors.threadpool.{ThreadPoolExecutor, TimeUnit, LinkedBlockingQueue}
+import scala.actors.{Debug, IScheduler}
+import scala.concurrent.ManagedBlocker
+
+/**
+ * This scheduler class uses a <code>ThreadPoolExecutor</code>
+ * to execute <code>Actor</code>s.
+ *
+ * The scheduler attempts to shut down itself and the underlying
+ * <code>ThreadPoolExecutor</code> only if <code>terminate</code>
+ * is set to true. Otherwise, the scheduler must be shut down
+ * explicitly.
+ *
+ * @author Philipp Haller
+ */
+class ResizableThreadPoolScheduler(protected val terminate: Boolean,
+ protected val daemon: Boolean)
+ extends Thread with IScheduler with TerminationMonitor {
+
+ setDaemon(daemon)
+
+ // guarded by this
+ private var terminating = false
+ // guarded by this
+ private var suspending = false
+
+ // this has to be a java.util.Collection, since this is what
+ // the ForkJoinPool returns.
+ @volatile
+ private var drainedTasks: java.util.List[_] = null
+
+ // guarded by this
+ private var coreSize = ThreadPoolConfig.corePoolSize
+ private val maxSize = ThreadPoolConfig.maxPoolSize
+ private val numCores = Runtime.getRuntime().availableProcessors()
+
+ protected val CHECK_FREQ = 10
+
+ private def makeNewPool(): ThreadPoolExecutor = {
+ val workQueue = new LinkedBlockingQueue
+ new ThreadPoolExecutor(coreSize,
+ maxSize,
+ 60000L,
+ TimeUnit.MILLISECONDS,
+ workQueue,
+ new ThreadPoolExecutor.CallerRunsPolicy)
+ }
+
+ // guarded by this
+ private var executor = makeNewPool()
+
+ Debug.info(this+": corePoolSize = "+coreSize+", maxPoolSize = "+maxSize)
+
+ def this(d: Boolean) {
+ this(true, d)
+ }
+
+ def this() {
+ this(false)
+ }
+
+ private def numWorkersBlocked = {
+ executor.mainLock.lock()
+ val iter = executor.workers.iterator()
+ var numBlocked = 0
+ while (iter.hasNext()) {
+ val w = iter.next().asInstanceOf[ThreadPoolExecutor#Worker]
+ if (w.tryLock()) {
+ // worker is idle
+ w.unlock()
+ } else {
+ val s = w.thread.getState()
+ if (s == Thread.State.WAITING || s == Thread.State.TIMED_WAITING)
+ numBlocked += 1
+ }
+ }
+ executor.mainLock.unlock()
+ numBlocked
+ }
+
+ override def run() {
+ try {
+ while (true) {
+ this.synchronized {
+ try {
+ wait(CHECK_FREQ)
+ } catch {
+ case _: InterruptedException =>
+ }
+
+ if (terminating)
+ throw new QuitException
+
+ if (!suspending) {
+ gc()
+
+ // check if we need more worker threads
+ val activeBlocked = numWorkersBlocked
+ if (coreSize - activeBlocked < numCores && coreSize < maxSize) {
+ coreSize = numCores + activeBlocked
+ executor.setCorePoolSize(coreSize)
+ } else if (terminate && allTerminated) {
+ // if all worker threads idle terminate
+ if (executor.getActiveCount() == 0) {
+ Debug.info(this+": initiating shutdown...")
+ Debug.info(this+": corePoolSize = "+coreSize+", maxPoolSize = "+maxSize)
+
+ terminating = true
+ throw new QuitException
+ }
+ }
+ } else {
+ drainedTasks = executor.shutdownNow()
+ Debug.info(this+": drained "+drainedTasks.size()+" tasks")
+ terminating = true
+ throw new QuitException
+ }
+ } // sync
+ }
+ } catch {
+ case _: QuitException =>
+ executor.shutdown()
+ // allow thread to exit
+ }
+ }
+
+ def execute(task: Runnable): Unit =
+ executor execute task
+
+ def execute(fun: => Unit): Unit =
+ executor.execute(new Runnable {
+ def run() { fun }
+ })
+
+ /** Shuts down the scheduler.
+ */
+ def shutdown(): Unit = synchronized {
+ terminating = true
+ }
+
+ def isActive = synchronized {
+ !terminating && (executor ne null) && !executor.isShutdown()
+ }
+
+ def managedBlock(blocker: ManagedBlocker) {
+ blocker.block()
+ }
+
+ /** Suspends the scheduler. All threads that were in use by the
+ * scheduler and its internal thread pool are terminated.
+ */
+ def snapshot() = synchronized {
+ suspending = true
+ }
+
+ /** Resumes the execution of the scheduler if it was previously
+ * suspended using <code>snapshot</code>.
+ */
+ def restart() {
+ synchronized {
+ if (!suspending)
+ error("snapshot has not been invoked")
+ else if (isActive)
+ error("scheduler is still active")
+ else
+ suspending = false
+
+ executor = makeNewPool()
+ }
+ val iter = drainedTasks.iterator()
+ while (iter.hasNext()) {
+ executor.execute(iter.next().asInstanceOf[Runnable])
+ }
+ start()
+ }
+
+}
diff --git a/src/actors/scala/actors/threadpool/AbstractCollection.java b/src/actors/scala/actors/threadpool/AbstractCollection.java
new file mode 100644
index 0000000000..f3dc1e1292
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/AbstractCollection.java
@@ -0,0 +1,32 @@
+/*
+ * Written by Dawid Kurzyniec, based on public domain code written by Doug Lea
+ * and publictly available documentation, and released to the public domain, as
+ * explained at http://creativecommons.org/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+import scala.actors.threadpool.helpers.Utils;
+
+/**
+ * Overrides toArray() and toArray(Object[]) in AbstractCollection to provide
+ * implementations valid for concurrent collections.
+ *
+ * @author Doug Lea
+ * @author Dawid Kurzyniec
+ */
+public abstract class AbstractCollection extends java.util.AbstractCollection {
+
+ /**
+ * Sole constructor. (For invocation by subclass constructors, typically
+ * implicit.)
+ */
+ protected AbstractCollection() { super(); }
+
+ public Object[] toArray() {
+ return Utils.collectionToArray(this);
+ }
+
+ public Object[] toArray(Object[] a) {
+ return Utils.collectionToArray(this, a);
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/AbstractExecutorService.java b/src/actors/scala/actors/threadpool/AbstractExecutorService.java
new file mode 100644
index 0000000000..7953bfe30f
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/AbstractExecutorService.java
@@ -0,0 +1,292 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+import scala.actors.threadpool.helpers.*;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * Provides default implementations of {@link ExecutorService}
+ * execution methods. This class implements the <tt>submit</tt>,
+ * <tt>invokeAny</tt> and <tt>invokeAll</tt> methods using a
+ * {@link RunnableFuture} returned by <tt>newTaskFor</tt>, which defaults
+ * to the {@link FutureTask} class provided in this package. For example,
+ * the implementation of <tt>submit(Runnable)</tt> creates an
+ * associated <tt>RunnableFuture</tt> that is executed and
+ * returned. Subclasses may override the <tt>newTaskFor</tt> methods
+ * to return <tt>RunnableFuture</tt> implementations other than
+ * <tt>FutureTask</tt>.
+ *
+ * <p> <b>Extension example</b>. Here is a sketch of a class
+ * that customizes {@link ThreadPoolExecutor} to use
+ * a <tt>CustomTask</tt> class instead of the default <tt>FutureTask</tt>:
+ * <pre>
+ * public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
+ *
+ * static class CustomTask&lt;V&gt; implements RunnableFuture&lt;V&gt; {...}
+ *
+ * protected &lt;V&gt; RunnableFuture&lt;V&gt; newTaskFor(Callable&lt;V&gt; c) {
+ * return new CustomTask&lt;V&gt;(c);
+ * }
+ * protected &lt;V&gt; RunnableFuture&lt;V&gt; newTaskFor(Runnable r, V v) {
+ * return new CustomTask&lt;V&gt;(r, v);
+ * }
+ * // ... add constructors, etc.
+ * }
+ * </pre>
+ * @since 1.5
+ * @author Doug Lea
+ */
+public abstract class AbstractExecutorService implements ExecutorService {
+
+ /**
+ * Returns a <tt>RunnableFuture</tt> for the given runnable and default
+ * value.
+ *
+ * @param runnable the runnable task being wrapped
+ * @param value the default value for the returned future
+ * @return a <tt>RunnableFuture</tt> which when run will run the
+ * underlying runnable and which, as a <tt>Future</tt>, will yield
+ * the given value as its result and provide for cancellation of
+ * the underlying task.
+ * @since 1.6
+ */
+ protected RunnableFuture newTaskFor(Runnable runnable, Object value) {
+ return new FutureTask(runnable, value);
+ }
+
+ /**
+ * Returns a <tt>RunnableFuture</tt> for the given callable task.
+ *
+ * @param callable the callable task being wrapped
+ * @return a <tt>RunnableFuture</tt> which when run will call the
+ * underlying callable and which, as a <tt>Future</tt>, 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, Object 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 Object 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();
+ List 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;
+ long lastTime = (timed)? Utils.nanoTime() : 0;
+ Iterator it = tasks.iterator();
+
+ // Start one task for sure; the rest incrementally
+ futures.add(ecs.submit((Callable)it.next()));
+ --ntasks;
+ int active = 1;
+
+ for (;;) {
+ Future f = ecs.poll();
+ if (f == null) {
+ if (ntasks > 0) {
+ --ntasks;
+ futures.add(ecs.submit((Callable)it.next()));
+ ++active;
+ }
+ else if (active == 0)
+ break;
+ else if (timed) {
+ f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
+ if (f == null)
+ throw new TimeoutException();
+ long now = Utils.nanoTime();
+ nanos -= now - lastTime;
+ lastTime = now;
+ }
+ else
+ f = ecs.take();
+ }
+ if (f != null) {
+ --active;
+ try {
+ return f.get();
+ } catch (InterruptedException ie) {
+ throw ie;
+ } catch (ExecutionException eex) {
+ ee = eex;
+ } catch (RuntimeException rex) {
+ ee = new ExecutionException(rex);
+ }
+ }
+ }
+
+ if (ee == null)
+ ee = new ExecutionException();
+ throw ee;
+
+ } finally {
+ for (Iterator f = futures.iterator(); f.hasNext();)
+ ((Future)f.next()).cancel(true);
+ }
+ }
+
+ public Object invokeAny(Collection tasks)
+ throws InterruptedException, ExecutionException {
+ try {
+ return doInvokeAny(tasks, false, 0);
+ } catch (TimeoutException cannotHappen) {
+ assert false;
+ return null;
+ }
+ }
+
+ public Object 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();
+ List futures = new ArrayList(tasks.size());
+ boolean done = false;
+ try {
+ for (Iterator t = tasks.iterator(); t.hasNext();) {
+ RunnableFuture f = newTaskFor((Callable)t.next());
+ futures.add(f);
+ execute(f);
+ }
+ for (Iterator i = futures.iterator(); i.hasNext();) {
+ Future f = (Future) i.next();
+ if (!f.isDone()) {
+ try {
+ f.get();
+ } catch (CancellationException ignore) {
+ } catch (ExecutionException ignore) {
+ }
+ }
+ }
+ done = true;
+ return futures;
+ } finally {
+ if (!done)
+ for (Iterator i = futures.iterator(); i.hasNext();) {
+ Future f = (Future) i.next();
+ f.cancel(true);
+ }
+ }
+ }
+
+ public List invokeAll(Collection tasks,
+ long timeout, TimeUnit unit)
+ throws InterruptedException {
+ if (tasks == null || unit == null)
+ throw new NullPointerException();
+ long nanos = unit.toNanos(timeout);
+ List futures = new ArrayList(tasks.size());
+ boolean done = false;
+ try {
+ for (Iterator t = tasks.iterator(); t.hasNext();)
+ futures.add(newTaskFor((Callable)t.next()));
+
+ long lastTime = Utils.nanoTime();
+
+ // Interleave time checks and calls to execute in case
+ // executor doesn't have any/much parallelism.
+ Iterator it = futures.iterator();
+ while (it.hasNext()) {
+ execute((Runnable)(it.next()));
+ long now = Utils.nanoTime();
+ nanos -= (now - lastTime);
+ lastTime = now;
+ if (nanos <= 0)
+ return futures;
+ }
+
+ for (Iterator i = futures.iterator(); i.hasNext();) {
+ Future f = (Future)i.next();
+ if (!f.isDone()) {
+ if (nanos <= 0)
+ return futures;
+ try {
+ f.get(nanos, TimeUnit.NANOSECONDS);
+ } catch (CancellationException ignore) {
+ } catch (ExecutionException ignore) {
+ } catch (TimeoutException toe) {
+ return futures;
+ }
+ long now = Utils.nanoTime();
+ nanos -= now - lastTime;
+ lastTime = now;
+ }
+ }
+ done = true;
+ return futures;
+ } finally {
+ if (!done)
+ for (Iterator i = futures.iterator(); i.hasNext();) {
+ Future f = (Future) i.next();
+ f.cancel(true);
+ }
+ }
+ }
+
+}
diff --git a/src/actors/scala/actors/threadpool/AbstractQueue.java b/src/actors/scala/actors/threadpool/AbstractQueue.java
new file mode 100644
index 0000000000..84ddc136bc
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/AbstractQueue.java
@@ -0,0 +1,170 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+/**
+ * This class provides skeletal implementations of some {@link Queue}
+ * operations. The implementations in this class are appropriate when
+ * the base implementation does <em>not</em> allow <tt>null</tt>
+ * elements. Methods {@link #add add}, {@link #remove remove}, and
+ * {@link #element element} are based on {@link #offer offer}, {@link
+ * #poll poll}, and {@link #peek peek}, respectively but throw
+ * exceptions instead of indicating failure via <tt>false</tt> or
+ * <tt>null</tt> returns.
+ *
+ * <p> A <tt>Queue</tt> implementation that extends this class must
+ * minimally define a method {@link Queue#offer} which does not permit
+ * insertion of <tt>null</tt> elements, along with methods {@link
+ * Queue#peek}, {@link Queue#poll}, {@link Collection#size}, and a
+ * {@link Collection#iterator} supporting {@link
+ * Iterator#remove}. Typically, additional methods will be overridden
+ * as well. If these requirements cannot be met, consider instead
+ * subclassing {@link AbstractCollection}.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public abstract class AbstractQueue
+ extends AbstractCollection
+ implements Queue {
+
+ /**
+ * Constructor for use by subclasses.
+ */
+ protected AbstractQueue() {
+ }
+
+ /**
+ * Inserts the specified element into this queue if it is possible to do so
+ * immediately without violating capacity restrictions, returning
+ * <tt>true</tt> upon success and throwing an <tt>IllegalStateException</tt>
+ * if no space is currently available.
+ *
+ * <p>This implementation returns <tt>true</tt> if <tt>offer</tt> succeeds,
+ * else throws an <tt>IllegalStateException</tt>.
+ *
+ * @param e the element to add
+ * @return <tt>true</tt> (as specified by {@link Collection#add})
+ * @throws IllegalStateException if the element cannot be added at this
+ * time due to capacity restrictions
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this queue
+ * @throws NullPointerException if the specified element is null and
+ * this queue does not permit null elements
+ * @throws IllegalArgumentException if some property of this element
+ * prevents it from being added to this queue
+ */
+ public boolean add(Object e) {
+ if (offer(e))
+ return true;
+ else
+ throw new IllegalStateException("Queue full");
+ }
+
+ /**
+ * Retrieves and removes the head of this queue. This method differs
+ * from {@link #poll poll} only in that it throws an exception if this
+ * queue is empty.
+ *
+ * <p>This implementation returns the result of <tt>poll</tt>
+ * unless the queue is empty.
+ *
+ * @return the head of this queue
+ * @throws NoSuchElementException if this queue is empty
+ */
+ public Object remove() {
+ Object x = poll();
+ if (x != null)
+ return x;
+ else
+ throw new NoSuchElementException();
+ }
+
+
+ /**
+ * Retrieves, but does not remove, the head of this queue. This method
+ * differs from {@link #peek peek} only in that it throws an exception if
+ * this queue is empty.
+ *
+ * <p>This implementation returns the result of <tt>peek</tt>
+ * unless the queue is empty.
+ *
+ * @return the head of this queue
+ * @throws NoSuchElementException if this queue is empty
+ */
+ public Object element() {
+ Object x = peek();
+ if (x != null)
+ return x;
+ else
+ throw new NoSuchElementException();
+ }
+
+ /**
+ * Removes all of the elements from this queue.
+ * The queue will be empty after this call returns.
+ *
+ * <p>This implementation repeatedly invokes {@link #poll poll} until it
+ * returns <tt>null</tt>.
+ */
+ public void clear() {
+ while (poll() != null)
+ ;
+ }
+
+ /**
+ * Adds all of the elements in the specified collection to this
+ * queue. Attempts to addAll of a queue to itself result in
+ * <tt>IllegalArgumentException</tt>. Further, the behavior of
+ * this operation is undefined if the specified collection is
+ * modified while the operation is in progress.
+ *
+ * <p>This implementation iterates over the specified collection,
+ * and adds each element returned by the iterator to this
+ * queue, in turn. A runtime exception encountered while
+ * trying to add an element (including, in particular, a
+ * <tt>null</tt> element) may result in only some of the elements
+ * having been successfully added when the associated exception is
+ * thrown.
+ *
+ * @param c collection containing elements to be added to this queue
+ * @return <tt>true</tt> if this queue changed as a result of the call
+ * @throws ClassCastException if the class of an element of the specified
+ * collection prevents it from being added to this queue
+ * @throws NullPointerException if the specified collection contains a
+ * null element and this queue does not permit null elements,
+ * or if the specified collection is null
+ * @throws IllegalArgumentException if some property of an element of the
+ * specified collection prevents it from being added to this
+ * queue, or if the specified collection is this queue
+ * @throws IllegalStateException if not all the elements can be added at
+ * this time due to insertion restrictions
+ * @see #add(Object)
+ */
+ public boolean addAll(Collection c) {
+ if (c == null)
+ throw new NullPointerException();
+ if (c == this)
+ throw new IllegalArgumentException();
+ boolean modified = false;
+ Iterator e = c.iterator();
+ while (e.hasNext()) {
+ if (add(e.next()))
+ modified = true;
+ }
+ return modified;
+ }
+
+}
diff --git a/src/actors/scala/actors/threadpool/Arrays.java b/src/actors/scala/actors/threadpool/Arrays.java
new file mode 100644
index 0000000000..85e7c8fa00
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/Arrays.java
@@ -0,0 +1,811 @@
+/*
+ * Written by Dawid Kurzyniec, based on code written by Doug Lea with assistance
+ * from members of JCP JSR-166 Expert Group. Released to the public domain,
+ * as explained at http://creativecommons.org/licenses/publicdomain.
+ */
+
+package scala.actors.threadpool;
+
+import java.lang.reflect.Array;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Comparator;
+
+public class Arrays {
+
+ private Arrays() {}
+
+ public static void sort(long[] a) {
+ java.util.Arrays.sort(a);
+ }
+
+ public static void sort(long[] a, int fromIndex, int toIndex) {
+ java.util.Arrays.sort(a, fromIndex, toIndex);
+ }
+
+ public static void sort(int[] a) {
+ java.util.Arrays.sort(a);
+ }
+
+ public static void sort(int[] a, int fromIndex, int toIndex) {
+ java.util.Arrays.sort(a, fromIndex, toIndex);
+ }
+
+ public static void sort(short[] a) {
+ java.util.Arrays.sort(a);
+ }
+
+ public static void sort(short[] a, int fromIndex, int toIndex) {
+ java.util.Arrays.sort(a, fromIndex, toIndex);
+ }
+
+ public static void sort(char[] a) {
+ java.util.Arrays.sort(a);
+ }
+
+ public static void sort(char[] a, int fromIndex, int toIndex) {
+ java.util.Arrays.sort(a, fromIndex, toIndex);
+ }
+
+ public static void sort(byte[] a) {
+ java.util.Arrays.sort(a);
+ }
+
+ public static void sort(byte[] a, int fromIndex, int toIndex) {
+ java.util.Arrays.sort(a, fromIndex, toIndex);
+ }
+
+ public static void sort(double[] a) {
+ java.util.Arrays.sort(a);
+ }
+
+ public static void sort(double[] a, int fromIndex, int toIndex) {
+ java.util.Arrays.sort(a, fromIndex, toIndex);
+ }
+
+ public static void sort(float[] a) {
+ java.util.Arrays.sort(a);
+ }
+
+ public static void sort(float[] a, int fromIndex, int toIndex) {
+ java.util.Arrays.sort(a, fromIndex, toIndex);
+ }
+
+
+ public static void sort(Object[] a) {
+ java.util.Arrays.sort(a);
+ }
+
+ public static void sort(Object[] a, int fromIndex, int toIndex) {
+ java.util.Arrays.sort(a, fromIndex, toIndex);
+ }
+
+ public static void sort(Object[] a, Comparator c) {
+ java.util.Arrays.sort(a, c);
+ }
+
+ public static void sort(Object[] a, int fromIndex, int toIndex, Comparator c) {
+ java.util.Arrays.sort(a, fromIndex, toIndex, c);
+ }
+
+
+ // Searching
+
+ public static int binarySearch(long[] a, long key) {
+ return java.util.Arrays.binarySearch(a, key);
+ }
+
+ public static int binarySearch(int[] a, int key) {
+ return java.util.Arrays.binarySearch(a, key);
+ }
+
+ public static int binarySearch(short[] a, short key) {
+ return java.util.Arrays.binarySearch(a, key);
+ }
+
+ public static int binarySearch(char[] a, char key) {
+ return java.util.Arrays.binarySearch(a, key);
+ }
+
+ public static int binarySearch(byte[] a, byte key) {
+ return java.util.Arrays.binarySearch(a, key);
+ }
+
+ public static int binarySearch(double[] a, double key) {
+ return java.util.Arrays.binarySearch(a, key);
+ }
+
+ public static int binarySearch(float[] a, float key) {
+ return java.util.Arrays.binarySearch(a, key);
+ }
+
+ public static int binarySearch(Object[] a, Object key) {
+ return java.util.Arrays.binarySearch(a, key);
+ }
+
+ public static int binarySearch(Object[] a, Object key, Comparator c) {
+ return java.util.Arrays.binarySearch(a, key, c);
+ }
+
+
+ // Equality Testing
+
+ public static boolean equals(long[] a, long[] a2) {
+ return java.util.Arrays.equals(a, a2);
+ }
+
+ public static boolean equals(int[] a, int[] a2) {
+ return java.util.Arrays.equals(a, a2);
+ }
+
+ public static boolean equals(short[] a, short a2[]) {
+ return java.util.Arrays.equals(a, a2);
+ }
+
+ public static boolean equals(char[] a, char[] a2) {
+ return java.util.Arrays.equals(a, a2);
+ }
+
+ public static boolean equals(byte[] a, byte[] a2) {
+ return java.util.Arrays.equals(a, a2);
+ }
+
+ public static boolean equals(boolean[] a, boolean[] a2) {
+ return java.util.Arrays.equals(a, a2);
+ }
+
+ public static boolean equals(double[] a, double[] a2) {
+ return java.util.Arrays.equals(a, a2);
+ }
+
+ public static boolean equals(float[] a, float[] a2) {
+ return java.util.Arrays.equals(a, a2);
+ }
+
+ public static boolean equals(Object[] a, Object[] a2) {
+ return java.util.Arrays.equals(a, a2);
+ }
+
+
+ // Filling
+
+ public static void fill(long[] a, long val) {
+ java.util.Arrays.fill(a, val);
+ }
+
+ public static void fill(long[] a, int fromIndex, int toIndex, long val) {
+ java.util.Arrays.fill(a, fromIndex, toIndex, val);
+ }
+
+ public static void fill(int[] a, int val) {
+ java.util.Arrays.fill(a, val);
+ }
+
+ public static void fill(int[] a, int fromIndex, int toIndex, int val) {
+ java.util.Arrays.fill(a, fromIndex, toIndex, val);
+ }
+
+ public static void fill(short[] a, short val) {
+ java.util.Arrays.fill(a, val);
+ }
+
+ public static void fill(short[] a, int fromIndex, int toIndex, short val) {
+ java.util.Arrays.fill(a, fromIndex, toIndex, val);
+ }
+
+ public static void fill(char[] a, char val) {
+ java.util.Arrays.fill(a, val);
+ }
+
+ public static void fill(char[] a, int fromIndex, int toIndex, char val) {
+ java.util.Arrays.fill(a, fromIndex, toIndex, val);
+ }
+
+ public static void fill(byte[] a, byte val) {
+ java.util.Arrays.fill(a, val);
+ }
+
+ public static void fill(byte[] a, int fromIndex, int toIndex, byte val) {
+ java.util.Arrays.fill(a, fromIndex, toIndex, val);
+ }
+
+ public static void fill(boolean[] a, boolean val) {
+ java.util.Arrays.fill(a, val);
+ }
+
+ public static void fill(boolean[] a, int fromIndex, int toIndex,
+ boolean val) {
+ java.util.Arrays.fill(a, fromIndex, toIndex, val);
+ }
+
+ public static void fill(double[] a, double val) {
+ java.util.Arrays.fill(a, val);
+ }
+
+ public static void fill(double[] a, int fromIndex, int toIndex,double val) {
+ java.util.Arrays.fill(a, fromIndex, toIndex, val);
+ }
+
+ public static void fill(float[] a, float val) {
+ java.util.Arrays.fill(a, val);
+ }
+
+ public static void fill(float[] a, int fromIndex, int toIndex, float val) {
+ java.util.Arrays.fill(a, fromIndex, toIndex, val);
+ }
+
+ public static void fill(Object[] a, Object val) {
+ java.util.Arrays.fill(a, val);
+ }
+
+ public static void fill(Object[] a, int fromIndex, int toIndex, Object val) {
+ java.util.Arrays.fill(a, fromIndex, toIndex, val);
+ }
+
+
+ // Cloning
+
+ /**
+ * @since 1.6
+ */
+ public static Object[] copyOf(Object[] original, int newLength) {
+ return copyOf(original, newLength, original.getClass());
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static Object[] copyOf(Object[] original, int newLength, Class newType) {
+ Object[] arr = (newType == Object[].class) ? new Object[newLength] :
+ (Object[])Array.newInstance(newType.getComponentType(), newLength);
+ int len = (original.length < newLength ? original.length : newLength);
+ System.arraycopy(original, 0, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static byte[] copyOf(byte[] original, int newLength) {
+ byte[] arr = new byte[newLength];
+ int len = (original.length < newLength ? original.length : newLength);
+ System.arraycopy(original, 0, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static short[] copyOf(short[] original, int newLength) {
+ short[] arr = new short[newLength];
+ int len = (original.length < newLength ? original.length : newLength);
+ System.arraycopy(original, 0, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static int[] copyOf(int[] original, int newLength) {
+ int[] arr = new int[newLength];
+ int len = (original.length < newLength ? original.length : newLength);
+ System.arraycopy(original, 0, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static long[] copyOf(long[] original, int newLength) {
+ long[] arr = new long[newLength];
+ int len = (original.length < newLength ? original.length : newLength);
+ System.arraycopy(original, 0, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static char[] copyOf(char[] original, int newLength) {
+ char[] arr = new char[newLength];
+ int len = (original.length < newLength ? original.length : newLength);
+ System.arraycopy(original, 0, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static float[] copyOf(float[] original, int newLength) {
+ float[] arr = new float[newLength];
+ int len = (original.length < newLength ? original.length : newLength);
+ System.arraycopy(original, 0, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static double[] copyOf(double[] original, int newLength) {
+ double[] arr = new double[newLength];
+ int len = (original.length < newLength ? original.length : newLength);
+ System.arraycopy(original, 0, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static boolean[] copyOf(boolean[] original, int newLength) {
+ boolean[] arr = new boolean[newLength];
+ int len = (original.length < newLength ? original.length : newLength);
+ System.arraycopy(original, 0, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static Object[] copyOfRange(Object[] original, int from, int to) {
+ return copyOfRange(original, from, to, original.getClass());
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static Object[] copyOfRange(Object[] original, int from, int to, Class newType) {
+ int newLength = to - from;
+ if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
+ Object[] arr = (newType == Object[].class) ? new Object[newLength] :
+ (Object[])Array.newInstance(newType.getComponentType(), newLength);
+ int ceil = original.length-from;
+ int len = (ceil < newLength) ? ceil : newLength;
+ System.arraycopy(original, from, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static byte[] copyOfRange(byte[] original, int from, int to) {
+ int newLength = to - from;
+ if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
+ byte[] arr = new byte[newLength];
+ int ceil = original.length-from;
+ int len = (ceil < newLength) ? ceil : newLength;
+ System.arraycopy(original, from, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static short[] copyOfRange(short[] original, int from, int to) {
+ int newLength = to - from;
+ if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
+ short[] arr = new short[newLength];
+ int ceil = original.length-from;
+ int len = (ceil < newLength) ? ceil : newLength;
+ System.arraycopy(original, from, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static int[] copyOfRange(int[] original, int from, int to) {
+ int newLength = to - from;
+ if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
+ int[] arr = new int[newLength];
+ int ceil = original.length-from;
+ int len = (ceil < newLength) ? ceil : newLength;
+ System.arraycopy(original, from, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static long[] copyOfRange(long[] original, int from, int to) {
+ int newLength = to - from;
+ if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
+ long[] arr = new long[newLength];
+ int ceil = original.length-from;
+ int len = (ceil < newLength) ? ceil : newLength;
+ System.arraycopy(original, from, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static char[] copyOfRange(char[] original, int from, int to) {
+ int newLength = to - from;
+ if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
+ char[] arr = new char[newLength];
+ int ceil = original.length-from;
+ int len = (ceil < newLength) ? ceil : newLength;
+ System.arraycopy(original, from, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static float[] copyOfRange(float[] original, int from, int to) {
+ int newLength = to - from;
+ if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
+ float[] arr = new float[newLength];
+ int ceil = original.length-from;
+ int len = (ceil < newLength) ? ceil : newLength;
+ System.arraycopy(original, from, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static double[] copyOfRange(double[] original, int from, int to) {
+ int newLength = to - from;
+ if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
+ double[] arr = new double[newLength];
+ int ceil = original.length-from;
+ int len = (ceil < newLength) ? ceil : newLength;
+ System.arraycopy(original, from, arr, 0, len);
+ return arr;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public static boolean[] copyOfRange(boolean[] original, int from, int to) {
+ int newLength = to - from;
+ if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
+ boolean[] arr = new boolean[newLength];
+ int ceil = original.length-from;
+ int len = (ceil < newLength) ? ceil : newLength;
+ System.arraycopy(original, from, arr, 0, len);
+ return arr;
+ }
+
+
+ public static List asList(Object[] a) {
+ return java.util.Arrays.asList(a);
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static int hashCode(long a[]) {
+ if (a == null) return 0;
+ int hash = 1;
+ for (int i=0; i<a.length; i++) {
+ long e = a[i];
+ hash = 31*hash + (int)(e ^ (e >>> 32));
+ }
+ return hash;
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static int hashCode(int a[]) {
+ if (a == null) return 0;
+ int hash = 1;
+ for (int i=0; i<a.length; i++) {
+ hash = 31*hash + a[i];
+ }
+ return hash;
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static int hashCode(short a[]) {
+ if (a == null) return 0;
+ int hash = 1;
+ for (int i=0; i<a.length; i++) {
+ hash = 31*hash + a[i];
+ }
+ return hash;
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static int hashCode(char a[]) {
+ if (a == null) return 0;
+ int hash = 1;
+ for (int i=0; i<a.length; i++) {
+ hash = 31*hash + a[i];
+ }
+ return hash;
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static int hashCode(byte a[]) {
+ if (a == null) return 0;
+ int hash = 1;
+ for (int i=0; i<a.length; i++) {
+ hash = 31*hash + a[i];
+ }
+ return hash;
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static int hashCode(boolean a[]) {
+ if (a == null) return 0;
+ int hash = 1;
+ for (int i=0; i<a.length; i++) {
+ hash = 31*hash + (a[i] ? 1231 : 1237);
+ }
+ return hash;
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static int hashCode(float a[]) {
+ if (a == null) return 0;
+ int hash = 1;
+ for (int i=0; i<a.length; i++) {
+ hash = 31*hash + Float.floatToIntBits(a[i]);
+ }
+ return hash;
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static int hashCode(double a[]) {
+ if (a == null) return 0;
+ int hash = 1;
+ for (int i=0; i<a.length; i++) {
+ long e = Double.doubleToLongBits(a[i]);
+ hash = 31*hash + (int)(e ^ (e >>> 32));
+ }
+ return hash;
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static int hashCode(Object a[]) {
+ if (a == null) return 0;
+ int hash = 1;
+ for (int i=0; i<a.length; i++) {
+ Object e = a[i];
+ hash = 31*hash + (e == null ? 0 : e.hashCode());
+ }
+ return hash;
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static int deepHashCode(Object a[]) {
+ if (a == null) return 0;
+ int hash = 1;
+ for (int i=0; i<a.length; i++) {
+ Object e = a[i];
+ hash = 31*hash +
+ (e instanceof Object[] ? deepHashCode((Object[])e) :
+ (e instanceof byte[] ? hashCode((byte[])e) :
+ (e instanceof short[] ? hashCode((short[])e) :
+ (e instanceof int[] ? hashCode((int[])e) :
+ (e instanceof long[] ? hashCode((long[])e) :
+ (e instanceof char[] ? hashCode((char[])e) :
+ (e instanceof boolean[] ? hashCode((boolean[])e) :
+ (e instanceof float[] ? hashCode((float[])e) :
+ (e instanceof double[] ? hashCode((double[])e) :
+ (e != null ? e.hashCode() : 0))))))))));
+ }
+ return hash;
+
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static boolean deepEquals(Object[] a1, Object[] a2) {
+ if (a1 == a2) return true;
+ if (a1 == null || a2==null) return false;
+ int len = a1.length;
+ if (len != a2.length) return false;
+ for (int i = 0; i < len; i++) {
+ Object e1 = a1[i];
+ Object e2 = a2[i];
+ if (e1 == e2) continue;
+ if (e1 == null) return false;
+ boolean eq =
+ (e1.getClass() != e2.getClass() || e1.getClass().isArray()) ?
+ e1.equals(e2) :
+ (e1 instanceof Object[] && e2 instanceof Object[]) ?
+ deepEquals((Object[])e1, (Object[])e2) :
+ (e1 instanceof byte[] && e2 instanceof byte[]) ?
+ equals((byte[])e1, (byte[])e2) :
+ (e1 instanceof short[] && e2 instanceof short[]) ?
+ equals((short[])e1, (short[])e2) :
+ (e1 instanceof int[] && e2 instanceof int[]) ?
+ equals((int[])e1, (int[])e2) :
+ (e1 instanceof long[] && e2 instanceof long[]) ?
+ equals((long[])e1, (long[])e2) :
+ (e1 instanceof char[] && e2 instanceof char[]) ?
+ equals((char[])e1, (char[])e2) :
+ (e1 instanceof boolean[] && e2 instanceof boolean[]) ?
+ equals((boolean[])e1, (boolean[])e2) :
+ (e1 instanceof float[] && e2 instanceof float[]) ?
+ equals((float[])e1, (float[])e2) :
+ (e1 instanceof double[] && e2 instanceof double[]) ?
+ equals((double[])e1, (double[])e2) :
+ e1.equals(e2);
+
+ if (!eq) return false;
+ }
+ return true;
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static String toString(long[] a) {
+ if (a == null) return "null";
+ if (a.length == 0) return "[]";
+ StringBuffer buf = new StringBuffer();
+ buf.append('[').append(a[0]);
+ for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]);
+ buf.append(']');
+ return buf.toString();
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static String toString(int[] a) {
+ if (a == null) return "null";
+ if (a.length == 0) return "[]";
+ StringBuffer buf = new StringBuffer();
+ buf.append('[').append(a[0]);
+ for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]);
+ buf.append(']');
+ return buf.toString();
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static String toString(short[] a) {
+ if (a == null) return "null";
+ if (a.length == 0) return "[]";
+ StringBuffer buf = new StringBuffer();
+ buf.append('[').append(a[0]);
+ for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]);
+ buf.append(']');
+ return buf.toString();
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static String toString(char[] a) {
+ if (a == null) return "null";
+ if (a.length == 0) return "[]";
+ StringBuffer buf = new StringBuffer();
+ buf.append('[').append(a[0]);
+ for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]);
+ buf.append(']');
+ return buf.toString();
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static String toString(byte[] a) {
+ if (a == null) return "null";
+ if (a.length == 0) return "[]";
+ StringBuffer buf = new StringBuffer();
+ buf.append('[').append(a[0]);
+ for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]);
+ buf.append(']');
+ return buf.toString();
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static String toString(boolean[] a) {
+ if (a == null) return "null";
+ if (a.length == 0) return "[]";
+ StringBuffer buf = new StringBuffer();
+ buf.append('[').append(a[0]);
+ for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]);
+ buf.append(']');
+ return buf.toString();
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static String toString(float[] a) {
+ if (a == null) return "null";
+ if (a.length == 0) return "[]";
+ StringBuffer buf = new StringBuffer();
+ buf.append('[').append(a[0]);
+ for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]);
+ buf.append(']');
+ return buf.toString();
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static String toString(double[] a) {
+ if (a == null) return "null";
+ if (a.length == 0) return "[]";
+ StringBuffer buf = new StringBuffer();
+ buf.append('[').append(a[0]);
+ for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]);
+ buf.append(']');
+ return buf.toString();
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static String toString(Object[] a) {
+ if (a == null) return "null";
+ if (a.length == 0) return "[]";
+ StringBuffer buf = new StringBuffer();
+ buf.append('[').append(a[0]);
+ for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]);
+ buf.append(']');
+ return buf.toString();
+ }
+
+ /**
+ * @since 1.5
+ */
+ public static String deepToString(Object[] a) {
+ if (a == null) return "null";
+ StringBuffer buf = new StringBuffer();
+ deepToString(a, buf, new ArrayList());
+ return buf.toString();
+ }
+
+ private static void deepToString(Object[] a, StringBuffer buf, List seen) {
+ seen.add(a);
+ buf.append('[');
+ for (int i = 0; i < a.length; i++) {
+ if (i>0) buf.append(", ");
+ Object e = a[i];
+ if (e == null) {
+ buf.append("null");
+ }
+ else if (!e.getClass().isArray()) {
+ buf.append(e.toString());
+ }
+ else if (e instanceof Object[]) {
+ if (seen.contains(e)) buf.append("[...]");
+ else deepToString((Object[])e, buf, seen);
+ }
+ else {
+ // primitive arr
+ buf.append(
+ (e instanceof byte[]) ? toString( (byte[]) e) :
+ (e instanceof short[]) ? toString( (short[]) e) :
+ (e instanceof int[]) ? toString( (int[]) e) :
+ (e instanceof long[]) ? toString( (long[]) e) :
+ (e instanceof char[]) ? toString( (char[]) e) :
+ (e instanceof boolean[]) ? toString( (boolean[]) e) :
+ (e instanceof float[]) ? toString( (float[]) e) :
+ (e instanceof double[]) ? toString( (double[]) e) : "");
+ }
+ }
+ buf.append(']');
+ seen.remove(seen.size()-1);
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/AtomicInteger.java b/src/actors/scala/actors/threadpool/AtomicInteger.java
new file mode 100644
index 0000000000..eedb84512a
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/AtomicInteger.java
@@ -0,0 +1,210 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * An {@code int} value that may be updated atomically. See the
+ * {@link edu.emory.mathcs.backport.java.util.concurrent.atomic} package specification for
+ * description of the properties of atomic variables. An
+ * {@code AtomicInteger} is used in applications such as atomically
+ * incremented counters, and cannot be used as a replacement for an
+ * {@link java.lang.Integer}. However, this class does extend
+ * {@code Number} to allow uniform access by tools and utilities that
+ * deal with numerically-based classes.
+ *
+ * @since 1.5
+ * @author Doug Lea
+*/
+public class AtomicInteger extends Number implements java.io.Serializable {
+ private static final long serialVersionUID = 6214790243416807050L;
+
+ private volatile int value;
+
+ /**
+ * Creates a new AtomicInteger with the given initial value.
+ *
+ * @param initialValue the initial value
+ */
+ public AtomicInteger(int initialValue) {
+ value = initialValue;
+ }
+
+ /**
+ * Creates a new AtomicInteger with initial value {@code 0}.
+ */
+ public AtomicInteger() {
+ }
+
+ /**
+ * Gets the current value.
+ *
+ * @return the current value
+ */
+ public final int get() {
+ return value;
+ }
+
+ /**
+ * Sets to the given value.
+ *
+ * @param newValue the new value
+ */
+ public final synchronized void set(int newValue) {
+ value = newValue;
+ }
+
+ /**
+ * Eventually sets to the given value.
+ *
+ * @param newValue the new value
+ * @since 1.6
+ */
+ public final synchronized void lazySet(int newValue) {
+ value = newValue;
+ }
+
+ /**
+ * Atomically sets to the given value and returns the old value.
+ *
+ * @param newValue the new value
+ * @return the previous value
+ */
+ public final synchronized int getAndSet(int newValue) {
+ int old = value;
+ value = newValue;
+ return old;
+ }
+
+ /**
+ * Atomically sets the value to the given updated value
+ * if the current value {@code ==} the expected value.
+ *
+ * @param expect the expected value
+ * @param update the new value
+ * @return true if successful. False return indicates that
+ * the actual value was not equal to the expected value.
+ */
+ public final synchronized boolean compareAndSet(int expect, int update) {
+ if (value == expect) {
+ value = update;
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ /**
+ * Atomically sets the value to the given updated value
+ * if the current value {@code ==} the expected value.
+ *
+ * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
+ * and does not provide ordering guarantees, so is only rarely an
+ * appropriate alternative to {@code compareAndSet}.
+ *
+ * @param expect the expected value
+ * @param update the new value
+ * @return true if successful.
+ */
+ public final synchronized boolean weakCompareAndSet(int expect, int update) {
+ if (value == expect) {
+ value = update;
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+
+ /**
+ * Atomically increments by one the current value.
+ *
+ * @return the previous value
+ */
+ public final synchronized int getAndIncrement() {
+ return value++;
+ }
+
+
+ /**
+ * Atomically decrements by one the current value.
+ *
+ * @return the previous value
+ */
+ public final synchronized int getAndDecrement() {
+ return value--;
+ }
+
+
+ /**
+ * Atomically adds the given value to the current value.
+ *
+ * @param delta the value to add
+ * @return the previous value
+ */
+ public final synchronized int getAndAdd(int delta) {
+ int old = value;
+ value += delta;
+ return old;
+ }
+
+ /**
+ * Atomically increments by one the current value.
+ *
+ * @return the updated value
+ */
+ public final synchronized int incrementAndGet() {
+ return ++value;
+ }
+
+ /**
+ * Atomically decrements by one the current value.
+ *
+ * @return the updated value
+ */
+ public final synchronized int decrementAndGet() {
+ return --value;
+ }
+
+
+ /**
+ * Atomically adds the given value to the current value.
+ *
+ * @param delta the value to add
+ * @return the updated value
+ */
+ public final synchronized int addAndGet(int delta) {
+ return value += delta;
+ }
+
+ /**
+ * Returns the String representation of the current value.
+ * @return the String representation of the current value.
+ */
+ public String toString() {
+ return Integer.toString(get());
+ }
+
+
+ public int intValue() {
+ return get();
+ }
+
+ public long longValue() {
+ return (long)get();
+ }
+
+ public float floatValue() {
+ return (float)get();
+ }
+
+ public double doubleValue() {
+ return (double)get();
+ }
+
+}
diff --git a/src/actors/scala/actors/threadpool/BlockingQueue.java b/src/actors/scala/actors/threadpool/BlockingQueue.java
new file mode 100644
index 0000000000..880c2580da
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/BlockingQueue.java
@@ -0,0 +1,342 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+import java.util.Collection;
+
+/**
+ * A {@link edu.emory.mathcs.backport.java.util.Queue} that additionally supports operations
+ * that wait for the queue to become non-empty when retrieving an
+ * element, and wait for space to become available in the queue when
+ * storing an element.
+ *
+ * <p><tt>BlockingQueue</tt> methods come in four forms, with different ways
+ * of handling operations that cannot be satisfied immediately, but may be
+ * satisfied at some point in the future:
+ * one throws an exception, the second returns a special value (either
+ * <tt>null</tt> or <tt>false</tt>, depending on the operation), the third
+ * blocks the current thread indefinitely until the operation can succeed,
+ * and the fourth blocks for only a given maximum time limit before giving
+ * up. These methods are summarized in the following table:
+ *
+ * <p>
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <tr>
+ * <td></td>
+ * <td ALIGN=CENTER><em>Throws exception</em></td>
+ * <td ALIGN=CENTER><em>Special value</em></td>
+ * <td ALIGN=CENTER><em>Blocks</em></td>
+ * <td ALIGN=CENTER><em>Times out</em></td>
+ * </tr>
+ * <tr>
+ * <td><b>Insert</b></td>
+ * <td>{@link #add add(e)}</td>
+ * <td>{@link #offer offer(e)}</td>
+ * <td>{@link #put put(e)}</td>
+ * <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
+ * </tr>
+ * <tr>
+ * <td><b>Remove</b></td>
+ * <td>{@link #remove remove()}</td>
+ * <td>{@link #poll poll()}</td>
+ * <td>{@link #take take()}</td>
+ * <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
+ * </tr>
+ * <tr>
+ * <td><b>Examine</b></td>
+ * <td>{@link #element element()}</td>
+ * <td>{@link #peek peek()}</td>
+ * <td><em>not applicable</em></td>
+ * <td><em>not applicable</em></td>
+ * </tr>
+ * </table>
+ *
+ * <p>A <tt>BlockingQueue</tt> does not accept <tt>null</tt> elements.
+ * Implementations throw <tt>NullPointerException</tt> on attempts
+ * to <tt>add</tt>, <tt>put</tt> or <tt>offer</tt> a <tt>null</tt>. A
+ * <tt>null</tt> is used as a sentinel value to indicate failure of
+ * <tt>poll</tt> operations.
+ *
+ * <p>A <tt>BlockingQueue</tt> may be capacity bounded. At any given
+ * time it may have a <tt>remainingCapacity</tt> beyond which no
+ * additional elements can be <tt>put</tt> without blocking.
+ * A <tt>BlockingQueue</tt> without any intrinsic capacity constraints always
+ * reports a remaining capacity of <tt>Integer.MAX_VALUE</tt>.
+ *
+ * <p> <tt>BlockingQueue</tt> implementations are designed to be used
+ * primarily for producer-consumer queues, but additionally support
+ * the {@link java.util.Collection} interface. So, for example, it is
+ * possible to remove an arbitrary element from a queue using
+ * <tt>remove(x)</tt>. However, such operations are in general
+ * <em>not</em> performed very efficiently, and are intended for only
+ * occasional use, such as when a queued message is cancelled.
+ *
+ * <p> <tt>BlockingQueue</tt> implementations are thread-safe. All
+ * queuing methods achieve their effects atomically using internal
+ * locks or other forms of concurrency control. However, the
+ * <em>bulk</em> Collection operations <tt>addAll</tt>,
+ * <tt>containsAll</tt>, <tt>retainAll</tt> and <tt>removeAll</tt> are
+ * <em>not</em> necessarily performed atomically unless specified
+ * otherwise in an implementation. So it is possible, for example, for
+ * <tt>addAll(c)</tt> to fail (throwing an exception) after adding
+ * only some of the elements in <tt>c</tt>.
+ *
+ * <p>A <tt>BlockingQueue</tt> does <em>not</em> intrinsically support
+ * any kind of &quot;close&quot; or &quot;shutdown&quot; operation to
+ * indicate that no more items will be added. The needs and usage of
+ * such features tend to be implementation-dependent. For example, a
+ * common tactic is for producers to insert special
+ * <em>end-of-stream</em> or <em>poison</em> objects, that are
+ * interpreted accordingly when taken by consumers.
+ *
+ * <p>
+ * Usage example, based on a typical producer-consumer scenario.
+ * Note that a <tt>BlockingQueue</tt> can safely be used with multiple
+ * producers and multiple consumers.
+ * <pre>
+ * class Producer implements Runnable {
+ * private final BlockingQueue queue;
+ * Producer(BlockingQueue q) { queue = q; }
+ * public void run() {
+ * try {
+ * while (true) { queue.put(produce()); }
+ * } catch (InterruptedException ex) { ... handle ...}
+ * }
+ * Object produce() { ... }
+ * }
+ *
+ * class Consumer implements Runnable {
+ * private final BlockingQueue queue;
+ * Consumer(BlockingQueue q) { queue = q; }
+ * public void run() {
+ * try {
+ * while (true) { consume(queue.take()); }
+ * } catch (InterruptedException ex) { ... handle ...}
+ * }
+ * void consume(Object x) { ... }
+ * }
+ *
+ * class Setup {
+ * void main() {
+ * BlockingQueue q = new SomeQueueImplementation();
+ * Producer p = new Producer(q);
+ * Consumer c1 = new Consumer(q);
+ * Consumer c2 = new Consumer(q);
+ * new Thread(p).start();
+ * new Thread(c1).start();
+ * new Thread(c2).start();
+ * }
+ * }
+ * </pre>
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code BlockingQueue}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code BlockingQueue} in another thread.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface BlockingQueue extends Queue {
+ /**
+ * Inserts the specified element into this queue if it is possible to do
+ * so immediately without violating capacity restrictions, returning
+ * <tt>true</tt> upon success and throwing an
+ * <tt>IllegalStateException</tt> if no space is currently available.
+ * When using a capacity-restricted queue, it is generally preferable to
+ * use {@link #offer(Object) offer}.
+ *
+ * @param e the element to add
+ * @return <tt>true</tt> (as specified by {@link java.util.Collection#add})
+ * @throws IllegalStateException if the element cannot be added at this
+ * time due to capacity restrictions
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this queue
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this queue
+ */
+ boolean add(Object e);
+
+ /**
+ * Inserts the specified element into this queue if it is possible to do
+ * so immediately without violating capacity restrictions, returning
+ * <tt>true</tt> upon success and <tt>false</tt> if no space is currently
+ * available. When using a capacity-restricted queue, this method is
+ * generally preferable to {@link #add}, which can fail to insert an
+ * element only by throwing an exception.
+ *
+ * @param e the element to add
+ * @return <tt>true</tt> if the element was added to this queue, else
+ * <tt>false</tt>
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this queue
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this queue
+ */
+ boolean offer(Object e);
+
+ /**
+ * Inserts the specified element into this queue, waiting if necessary
+ * for space to become available.
+ *
+ * @param e the element to add
+ * @throws InterruptedException if interrupted while waiting
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this queue
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this queue
+ */
+ void put(Object e) throws InterruptedException;
+
+ /**
+ * Inserts the specified element into this queue, waiting up to the
+ * specified wait time if necessary for space to become available.
+ *
+ * @param e the element to add
+ * @param timeout how long to wait before giving up, in units of
+ * <tt>unit</tt>
+ * @param unit a <tt>TimeUnit</tt> determining how to interpret the
+ * <tt>timeout</tt> parameter
+ * @return <tt>true</tt> if successful, or <tt>false</tt> if
+ * the specified waiting time elapses before space is available
+ * @throws InterruptedException if interrupted while waiting
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this queue
+ * @throws NullPointerException if the specified element is null
+ * @throws IllegalArgumentException if some property of the specified
+ * element prevents it from being added to this queue
+ */
+ boolean offer(Object e, long timeout, TimeUnit unit)
+ throws InterruptedException;
+
+ /**
+ * Retrieves and removes the head of this queue, waiting if necessary
+ * until an element becomes available.
+ *
+ * @return the head of this queue
+ * @throws InterruptedException if interrupted while waiting
+ */
+ Object take() throws InterruptedException;
+
+ /**
+ * Retrieves and removes the head of this queue, waiting up to the
+ * specified wait time if necessary for an element to become available.
+ *
+ * @param timeout how long to wait before giving up, in units of
+ * <tt>unit</tt>
+ * @param unit a <tt>TimeUnit</tt> determining how to interpret the
+ * <tt>timeout</tt> parameter
+ * @return the head of this queue, or <tt>null</tt> if the
+ * specified waiting time elapses before an element is available
+ * @throws InterruptedException if interrupted while waiting
+ */
+ Object poll(long timeout, TimeUnit unit)
+ throws InterruptedException;
+
+ /**
+ * Returns the number of additional elements that this queue can ideally
+ * (in the absence of memory or resource constraints) accept without
+ * blocking, or <tt>Integer.MAX_VALUE</tt> if there is no intrinsic
+ * limit.
+ *
+ * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+ * an element will succeed by inspecting <tt>remainingCapacity</tt>
+ * because it may be the case that another thread is about to
+ * insert or remove an element.
+ *
+ * @return the remaining capacity
+ */
+ int remainingCapacity();
+
+ /**
+ * Removes a single instance of the specified element from this queue,
+ * if it is present. More formally, removes an element <tt>e</tt> such
+ * that <tt>o.equals(e)</tt>, if this queue contains one or more such
+ * elements.
+ * Returns <tt>true</tt> if this queue contained the specified element
+ * (or equivalently, if this queue changed as a result of the call).
+ *
+ * @param o element to be removed from this queue, if present
+ * @return <tt>true</tt> if this queue changed as a result of the call
+ * @throws ClassCastException if the class of the specified element
+ * is incompatible with this queue (optional)
+ * @throws NullPointerException if the specified element is null (optional)
+ */
+ boolean remove(Object o);
+
+ /**
+ * Returns <tt>true</tt> if this queue contains the specified element.
+ * More formally, returns <tt>true</tt> if and only if this queue contains
+ * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>.
+ *
+ * @param o object to be checked for containment in this queue
+ * @return <tt>true</tt> if this queue contains the specified element
+ * @throws ClassCastException if the class of the specified element
+ * is incompatible with this queue (optional)
+ * @throws NullPointerException if the specified element is null (optional)
+ */
+ public boolean contains(Object o);
+
+ /**
+ * Removes all available elements from this queue and adds them
+ * to the given collection. This operation may be more
+ * efficient than repeatedly polling this queue. A failure
+ * encountered while attempting to add elements to
+ * collection <tt>c</tt> may result in elements being in neither,
+ * either or both collections when the associated exception is
+ * thrown. Attempts to drain a queue to itself result in
+ * <tt>IllegalArgumentException</tt>. Further, the behavior of
+ * this operation is undefined if the specified collection is
+ * modified while the operation is in progress.
+ *
+ * @param c the collection to transfer elements into
+ * @return the number of elements transferred
+ * @throws UnsupportedOperationException if addition of elements
+ * is not supported by the specified collection
+ * @throws ClassCastException if the class of an element of this queue
+ * prevents it from being added to the specified collection
+ * @throws NullPointerException if the specified collection is null
+ * @throws IllegalArgumentException if the specified collection is this
+ * queue, or some property of an element of this queue prevents
+ * it from being added to the specified collection
+ */
+ int drainTo(Collection c);
+
+ /**
+ * Removes at most the given number of available elements from
+ * this queue and adds them to the given collection. A failure
+ * encountered while attempting to add elements to
+ * collection <tt>c</tt> may result in elements being in neither,
+ * either or both collections when the associated exception is
+ * thrown. Attempts to drain a queue to itself result in
+ * <tt>IllegalArgumentException</tt>. Further, the behavior of
+ * this operation is undefined if the specified collection is
+ * modified while the operation is in progress.
+ *
+ * @param c the collection to transfer elements into
+ * @param maxElements the maximum number of elements to transfer
+ * @return the number of elements transferred
+ * @throws UnsupportedOperationException if addition of elements
+ * is not supported by the specified collection
+ * @throws ClassCastException if the class of an element of this queue
+ * prevents it from being added to the specified collection
+ * @throws NullPointerException if the specified collection is null
+ * @throws IllegalArgumentException if the specified collection is this
+ * queue, or some property of an element of this queue prevents
+ * it from being added to the specified collection
+ */
+ int drainTo(Collection c, int maxElements);
+}
diff --git a/src/actors/scala/actors/threadpool/Callable.java b/src/actors/scala/actors/threadpool/Callable.java
new file mode 100644
index 0000000000..f1b200c022
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/Callable.java
@@ -0,0 +1,35 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * A task that returns a result and may throw an exception.
+ * Implementors define a single method with no arguments called
+ * <tt>call</tt>.
+ *
+ * <p>The <tt>Callable</tt> interface is similar to {@link
+ * java.lang.Runnable}, in that both are designed for classes whose
+ * instances are potentially executed by another thread. A
+ * <tt>Runnable</tt>, however, does not return a result and cannot
+ * throw a checked exception.
+ *
+ * <p> The {@link Executors} class contains utility methods to
+ * convert from other common forms to <tt>Callable</tt> classes.
+ *
+ * @see Executor
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Callable {
+ /**
+ * Computes a result, or throws an exception if unable to do so.
+ *
+ * @return computed result
+ * @throws Exception if unable to compute a result
+ */
+ Object call() throws Exception;
+}
diff --git a/src/actors/scala/actors/threadpool/CancellationException.java b/src/actors/scala/actors/threadpool/CancellationException.java
new file mode 100644
index 0000000000..c2163b83c7
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/CancellationException.java
@@ -0,0 +1,34 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * Exception indicating that the result of a value-producing task,
+ * such as a {@link FutureTask}, cannot be retrieved because the task
+ * was cancelled.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class CancellationException extends IllegalStateException {
+ private static final long serialVersionUID = -9202173006928992231L;
+
+ /**
+ * Constructs a <tt>CancellationException</tt> with no detail message.
+ */
+ public CancellationException() {}
+
+ /**
+ * Constructs a <tt>CancellationException</tt> with the specified detail
+ * message.
+ *
+ * @param message the detail message
+ */
+ public CancellationException(String message) {
+ super(message);
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/CompletionService.java b/src/actors/scala/actors/threadpool/CompletionService.java
new file mode 100644
index 0000000000..219ab7affa
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/CompletionService.java
@@ -0,0 +1,97 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * A service that decouples the production of new asynchronous tasks
+ * from the consumption of the results of completed tasks. Producers
+ * <tt>submit</tt> tasks for execution. Consumers <tt>take</tt>
+ * completed tasks and process their results in the order they
+ * complete. A <tt>CompletionService</tt> can for example be used to
+ * manage asynchronous IO, in which tasks that perform reads are
+ * submitted in one part of a program or system, and then acted upon
+ * in a different part of the program when the reads complete,
+ * possibly in a different order than they were requested.
+ *
+ * <p>Typically, a <tt>CompletionService</tt> relies on a separate
+ * {@link Executor} to actually execute the tasks, in which case the
+ * <tt>CompletionService</tt> only manages an internal completion
+ * queue. The {@link ExecutorCompletionService} class provides an
+ * implementation of this approach.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to
+ * submitting a task to a {@code CompletionService}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions taken by that task, which in turn <i>happen-before</i>
+ * actions following a successful return from the corresponding {@code take()}.
+ *
+ */
+public interface CompletionService {
+ /**
+ * Submits a value-returning task for execution and returns a Future
+ * representing the pending results of the task. Upon completion,
+ * this task may be taken or polled.
+ *
+ * @param task the task to submit
+ * @return a Future representing pending completion of the task
+ * @throws RejectedExecutionException if the task cannot be
+ * scheduled for execution
+ * @throws NullPointerException if the task is null
+ */
+ Future submit(Callable task);
+
+ /**
+ * Submits a Runnable task for execution and returns a Future
+ * representing that task. Upon completion, this task may be
+ * taken or polled.
+ *
+ * @param task the task to submit
+ * @param result the result to return upon successful completion
+ * @return a Future representing pending completion of the task,
+ * and whose <tt>get()</tt> method will return the given
+ * result value upon completion
+ * @throws RejectedExecutionException if the task cannot be
+ * scheduled for execution
+ * @throws NullPointerException if the task is null
+ */
+ Future submit(Runnable task, Object result);
+
+ /**
+ * Retrieves and removes the Future representing the next
+ * completed task, waiting if none are yet present.
+ *
+ * @return the Future representing the next completed task
+ * @throws InterruptedException if interrupted while waiting
+ */
+ Future take() throws InterruptedException;
+
+
+ /**
+ * Retrieves and removes the Future representing the next
+ * completed task or <tt>null</tt> if none are present.
+ *
+ * @return the Future representing the next completed task, or
+ * <tt>null</tt> if none are present
+ */
+ Future poll();
+
+ /**
+ * Retrieves and removes the Future representing the next
+ * completed task, waiting if necessary up to the specified wait
+ * time if none are yet present.
+ *
+ * @param timeout how long to wait before giving up, in units of
+ * <tt>unit</tt>
+ * @param unit a <tt>TimeUnit</tt> determining how to interpret the
+ * <tt>timeout</tt> parameter
+ * @return the Future representing the next completed task or
+ * <tt>null</tt> if the specified waiting time elapses
+ * before one is present
+ * @throws InterruptedException if interrupted while waiting
+ */
+ Future poll(long timeout, TimeUnit unit) throws InterruptedException;
+}
diff --git a/src/actors/scala/actors/threadpool/ExecutionException.java b/src/actors/scala/actors/threadpool/ExecutionException.java
new file mode 100644
index 0000000000..912f965acf
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/ExecutionException.java
@@ -0,0 +1,65 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * 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 ExecutionException extends Exception {
+ private static final long serialVersionUID = 7830266012832686185L;
+
+ /**
+ * Constructs an <tt>ExecutionException</tt> with no detail message.
+ * The cause is not initialized, and may subsequently be
+ * initialized by a call to {@link #initCause(Throwable) initCause}.
+ */
+ protected ExecutionException() { }
+
+ /**
+ * Constructs an <tt>ExecutionException</tt> with the specified detail
+ * message. The cause is not initialized, and may subsequently be
+ * initialized by a call to {@link #initCause(Throwable) initCause}.
+ *
+ * @param message the detail message
+ */
+ protected ExecutionException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs an <tt>ExecutionException</tt> with the specified detail
+ * message and cause.
+ *
+ * @param message the detail message
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method)
+ */
+ public ExecutionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs an <tt>ExecutionException</tt> with the specified cause.
+ * The detail message is set to:
+ * <pre>
+ * (cause == null ? null : cause.toString())</pre>
+ * (which typically contains the class and detail message of
+ * <tt>cause</tt>).
+ *
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method)
+ */
+ public ExecutionException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/Executor.java b/src/actors/scala/actors/threadpool/Executor.java
new file mode 100644
index 0000000000..e444e64dff
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/Executor.java
@@ -0,0 +1,112 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * An object that executes submitted {@link Runnable} tasks. This
+ * interface provides a way of decoupling task submission from the
+ * mechanics of how each task will be run, including details of thread
+ * use, scheduling, etc. An <tt>Executor</tt> is normally used
+ * instead of explicitly creating threads. For example, rather than
+ * invoking <tt>new Thread(new(RunnableTask())).start()</tt> for each
+ * of a set of tasks, you might use:
+ *
+ * <pre>
+ * Executor executor = <em>anExecutor</em>;
+ * executor.execute(new RunnableTask1());
+ * executor.execute(new RunnableTask2());
+ * ...
+ * </pre>
+ *
+ * However, the <tt>Executor</tt> interface does not strictly
+ * require that execution be asynchronous. In the simplest case, an
+ * executor can run the submitted task immediately in the caller's
+ * thread:
+ *
+ * <pre>
+ * class DirectExecutor implements Executor {
+ * public void execute(Runnable r) {
+ * r.run();
+ * }
+ * }</pre>
+ *
+ * More typically, tasks are executed in some thread other
+ * than the caller's thread. The executor below spawns a new thread
+ * for each task.
+ *
+ * <pre>
+ * class ThreadPerTaskExecutor implements Executor {
+ * public void execute(Runnable r) {
+ * new Thread(r).start();
+ * }
+ * }</pre>
+ *
+ * Many <tt>Executor</tt> implementations impose some sort of
+ * limitation on how and when tasks are scheduled. The executor below
+ * serializes the submission of tasks to a second executor,
+ * illustrating a composite executor.
+ *
+ * <pre>
+ * class SerialExecutor implements Executor {
+ * final Queue&lt;Runnable&gt; tasks = new ArrayDeque&lt;Runnable&gt;();
+ * final Executor executor;
+ * Runnable active;
+ *
+ * SerialExecutor(Executor executor) {
+ * this.executor = executor;
+ * }
+ *
+ * public synchronized void execute(final Runnable r) {
+ * tasks.offer(new Runnable() {
+ * public void run() {
+ * try {
+ * r.run();
+ * } finally {
+ * scheduleNext();
+ * }
+ * }
+ * });
+ * if (active == null) {
+ * scheduleNext();
+ * }
+ * }
+ *
+ * protected synchronized void scheduleNext() {
+ * if ((active = tasks.poll()) != null) {
+ * executor.execute(active);
+ * }
+ * }
+ * }</pre>
+ *
+ * The <tt>Executor</tt> implementations provided in this package
+ * implement {@link ExecutorService}, which is a more extensive
+ * interface. The {@link ThreadPoolExecutor} class provides an
+ * extensible thread pool implementation. The {@link Executors} class
+ * provides convenient factory methods for these Executors.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to
+ * submitting a {@code Runnable} object to an {@code Executor}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * its execution begins, perhaps in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Executor {
+
+ /**
+ * Executes the given command at some time in the future. The command
+ * may execute in a new thread, in a pooled thread, or in the calling
+ * thread, at the discretion of the <tt>Executor</tt> implementation.
+ *
+ * @param command the runnable task
+ * @throws RejectedExecutionException if this task cannot be
+ * accepted for execution.
+ * @throws NullPointerException if command is null
+ */
+ void execute(Runnable command);
+}
diff --git a/src/actors/scala/actors/threadpool/ExecutorCompletionService.java b/src/actors/scala/actors/threadpool/ExecutorCompletionService.java
new file mode 100644
index 0000000000..9a4a4fb71c
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/ExecutorCompletionService.java
@@ -0,0 +1,178 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+import scala.actors.threadpool.*; // for javadoc (till 6280605 is fixed)
+
+/**
+ * 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 <tt>take</tt>.
+ * The class is lightweight enough to be suitable for transient use
+ * when processing groups of tasks.
+ *
+ * <p>
+ *
+ * <b>Usage Examples.</b>
+ *
+ * Suppose you have a set of solvers for a certain problem, each
+ * returning a value of some type <tt>Result</tt>, and would like to
+ * run them concurrently, processing the results of each of them that
+ * return a non-null value, in some method <tt>use(Result r)</tt>. You
+ * could write this as:
+ *
+ * <pre>
+ * void solve(Executor e,
+ * Collection&lt;Callable&lt;Result&gt;&gt; solvers)
+ * throws InterruptedException, ExecutionException {
+ * CompletionService&lt;Result&gt; ecs
+ * = new ExecutorCompletionService&lt;Result&gt;(e);
+ * for (Callable&lt;Result&gt; s : solvers)
+ * ecs.submit(s);
+ * int n = solvers.size();
+ * for (int i = 0; i &lt; n; ++i) {
+ * Result r = ecs.take().get();
+ * if (r != null)
+ * use(r);
+ * }
+ * }
+ * </pre>
+ *
+ * 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:
+ *
+ * <pre>
+ * void solve(Executor e,
+ * Collection&lt;Callable&lt;Result&gt;&gt; solvers)
+ * throws InterruptedException {
+ * CompletionService&lt;Result&gt; ecs
+ * = new ExecutorCompletionService&lt;Result&gt;(e);
+ * int n = solvers.size();
+ * List&lt;Future&lt;Result&gt;&gt; futures
+ * = new ArrayList&lt;Future&lt;Result&gt;&gt;(n);
+ * Result result = null;
+ * try {
+ * for (Callable&lt;Result&gt; s : solvers)
+ * futures.add(ecs.submit(s));
+ * for (int i = 0; i &lt; n; ++i) {
+ * try {
+ * Result r = ecs.take().get();
+ * if (r != null) {
+ * result = r;
+ * break;
+ * }
+ * } catch (ExecutionException ignore) {}
+ * }
+ * }
+ * finally {
+ * for (Future&lt;Result&gt; f : futures)
+ * f.cancel(true);
+ * }
+ *
+ * if (result != null)
+ * use(result);
+ * }
+ * </pre>
+ */
+public class ExecutorCompletionService implements CompletionService {
+ private final Executor executor;
+ private final AbstractExecutorService aes;
+ private final BlockingQueue completionQueue;
+
+ /**
+ * FutureTask extension to enqueue upon completion
+ */
+ private class QueueingFuture extends FutureTask {
+ QueueingFuture(RunnableFuture task) {
+ super(task, null);
+ this.task = task;
+ }
+ protected void done() { completionQueue.add(task); }
+ private final Future task;
+ }
+
+ private RunnableFuture newTaskFor(Callable task) {
+ if (aes == null)
+ return new FutureTask(task);
+ else
+ return aes.newTaskFor(task);
+ }
+
+ private RunnableFuture newTaskFor(Runnable task, Object result) {
+ if (aes == null)
+ return new FutureTask(task, result);
+ else
+ return aes.newTaskFor(task, result);
+ }
+
+ /**
+ * Creates an ExecutorCompletionService using the supplied
+ * executor for base task execution and a
+ * {@link LinkedBlockingQueue} as a completion queue.
+ *
+ * @param executor the executor to use
+ * @throws NullPointerException if executor is <tt>null</tt>
+ */
+ public ExecutorCompletionService(Executor executor) {
+ if (executor == null)
+ throw new NullPointerException();
+ this.executor = executor;
+ this.aes = (executor instanceof AbstractExecutorService) ?
+ (AbstractExecutorService) executor : null;
+ this.completionQueue = new LinkedBlockingQueue();
+ }
+
+ /**
+ * Creates an ExecutorCompletionService using the supplied
+ * executor for base task execution and the supplied queue as its
+ * completion queue.
+ *
+ * @param executor the executor to use
+ * @param completionQueue the queue to use as the completion queue
+ * normally one dedicated for use by this service. This queue is
+ * treated as unbounded -- failed attempted <tt>Queue.add</tt>
+ * operations for completed taskes cause them not to be
+ * retrievable.
+ * @throws NullPointerException if executor or completionQueue are <tt>null</tt>
+ */
+ public ExecutorCompletionService(Executor executor,
+ BlockingQueue completionQueue) {
+ if (executor == null || completionQueue == null)
+ throw new NullPointerException();
+ this.executor = executor;
+ this.aes = (executor instanceof AbstractExecutorService) ?
+ (AbstractExecutorService) executor : null;
+ this.completionQueue = completionQueue;
+ }
+
+ public Future submit(Callable task) {
+ if (task == null) throw new NullPointerException();
+ RunnableFuture f = newTaskFor(task);
+ executor.execute(new QueueingFuture(f));
+ return f;
+ }
+
+ public Future submit(Runnable task, Object result) {
+ if (task == null) throw new NullPointerException();
+ RunnableFuture f = newTaskFor(task, result);
+ executor.execute(new QueueingFuture(f));
+ return f;
+ }
+
+ public Future take() throws InterruptedException {
+ return (Future)completionQueue.take();
+ }
+
+ public Future poll() {
+ return (Future)completionQueue.poll();
+ }
+
+ public Future poll(long timeout, TimeUnit unit) throws InterruptedException {
+ return (Future)completionQueue.poll(timeout, unit);
+ }
+
+}
diff --git a/src/actors/scala/actors/threadpool/ExecutorService.java b/src/actors/scala/actors/threadpool/ExecutorService.java
new file mode 100644
index 0000000000..d3a9a3b8a8
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/ExecutorService.java
@@ -0,0 +1,331 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+import scala.actors.threadpool.*; // for javadoc (till 6280605 is fixed)
+import java.util.List;
+import java.util.Collection;
+
+/**
+ * An {@link Executor} that provides methods to manage termination and
+ * methods that can produce a {@link Future} for tracking progress of
+ * one or more asynchronous tasks.
+ *
+ * <p> An <tt>ExecutorService</tt> can be shut down, which will cause
+ * it to reject new tasks. Two different methods are provided for
+ * shutting down an <tt>ExecutorService</tt>. The {@link #shutdown}
+ * method will allow previously submitted tasks to execute before
+ * terminating, while the {@link #shutdownNow} method prevents waiting
+ * tasks from starting and attempts to stop currently executing tasks.
+ * Upon termination, an executor has no tasks actively executing, no
+ * tasks awaiting execution, and no new tasks can be submitted. An
+ * unused <tt>ExecutorService</tt> should be shut down to allow
+ * reclamation of its resources.
+ *
+ * <p> Method <tt>submit</tt> extends base method {@link
+ * Executor#execute} by creating and returning a {@link Future} that
+ * can be used to cancel execution and/or wait for completion.
+ * Methods <tt>invokeAny</tt> and <tt>invokeAll</tt> perform the most
+ * commonly useful forms of bulk execution, executing a collection of
+ * tasks and then waiting for at least one, or all, to
+ * complete. (Class {@link ExecutorCompletionService} can be used to
+ * write customized variants of these methods.)
+ *
+ * <p>The {@link Executors} class provides factory methods for the
+ * executor services provided in this package.
+ *
+ * <h3>Usage Example</h3>
+ *
+ * Here is a sketch of a network service in which threads in a thread
+ * pool service incoming requests. It uses the preconfigured {@link
+ * Executors#newFixedThreadPool} factory method:
+ *
+ * <pre>
+ * class NetworkService implements Runnable {
+ * private final ServerSocket serverSocket;
+ * private final ExecutorService pool;
+ *
+ * public NetworkService(int port, int poolSize)
+ * throws IOException {
+ * serverSocket = new ServerSocket(port);
+ * pool = Executors.newFixedThreadPool(poolSize);
+ * }
+ *
+ * public void run() { // run the service
+ * try {
+ * for (;;) {
+ * pool.execute(new Handler(serverSocket.accept()));
+ * }
+ * } catch (IOException ex) {
+ * pool.shutdown();
+ * }
+ * }
+ * }
+ *
+ * class Handler implements Runnable {
+ * private final Socket socket;
+ * Handler(Socket socket) { this.socket = socket; }
+ * public void run() {
+ * // read and service request on socket
+ * }
+ * }
+ * </pre>
+ *
+ * The following method shuts down an <tt>ExecutorService</tt> in two phases,
+ * first by calling <tt>shutdown</tt> to reject incoming tasks, and then
+ * calling <tt>shutdownNow</tt>, if necessary, to cancel any lingering tasks:
+ *
+ * <pre>
+ * void shutdownAndAwaitTermination(ExecutorService pool) {
+ * pool.shutdown(); // Disable new tasks from being submitted
+ * try {
+ * // Wait a while for existing tasks to terminate
+ * if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
+ * pool.shutdownNow(); // Cancel currently executing tasks
+ * // Wait a while for tasks to respond to being cancelled
+ * if (!pool.awaitTermination(60, TimeUnit.SECONDS))
+ * System.err.println("Pool did not terminate");
+ * }
+ * } catch (InterruptedException ie) {
+ * // (Re-)Cancel if current thread also interrupted
+ * pool.shutdownNow();
+ * // Preserve interrupt status
+ * Thread.currentThread().interrupt();
+ * }
+ * }
+ * </pre>
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to the
+ * submission of a {@code Runnable} or {@code Callable} task to an
+ * {@code ExecutorService}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * any actions taken by that task, which in turn <i>happen-before</i> the
+ * result is retrieved via {@code Future.get()}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ExecutorService extends Executor {
+
+ /**
+ * Initiates an orderly shutdown in which previously submitted
+ * tasks are executed, but no new tasks will be accepted.
+ * Invocation has no additional effect if already shut down.
+ *
+ * @throws SecurityException if a security manager exists and
+ * shutting down this ExecutorService may manipulate
+ * threads that the caller is not permitted to modify
+ * because it does not hold {@link
+ * java.lang.RuntimePermission}<tt>("modifyThread")</tt>,
+ * or the security manager's <tt>checkAccess</tt> method
+ * denies access.
+ */
+ void shutdown();
+
+ /**
+ * Attempts to stop all actively executing tasks, halts the
+ * processing of waiting tasks, and returns a list of the tasks that were
+ * awaiting execution.
+ *
+ * <p>There are no guarantees beyond best-effort attempts to stop
+ * processing actively executing tasks. For example, typical
+ * implementations will cancel via {@link Thread#interrupt}, so any
+ * task that fails to respond to interrupts may never terminate.
+ *
+ * @return list of tasks that never commenced execution
+ * @throws SecurityException if a security manager exists and
+ * shutting down this ExecutorService may manipulate
+ * threads that the caller is not permitted to modify
+ * because it does not hold {@link
+ * java.lang.RuntimePermission}<tt>("modifyThread")</tt>,
+ * or the security manager's <tt>checkAccess</tt> method
+ * denies access.
+ */
+ List shutdownNow();
+
+ /**
+ * Returns <tt>true</tt> if this executor has been shut down.
+ *
+ * @return <tt>true</tt> if this executor has been shut down
+ */
+ boolean isShutdown();
+
+ /**
+ * Returns <tt>true</tt> if all tasks have completed following shut down.
+ * Note that <tt>isTerminated</tt> is never <tt>true</tt> unless
+ * either <tt>shutdown</tt> or <tt>shutdownNow</tt> was called first.
+ *
+ * @return <tt>true</tt> if all tasks have completed following shut down
+ */
+ boolean isTerminated();
+
+ /**
+ * Blocks until all tasks have completed execution after a shutdown
+ * request, or the timeout occurs, or the current thread is
+ * interrupted, whichever happens first.
+ *
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the timeout argument
+ * @return <tt>true</tt> if this executor terminated and
+ * <tt>false</tt> if the timeout elapsed before termination
+ * @throws InterruptedException if interrupted while waiting
+ */
+ boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException;
+
+
+ /**
+ * Submits a value-returning task for execution and returns a
+ * Future representing the pending results of the task. The
+ * Future's <tt>get</tt> method will return the task's result upon
+ * successful completion.
+ *
+ * <p>
+ * If you would like to immediately block waiting
+ * for a task, you can use constructions of the form
+ * <tt>result = exec.submit(aCallable).get();</tt>
+ *
+ * <p> Note: The {@link Executors} class includes a set of methods
+ * that can convert some other common closure-like objects,
+ * for example, {@link java.security.PrivilegedAction} to
+ * {@link Callable} form so they can be submitted.
+ *
+ * @param task the task to submit
+ * @return a Future representing pending completion of the task
+ * @throws RejectedExecutionException if the task cannot be
+ * scheduled for execution
+ * @throws NullPointerException if the task is null
+ */
+ Future submit(Callable task);
+
+ /**
+ * Submits a Runnable task for execution and returns a Future
+ * representing that task. The Future's <tt>get</tt> method will
+ * return the given result upon successful completion.
+ *
+ * @param task the task to submit
+ * @param result the result to return
+ * @return a Future representing pending completion of the task
+ * @throws RejectedExecutionException if the task cannot be
+ * scheduled for execution
+ * @throws NullPointerException if the task is null
+ */
+ Future submit(Runnable task, Object result);
+
+ /**
+ * Submits a Runnable task for execution and returns a Future
+ * representing that task. The Future's <tt>get</tt> method will
+ * return <tt>null</tt> upon <em>successful</em> completion.
+ *
+ * @param task the task to submit
+ * @return a Future representing pending completion of the task
+ * @throws RejectedExecutionException if the task cannot be
+ * scheduled for execution
+ * @throws NullPointerException if the task is null
+ */
+ Future submit(Runnable task);
+
+ /**
+ * Executes the given tasks, returning a list of Futures holding
+ * their status and results when all complete.
+ * {@link Future#isDone} is <tt>true</tt> for each
+ * element of the returned list.
+ * Note that a <em>completed</em> task could have
+ * terminated either normally or by throwing an exception.
+ * The results of this method are undefined if the given
+ * collection is modified while this operation is in progress.
+ *
+ * @param tasks the collection of tasks
+ * @return A list of Futures representing the tasks, in the same
+ * sequential order as produced by the iterator for the
+ * given task list, each of which has completed.
+ * @throws InterruptedException if interrupted while waiting, in
+ * which case unfinished tasks are cancelled.
+ * @throws NullPointerException if tasks or any of its elements are <tt>null</tt>
+ * @throws RejectedExecutionException if any task cannot be
+ * scheduled for execution
+ */
+
+ List invokeAll(Collection tasks)
+ throws InterruptedException;
+
+ /**
+ * Executes the given tasks, returning a list of Futures holding
+ * their status and results
+ * when all complete or the timeout expires, whichever happens first.
+ * {@link Future#isDone} is <tt>true</tt> for each
+ * element of the returned list.
+ * Upon return, tasks that have not completed are cancelled.
+ * Note that a <em>completed</em> task could have
+ * terminated either normally or by throwing an exception.
+ * The results of this method are undefined if the given
+ * collection is modified while this operation is in progress.
+ *
+ * @param tasks the collection of tasks
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the timeout argument
+ * @return a list of Futures representing the tasks, in the same
+ * sequential order as produced by the iterator for the
+ * given task list. If the operation did not time out,
+ * each task will have completed. If it did time out, some
+ * of these tasks will not have completed.
+ * @throws InterruptedException if interrupted while waiting, in
+ * which case unfinished tasks are cancelled
+ * @throws NullPointerException if tasks, any of its elements, or
+ * unit are <tt>null</tt>
+ * @throws RejectedExecutionException if any task cannot be scheduled
+ * for execution
+ */
+ List invokeAll(Collection tasks, long timeout, TimeUnit unit)
+ throws InterruptedException;
+
+ /**
+ * Executes the given tasks, returning the result
+ * of one that has completed successfully (i.e., without throwing
+ * an exception), if any do. Upon normal or exceptional return,
+ * tasks that have not completed are cancelled.
+ * The results of this method are undefined if the given
+ * collection is modified while this operation is in progress.
+ *
+ * @param tasks the collection of tasks
+ * @return the result returned by one of the tasks
+ * @throws InterruptedException if interrupted while waiting
+ * @throws NullPointerException if tasks or any of its elements
+ * are <tt>null</tt>
+ * @throws IllegalArgumentException if tasks is empty
+ * @throws ExecutionException if no task successfully completes
+ * @throws RejectedExecutionException if tasks cannot be scheduled
+ * for execution
+ */
+ Object invokeAny(Collection tasks)
+ throws InterruptedException, ExecutionException;
+
+ /**
+ * Executes the given tasks, returning the result
+ * of one that has completed successfully (i.e., without throwing
+ * an exception), if any do before the given timeout elapses.
+ * Upon normal or exceptional return, tasks that have not
+ * completed are cancelled.
+ * The results of this method are undefined if the given
+ * collection is modified while this operation is in progress.
+ *
+ * @param tasks the collection of tasks
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the timeout argument
+ * @return the result returned by one of the tasks.
+ * @throws InterruptedException if interrupted while waiting
+ * @throws NullPointerException if tasks, any of its elements, or
+ * unit are <tt>null</tt>
+ * @throws TimeoutException if the given timeout elapses before
+ * any task successfully completes
+ * @throws ExecutionException if no task successfully completes
+ * @throws RejectedExecutionException if tasks cannot be scheduled
+ * for execution
+ */
+ Object invokeAny(Collection tasks, long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException;
+}
diff --git a/src/actors/scala/actors/threadpool/Executors.java b/src/actors/scala/actors/threadpool/Executors.java
new file mode 100644
index 0000000000..e74d665f33
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/Executors.java
@@ -0,0 +1,667 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+//import edu.emory.mathcs.backport.java.util.*;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.AccessControlException;
+import java.util.List;
+import java.util.Collection;
+
+/**
+ * Factory and utility methods for {@link Executor}, {@link
+ * ExecutorService}, {@link ScheduledExecutorService}, {@link
+ * ThreadFactory}, and {@link Callable} classes defined in this
+ * package. This class supports the following kinds of methods:
+ *
+ * <ul>
+ * <li> Methods that create and return an {@link ExecutorService}
+ * set up with commonly useful configuration settings.
+ * <li> Methods that create and return a {@link ScheduledExecutorService}
+ * set up with commonly useful configuration settings.
+ * <li> Methods that create and return a "wrapped" ExecutorService, that
+ * disables reconfiguration by making implementation-specific methods
+ * inaccessible.
+ * <li> Methods that create and return a {@link ThreadFactory}
+ * that sets newly created threads to a known state.
+ * <li> Methods that create and return a {@link Callable}
+ * out of other closure-like forms, so they can be used
+ * in execution methods requiring <tt>Callable</tt>.
+ * </ul>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class Executors {
+
+ /**
+ * Creates a thread pool that reuses a fixed number of threads
+ * operating off a shared unbounded queue. At any point, at most
+ * <tt>nThreads</tt> threads will be active processing tasks.
+ * If additional tasks are submitted when all threads are active,
+ * they will wait in the queue until a thread is available.
+ * If any thread terminates due to a failure during execution
+ * prior to shutdown, a new one will take its place if needed to
+ * execute subsequent tasks. The threads in the pool will exist
+ * until it is explicitly {@link ExecutorService#shutdown shutdown}.
+ *
+ * @param nThreads the number of threads in the pool
+ * @return the newly created thread pool
+ * @throws IllegalArgumentException if <tt>nThreads &lt;= 0</tt>
+ */
+ public static ExecutorService newFixedThreadPool(int nThreads) {
+ return new ThreadPoolExecutor(nThreads, nThreads,
+ 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue());
+ }
+
+ /**
+ * Creates a thread pool that reuses a fixed number of threads
+ * operating off a shared unbounded queue, using the provided
+ * ThreadFactory to create new threads when needed. At any point,
+ * at most <tt>nThreads</tt> threads will be active processing
+ * tasks. If additional tasks are submitted when all threads are
+ * active, they will wait in the queue until a thread is
+ * available. If any thread terminates due to a failure during
+ * execution prior to shutdown, a new one will take its place if
+ * needed to execute subsequent tasks. The threads in the pool will
+ * exist until it is explicitly {@link ExecutorService#shutdown
+ * shutdown}.
+ *
+ * @param nThreads the number of threads in the pool
+ * @param threadFactory the factory to use when creating new threads
+ * @return the newly created thread pool
+ * @throws NullPointerException if threadFactory is null
+ * @throws IllegalArgumentException if <tt>nThreads &lt;= 0</tt>
+ */
+ public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
+ return new ThreadPoolExecutor(nThreads, nThreads,
+ 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue(),
+ threadFactory);
+ }
+
+ /**
+ * Creates an Executor that uses a single worker thread operating
+ * off an unbounded queue. (Note however that if this single
+ * thread terminates due to a failure during execution prior to
+ * shutdown, a new one will take its place if needed to execute
+ * subsequent tasks.) Tasks are guaranteed to execute
+ * sequentially, and no more than one task will be active at any
+ * given time. Unlike the otherwise equivalent
+ * <tt>newFixedThreadPool(1)</tt> the returned executor is
+ * guaranteed not to be reconfigurable to use additional threads.
+ *
+ * @return the newly created single-threaded Executor
+ */
+ public static ExecutorService newSingleThreadExecutor() {
+ return new FinalizableDelegatedExecutorService
+ (new ThreadPoolExecutor(1, 1,
+ 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue()));
+ }
+
+ /**
+ * Creates an Executor that uses a single worker thread operating
+ * off an unbounded queue, and uses the provided ThreadFactory to
+ * create a new thread when needed. Unlike the otherwise
+ * equivalent <tt>newFixedThreadPool(1, threadFactory)</tt> the
+ * returned executor is guaranteed not to be reconfigurable to use
+ * additional threads.
+ *
+ * @param threadFactory the factory to use when creating new
+ * threads
+ *
+ * @return the newly created single-threaded Executor
+ * @throws NullPointerException if threadFactory is null
+ */
+ public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
+ return new FinalizableDelegatedExecutorService
+ (new ThreadPoolExecutor(1, 1,
+ 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue(),
+ threadFactory));
+ }
+
+ /**
+ * Creates a thread pool that creates new threads as needed, but
+ * will reuse previously constructed threads when they are
+ * available. These pools will typically improve the performance
+ * of programs that execute many short-lived asynchronous tasks.
+ * Calls to <tt>execute</tt> will reuse previously constructed
+ * threads if available. If no existing thread is available, a new
+ * thread will be created and added to the pool. Threads that have
+ * not been used for sixty seconds are terminated and removed from
+ * the cache. Thus, a pool that remains idle for long enough will
+ * not consume any resources. Note that pools with similar
+ * properties but different details (for example, timeout parameters)
+ * may be created using {@link ThreadPoolExecutor} constructors.
+ *
+ * @return the newly created thread pool
+ */
+ public static ExecutorService newCachedThreadPool() {
+ return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
+ 60L, TimeUnit.SECONDS,
+ new SynchronousQueue());
+ }
+
+ /**
+ * Creates a thread pool that creates new threads as needed, but
+ * will reuse previously constructed threads when they are
+ * available, and uses the provided
+ * ThreadFactory to create new threads when needed.
+ * @param threadFactory the factory to use when creating new threads
+ * @return the newly created thread pool
+ * @throws NullPointerException if threadFactory is null
+ */
+ public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
+ return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
+ 60L, TimeUnit.SECONDS,
+ new SynchronousQueue(),
+ threadFactory);
+ }
+
+ /**
+ * Creates a single-threaded executor that can schedule commands
+ * to run after a given delay, or to execute periodically.
+ * (Note however that if this single
+ * thread terminates due to a failure during execution prior to
+ * shutdown, a new one will take its place if needed to execute
+ * subsequent tasks.) Tasks are guaranteed to execute
+ * sequentially, and no more than one task will be active at any
+ * given time. Unlike the otherwise equivalent
+ * <tt>newScheduledThreadPool(1)</tt> the returned executor is
+ * guaranteed not to be reconfigurable to use additional threads.
+ * @return the newly created scheduled executor
+ */
+ /* public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
+ return new DelegatedScheduledExecutorService
+ (new ScheduledThreadPoolExecutor(1));
+ }
+ */
+ /**
+ * Creates a single-threaded executor that can schedule commands
+ * to run after a given delay, or to execute periodically. (Note
+ * however that if this single thread terminates due to a failure
+ * during execution prior to shutdown, a new one will take its
+ * place if needed to execute subsequent tasks.) Tasks are
+ * guaranteed to execute sequentially, and no more than one task
+ * will be active at any given time. Unlike the otherwise
+ * equivalent <tt>newScheduledThreadPool(1, threadFactory)</tt>
+ * the returned executor is guaranteed not to be reconfigurable to
+ * use additional threads.
+ * @param threadFactory the factory to use when creating new
+ * threads
+ * @return a newly created scheduled executor
+ * @throws NullPointerException if threadFactory is null
+ */
+ /* public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
+ return new DelegatedScheduledExecutorService
+ (new ScheduledThreadPoolExecutor(1, threadFactory));
+ }
+ */
+ /**
+ * Creates a thread pool that can schedule commands to run after a
+ * given delay, or to execute periodically.
+ * @param corePoolSize the number of threads to keep in the pool,
+ * even if they are idle.
+ * @return a newly created scheduled thread pool
+ * @throws IllegalArgumentException if <tt>corePoolSize &lt; 0</tt>
+ */
+ /* public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
+ return new ScheduledThreadPoolExecutor(corePoolSize);
+ }
+ */
+ /**
+ * Creates a thread pool that can schedule commands to run after a
+ * given delay, or to execute periodically.
+ * @param corePoolSize the number of threads to keep in the pool,
+ * even if they are idle.
+ * @param threadFactory the factory to use when the executor
+ * creates a new thread.
+ * @return a newly created scheduled thread pool
+ * @throws IllegalArgumentException if <tt>corePoolSize &lt; 0</tt>
+ * @throws NullPointerException if threadFactory is null
+ */
+ /* public static ScheduledExecutorService newScheduledThreadPool(
+ int corePoolSize, ThreadFactory threadFactory) {
+ return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
+ }
+ */
+
+ /**
+ * Returns an object that delegates all defined {@link
+ * ExecutorService} methods to the given executor, but not any
+ * other methods that might otherwise be accessible using
+ * casts. This provides a way to safely "freeze" configuration and
+ * disallow tuning of a given concrete implementation.
+ * @param executor the underlying implementation
+ * @return an <tt>ExecutorService</tt> instance
+ * @throws NullPointerException if executor null
+ */
+ public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
+ if (executor == null)
+ throw new NullPointerException();
+ return new DelegatedExecutorService(executor);
+ }
+
+ /**
+ * Returns an object that delegates all defined {@link
+ * ScheduledExecutorService} methods to the given executor, but
+ * not any other methods that might otherwise be accessible using
+ * casts. This provides a way to safely "freeze" configuration and
+ * disallow tuning of a given concrete implementation.
+ * @param executor the underlying implementation
+ * @return a <tt>ScheduledExecutorService</tt> instance
+ * @throws NullPointerException if executor null
+ */
+ /* public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
+ if (executor == null)
+ throw new NullPointerException();
+ return new DelegatedScheduledExecutorService(executor);
+ }
+ */
+ /**
+ * Returns a default thread factory used to create new threads.
+ * This factory creates all new threads used by an Executor in the
+ * same {@link ThreadGroup}. If there is a {@link
+ * java.lang.SecurityManager}, it uses the group of {@link
+ * System#getSecurityManager}, else the group of the thread
+ * invoking this <tt>defaultThreadFactory</tt> method. Each new
+ * thread is created as a non-daemon thread with priority set to
+ * the smaller of <tt>Thread.NORM_PRIORITY</tt> and the maximum
+ * priority permitted in the thread group. New threads have names
+ * accessible via {@link Thread#getName} of
+ * <em>pool-N-thread-M</em>, where <em>N</em> is the sequence
+ * number of this factory, and <em>M</em> is the sequence number
+ * of the thread created by this factory.
+ * @return a thread factory
+ */
+ public static ThreadFactory defaultThreadFactory() {
+ return new DefaultThreadFactory();
+ }
+
+ /**
+ * Returns a thread factory used to create new threads that
+ * have the same permissions as the current thread.
+ * This factory creates threads with the same settings as {@link
+ * Executors#defaultThreadFactory}, additionally setting the
+ * AccessControlContext and contextClassLoader of new threads to
+ * be the same as the thread invoking this
+ * <tt>privilegedThreadFactory</tt> method. A new
+ * <tt>privilegedThreadFactory</tt> can be created within an
+ * {@link AccessController#doPrivileged} action setting the
+ * current thread's access control context to create threads with
+ * the selected permission settings holding within that action.
+ *
+ * <p> Note that while tasks running within such threads will have
+ * the same access control and class loader settings as the
+ * current thread, they need not have the same {@link
+ * java.lang.ThreadLocal} or {@link
+ * java.lang.InheritableThreadLocal} values. If necessary,
+ * particular values of thread locals can be set or reset before
+ * any task runs in {@link ThreadPoolExecutor} subclasses using
+ * {@link ThreadPoolExecutor#beforeExecute}. Also, if it is
+ * necessary to initialize worker threads to have the same
+ * InheritableThreadLocal settings as some other designated
+ * thread, you can create a custom ThreadFactory in which that
+ * thread waits for and services requests to create others that
+ * will inherit its values.
+ *
+ * @return a thread factory
+ * @throws AccessControlException if the current access control
+ * context does not have permission to both get and set context
+ * class loader.
+ */
+ public static ThreadFactory privilegedThreadFactory() {
+ return new PrivilegedThreadFactory();
+ }
+
+ /**
+ * Returns a {@link Callable} object that, when
+ * called, runs the given task and returns the given result. This
+ * can be useful when applying methods requiring a
+ * <tt>Callable</tt> to an otherwise resultless action.
+ * @param task the task to run
+ * @param result the result to return
+ * @return a callable object
+ * @throws NullPointerException if task null
+ */
+ public static Callable callable(Runnable task, Object result) {
+ if (task == null)
+ throw new NullPointerException();
+ return new RunnableAdapter(task, result);
+ }
+
+ /**
+ * Returns a {@link Callable} object that, when
+ * called, runs the given task and returns <tt>null</tt>.
+ * @param task the task to run
+ * @return a callable object
+ * @throws NullPointerException if task null
+ */
+ public static Callable callable(Runnable task) {
+ if (task == null)
+ throw new NullPointerException();
+ return new RunnableAdapter(task, null);
+ }
+
+ /**
+ * Returns a {@link Callable} object that, when
+ * called, runs the given privileged action and returns its result.
+ * @param action the privileged action to run
+ * @return a callable object
+ * @throws NullPointerException if action null
+ */
+ public static Callable callable(final PrivilegedAction action) {
+ if (action == null)
+ throw new NullPointerException();
+ return new Callable() {
+ public Object call() { return action.run(); }};
+ }
+
+ /**
+ * Returns a {@link Callable} object that, when
+ * called, runs the given privileged exception action and returns
+ * its result.
+ * @param action the privileged exception action to run
+ * @return a callable object
+ * @throws NullPointerException if action null
+ */
+ public static Callable callable(final PrivilegedExceptionAction action) {
+ if (action == null)
+ throw new NullPointerException();
+ return new Callable() {
+ public Object call() throws Exception { return action.run(); }};
+ }
+
+ /**
+ * Returns a {@link Callable} object that will, when
+ * called, execute the given <tt>callable</tt> under the current
+ * access control context. This method should normally be
+ * invoked within an {@link AccessController#doPrivileged} action
+ * to create callables that will, if possible, execute under the
+ * selected permission settings holding within that action; or if
+ * not possible, throw an associated {@link
+ * AccessControlException}.
+ * @param callable the underlying task
+ * @return a callable object
+ * @throws NullPointerException if callable null
+ *
+ */
+ public static Callable privilegedCallable(Callable callable) {
+ if (callable == null)
+ throw new NullPointerException();
+ return new PrivilegedCallable(callable);
+ }
+
+ /**
+ * Returns a {@link Callable} object that will, when
+ * called, execute the given <tt>callable</tt> under the current
+ * access control context, with the current context class loader
+ * as the context class loader. This method should normally be
+ * invoked within an {@link AccessController#doPrivileged} action
+ * to create callables that will, if possible, execute under the
+ * selected permission settings holding within that action; or if
+ * not possible, throw an associated {@link
+ * AccessControlException}.
+ * @param callable the underlying task
+ *
+ * @return a callable object
+ * @throws NullPointerException if callable null
+ * @throws AccessControlException if the current access control
+ * context does not have permission to both set and get context
+ * class loader.
+ */
+ public static Callable privilegedCallableUsingCurrentClassLoader(Callable callable) {
+ if (callable == null)
+ throw new NullPointerException();
+ return new PrivilegedCallableUsingCurrentClassLoader(callable);
+ }
+
+ // Non-public classes supporting the public methods
+
+ /**
+ * A callable that runs given task and returns given result
+ */
+ static final class RunnableAdapter implements Callable {
+ final Runnable task;
+ final Object result;
+ RunnableAdapter(Runnable task, Object result) {
+ this.task = task;
+ this.result = result;
+ }
+ public Object call() {
+ task.run();
+ return result;
+ }
+ }
+
+ /**
+ * A callable that runs under established access control settings
+ */
+ static final class PrivilegedCallable implements Callable {
+ private final AccessControlContext acc;
+ private final Callable task;
+ private Object result;
+ private Exception exception;
+ PrivilegedCallable(Callable task) {
+ this.task = task;
+ this.acc = AccessController.getContext();
+ }
+
+ public Object call() throws Exception {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ try {
+ result = task.call();
+ } catch (Exception ex) {
+ exception = ex;
+ }
+ return null;
+ }
+ }, acc);
+ if (exception != null)
+ throw exception;
+ else
+ return result;
+ }
+ }
+
+ /**
+ * A callable that runs under established access control settings and
+ * current ClassLoader
+ */
+ static final class PrivilegedCallableUsingCurrentClassLoader implements Callable {
+ private final ClassLoader ccl;
+ private final AccessControlContext acc;
+ private final Callable task;
+ private Object result;
+ private Exception exception;
+ PrivilegedCallableUsingCurrentClassLoader(Callable task) {
+ this.task = task;
+ this.ccl = Thread.currentThread().getContextClassLoader();
+ this.acc = AccessController.getContext();
+ acc.checkPermission(new RuntimePermission("getContextClassLoader"));
+ acc.checkPermission(new RuntimePermission("setContextClassLoader"));
+ }
+
+ public Object call() throws Exception {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ ClassLoader savedcl = null;
+ Thread t = Thread.currentThread();
+ try {
+ ClassLoader cl = t.getContextClassLoader();
+ if (ccl != cl) {
+ t.setContextClassLoader(ccl);
+ savedcl = cl;
+ }
+ result = task.call();
+ } catch (Exception ex) {
+ exception = ex;
+ } finally {
+ if (savedcl != null)
+ t.setContextClassLoader(savedcl);
+ }
+ return null;
+ }
+ }, acc);
+ if (exception != null)
+ throw exception;
+ else
+ return result;
+ }
+ }
+
+ /**
+ * The default thread factory
+ */
+ static class DefaultThreadFactory implements ThreadFactory {
+ static final AtomicInteger poolNumber = new AtomicInteger(1);
+ final ThreadGroup group;
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ final String namePrefix;
+
+ DefaultThreadFactory() {
+ SecurityManager s = System.getSecurityManager();
+ group = (s != null)? s.getThreadGroup() :
+ Thread.currentThread().getThreadGroup();
+ namePrefix = "pool-" +
+ poolNumber.getAndIncrement() +
+ "-thread-";
+ }
+
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(group, r,
+ namePrefix + threadNumber.getAndIncrement(),
+ 0);
+ if (t.isDaemon())
+ t.setDaemon(false);
+ if (t.getPriority() != Thread.NORM_PRIORITY)
+ t.setPriority(Thread.NORM_PRIORITY);
+ return t;
+ }
+ }
+
+ /**
+ * Thread factory capturing access control and class loader
+ */
+ static class PrivilegedThreadFactory extends DefaultThreadFactory {
+ private final ClassLoader ccl;
+ private final AccessControlContext acc;
+
+ PrivilegedThreadFactory() {
+ super();
+ this.ccl = Thread.currentThread().getContextClassLoader();
+ this.acc = AccessController.getContext();
+ acc.checkPermission(new RuntimePermission("setContextClassLoader"));
+ }
+
+ public Thread newThread(final Runnable r) {
+ return super.newThread(new Runnable() {
+ public void run() {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ Thread.currentThread().setContextClassLoader(ccl);
+ r.run();
+ return null;
+ }
+ }, acc);
+ }
+ });
+ }
+
+ }
+
+ /**
+ * A wrapper class that exposes only the ExecutorService methods
+ * of an ExecutorService implementation.
+ */
+ static class DelegatedExecutorService extends AbstractExecutorService {
+ private final ExecutorService e;
+ DelegatedExecutorService(ExecutorService executor) { e = executor; }
+ public void execute(Runnable command) { e.execute(command); }
+ public void shutdown() { e.shutdown(); }
+ public List shutdownNow() { return e.shutdownNow(); }
+ public boolean isShutdown() { return e.isShutdown(); }
+ public boolean isTerminated() { return e.isTerminated(); }
+ public boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return e.awaitTermination(timeout, unit);
+ }
+ public Future submit(Runnable task) {
+ return e.submit(task);
+ }
+ public Future submit(Callable task) {
+ return e.submit(task);
+ }
+ public Future submit(Runnable task, Object result) {
+ return e.submit(task, result);
+ }
+ public List invokeAll(Collection tasks)
+ throws InterruptedException {
+ return e.invokeAll(tasks);
+ }
+ public List invokeAll(Collection tasks,
+ long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return e.invokeAll(tasks, timeout, unit);
+ }
+ public Object invokeAny(Collection tasks)
+ throws InterruptedException, ExecutionException {
+ return e.invokeAny(tasks);
+ }
+ public Object invokeAny(Collection tasks,
+ long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return e.invokeAny(tasks, timeout, unit);
+ }
+ }
+
+ static class FinalizableDelegatedExecutorService
+ extends DelegatedExecutorService {
+ FinalizableDelegatedExecutorService(ExecutorService executor) {
+ super(executor);
+ }
+ protected void finalize() {
+ super.shutdown();
+ }
+ }
+
+ /**
+ * A wrapper class that exposes only the ScheduledExecutorService
+ * methods of a ScheduledExecutorService implementation.
+ */
+ /* static class DelegatedScheduledExecutorService
+ extends DelegatedExecutorService
+ implements ScheduledExecutorService {
+ private final ScheduledExecutorService e;
+ DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
+ super(executor);
+ e = executor;
+ }
+ public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) {
+ return e.schedule(command, delay, unit);
+ }
+ public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) {
+ return e.schedule(callable, delay, unit);
+ }
+ public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
+ return e.scheduleAtFixedRate(command, initialDelay, period, unit);
+ }
+ public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
+ return e.scheduleWithFixedDelay(command, initialDelay, delay, unit);
+ }
+ }
+*/
+
+ /** Cannot instantiate. */
+ private Executors() {}
+}
diff --git a/src/actors/scala/actors/threadpool/Future.java b/src/actors/scala/actors/threadpool/Future.java
new file mode 100644
index 0000000000..5e1b3d414a
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/Future.java
@@ -0,0 +1,142 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+import scala.actors.threadpool.*; // for javadoc (till 6280605 is fixed)
+
+/**
+ * A <tt>Future</tt> represents the result of an asynchronous
+ * computation. Methods are provided to check if the computation is
+ * complete, to wait for its completion, and to retrieve the result of
+ * the computation. The result can only be retrieved using method
+ * <tt>get</tt> when the computation has completed, blocking if
+ * necessary until it is ready. Cancellation is performed by the
+ * <tt>cancel</tt> method. Additional methods are provided to
+ * determine if the task completed normally or was cancelled. Once a
+ * computation has completed, the computation cannot be cancelled.
+ * If you would like to use a <tt>Future</tt> for the sake
+ * of cancellability but not provide a usable result, you can
+ * declare types of the form <tt>Future&lt;?&gt;</tt> and
+ * return <tt>null</tt> as a result of the underlying task.
+ *
+ * <p>
+ * <b>Sample Usage</b> (Note that the following classes are all
+ * made-up.) <p>
+ * <pre>
+ * interface ArchiveSearcher { String search(String target); }
+ * class App {
+ * ExecutorService executor = ...
+ * ArchiveSearcher searcher = ...
+ * void showSearch(final String target)
+ * throws InterruptedException {
+ * Future&lt;String&gt; future
+ * = executor.submit(new Callable&lt;String&gt;() {
+ * public String call() {
+ * return searcher.search(target);
+ * }});
+ * displayOtherThings(); // do other things while searching
+ * try {
+ * displayText(future.get()); // use future
+ * } catch (ExecutionException ex) { cleanup(); return; }
+ * }
+ * }
+ * </pre>
+ *
+ * The {@link FutureTask} class is an implementation of <tt>Future</tt> that
+ * implements <tt>Runnable</tt>, and so may be executed by an <tt>Executor</tt>.
+ * For example, the above construction with <tt>submit</tt> could be replaced by:
+ * <pre>
+ * FutureTask&lt;String&gt; future =
+ * new FutureTask&lt;String&gt;(new Callable&lt;String&gt;() {
+ * public String call() {
+ * return searcher.search(target);
+ * }});
+ * executor.execute(future);
+ * </pre>
+ *
+ * <p>Memory consistency effects: Actions taken by the asynchronous computation
+ * <a href="package-summary.html#MemoryVisibility"> <i>happen-before</i></a>
+ * actions following the corresponding {@code Future.get()} in another thread.
+ *
+ * @see FutureTask
+ * @see Executor
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Future {
+
+ /**
+ * Attempts to cancel execution of this task. This attempt will
+ * fail if the task has already completed, has already been cancelled,
+ * or could not be cancelled for some other reason. If successful,
+ * and this task has not started when <tt>cancel</tt> is called,
+ * this task should never run. If the task has already started,
+ * then the <tt>mayInterruptIfRunning</tt> parameter determines
+ * whether the thread executing this task should be interrupted in
+ * an attempt to stop the task.
+ *
+ * <p>After this method returns, subsequent calls to {@link #isDone} will
+ * always return <tt>true</tt>. Subsequent calls to {@link #isCancelled}
+ * will always return <tt>true</tt> if this method returned <tt>true</tt>.
+ *
+ * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
+ * task should be interrupted; otherwise, in-progress tasks are allowed
+ * to complete
+ * @return <tt>false</tt> if the task could not be cancelled,
+ * typically because it has already completed normally;
+ * <tt>true</tt> otherwise
+ */
+ boolean cancel(boolean mayInterruptIfRunning);
+
+ /**
+ * Returns <tt>true</tt> if this task was cancelled before it completed
+ * normally.
+ *
+ * @return <tt>true</tt> if this task was cancelled before it completed
+ */
+ boolean isCancelled();
+
+ /**
+ * Returns <tt>true</tt> if this task completed.
+ *
+ * Completion may be due to normal termination, an exception, or
+ * cancellation -- in all of these cases, this method will return
+ * <tt>true</tt>.
+ *
+ * @return <tt>true</tt> if this task completed
+ */
+ boolean isDone();
+
+ /**
+ * Waits if necessary for the computation to complete, and then
+ * retrieves its result.
+ *
+ * @return the computed result
+ * @throws CancellationException if the computation was cancelled
+ * @throws ExecutionException if the computation threw an
+ * exception
+ * @throws InterruptedException if the current thread was interrupted
+ * while waiting
+ */
+ Object get() throws InterruptedException, ExecutionException;
+
+ /**
+ * Waits if necessary for at most the given time for the computation
+ * to complete, and then retrieves its result, if available.
+ *
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the timeout argument
+ * @return the computed result
+ * @throws CancellationException if the computation was cancelled
+ * @throws ExecutionException if the computation threw an
+ * exception
+ * @throws InterruptedException if the current thread was interrupted
+ * while waiting
+ * @throws TimeoutException if the wait timed out
+ */
+ Object get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException;
+}
diff --git a/src/actors/scala/actors/threadpool/FutureTask.java b/src/actors/scala/actors/threadpool/FutureTask.java
new file mode 100644
index 0000000000..d4dcfe38b3
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/FutureTask.java
@@ -0,0 +1,310 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain. Use, modify, and
+ * redistribute this code in any way without acknowledgement.
+ */
+
+package scala.actors.threadpool;
+
+import scala.actors.threadpool.*; // for javadoc
+import scala.actors.threadpool.helpers.*;
+
+/**
+ * A cancellable asynchronous computation. This class provides a base
+ * implementation of {@link Future}, with methods to start and cancel
+ * a computation, query to see if the computation is complete, and
+ * retrieve the result of the computation. The result can only be
+ * retrieved when the computation has completed; the <tt>get</tt>
+ * method will block if the computation has not yet completed. Once
+ * the computation has completed, the computation cannot be restarted
+ * or cancelled.
+ *
+ * <p>A <tt>FutureTask</tt> can be used to wrap a {@link Callable} or
+ * {@link java.lang.Runnable} object. Because <tt>FutureTask</tt>
+ * implements <tt>Runnable</tt>, a <tt>FutureTask</tt> can be
+ * submitted to an {@link Executor} for execution.
+ *
+ * <p>In addition to serving as a standalone class, this class provides
+ * <tt>protected</tt> functionality that may be useful when creating
+ * customized task classes.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class FutureTask implements RunnableFuture {
+
+ /** State value representing that task is ready to run */
+ private static final int READY = 0;
+ /** State value representing that task is running */
+ private static final int RUNNING = 1;
+ /** State value representing that task ran */
+ private static final int RAN = 2;
+ /** State value representing that task was cancelled */
+ private static final int CANCELLED = 4;
+
+ /** The underlying callable */
+ private final Callable callable;
+ /** The result to return from get() */
+ private Object result;
+ /** The exception to throw from get() */
+ private Throwable exception;
+
+ private int state;
+
+ /**
+ * The thread running task. When nulled after set/cancel, this
+ * indicates that the results are accessible. Must be
+ * volatile, to ensure visibility upon completion.
+ */
+ private volatile Thread runner;
+
+ /**
+ * Creates a <tt>FutureTask</tt> that will, upon running, execute the
+ * given <tt>Callable</tt>.
+ *
+ * @param callable the callable task
+ * @throws NullPointerException if callable is null
+ */
+ public FutureTask(Callable callable) {
+ if (callable == null)
+ throw new NullPointerException();
+ this.callable = callable;
+ }
+
+ /**
+ * Creates a <tt>FutureTask</tt> that will, upon running, execute the
+ * given <tt>Runnable</tt>, and arrange that <tt>get</tt> will return the
+ * given result on successful completion.
+ *
+ * @param runnable the runnable task
+ * @param result the result to return on successful completion. If
+ * you don't need a particular result, consider using
+ * constructions of the form:
+ * <tt>Future&lt;?&gt; f = new FutureTask&lt;Object&gt;(runnable, null)</tt>
+ * @throws NullPointerException if runnable is null
+ */
+ public FutureTask(Runnable runnable, Object result) {
+ this(Executors.callable(runnable, result));
+ }
+
+ public synchronized boolean isCancelled() {
+ return state == CANCELLED;
+ }
+
+ public synchronized boolean isDone() {
+ return ranOrCancelled() && runner == null;
+ }
+
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ synchronized (this) {
+ if (ranOrCancelled()) return false;
+ state = CANCELLED;
+ if (mayInterruptIfRunning) {
+ Thread r = runner;
+ if (r != null) r.interrupt();
+ }
+ runner = null;
+ notifyAll();
+ }
+ done();
+ return true;
+ }
+
+ /**
+ * @throws CancellationException {@inheritDoc}
+ */
+ public synchronized Object get()
+ throws InterruptedException, ExecutionException
+ {
+ waitFor();
+ return getResult();
+ }
+
+ /**
+ * @throws CancellationException {@inheritDoc}
+ */
+ public synchronized Object get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException
+ {
+ waitFor(unit.toNanos(timeout));
+ return getResult();
+ }
+
+ /**
+ * Protected method invoked when this task transitions to state
+ * <tt>isDone</tt> (whether normally or via cancellation). The
+ * default implementation does nothing. Subclasses may override
+ * this method to invoke completion callbacks or perform
+ * bookkeeping. Note that you can query status inside the
+ * implementation of this method to determine whether this task
+ * has been cancelled.
+ */
+ protected void done() { }
+
+ /**
+ * Sets the result of this Future to the given value unless
+ * this future has already been set or has been cancelled.
+ * This method is invoked internally by the <tt>run</tt> method
+ * upon successful completion of the computation.
+ * @param v the value
+ */
+ protected void set(Object v) {
+ setCompleted(v);
+ }
+
+ /**
+ * Causes this future to report an <tt>ExecutionException</tt>
+ * with the given throwable as its cause, unless this Future has
+ * already been set or has been cancelled.
+ * This method is invoked internally by the <tt>run</tt> method
+ * upon failure of the computation.
+ * @param t the cause of failure
+ */
+ protected void setException(Throwable t) {
+ setFailed(t);
+ }
+
+ /**
+ * Sets this Future to the result of its computation
+ * unless it has been cancelled.
+ */
+ public void run() {
+ synchronized (this) {
+ if (state != READY) return;
+ state = RUNNING;
+ runner = Thread.currentThread();
+ }
+ try {
+ set(callable.call());
+ }
+ catch (Throwable ex) {
+ setException(ex);
+ }
+ }
+
+ /**
+ * Executes the computation without setting its result, and then
+ * resets this Future to initial state, failing to do so if the
+ * computation encounters an exception or is cancelled. This is
+ * designed for use with tasks that intrinsically execute more
+ * than once.
+ * @return true if successfully run and reset
+ */
+ protected boolean runAndReset() {
+ synchronized (this) {
+ if (state != READY) return false;
+ state = RUNNING;
+ runner = Thread.currentThread();
+ }
+ try {
+ callable.call(); // don't set result
+ synchronized (this) {
+ runner = null;
+ if (state == RUNNING) {
+ state = READY;
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+ catch (Throwable ex) {
+ setException(ex);
+ return false;
+ }
+ }
+
+ // PRE: lock owned
+ private boolean ranOrCancelled() {
+ return (state & (RAN | CANCELLED)) != 0;
+ }
+
+ /**
+ * Marks the task as completed.
+ * @param result the result of a task.
+ */
+ private void setCompleted(Object result) {
+ synchronized (this) {
+ if (ranOrCancelled()) return;
+ this.state = RAN;
+ this.result = result;
+ this.runner = null;
+ notifyAll();
+ }
+
+ // invoking callbacks *after* setting future as completed and
+ // outside the synchronization block makes it safe to call
+ // interrupt() from within callback code (in which case it will be
+ // ignored rather than cause deadlock / illegal state exception)
+ done();
+ }
+
+ /**
+ * Marks the task as failed.
+ * @param exception the cause of abrupt completion.
+ */
+ private void setFailed(Throwable exception) {
+ synchronized (this) {
+ if (ranOrCancelled()) return;
+ this.state = RAN;
+ this.exception = exception;
+ this.runner = null;
+ notifyAll();
+ }
+
+ // invoking callbacks *after* setting future as completed and
+ // outside the synchronization block makes it safe to call
+ // interrupt() from within callback code (in which case it will be
+ // ignored rather than cause deadlock / illegal state exception)
+ done();
+ }
+
+ /**
+ * Waits for the task to complete.
+ * PRE: lock owned
+ */
+ private void waitFor() throws InterruptedException {
+ while (!isDone()) {
+ wait();
+ }
+ }
+
+ /**
+ * Waits for the task to complete for timeout nanoseconds or throw
+ * TimeoutException if still not completed after that
+ * PRE: lock owned
+ */
+ private void waitFor(long nanos) throws InterruptedException, TimeoutException {
+ if (nanos < 0) throw new IllegalArgumentException();
+ if (isDone()) return;
+ long deadline = Utils.nanoTime() + nanos;
+ while (nanos > 0) {
+ TimeUnit.NANOSECONDS.timedWait(this, nanos);
+ if (isDone()) return;
+ nanos = deadline - Utils.nanoTime();
+ }
+ throw new TimeoutException();
+ }
+
+ /**
+ * Gets the result of the task.
+ *
+ * PRE: task completed
+ * PRE: lock owned
+ */
+ private Object getResult() throws ExecutionException {
+ if (state == CANCELLED) {
+ throw new CancellationException();
+ }
+ if (exception != null) {
+ throw new ExecutionException(exception);
+ }
+ return result;
+ }
+
+ // todo: consider
+ //public String toString() {
+ // return callable.toString();
+ //}
+}
diff --git a/src/actors/scala/actors/threadpool/LinkedBlockingQueue.java b/src/actors/scala/actors/threadpool/LinkedBlockingQueue.java
new file mode 100644
index 0000000000..87fecff09c
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/LinkedBlockingQueue.java
@@ -0,0 +1,751 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+//import edu.emory.mathcs.backport.java.util.*;
+import scala.actors.threadpool.helpers.*;
+
+/**
+ * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
+ * linked nodes.
+ * This queue orders elements FIFO (first-in-first-out).
+ * The <em>head</em> of the queue is that element that has been on the
+ * queue the longest time.
+ * The <em>tail</em> of the queue is that element that has been on the
+ * queue the shortest time. New elements
+ * are inserted at the tail of the queue, and the queue retrieval
+ * operations obtain elements at the head of the queue.
+ * Linked queues typically have higher throughput than array-based queues but
+ * less predictable performance in most concurrent applications.
+ *
+ * <p> The optional capacity bound constructor argument serves as a
+ * way to prevent excessive queue expansion. The capacity, if unspecified,
+ * is equal to {@link Integer#MAX_VALUE}. Linked nodes are
+ * dynamically created upon each insertion unless this would bring the
+ * queue above capacity.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ *
+ */
+public class LinkedBlockingQueue extends AbstractQueue
+ implements BlockingQueue, java.io.Serializable {
+ private static final long serialVersionUID = -6903933977591709194L;
+
+ /*
+ * A variant of the "two lock queue" algorithm. The putLock gates
+ * entry to put (and offer), and has an associated condition for
+ * waiting puts. Similarly for the takeLock. The "count" field
+ * that they both rely on is maintained as an atomic to avoid
+ * needing to get both locks in most cases. Also, to minimize need
+ * for puts to get takeLock and vice-versa, cascading notifies are
+ * used. When a put notices that it has enabled at least one take,
+ * it signals taker. That taker in turn signals others if more
+ * items have been entered since the signal. And symmetrically for
+ * takes signalling puts. Operations such as remove(Object) and
+ * iterators acquire both locks.
+ */
+
+ /**
+ * Linked list node class
+ */
+ static class Node {
+ /** The item, volatile to ensure barrier separating write and read */
+ volatile Object item;
+ Node next;
+ Node(Object x) { item = x; }
+ }
+
+ /** The capacity bound, or Integer.MAX_VALUE if none */
+ private final int capacity;
+
+ /** Current number of elements */
+ private volatile int count = 0;
+
+ /** Head of linked list */
+ private transient Node head;
+
+ /** Tail of linked list */
+ private transient Node last;
+
+ /** Lock held by take, poll, etc */
+ private final Object takeLock = new SerializableLock();
+
+ /** Lock held by put, offer, etc */
+ private final Object putLock = new SerializableLock();
+
+ /**
+ * Signals a waiting take. Called only from put/offer (which do not
+ * otherwise ordinarily lock takeLock.)
+ */
+ private void signalNotEmpty() {
+ synchronized (takeLock) {
+ takeLock.notify();
+ }
+ }
+
+ /**
+ * Signals a waiting put. Called only from take/poll.
+ */
+ private void signalNotFull() {
+ synchronized (putLock) {
+ putLock.notify();
+ }
+ }
+
+ /**
+ * Creates a node and links it at end of queue.
+ * @param x the item
+ */
+ private void insert(Object x) {
+ last = last.next = new Node(x);
+ }
+
+ /**
+ * Removes a node from head of queue,
+ * @return the node
+ */
+ private Object extract() {
+ Node first = head.next;
+ head = first;
+ Object x = first.item;
+ first.item = null;
+ return x;
+ }
+
+
+ /**
+ * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of
+ * {@link Integer#MAX_VALUE}.
+ */
+ public LinkedBlockingQueue() {
+ this(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Creates a <tt>LinkedBlockingQueue</tt> with the given (fixed) capacity.
+ *
+ * @param capacity the capacity of this queue
+ * @throws IllegalArgumentException if <tt>capacity</tt> is not greater
+ * than zero
+ */
+ public LinkedBlockingQueue(int capacity) {
+ if (capacity <= 0) throw new IllegalArgumentException();
+ this.capacity = capacity;
+ last = head = new Node(null);
+ }
+
+ /**
+ * Creates a <tt>LinkedBlockingQueue</tt> with a capacity of
+ * {@link Integer#MAX_VALUE}, initially containing the elements of the
+ * given collection,
+ * added in traversal order of the collection's iterator.
+ *
+ * @param c the collection of elements to initially contain
+ * @throws NullPointerException if the specified collection or any
+ * of its elements are null
+ */
+ public LinkedBlockingQueue(Collection c) {
+ this(Integer.MAX_VALUE);
+ for (Iterator itr = c.iterator(); itr.hasNext();) {
+ Object e = itr.next();
+ add(e);
+ }
+ }
+
+
+ // this doc comment is overridden to remove the reference to collections
+ // greater in size than Integer.MAX_VALUE
+ /**
+ * Returns the number of elements in this queue.
+ *
+ * @return the number of elements in this queue
+ */
+ public int size() {
+ return count;
+ }
+
+ // this doc comment is a modified copy of the inherited doc comment,
+ // without the reference to unlimited queues.
+ /**
+ * Returns the number of additional elements that this queue can ideally
+ * (in the absence of memory or resource constraints) accept without
+ * blocking. This is always equal to the initial capacity of this queue
+ * less the current <tt>size</tt> of this queue.
+ *
+ * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+ * an element will succeed by inspecting <tt>remainingCapacity</tt>
+ * because it may be the case that another thread is about to
+ * insert or remove an element.
+ */
+ public int remainingCapacity() {
+ return capacity - count;
+ }
+
+ /**
+ * Inserts the specified element at the tail of this queue, waiting if
+ * necessary for space to become available.
+ *
+ * @throws InterruptedException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void put(Object e) throws InterruptedException {
+ if (e == null) throw new NullPointerException();
+ // Note: convention in all put/take/etc is to preset
+ // local var holding count negative to indicate failure unless set.
+ int c = -1;
+ synchronized (putLock) {
+ /*
+ * Note that count is used in wait guard even though it is
+ * not protected by lock. This works because count can
+ * only decrease at this point (all other puts are shut
+ * out by lock), and we (or some other waiting put) are
+ * signalled if it ever changes from
+ * capacity. Similarly for all other uses of count in
+ * other wait guards.
+ */
+ try {
+ while (count == capacity)
+ putLock.wait();
+ } catch (InterruptedException ie) {
+ putLock.notify(); // propagate to a non-interrupted thread
+ throw ie;
+ }
+ insert(e);
+ synchronized (this) { c = count++; }
+ if (c + 1 < capacity)
+ putLock.notify();
+ }
+
+ if (c == 0)
+ signalNotEmpty();
+ }
+
+ /**
+ * Inserts the specified element at the tail of this queue, waiting if
+ * necessary up to the specified wait time for space to become available.
+ *
+ * @return <tt>true</tt> if successful, or <tt>false</tt> if
+ * the specified waiting time elapses before space is available.
+ * @throws InterruptedException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean offer(Object e, long timeout, TimeUnit unit)
+ throws InterruptedException {
+
+ if (e == null) throw new NullPointerException();
+ long nanos = unit.toNanos(timeout);
+ int c = -1;
+ synchronized (putLock) {
+ long deadline = Utils.nanoTime() + nanos;
+ for (;;) {
+ if (count < capacity) {
+ insert(e);
+ synchronized (this) { c = count++; }
+ if (c + 1 < capacity)
+ putLock.notify();
+ break;
+ }
+ if (nanos <= 0)
+ return false;
+ try {
+ TimeUnit.NANOSECONDS.timedWait(putLock, nanos);
+ nanos = deadline - Utils.nanoTime();
+ } catch (InterruptedException ie) {
+ putLock.notify(); // propagate to a non-interrupted thread
+ throw ie;
+ }
+ }
+ }
+ if (c == 0)
+ signalNotEmpty();
+ return true;
+ }
+
+ /**
+ * Inserts the specified element at the tail of this queue if it is
+ * possible to do so immediately without exceeding the queue's capacity,
+ * returning <tt>true</tt> upon success and <tt>false</tt> if this queue
+ * is full.
+ * When using a capacity-restricted queue, this method is generally
+ * preferable to method {@link BlockingQueue#add add}, which can fail to
+ * insert an element only by throwing an exception.
+ *
+ * @throws NullPointerException if the specified element is null
+ */
+ public boolean offer(Object e) {
+ if (e == null) throw new NullPointerException();
+ if (count == capacity)
+ return false;
+ int c = -1;
+ synchronized (putLock) {
+ if (count < capacity) {
+ insert(e);
+ synchronized (this) { c = count++; }
+ if (c + 1 < capacity)
+ putLock.notify();
+ }
+ }
+ if (c == 0)
+ signalNotEmpty();
+ return c >= 0;
+ }
+
+
+ public Object take() throws InterruptedException {
+ Object x;
+ int c = -1;
+ synchronized (takeLock) {
+ try {
+ while (count == 0)
+ takeLock.wait();
+ } catch (InterruptedException ie) {
+ takeLock.notify(); // propagate to a non-interrupted thread
+ throw ie;
+ }
+
+ x = extract();
+ synchronized (this) { c = count--; }
+ if (c > 1)
+ takeLock.notify();
+ }
+ if (c == capacity)
+ signalNotFull();
+ return x;
+ }
+
+ public Object poll(long timeout, TimeUnit unit) throws InterruptedException {
+ Object x = null;
+ int c = -1;
+ long nanos = unit.toNanos(timeout);
+ synchronized (takeLock) {
+ long deadline = Utils.nanoTime() + nanos;
+ for (;;) {
+ if (count > 0) {
+ x = extract();
+ synchronized (this) { c = count--; }
+ if (c > 1)
+ takeLock.notify();
+ break;
+ }
+ if (nanos <= 0)
+ return null;
+ try {
+ TimeUnit.NANOSECONDS.timedWait(takeLock, nanos);
+ nanos = deadline - Utils.nanoTime();
+ } catch (InterruptedException ie) {
+ takeLock.notify(); // propagate to a non-interrupted thread
+ throw ie;
+ }
+ }
+ }
+ if (c == capacity)
+ signalNotFull();
+ return x;
+ }
+
+ public Object poll() {
+ if (count == 0)
+ return null;
+ Object x = null;
+ int c = -1;
+ synchronized (takeLock) {
+ if (count > 0) {
+ x = extract();
+ synchronized (this) { c = count--; }
+ if (c > 1)
+ takeLock.notify();
+ }
+ }
+ if (c == capacity)
+ signalNotFull();
+ return x;
+ }
+
+
+ public Object peek() {
+ if (count == 0)
+ return null;
+ synchronized (takeLock) {
+ Node first = head.next;
+ if (first == null)
+ return null;
+ else
+ return first.item;
+ }
+ }
+
+ /**
+ * Removes a single instance of the specified element from this queue,
+ * if it is present. More formally, removes an element <tt>e</tt> such
+ * that <tt>o.equals(e)</tt>, if this queue contains one or more such
+ * elements.
+ * Returns <tt>true</tt> if this queue contained the specified element
+ * (or equivalently, if this queue changed as a result of the call).
+ *
+ * @param o element to be removed from this queue, if present
+ * @return <tt>true</tt> if this queue changed as a result of the call
+ */
+ public boolean remove(Object o) {
+ if (o == null) return false;
+ boolean removed = false;
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ Node trail = head;
+ Node p = head.next;
+ while (p != null) {
+ if (o.equals(p.item)) {
+ removed = true;
+ break;
+ }
+ trail = p;
+ p = p.next;
+ }
+ if (removed) {
+ p.item = null;
+ trail.next = p.next;
+ if (last == p)
+ last = trail;
+ synchronized (this) {
+ if (count-- == capacity)
+ putLock.notifyAll();
+ }
+ }
+ }
+ }
+ return removed;
+ }
+
+ /**
+ * Returns an array containing all of the elements in this queue, in
+ * proper sequence.
+ *
+ * <p>The returned array will be "safe" in that no references to it are
+ * maintained by this queue. (In other words, this method must allocate
+ * a new array). The caller is thus free to modify the returned array.
+ *
+ * <p>This method acts as bridge between array-based and collection-based
+ * APIs.
+ *
+ * @return an array containing all of the elements in this queue
+ */
+ public Object[] toArray() {
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ int size = count;
+ Object[] a = new Object[size];
+ int k = 0;
+ for (Node p = head.next; p != null; p = p.next)
+ a[k++] = p.item;
+ return a;
+ }
+ }
+ }
+
+ /**
+ * Returns an array containing all of the elements in this queue, in
+ * proper sequence; the runtime type of the returned array is that of
+ * the specified array. If the queue fits in the specified array, it
+ * is returned therein. Otherwise, a new array is allocated with the
+ * runtime type of the specified array and the size of this queue.
+ *
+ * <p>If this queue fits in the specified array with room to spare
+ * (i.e., the array has more elements than this queue), the element in
+ * the array immediately following the end of the queue is set to
+ * <tt>null</tt>.
+ *
+ * <p>Like the {@link #toArray()} method, this method acts as bridge between
+ * array-based and collection-based APIs. Further, this method allows
+ * precise control over the runtime type of the output array, and may,
+ * under certain circumstances, be used to save allocation costs.
+ *
+ * <p>Suppose <tt>x</tt> is a queue known to contain only strings.
+ * The following code can be used to dump the queue into a newly
+ * allocated array of <tt>String</tt>:
+ *
+ * <pre>
+ * String[] y = x.toArray(new String[0]);</pre>
+ *
+ * Note that <tt>toArray(new Object[0])</tt> is identical in function to
+ * <tt>toArray()</tt>.
+ *
+ * @param a the array into which the elements of the queue are to
+ * be stored, if it is big enough; otherwise, a new array of the
+ * same runtime type is allocated for this purpose
+ * @return an array containing all of the elements in this queue
+ * @throws ArrayStoreException if the runtime type of the specified array
+ * is not a supertype of the runtime type of every element in
+ * this queue
+ * @throws NullPointerException if the specified array is null
+ */
+ public Object[] toArray(Object[] a) {
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ int size = count;
+ if (a.length < size)
+ a = (Object[])java.lang.reflect.Array.newInstance
+ (a.getClass().getComponentType(), size);
+
+ int k = 0;
+ for (Node p = head.next; p != null; p = p.next)
+ a[k++] = (Object)p.item;
+ if (a.length > k)
+ a[k] = null;
+ return a;
+ }
+ }
+ }
+
+ public String toString() {
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ return super.toString();
+ }
+ }
+ }
+
+ /**
+ * Atomically removes all of the elements from this queue.
+ * The queue will be empty after this call returns.
+ */
+ public void clear() {
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ head.next = null;
+ assert head.item == null;
+ last = head;
+ int c;
+ synchronized (this) {
+ c = count;
+ count = 0;
+ }
+ if (c == capacity)
+ putLock.notifyAll();
+ }
+ }
+ }
+
+ /**
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public int drainTo(Collection c) {
+ if (c == null)
+ throw new NullPointerException();
+ if (c == this)
+ throw new IllegalArgumentException();
+ Node first;
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ first = head.next;
+ head.next = null;
+ assert head.item == null;
+ last = head;
+ int cold;
+ synchronized (this) {
+ cold = count;
+ count = 0;
+ }
+ if (cold == capacity)
+ putLock.notifyAll();
+ }
+ }
+ // Transfer the elements outside of locks
+ int n = 0;
+ for (Node p = first; p != null; p = p.next) {
+ c.add(p.item);
+ p.item = null;
+ ++n;
+ }
+ return n;
+ }
+
+ /**
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public int drainTo(Collection c, int maxElements) {
+ if (c == null)
+ throw new NullPointerException();
+ if (c == this)
+ throw new IllegalArgumentException();
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ int n = 0;
+ Node p = head.next;
+ while (p != null && n < maxElements) {
+ c.add(p.item);
+ p.item = null;
+ p = p.next;
+ ++n;
+ }
+ if (n != 0) {
+ head.next = p;
+ assert head.item == null;
+ if (p == null)
+ last = head;
+ int cold;
+ synchronized (this) {
+ cold = count;
+ count -= n;
+ }
+ if (cold == capacity)
+ putLock.notifyAll();
+ }
+ return n;
+ }
+ }
+ }
+
+ /**
+ * Returns an iterator over the elements in this queue in proper sequence.
+ * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that
+ * will never throw {@link java.util.ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * @return an iterator over the elements in this queue in proper sequence
+ */
+ public Iterator iterator() {
+ return new Itr();
+ }
+
+ private class Itr implements Iterator {
+ /*
+ * Basic weak-consistent iterator. At all times hold the next
+ * item to hand out so that if hasNext() reports true, we will
+ * still have it to return even if lost race with a take etc.
+ */
+ private Node current;
+ private Node lastRet;
+ private Object currentElement;
+
+ Itr() {
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ current = head.next;
+ if (current != null)
+ currentElement = current.item;
+ }
+ }
+ }
+
+ public boolean hasNext() {
+ return current != null;
+ }
+
+ public Object next() {
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ if (current == null)
+ throw new NoSuchElementException();
+ Object x = currentElement;
+ lastRet = current;
+ current = current.next;
+ if (current != null)
+ currentElement = current.item;
+ return x;
+ }
+ }
+ }
+
+ public void remove() {
+ if (lastRet == null)
+ throw new IllegalStateException();
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ Node node = lastRet;
+ lastRet = null;
+ Node trail = head;
+ Node p = head.next;
+ while (p != null && p != node) {
+ trail = p;
+ p = p.next;
+ }
+ if (p == node) {
+ p.item = null;
+ trail.next = p.next;
+ if (last == p)
+ last = trail;
+ int c;
+ synchronized (this) { c = count--; }
+ if (c == capacity)
+ putLock.notifyAll();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Save the state to a stream (that is, serialize it).
+ *
+ * @serialData The capacity is emitted (int), followed by all of
+ * its elements (each an <tt>Object</tt>) in the proper order,
+ * followed by a null
+ * @param s the stream
+ */
+ private void writeObject(java.io.ObjectOutputStream s)
+ throws java.io.IOException {
+
+ synchronized (putLock) {
+ synchronized (takeLock) {
+ // Write out any hidden stuff, plus capacity
+ s.defaultWriteObject();
+
+ // Write out all elements in the proper order.
+ for (Node p = head.next; p != null; p = p.next)
+ s.writeObject(p.item);
+
+ // Use trailing null as sentinel
+ s.writeObject(null);
+ }
+ }
+ }
+
+ /**
+ * Reconstitute this queue instance from a stream (that is,
+ * deserialize it).
+ * @param s the stream
+ */
+ private void readObject(java.io.ObjectInputStream s)
+ throws java.io.IOException, ClassNotFoundException {
+ // Read in capacity, and any hidden stuff
+ s.defaultReadObject();
+
+ synchronized (this) { count = 0; }
+ last = head = new Node(null);
+
+ // Read in all elements and place in queue
+ for (;;) {
+ Object item = (Object)s.readObject();
+ if (item == null)
+ break;
+ add(item);
+ }
+ }
+
+ private static class SerializableLock implements java.io.Serializable {
+ private final static long serialVersionUID = -8856990691138858668L;
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/Perf.java b/src/actors/scala/actors/threadpool/Perf.java
new file mode 100644
index 0000000000..0f262b444f
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/Perf.java
@@ -0,0 +1,28 @@
+package scala.actors.threadpool;
+
+/**
+ * Compilation stub for pre-1.4.2 JREs. Thanks to it, the whole backport
+ * package compiles and works with 1.4.2 as well as wih earlier JREs, and takes
+ * advantage of native Perf class when running on 1.4.2 while seamlessly
+ * falling back to System.currentTimeMillis() on previous JREs. This class
+ * should NOT be included in the binary distribution of backport.
+ *
+ * @author Dawid Kurzyniec
+ * @version 1.0
+ */
+public final class Perf {
+
+ private static final Perf perf = new Perf();
+
+ public static Perf getPerf() { return perf; }
+
+ private Perf() {}
+
+ public long highResCounter() {
+ return System.currentTimeMillis();
+ }
+
+ public long highResFrequency() {
+ return 1000L;
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/Queue.java b/src/actors/scala/actors/threadpool/Queue.java
new file mode 100644
index 0000000000..f952e9d94c
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/Queue.java
@@ -0,0 +1,191 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+import java.util.Collection;
+
+/**
+ * A collection designed for holding elements prior to processing.
+ * Besides basic {@link java.util.Collection Collection} operations,
+ * queues provide additional insertion, extraction, and inspection
+ * operations. Each of these methods exists in two forms: one throws
+ * an exception if the operation fails, the other returns a special
+ * value (either <tt>null</tt> or <tt>false</tt>, depending on the
+ * operation). The latter form of the insert operation is designed
+ * specifically for use with capacity-restricted <tt>Queue</tt>
+ * implementations; in most implementations, insert operations cannot
+ * fail.
+ *
+ * <p>
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <tr>
+ * <td></td>
+ * <td ALIGN=CENTER><em>Throws exception</em></td>
+ * <td ALIGN=CENTER><em>Returns special value</em></td>
+ * </tr>
+ * <tr>
+ * <td><b>Insert</b></td>
+ * <td>{@link #add add(e)}</td>
+ * <td>{@link #offer offer(e)}</td>
+ * </tr>
+ * <tr>
+ * <td><b>Remove</b></td>
+ * <td>{@link #remove remove()}</td>
+ * <td>{@link #poll poll()}</td>
+ * </tr>
+ * <tr>
+ * <td><b>Examine</b></td>
+ * <td>{@link #element element()}</td>
+ * <td>{@link #peek peek()}</td>
+ * </tr>
+ * </table>
+ *
+ * <p>Queues typically, but do not necessarily, order elements in a
+ * FIFO (first-in-first-out) manner. Among the exceptions are
+ * priority queues, which order elements according to a supplied
+ * comparator, or the elements' natural ordering, and LIFO queues (or
+ * stacks) which order the elements LIFO (last-in-first-out).
+ * Whatever the ordering used, the <em>head</em> of the queue is that
+ * element which would be removed by a call to {@link #remove() } or
+ * {@link #poll()}. In a FIFO queue, all new elements are inserted at
+ * the <em> tail</em> of the queue. Other kinds of queues may use
+ * different placement rules. Every <tt>Queue</tt> implementation
+ * must specify its ordering properties.
+ *
+ * <p>The {@link #offer offer} method inserts an element if possible,
+ * otherwise returning <tt>false</tt>. This differs from the {@link
+ * java.util.Collection#add Collection.add} method, which can fail to
+ * add an element only by throwing an unchecked exception. The
+ * <tt>offer</tt> method is designed for use when failure is a normal,
+ * rather than exceptional occurrence, for example, in fixed-capacity
+ * (or &quot;bounded&quot;) queues.
+ *
+ * <p>The {@link #remove()} and {@link #poll()} methods remove and
+ * return the head of the queue.
+ * Exactly which element is removed from the queue is a
+ * function of the queue's ordering policy, which differs from
+ * implementation to implementation. The <tt>remove()</tt> and
+ * <tt>poll()</tt> methods differ only in their behavior when the
+ * queue is empty: the <tt>remove()</tt> method throws an exception,
+ * while the <tt>poll()</tt> method returns <tt>null</tt>.
+ *
+ * <p>The {@link #element()} and {@link #peek()} methods return, but do
+ * not remove, the head of the queue.
+ *
+ * <p>The <tt>Queue</tt> interface does not define the <i>blocking queue
+ * methods</i>, which are common in concurrent programming. These methods,
+ * which wait for elements to appear or for space to become available, are
+ * defined in the {@link edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue} interface, which
+ * extends this interface.
+ *
+ * <p><tt>Queue</tt> implementations generally do not allow insertion
+ * of <tt>null</tt> elements, although some implementations, such as
+ * {@link LinkedList}, do not prohibit insertion of <tt>null</tt>.
+ * Even in the implementations that permit it, <tt>null</tt> should
+ * not be inserted into a <tt>Queue</tt>, as <tt>null</tt> is also
+ * used as a special return value by the <tt>poll</tt> method to
+ * indicate that the queue contains no elements.
+ *
+ * <p><tt>Queue</tt> implementations generally do not define
+ * element-based versions of methods <tt>equals</tt> and
+ * <tt>hashCode</tt> but instead inherit the identity based versions
+ * from class <tt>Object</tt>, because element-based equality is not
+ * always well-defined for queues with the same elements but different
+ * ordering properties.
+ *
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @see java.util.Collection
+ * @see LinkedList
+ * @see PriorityQueue
+ * @see edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue
+ * @see edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue
+ * @see edu.emory.mathcs.backport.java.util.concurrent.ArrayBlockingQueue
+ * @see edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue
+ * @see edu.emory.mathcs.backport.java.util.concurrent.PriorityBlockingQueue
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Queue extends Collection {
+ /**
+ * Inserts the specified element into this queue if it is possible to do so
+ * immediately without violating capacity restrictions, returning
+ * <tt>true</tt> upon success and throwing an <tt>IllegalStateException</tt>
+ * if no space is currently available.
+ *
+ * @param e the element to add
+ * @return <tt>true</tt> (as specified by {@link Collection#add})
+ * @throws IllegalStateException if the element cannot be added at this
+ * time due to capacity restrictions
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this queue
+ * @throws NullPointerException if the specified element is null and
+ * this queue not permit null elements
+ * @throws IllegalArgumentException if some property of this element
+ * prevents it from being added to this queue
+ */
+ boolean add(Object e);
+
+ /**
+ * Inserts the specified element into this queue if it is possible to do
+ * so immediately without violating capacity restrictions.
+ * When using a capacity-restricted queue, this method is generally
+ * preferable to {@link #add}, which can fail to insert an element only
+ * by throwing an exception.
+ *
+ * @param e the element to add
+ * @return <tt>true</tt> if the element was added to this queue, else
+ * <tt>false</tt>
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this queue
+ * @throws NullPointerException if the specified element is null and
+ * this queue does not permit null elements
+ * @throws IllegalArgumentException if some property of this element
+ * prevents it from being added to this queue
+ */
+ boolean offer(Object e);
+
+ /**
+ * Retrieves and removes the head of this queue. This method differs
+ * from {@link #poll poll} only in that it throws an exception if this
+ * queue is empty.
+ * is empty.
+ *
+ * @return the head of this queue
+ * @throws NoSuchElementException if this queue is empty
+ */
+ Object remove();
+
+ /**
+ * Retrieves and removes the head of this queue,
+ * or returns <tt>null</tt> if this queue is empty.
+ *
+ * @return the head of this queue, or <tt>null</tt> if this queue is empty
+ */
+ Object poll();
+
+ /**
+ * Retrieves, but does not remove, the head of this queue. This method
+ * differs from {@link #peek peek} only in that it throws an exception
+ * if this queue is empty.
+ *
+ * @return the head of this queue
+ * @throws NoSuchElementException if this queue is empty
+ */
+ Object element();
+
+ /**
+ * Retrieves, but does not remove, the head of this queue,
+ * or returns <tt>null</tt> if this queue is empty.
+ *
+ * @return the head of this queue, or <tt>null</tt> if this queue is empty
+ */
+ Object peek();
+}
diff --git a/src/actors/scala/actors/threadpool/RejectedExecutionException.java b/src/actors/scala/actors/threadpool/RejectedExecutionException.java
new file mode 100644
index 0000000000..1b61d35974
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/RejectedExecutionException.java
@@ -0,0 +1,62 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * Exception thrown by an {@link Executor} when a task cannot be
+ * accepted for execution.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class RejectedExecutionException extends RuntimeException {
+ private static final long serialVersionUID = -375805702767069545L;
+
+ /**
+ * Constructs a <tt>RejectedExecutionException</tt> with no detail message.
+ * The cause is not initialized, and may subsequently be
+ * initialized by a call to {@link #initCause(Throwable) initCause}.
+ */
+ public RejectedExecutionException() { }
+
+ /**
+ * Constructs a <tt>RejectedExecutionException</tt> with the
+ * specified detail message. The cause is not initialized, and may
+ * subsequently be initialized by a call to {@link
+ * #initCause(Throwable) initCause}.
+ *
+ * @param message the detail message
+ */
+ public RejectedExecutionException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a <tt>RejectedExecutionException</tt> with the
+ * specified detail message and cause.
+ *
+ * @param message the detail message
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method)
+ */
+ public RejectedExecutionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a <tt>RejectedExecutionException</tt> with the
+ * specified cause. The detail message is set to: <pre> (cause ==
+ * null ? null : cause.toString())</pre> (which typically contains
+ * the class and detail message of <tt>cause</tt>).
+ *
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method)
+ */
+ public RejectedExecutionException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/RejectedExecutionHandler.java b/src/actors/scala/actors/threadpool/RejectedExecutionHandler.java
new file mode 100644
index 0000000000..86e6d18a40
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/RejectedExecutionHandler.java
@@ -0,0 +1,34 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * A handler for tasks that cannot be executed by a {@link ThreadPoolExecutor}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface RejectedExecutionHandler {
+
+ /**
+ * Method that may be invoked by a {@link ThreadPoolExecutor} when
+ * {@link ThreadPoolExecutor#execute execute} cannot accept a
+ * task. This may occur when no more threads or queue slots are
+ * available because their bounds would be exceeded, or upon
+ * shutdown of the Executor.
+ *
+ * <p>In the absence of other alternatives, the method may throw
+ * an unchecked {@link RejectedExecutionException}, which will be
+ * propagated to the caller of {@code execute}.
+ *
+ * @param r the runnable task requested to be executed
+ * @param executor the executor attempting to execute this task
+ * @throws RejectedExecutionException if there is no remedy
+ */
+
+ void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
+}
diff --git a/src/actors/scala/actors/threadpool/RunnableFuture.java b/src/actors/scala/actors/threadpool/RunnableFuture.java
new file mode 100644
index 0000000000..bbd63a2d92
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/RunnableFuture.java
@@ -0,0 +1,24 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * A {@link Future} that is {@link Runnable}. Successful execution of
+ * the <tt>run</tt> method causes completion of the <tt>Future</tt>
+ * and allows access to its results.
+ * @see FutureTask
+ * @see Executor
+ * @since 1.6
+ * @author Doug Lea
+ */
+public interface RunnableFuture extends Runnable, Future {
+ /**
+ * Sets this Future to the result of its computation
+ * unless it has been cancelled.
+ */
+ void run();
+}
diff --git a/src/actors/scala/actors/threadpool/SynchronousQueue.java b/src/actors/scala/actors/threadpool/SynchronousQueue.java
new file mode 100644
index 0000000000..739b0043dd
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/SynchronousQueue.java
@@ -0,0 +1,833 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+import scala.actors.threadpool.locks.*;
+//import edu.emory.mathcs.backport.java.util.*;
+import java.util.Collection;
+import java.util.Iterator;
+import scala.actors.threadpool.helpers.Utils;
+import java.util.NoSuchElementException;
+
+/**
+ * A {@linkplain BlockingQueue blocking queue} in which each insert
+ * operation must wait for a corresponding remove operation by another
+ * thread, and vice versa. A synchronous queue does not have any
+ * internal capacity, not even a capacity of one. You cannot
+ * <tt>peek</tt> at a synchronous queue because an element is only
+ * present when you try to remove it; you cannot insert an element
+ * (using any method) unless another thread is trying to remove it;
+ * you cannot iterate as there is nothing to iterate. The
+ * <em>head</em> of the queue is the element that the first queued
+ * inserting thread is trying to add to the queue; if there is no such
+ * queued thread then no element is available for removal and
+ * <tt>poll()</tt> will return <tt>null</tt>. For purposes of other
+ * <tt>Collection</tt> methods (for example <tt>contains</tt>), a
+ * <tt>SynchronousQueue</tt> acts as an empty collection. This queue
+ * does not permit <tt>null</tt> elements.
+ *
+ * <p>Synchronous queues are similar to rendezvous channels used in
+ * CSP and Ada. They are well suited for handoff designs, in which an
+ * object running in one thread must sync up with an object running
+ * in another thread in order to hand it some information, event, or
+ * task.
+ *
+ * <p> This class supports an optional fairness policy for ordering
+ * waiting producer and consumer threads. By default, this ordering
+ * is not guaranteed. However, a queue constructed with fairness set
+ * to <tt>true</tt> grants threads access in FIFO order. Fairness
+ * generally decreases throughput but reduces variability and avoids
+ * starvation.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class SynchronousQueue extends AbstractQueue
+ implements BlockingQueue, java.io.Serializable {
+ private static final long serialVersionUID = -3223113410248163686L;
+
+ /*
+ This implementation divides actions into two cases for puts:
+
+ * An arriving producer that does not already have a waiting consumer
+ creates a node holding item, and then waits for a consumer to take it.
+ * An arriving producer that does already have a waiting consumer fills
+ the slot node created by the consumer, and notifies it to continue.
+
+ And symmetrically, two for takes:
+
+ * An arriving consumer that does not already have a waiting producer
+ creates an empty slot node, and then waits for a producer to fill it.
+ * An arriving consumer that does already have a waiting producer takes
+ item from the node created by the producer, and notifies it to continue.
+
+ When a put or take waiting for the actions of its counterpart
+ aborts due to interruption or timeout, it marks the node
+ it created as "CANCELLED", which causes its counterpart to retry
+ the entire put or take sequence.
+
+ This requires keeping two simple queues, waitingProducers and
+ waitingConsumers. Each of these can be FIFO (preserves fairness)
+ or LIFO (improves throughput).
+ */
+
+ /** Lock protecting both wait queues */
+ private final ReentrantLock qlock;
+ /** Queue holding waiting puts */
+ private final WaitQueue waitingProducers;
+ /** Queue holding waiting takes */
+ private final WaitQueue waitingConsumers;
+
+ /**
+ * Creates a <tt>SynchronousQueue</tt> with nonfair access policy.
+ */
+ public SynchronousQueue() {
+ this(false);
+ }
+
+ /**
+ * Creates a <tt>SynchronousQueue</tt> with specified fairness policy.
+ * @param fair if true, threads contend in FIFO order for access;
+ * otherwise the order is unspecified.
+ */
+ public SynchronousQueue(boolean fair) {
+ if (fair) {
+ qlock = new ReentrantLock(true);
+ waitingProducers = new FifoWaitQueue();
+ waitingConsumers = new FifoWaitQueue();
+ }
+ else {
+ qlock = new ReentrantLock();
+ waitingProducers = new LifoWaitQueue();
+ waitingConsumers = new LifoWaitQueue();
+ }
+ }
+
+ /**
+ * Queue to hold waiting puts/takes; specialized to Fifo/Lifo below.
+ * These queues have all transient fields, but are serializable
+ * in order to recover fairness settings when deserialized.
+ */
+ static abstract class WaitQueue implements java.io.Serializable {
+ /** Creates, adds, and returns node for x. */
+ abstract Node enq(Object x);
+ /** Removes and returns node, or null if empty. */
+ abstract Node deq();
+ /** Removes a cancelled node to avoid garbage retention. */
+ abstract void unlink(Node node);
+ /** Returns true if a cancelled node might be on queue. */
+ abstract boolean shouldUnlink(Node node);
+ }
+
+ /**
+ * FIFO queue to hold waiting puts/takes.
+ */
+ static final class FifoWaitQueue extends WaitQueue implements java.io.Serializable {
+ private static final long serialVersionUID = -3623113410248163686L;
+ private transient Node head;
+ private transient Node last;
+
+ Node enq(Object x) {
+ Node p = new Node(x);
+ if (last == null)
+ last = head = p;
+ else
+ last = last.next = p;
+ return p;
+ }
+
+ Node deq() {
+ Node p = head;
+ if (p != null) {
+ if ((head = p.next) == null)
+ last = null;
+ p.next = null;
+ }
+ return p;
+ }
+
+ boolean shouldUnlink(Node node) {
+ return (node == last || node.next != null);
+ }
+
+ void unlink(Node node) {
+ Node p = head;
+ Node trail = null;
+ while (p != null) {
+ if (p == node) {
+ Node next = p.next;
+ if (trail == null)
+ head = next;
+ else
+ trail.next = next;
+ if (last == node)
+ last = trail;
+ break;
+ }
+ trail = p;
+ p = p.next;
+ }
+ }
+ }
+
+ /**
+ * LIFO queue to hold waiting puts/takes.
+ */
+ static final class LifoWaitQueue extends WaitQueue implements java.io.Serializable {
+ private static final long serialVersionUID = -3633113410248163686L;
+ private transient Node head;
+
+ Node enq(Object x) {
+ return head = new Node(x, head);
+ }
+
+ Node deq() {
+ Node p = head;
+ if (p != null) {
+ head = p.next;
+ p.next = null;
+ }
+ return p;
+ }
+
+ boolean shouldUnlink(Node node) {
+ // Return false if already dequeued or is bottom node (in which
+ // case we might retain at most one garbage node)
+ return (node == head || node.next != null);
+ }
+
+ void unlink(Node node) {
+ Node p = head;
+ Node trail = null;
+ while (p != null) {
+ if (p == node) {
+ Node next = p.next;
+ if (trail == null)
+ head = next;
+ else
+ trail.next = next;
+ break;
+ }
+ trail = p;
+ p = p.next;
+ }
+ }
+ }
+
+ /**
+ * Unlinks the given node from consumer queue. Called by cancelled
+ * (timeout, interrupt) waiters to avoid garbage retention in the
+ * absence of producers.
+ */
+ private void unlinkCancelledConsumer(Node node) {
+ // Use a form of double-check to avoid unnecessary locking and
+ // traversal. The first check outside lock might
+ // conservatively report true.
+ if (waitingConsumers.shouldUnlink(node)) {
+ qlock.lock();
+ try {
+ if (waitingConsumers.shouldUnlink(node))
+ waitingConsumers.unlink(node);
+ } finally {
+ qlock.unlock();
+ }
+ }
+ }
+
+ /**
+ * Unlinks the given node from producer queue. Symmetric
+ * to unlinkCancelledConsumer.
+ */
+ private void unlinkCancelledProducer(Node node) {
+ if (waitingProducers.shouldUnlink(node)) {
+ qlock.lock();
+ try {
+ if (waitingProducers.shouldUnlink(node))
+ waitingProducers.unlink(node);
+ } finally {
+ qlock.unlock();
+ }
+ }
+ }
+
+ /**
+ * Nodes each maintain an item and handle waits and signals for
+ * getting and setting it. The class extends
+ * AbstractQueuedSynchronizer to manage blocking, using AQS state
+ * 0 for waiting, 1 for ack, -1 for cancelled.
+ */
+ static final class Node implements java.io.Serializable {
+ private static final long serialVersionUID = -3223113410248163686L;
+
+ /** Synchronization state value representing that node acked */
+ private static final int ACK = 1;
+ /** Synchronization state value representing that node cancelled */
+ private static final int CANCEL = -1;
+
+ int state = 0;
+
+ /** The item being transferred */
+ Object item;
+ /** Next node in wait queue */
+ Node next;
+
+ /** Creates a node with initial item */
+ Node(Object x) { item = x; }
+
+ /** Creates a node with initial item and next */
+ Node(Object x, Node n) { item = x; next = n; }
+
+ /**
+ * Takes item and nulls out field (for sake of GC)
+ *
+ * PRE: lock owned
+ */
+ private Object extract() {
+ Object x = item;
+ item = null;
+ return x;
+ }
+
+ /**
+ * Tries to cancel on interrupt; if so rethrowing,
+ * else setting interrupt state
+ *
+ * PRE: lock owned
+ */
+ private void checkCancellationOnInterrupt(InterruptedException ie)
+ throws InterruptedException
+ {
+ if (state == 0) {
+ state = CANCEL;
+ notify();
+ throw ie;
+ }
+ Thread.currentThread().interrupt();
+ }
+
+ /**
+ * Fills in the slot created by the consumer and signal consumer to
+ * continue.
+ */
+ synchronized boolean setItem(Object x) {
+ if (state != 0) return false;
+ item = x;
+ state = ACK;
+ notify();
+ return true;
+ }
+
+ /**
+ * Removes item from slot created by producer and signal producer
+ * to continue.
+ */
+ synchronized Object getItem() {
+ if (state != 0) return null;
+ state = ACK;
+ notify();
+ return extract();
+ }
+
+ /**
+ * Waits for a consumer to take item placed by producer.
+ */
+ synchronized void waitForTake() throws InterruptedException {
+ try {
+ while (state == 0) wait();
+ } catch (InterruptedException ie) {
+ checkCancellationOnInterrupt(ie);
+ }
+ }
+
+ /**
+ * Waits for a producer to put item placed by consumer.
+ */
+ synchronized Object waitForPut() throws InterruptedException {
+ try {
+ while (state == 0) wait();
+ } catch (InterruptedException ie) {
+ checkCancellationOnInterrupt(ie);
+ }
+ return extract();
+ }
+
+ private boolean attempt(long nanos) throws InterruptedException {
+ if (state != 0) return true;
+ if (nanos <= 0) {
+ state = CANCEL;
+ notify();
+ return false;
+ }
+ long deadline = Utils.nanoTime() + nanos;
+ while (true) {
+ TimeUnit.NANOSECONDS.timedWait(this, nanos);
+ if (state != 0) return true;
+ nanos = deadline - Utils.nanoTime();
+ if (nanos <= 0) {
+ state = CANCEL;
+ notify();
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Waits for a consumer to take item placed by producer or time out.
+ */
+ synchronized boolean waitForTake(long nanos) throws InterruptedException {
+ try {
+ if (!attempt(nanos)) return false;
+ } catch (InterruptedException ie) {
+ checkCancellationOnInterrupt(ie);
+ }
+ return true;
+ }
+
+ /**
+ * Waits for a producer to put item placed by consumer, or time out.
+ */
+ synchronized Object waitForPut(long nanos) throws InterruptedException {
+ try {
+ if (!attempt(nanos)) return null;
+ } catch (InterruptedException ie) {
+ checkCancellationOnInterrupt(ie);
+ }
+ return extract();
+ }
+ }
+
+ /**
+ * Adds the specified element to this queue, waiting if necessary for
+ * another thread to receive it.
+ *
+ * @throws InterruptedException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public void put(Object e) throws InterruptedException {
+ if (e == null) throw new NullPointerException();
+ final ReentrantLock qlock = this.qlock;
+
+ for (;;) {
+ Node node;
+ boolean mustWait;
+ if (Thread.interrupted()) throw new InterruptedException();
+ qlock.lock();
+ try {
+ node = waitingConsumers.deq();
+ if ( (mustWait = (node == null)) )
+ node = waitingProducers.enq(e);
+ } finally {
+ qlock.unlock();
+ }
+
+ if (mustWait) {
+ try {
+ node.waitForTake();
+ return;
+ } catch (InterruptedException ex) {
+ unlinkCancelledProducer(node);
+ throw ex;
+ }
+ }
+
+ else if (node.setItem(e))
+ return;
+
+ // else consumer cancelled, so retry
+ }
+ }
+
+ /**
+ * Inserts the specified element into this queue, waiting if necessary
+ * up to the specified wait time for another thread to receive it.
+ *
+ * @return <tt>true</tt> if successful, or <tt>false</tt> if the
+ * specified waiting time elapses before a consumer appears.
+ * @throws InterruptedException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public boolean offer(Object e, long timeout, TimeUnit unit) throws InterruptedException {
+ if (e == null) throw new NullPointerException();
+ long nanos = unit.toNanos(timeout);
+ final ReentrantLock qlock = this.qlock;
+ for (;;) {
+ Node node;
+ boolean mustWait;
+ if (Thread.interrupted()) throw new InterruptedException();
+ qlock.lock();
+ try {
+ node = waitingConsumers.deq();
+ if ( (mustWait = (node == null)) )
+ node = waitingProducers.enq(e);
+ } finally {
+ qlock.unlock();
+ }
+
+ if (mustWait) {
+ try {
+ boolean x = node.waitForTake(nanos);
+ if (!x)
+ unlinkCancelledProducer(node);
+ return x;
+ } catch (InterruptedException ex) {
+ unlinkCancelledProducer(node);
+ throw ex;
+ }
+ }
+
+ else if (node.setItem(e))
+ return true;
+
+ // else consumer cancelled, so retry
+ }
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, waiting if necessary
+ * for another thread to insert it.
+ *
+ * @return the head of this queue
+ * @throws InterruptedException {@inheritDoc}
+ */
+ public Object take() throws InterruptedException {
+ final ReentrantLock qlock = this.qlock;
+ for (;;) {
+ Node node;
+ boolean mustWait;
+
+ if (Thread.interrupted()) throw new InterruptedException();
+ qlock.lock();
+ try {
+ node = waitingProducers.deq();
+ if ( (mustWait = (node == null)) )
+ node = waitingConsumers.enq(null);
+ } finally {
+ qlock.unlock();
+ }
+
+ if (mustWait) {
+ try {
+ Object x = node.waitForPut();
+ return (Object)x;
+ } catch (InterruptedException ex) {
+ unlinkCancelledConsumer(node);
+ throw ex;
+ }
+ }
+ else {
+ Object x = node.getItem();
+ if (x != null)
+ return (Object)x;
+ // else cancelled, so retry
+ }
+ }
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, waiting
+ * if necessary up to the specified wait time, for another thread
+ * to insert it.
+ *
+ * @return the head of this queue, or <tt>null</tt> if the
+ * specified waiting time elapses before an element is present.
+ * @throws InterruptedException {@inheritDoc}
+ */
+ public Object poll(long timeout, TimeUnit unit) throws InterruptedException {
+ long nanos = unit.toNanos(timeout);
+ final ReentrantLock qlock = this.qlock;
+
+ for (;;) {
+ Node node;
+ boolean mustWait;
+
+ if (Thread.interrupted()) throw new InterruptedException();
+ qlock.lock();
+ try {
+ node = waitingProducers.deq();
+ if ( (mustWait = (node == null)) )
+ node = waitingConsumers.enq(null);
+ } finally {
+ qlock.unlock();
+ }
+
+ if (mustWait) {
+ try {
+ Object x = node.waitForPut(nanos);
+ if (x == null)
+ unlinkCancelledConsumer(node);
+ return (Object)x;
+ } catch (InterruptedException ex) {
+ unlinkCancelledConsumer(node);
+ throw ex;
+ }
+ }
+ else {
+ Object x = node.getItem();
+ if (x != null)
+ return (Object)x;
+ // else cancelled, so retry
+ }
+ }
+ }
+
+ // Untimed nonblocking versions
+
+ /**
+ * Inserts the specified element into this queue, if another thread is
+ * waiting to receive it.
+ *
+ * @param e the element to add
+ * @return <tt>true</tt> if the element was added to this queue, else
+ * <tt>false</tt>
+ * @throws NullPointerException if the specified element is null
+ */
+ public boolean offer(Object e) {
+ if (e == null) throw new NullPointerException();
+ final ReentrantLock qlock = this.qlock;
+
+ for (;;) {
+ Node node;
+ qlock.lock();
+ try {
+ node = waitingConsumers.deq();
+ } finally {
+ qlock.unlock();
+ }
+ if (node == null)
+ return false;
+
+ else if (node.setItem(e))
+ return true;
+ // else retry
+ }
+ }
+
+ /**
+ * Retrieves and removes the head of this queue, if another thread
+ * is currently making an element available.
+ *
+ * @return the head of this queue, or <tt>null</tt> if no
+ * element is available.
+ */
+ public Object poll() {
+ final ReentrantLock qlock = this.qlock;
+ for (;;) {
+ Node node;
+ qlock.lock();
+ try {
+ node = waitingProducers.deq();
+ } finally {
+ qlock.unlock();
+ }
+ if (node == null)
+ return null;
+
+ else {
+ Object x = node.getItem();
+ if (x != null)
+ return (Object)x;
+ // else retry
+ }
+ }
+ }
+
+ /**
+ * Always returns <tt>true</tt>.
+ * A <tt>SynchronousQueue</tt> has no internal capacity.
+ *
+ * @return <tt>true</tt>
+ */
+ public boolean isEmpty() {
+ return true;
+ }
+
+ /**
+ * Always returns zero.
+ * A <tt>SynchronousQueue</tt> has no internal capacity.
+ *
+ * @return zero
+ */
+ public int size() {
+ return 0;
+ }
+
+ /**
+ * Always returns zero.
+ * A <tt>SynchronousQueue</tt> has no internal capacity.
+ *
+ * @return zero
+ */
+ public int remainingCapacity() {
+ return 0;
+ }
+
+ /**
+ * Does nothing.
+ * A <tt>SynchronousQueue</tt> has no internal capacity.
+ */
+ public void clear() {}
+
+ /**
+ * Always returns <tt>false</tt>.
+ * A <tt>SynchronousQueue</tt> has no internal capacity.
+ *
+ * @param o object to be checked for containment in this queue
+ * @return <tt>false</tt>
+ */
+ public boolean contains(Object o) {
+ return false;
+ }
+
+ /**
+ * Always returns <tt>false</tt>.
+ * A <tt>SynchronousQueue</tt> has no internal capacity.
+ *
+ * @param o the element to remove
+ * @return <tt>false</tt>
+ */
+ public boolean remove(Object o) {
+ return false;
+ }
+
+ /**
+ * Returns <tt>false</tt> unless the given collection is empty.
+ * A <tt>SynchronousQueue</tt> has no internal capacity.
+ *
+ * @param c the collection
+ * @return <tt>false</tt> unless the given collection is empty
+ * @throws NullPointerException if the specified collection is null
+ */
+ public boolean containsAll(Collection c) {
+ return c.isEmpty();
+ }
+
+ /**
+ * Always returns <tt>false</tt>.
+ * A <tt>SynchronousQueue</tt> has no internal capacity.
+ *
+ * @param c the collection
+ * @return <tt>false</tt>
+ */
+ public boolean removeAll(Collection c) {
+ return false;
+ }
+
+ /**
+ * Always returns <tt>false</tt>.
+ * A <tt>SynchronousQueue</tt> has no internal capacity.
+ *
+ * @param c the collection
+ * @return <tt>false</tt>
+ */
+ public boolean retainAll(Collection c) {
+ return false;
+ }
+
+ /**
+ * Always returns <tt>null</tt>.
+ * A <tt>SynchronousQueue</tt> does not return elements
+ * unless actively waited on.
+ *
+ * @return <tt>null</tt>
+ */
+ public Object peek() {
+ return null;
+ }
+
+
+ static class EmptyIterator implements Iterator {
+ public boolean hasNext() {
+ return false;
+ }
+ public Object next() {
+ throw new NoSuchElementException();
+ }
+ public void remove() {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * Returns an empty iterator in which <tt>hasNext</tt> always returns
+ * <tt>false</tt>.
+ *
+ * @return an empty iterator
+ */
+ public Iterator iterator() {
+ return new EmptyIterator();
+ }
+
+
+ /**
+ * Returns a zero-length array.
+ * @return a zero-length array
+ */
+ public Object[] toArray() {
+ return new Object[0];
+ }
+
+ /**
+ * Sets the zeroeth element of the specified array to <tt>null</tt>
+ * (if the array has non-zero length) and returns it.
+ *
+ * @param a the array
+ * @return the specified array
+ * @throws NullPointerException if the specified array is null
+ */
+ public Object[] toArray(Object[] a) {
+ if (a.length > 0)
+ a[0] = null;
+ return a;
+ }
+
+ /**
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public int drainTo(Collection c) {
+ if (c == null)
+ throw new NullPointerException();
+ if (c == this)
+ throw new IllegalArgumentException();
+ int n = 0;
+ Object e;
+ while ( (e = poll()) != null) {
+ c.add(e);
+ ++n;
+ }
+ return n;
+ }
+
+ /**
+ * @throws UnsupportedOperationException {@inheritDoc}
+ * @throws ClassCastException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ * @throws IllegalArgumentException {@inheritDoc}
+ */
+ public int drainTo(Collection c, int maxElements) {
+ if (c == null)
+ throw new NullPointerException();
+ if (c == this)
+ throw new IllegalArgumentException();
+ int n = 0;
+ Object e;
+ while (n < maxElements && (e = poll()) != null) {
+ c.add(e);
+ ++n;
+ }
+ return n;
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/ThreadFactory.java b/src/actors/scala/actors/threadpool/ThreadFactory.java
new file mode 100644
index 0000000000..ed6e90ccaa
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/ThreadFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * An object that creates new threads on demand. Using thread factories
+ * removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread},
+ * enabling applications to use special thread subclasses, priorities, etc.
+ *
+ * <p>
+ * The simplest implementation of this interface is just:
+ * <pre>
+ * class SimpleThreadFactory implements ThreadFactory {
+ * public Thread newThread(Runnable r) {
+ * return new Thread(r);
+ * }
+ * }
+ * </pre>
+ *
+ * The {@link Executors#defaultThreadFactory} method provides a more
+ * useful simple implementation, that sets the created thread context
+ * to known values before returning it.
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ThreadFactory {
+
+ /**
+ * Constructs a new {@code Thread}. Implementations may also initialize
+ * priority, name, daemon status, {@code ThreadGroup}, etc.
+ *
+ * @param r a runnable to be executed by new thread instance
+ * @return constructed thread, or {@code null} if the request to
+ * create a thread is rejected
+ */
+ Thread newThread(Runnable r);
+}
diff --git a/src/actors/scala/actors/threadpool/ThreadPoolExecutor.java b/src/actors/scala/actors/threadpool/ThreadPoolExecutor.java
new file mode 100644
index 0000000000..f41b2790b6
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/ThreadPoolExecutor.java
@@ -0,0 +1,1968 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+import scala.actors.threadpool.locks.*;
+import scala.actors.threadpool.helpers.Utils;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+
+/**
+ * An {@link ExecutorService} that executes each submitted task using
+ * one of possibly several pooled threads, normally configured
+ * using {@link Executors} factory methods.
+ *
+ * <p>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.
+ *
+ * <p>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:
+ *
+ * <dl>
+ *
+ * <dt>Core and maximum pool sizes</dt>
+ *
+ * <dd>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}, 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}. </dd>
+ *
+ * <dt>On-demand construction</dt>
+ *
+ * <dd> 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. </dd>
+ *
+ * <dt>Creating new threads</dt>
+ *
+ * <dd>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.</dd>
+ *
+ * <dt>Keep-alive times</dt>
+ *
+ * <dd>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}). 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}. 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 corePoolSizeThreads. 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. </dd>
+ *
+ * <dt>Queuing</dt>
+ *
+ * <dd>Any {@link BlockingQueue} may be used to transfer and hold
+ * submitted tasks. The use of this queue interacts with pool sizing:
+ *
+ * <ul>
+ *
+ * <li> If fewer than corePoolSize threads are running, the Executor
+ * always prefers adding a new thread
+ * rather than queuing.</li>
+ *
+ * <li> If corePoolSize or more threads are running, the Executor
+ * always prefers queuing a request rather than adding a new
+ * thread.</li>
+ *
+ * <li> If a request cannot be queued, a new thread is created unless
+ * this would exceed maximumPoolSize, in which case, the task will be
+ * rejected.</li>
+ *
+ * </ul>
+ *
+ * There are three general strategies for queuing:
+ * <ol>
+ *
+ * <li> <em> Direct handoffs.</em> 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. </li>
+ *
+ * <li><em> Unbounded queues.</em> 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. </li>
+ *
+ * <li><em>Bounded queues.</em> 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. </li>
+ *
+ * </ol>
+ *
+ * </dd>
+ *
+ * <dt>Rejected tasks</dt>
+ *
+ * <dd> New tasks submitted in method {@link #execute} will be
+ * <em>rejected</em> 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} method of its {@link
+ * RejectedExecutionHandler}. Four predefined handler policies are
+ * provided:
+ *
+ * <ol>
+ *
+ * <li> In the default {@link ThreadPoolExecutor.AbortPolicy}, the
+ * handler throws a runtime {@link RejectedExecutionException} upon
+ * rejection. </li>
+ *
+ * <li> In {@link ThreadPoolExecutor.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. </li>
+ *
+ * <li> In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
+ * cannot be executed is simply dropped. </li>
+ *
+ * <li>In {@link ThreadPoolExecutor.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.) </li>
+ *
+ * </ol>
+ *
+ * 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. </dd>
+ *
+ * <dt>Hook methods</dt>
+ *
+ * <dd>This class provides {@code protected} overridable {@link
+ * #beforeExecute} and {@link #afterExecute} 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.
+ *
+ * <p>If hook or callback methods throw exceptions, internal worker
+ * threads may in turn fail and abruptly terminate.</dd>
+ *
+ * <dt>Queue maintenance</dt>
+ *
+ * <dd> 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} and {@link #purge} are available to assist in
+ * storage reclamation when large numbers of queued tasks become
+ * cancelled.</dd>
+ *
+ * <dt>Finalization</dt>
+ *
+ * <dd> A pool that is no longer referenced in a program <em>AND</em>
+ * 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)}. </dd>
+ *
+ * </dl>
+ *
+ * <p> <b>Extension example</b>. 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:
+ *
+ * <pre> {@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();
+ * }
+ * }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ThreadPoolExecutor extends AbstractExecutorService {
+ /**
+ * The main pool control state, ctl, is an atomic integer packing
+ * two conceptual fields
+ * workerCount, indicating the effective number of threads
+ * runState, indicating whether running, shutting down etc
+ *
+ * In order to pack them into one int, we limit workerCount to
+ * (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2
+ * billion) otherwise representable. If this is ever an issue in
+ * the future, the variable can be changed to be an AtomicLong,
+ * and the shift/mask constants below adjusted. But until the need
+ * arises, this code is a bit faster and simpler using an int.
+ *
+ * The workerCount is the number of workers that have been
+ * permitted to start and not permitted to stop. The value may be
+ * transiently different from the actual number of live threads,
+ * for example when a ThreadFactory fails to create a thread when
+ * asked, and when exiting threads are still performing
+ * bookkeeping before terminating. The user-visible pool size is
+ * reported as the current size of the workers set.
+ *
+ * The runState provides the main lifecyle control, taking on values:
+ *
+ * RUNNING: Accept new tasks and process queued tasks
+ * SHUTDOWN: Don't accept new tasks, but process queued tasks
+ * STOP: Don't accept new tasks, don't process queued tasks,
+ * and interrupt in-progress tasks
+ * TIDYING: All tasks have terminated, workerCount is zero,
+ * the thread transitioning to state TIDYING
+ * will run the terminated() hook method
+ * TERMINATED: terminated() has completed
+ *
+ * The numerical order among these values matters, to allow
+ * ordered comparisons. The runState monotonically increases over
+ * time, but need not hit each state. The transitions are:
+ *
+ * RUNNING -> SHUTDOWN
+ * On invocation of shutdown(), perhaps implicitly in finalize()
+ * (RUNNING or SHUTDOWN) -> STOP
+ * On invocation of shutdownNow()
+ * SHUTDOWN -> TIDYING
+ * When both queue and pool are empty
+ * STOP -> TIDYING
+ * When pool is empty
+ * TIDYING -> TERMINATED
+ * When the terminated() hook method has completed
+ *
+ * Threads waiting in awaitTermination() will return when the
+ * state reaches TERMINATED.
+ *
+ * Detecting the transition from SHUTDOWN to TIDYING is less
+ * straightforward than you'd like because the queue may become
+ * empty after non-empty and vice versa during SHUTDOWN state, but
+ * we can only terminate if, after seeing that it is empty, we see
+ * that workerCount is 0 (which sometimes entails a recheck -- see
+ * below).
+ */
+ private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
+ private static final int COUNT_BITS = 29; // Integer.SIZE - 3;
+ private static final int CAPACITY = (1 << COUNT_BITS) - 1;
+
+ // runState is stored in the high-order bits
+ private static final int RUNNING = -1 << COUNT_BITS;
+ private static final int SHUTDOWN = 0 << COUNT_BITS;
+ private static final int STOP = 1 << COUNT_BITS;
+ private static final int TIDYING = 2 << COUNT_BITS;
+ private static final int TERMINATED = 3 << COUNT_BITS;
+
+ // Packing and unpacking ctl
+ private static int runStateOf(int c) { return c & ~CAPACITY; }
+ private static int workerCountOf(int c) { return c & CAPACITY; }
+ private static int ctlOf(int rs, int wc) { return rs | wc; }
+
+ /*
+ * Bit field accessors that don't require unpacking ctl.
+ * These depend on the bit layout and on workerCount being never negative.
+ */
+
+ private static boolean runStateLessThan(int c, int s) {
+ return c < s;
+ }
+
+ private static boolean runStateAtLeast(int c, int s) {
+ return c >= s;
+ }
+
+ private static boolean isRunning(int c) {
+ return c < SHUTDOWN;
+ }
+
+ /**
+ * Attempt to CAS-increment the workerCount field of ctl.
+ */
+ private boolean compareAndIncrementWorkerCount(int expect) {
+ return ctl.compareAndSet(expect, expect + 1);
+ }
+
+ /**
+ * Attempt to CAS-decrement the workerCount field of ctl.
+ */
+ private boolean compareAndDecrementWorkerCount(int expect) {
+ return ctl.compareAndSet(expect, expect - 1);
+ }
+
+ /**
+ * Decrements the workerCount field of ctl. This is called only on
+ * abrupt termination of a thread (see processWorkerExit). Other
+ * decrements are performed within getTask.
+ */
+ private void decrementWorkerCount() {
+ do {} while (! compareAndDecrementWorkerCount(ctl.get()));
+ }
+
+ /**
+ * The queue used for holding tasks and handing off to worker
+ * threads. We do not require that workQueue.poll() returning
+ * null necessarily means that workQueue.isEmpty(), so rely
+ * solely on isEmpty to see if the queue is empty (which we must
+ * do for example when deciding whether to transition from
+ * SHUTDOWN to TIDYING). This accommodates special-purpose
+ * queues such as DelayQueues for which poll() is allowed to
+ * return null even if it may later return non-null when delays
+ * expire.
+ */
+ private final BlockingQueue workQueue;
+
+ // TODO: DK: mainLock is used in lock(); try { ... } finally { unlock(); }
+ // Consider replacing with synchronized {} if performance reasons exist
+ /**
+ * Lock held on access to workers set and related bookkeeping.
+ * While we could use a concurrent set of some sort, it turns out
+ * to be generally preferable to use a lock. Among the reasons is
+ * that this serializes interruptIdleWorkers, which avoids
+ * unnecessary interrupt storms, especially during shutdown.
+ * Otherwise exiting threads would concurrently interrupt those
+ * that have not yet interrupted. It also simplifies some of the
+ * associated statistics bookkeeping of largestPoolSize etc. We
+ * also hold mainLock on shutdown and shutdownNow, for the sake of
+ * ensuring workers set is stable while separately checking
+ * permission to interrupt and actually interrupting.
+ */
+ public final ReentrantLock mainLock = new ReentrantLock();
+
+ /**
+ * Set containing all worker threads in pool. Accessed only when
+ * holding mainLock.
+ */
+ public final HashSet workers = new HashSet();
+
+ /**
+ * Wait condition to support awaitTermination
+ */
+ private final Condition termination = mainLock.newCondition();
+
+ /**
+ * Tracks largest attained pool size. Accessed only under
+ * mainLock.
+ */
+ private int largestPoolSize;
+
+ /**
+ * Counter for completed tasks. Updated only on termination of
+ * worker threads. Accessed only under mainLock.
+ */
+ private long completedTaskCount;
+
+ /*
+ * All user control parameters are declared as volatiles so that
+ * ongoing actions are based on freshest values, but without need
+ * for locking, since no internal invariants depend on them
+ * changing synchronously with respect to other actions.
+ */
+
+ /**
+ * Factory for new threads. All threads are created using this
+ * factory (via method addWorker). All callers must be prepared
+ * for addWorker to fail, which may reflect a system or user's
+ * policy limiting the number of threads. Even though it is not
+ * treated as an error, failure to create threads may result in
+ * new tasks being rejected or existing ones remaining stuck in
+ * the queue. On the other hand, no special precautions exist to
+ * handle OutOfMemoryErrors that might be thrown while trying to
+ * create threads, since there is generally no recourse from
+ * within this class.
+ */
+ private volatile ThreadFactory threadFactory;
+
+ /**
+ * Handler called when saturated or shutdown in execute.
+ */
+ private volatile RejectedExecutionHandler handler;
+
+ /**
+ * Timeout in nanoseconds for idle threads waiting for work.
+ * Threads use this timeout when there are more than corePoolSize
+ * present or if allowCoreThreadTimeOut. Otherwise they wait
+ * forever for new work.
+ */
+ private volatile long keepAliveTime;
+
+ /**
+ * If false (default), core threads stay alive even when idle.
+ * If true, core threads use keepAliveTime to time out waiting
+ * for work.
+ */
+ private volatile boolean allowCoreThreadTimeOut;
+
+ /**
+ * Core pool size is the minimum number of workers to keep alive
+ * (and not allow to time out etc) unless allowCoreThreadTimeOut
+ * is set, in which case the minimum is zero.
+ */
+ private volatile int corePoolSize;
+
+ /**
+ * Maximum pool size. Note that the actual maximum is internally
+ * bounded by CAPACITY.
+ */
+ private volatile int maximumPoolSize;
+
+ /**
+ * The default rejected execution handler
+ */
+ private static final RejectedExecutionHandler defaultHandler =
+ new AbortPolicy();
+
+ /**
+ * Permission required for callers of shutdown and shutdownNow.
+ * We additionally require (see checkShutdownAccess) that callers
+ * have permission to actually interrupt threads in the worker set
+ * (as governed by Thread.interrupt, which relies on
+ * ThreadGroup.checkAccess, which in turn relies on
+ * SecurityManager.checkAccess). Shutdowns are attempted only if
+ * these checks pass.
+ *
+ * All actual invocations of Thread.interrupt (see
+ * interruptIdleWorkers and interruptWorkers) ignore
+ * SecurityExceptions, meaning that the attempted interrupts
+ * silently fail. In the case of shutdown, they should not fail
+ * unless the SecurityManager has inconsistent policies, sometimes
+ * allowing access to a thread and sometimes not. In such cases,
+ * failure to actually interrupt threads may disable or delay full
+ * termination. Other uses of interruptIdleWorkers are advisory,
+ * and failure to actually interrupt will merely delay response to
+ * configuration changes so is not handled exceptionally.
+ */
+ private static final RuntimePermission shutdownPerm =
+ new RuntimePermission("modifyThread");
+
+ /**
+ * Class Worker mainly maintains interrupt control state for
+ * threads running tasks, along with other minor bookkeeping. This
+ * class opportunistically extends ReentrantLock to simplify
+ * acquiring and releasing a lock surrounding each task execution.
+ * This protects against interrupts that are intended to wake up a
+ * worker thread waiting for a task from instead interrupting a
+ * task being run.
+ */
+ public final class Worker extends ReentrantLock implements Runnable {
+ /**
+ * This class will never be serialized, but we provide a
+ * serialVersionUID to suppress a javac warning.
+ */
+ private static final long serialVersionUID = 6138294804551838833L;
+
+ /** Thread this worker is running in. Null if factory fails. */
+ public final Thread thread;
+ /** Initial task to run. Possibly null. */
+ Runnable firstTask;
+ /** Per-thread task counter */
+ volatile long completedTasks;
+
+ /**
+ * Creates with given first task and thread from ThreadFactory.
+ * @param firstTask the first task (null if none)
+ */
+ Worker(Runnable firstTask) {
+ this.firstTask = firstTask;
+ this.thread = getThreadFactory().newThread(this);
+ }
+
+ /** Delegates main run loop to outer runWorker */
+ public void run() {
+ runWorker(this);
+ }
+ }
+
+ /*
+ * Methods for setting control state
+ */
+
+ /**
+ * Transitions runState to given target, or leaves it alone if
+ * already at least the given target.
+ *
+ * @param targetState the desired state, either SHUTDOWN or STOP
+ * (but not TIDYING or TERMINATED -- use tryTerminate for that)
+ */
+ private void advanceRunState(int targetState) {
+ for (;;) {
+ int c = ctl.get();
+ if (runStateAtLeast(c, targetState) ||
+ ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
+ break;
+ }
+ }
+
+ /**
+ * Transitions to TERMINATED state if either (SHUTDOWN and pool
+ * and queue empty) or (STOP and pool empty). If otherwise
+ * eligible to terminate but workerCount is nonzero, interrupts an
+ * idle worker to ensure that shutdown signals propagate. This
+ * method must be called following any action that might make
+ * termination possible -- reducing worker count or removing tasks
+ * from the queue during shutdown. The method is non-private to
+ * allow access from ScheduledThreadPoolExecutor.
+ */
+ final void tryTerminate() {
+ for (;;) {
+ int c = ctl.get();
+ if (isRunning(c) ||
+ runStateAtLeast(c, TIDYING) ||
+ (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
+ return;
+ if (workerCountOf(c) != 0) { // Eligible to terminate
+ interruptIdleWorkers(ONLY_ONE);
+ return;
+ }
+
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
+ try {
+ terminated();
+ } finally {
+ ctl.set(ctlOf(TERMINATED, 0));
+ termination.signalAll();
+ }
+ return;
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ // else retry on failed CAS
+ }
+ }
+
+ /*
+ * Methods for controlling interrupts to worker threads.
+ */
+
+ /**
+ * If there is a security manager, makes sure caller has
+ * permission to shut down threads in general (see shutdownPerm).
+ * If this passes, additionally makes sure the caller is allowed
+ * to interrupt each worker thread. This might not be true even if
+ * first check passed, if the SecurityManager treats some threads
+ * specially.
+ */
+ private void checkShutdownAccess() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkPermission(shutdownPerm);
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ for (Iterator itr = workers.iterator(); itr.hasNext();) {
+ Worker w = (Worker)itr.next();
+ security.checkAccess(w.thread);
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ }
+ }
+
+ /**
+ * Interrupts all threads, even if active. Ignores SecurityExceptions
+ * (in which case some threads may remain uninterrupted).
+ */
+ private void interruptWorkers() {
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ for (Iterator itr = workers.iterator(); itr.hasNext();) {
+ Worker w = (Worker)itr.next();
+ try {
+ w.thread.interrupt();
+ } catch (SecurityException ignore) {
+ }
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Interrupts threads that might be waiting for tasks (as
+ * indicated by not being locked) so they can check for
+ * termination or configuration changes. Ignores
+ * SecurityExceptions (in which case some threads may remain
+ * uninterrupted).
+ *
+ * @param onlyOne If true, interrupt at most one worker. This is
+ * called only from tryTerminate when termination is otherwise
+ * enabled but there are still other workers. In this case, at
+ * most one waiting worker is interrupted to propagate shutdown
+ * signals in case all threads are currently waiting.
+ * Interrupting any arbitrary thread ensures that newly arriving
+ * workers since shutdown began will also eventually exit.
+ * To guarantee eventual termination, it suffices to always
+ * interrupt only one idle worker, but shutdown() interrupts all
+ * idle workers so that redundant workers exit promptly, not
+ * waiting for a straggler task to finish.
+ */
+ private void interruptIdleWorkers(boolean onlyOne) {
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ Iterator it = workers.iterator();
+ while (it.hasNext()) {
+ Worker w = (Worker)it.next();
+ Thread t = w.thread;
+ if (!t.isInterrupted() && w.tryLock()) {
+ try {
+ t.interrupt();
+ } catch (SecurityException ignore) {
+ } finally {
+ w.unlock();
+ }
+ }
+ if (onlyOne)
+ break;
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Common form of interruptIdleWorkers, to avoid having to
+ * remember what the boolean argument means.
+ */
+ private void interruptIdleWorkers() {
+ interruptIdleWorkers(false);
+ }
+
+ private static final boolean ONLY_ONE = true;
+
+ /**
+ * Ensures that unless the pool is stopping, the current thread
+ * does not have its interrupt set. This requires a double-check
+ * of state in case the interrupt was cleared concurrently with a
+ * shutdownNow -- if so, the interrupt is re-enabled.
+ */
+ private void clearInterruptsForTaskRun() {
+ if (runStateLessThan(ctl.get(), STOP) &&
+ Thread.interrupted() &&
+ runStateAtLeast(ctl.get(), STOP))
+ Thread.currentThread().interrupt();
+ }
+
+ /*
+ * Misc utilities, most of which are also exported to
+ * ScheduledThreadPoolExecutor
+ */
+
+ /**
+ * Invokes the rejected execution handler for the given command.
+ * Package-protected for use by ScheduledThreadPoolExecutor.
+ */
+ final void reject(Runnable command) {
+ handler.rejectedExecution(command, this);
+ }
+
+ /**
+ * Performs any further cleanup following run state transition on
+ * invocation of shutdown. A no-op here, but used by
+ * ScheduledThreadPoolExecutor to cancel delayed tasks.
+ */
+ void onShutdown() {
+ }
+
+ /**
+ * State check needed by ScheduledThreadPoolExecutor to
+ * enable running tasks during shutdown.
+ *
+ * @param shutdownOK true if should return true if SHUTDOWN
+ */
+ final boolean isRunningOrShutdown(boolean shutdownOK) {
+ int rs = runStateOf(ctl.get());
+ return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
+ }
+
+ /**
+ * Drains the task queue into a new list, normally using
+ * drainTo. But if the queue is a DelayQueue or any other kind of
+ * queue for which poll or drainTo may fail to remove some
+ * elements, it deletes them one by one.
+ */
+ private List drainQueue() {
+ BlockingQueue q = workQueue;
+ List taskList = new ArrayList();
+ q.drainTo(taskList);
+ if (!q.isEmpty()) {
+ Runnable[] arr = (Runnable[])q.toArray(new Runnable[0]);
+ for (int i=0; i<arr.length; i++) {
+ Runnable r = arr[i];
+ if (q.remove(r))
+ taskList.add(r);
+ }
+ }
+ return taskList;
+ }
+
+ /*
+ * Methods for creating, running and cleaning up after workers
+ */
+
+ /**
+ * Checks if a new worker can be added with respect to current
+ * pool state and the given bound (either core or maximum). If so,
+ * the worker count is adjusted accordingly, and, if possible, a
+ * new worker is created and started running firstTask as its
+ * first task. This method returns false if the pool is stopped or
+ * eligible to shut down. It also returns false if the thread
+ * factory fails to create a thread when asked, which requires a
+ * backout of workerCount, and a recheck for termination, in case
+ * the existence of this worker was holding up termination.
+ *
+ * @param firstTask the task the new thread should run first (or
+ * null if none). Workers are created with an initial first task
+ * (in method execute()) to bypass queuing when there are fewer
+ * than corePoolSize threads (in which case we always start one),
+ * or when the queue is full (in which case we must bypass queue).
+ * Initially idle threads are usually created via
+ * prestartCoreThread or to replace other dying workers.
+ *
+ * @param core if true use corePoolSize as bound, else
+ * maximumPoolSize. (A boolean indicator is used here rather than a
+ * value to ensure reads of fresh values after checking other pool
+ * state).
+ * @return true if successful
+ */
+ private boolean addWorker(Runnable firstTask, boolean core) {
+ retry:
+ for (;;) {
+ int c = ctl.get();
+ int rs = runStateOf(c);
+
+ // Check if queue empty only if necessary.
+ if (rs >= SHUTDOWN &&
+ ! (rs == SHUTDOWN &&
+ firstTask == null &&
+ ! workQueue.isEmpty()))
+ return false;
+
+ for (;;) {
+ int wc = workerCountOf(c);
+ if (wc >= CAPACITY ||
+ wc >= (core ? corePoolSize : maximumPoolSize))
+ return false;
+ if (compareAndIncrementWorkerCount(c))
+ break retry;
+ c = ctl.get(); // Re-read ctl
+ if (runStateOf(c) != rs)
+ continue retry;
+ // else CAS failed due to workerCount change; retry inner loop
+ }
+ }
+
+ Worker w = new Worker(firstTask);
+ Thread t = w.thread;
+
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ // Recheck while holding lock.
+ // Back out on ThreadFactory failure or if
+ // shut down before lock acquired.
+ int c = ctl.get();
+ int rs = runStateOf(c);
+
+ if (t == null ||
+ (rs >= SHUTDOWN &&
+ ! (rs == SHUTDOWN &&
+ firstTask == null))) {
+ decrementWorkerCount();
+ tryTerminate();
+ return false;
+ }
+
+ workers.add(w);
+
+ int s = workers.size();
+ if (s > largestPoolSize)
+ largestPoolSize = s;
+ } finally {
+ mainLock.unlock();
+ }
+
+ t.start();
+ // It is possible (but unlikely) for a thread to have been
+ // added to workers, but not yet started, during transition to
+ // STOP, which could result in a rare missed interrupt,
+ // because Thread.interrupt is not guaranteed to have any effect
+ // on a non-yet-started Thread (see Thread#interrupt).
+ if (runStateOf(ctl.get()) == STOP && ! t.isInterrupted())
+ t.interrupt();
+
+ return true;
+ }
+
+ /**
+ * Performs cleanup and bookkeeping for a dying worker. Called
+ * only from worker threads. Unless completedAbruptly is set,
+ * assumes that workerCount has already been adjusted to account
+ * for exit. This method removes thread from worker set, and
+ * possibly terminates the pool or replaces the worker if either
+ * it exited due to user task exception or if fewer than
+ * corePoolSize workers are running or queue is non-empty but
+ * there are no workers.
+ *
+ * @param w the worker
+ * @param completedAbruptly if the worker died due to user exception
+ */
+ private void processWorkerExit(Worker w, boolean completedAbruptly) {
+ if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
+ decrementWorkerCount();
+
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ completedTaskCount += w.completedTasks;
+ workers.remove(w);
+ } finally {
+ mainLock.unlock();
+ }
+
+ tryTerminate();
+
+ int c = ctl.get();
+ if (runStateLessThan(c, STOP)) {
+ if (!completedAbruptly) {
+ int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
+ if (min == 0 && ! workQueue.isEmpty())
+ min = 1;
+ if (workerCountOf(c) >= min)
+ return; // replacement not needed
+ }
+ addWorker(null, false);
+ }
+ }
+
+ /**
+ * Performs blocking or timed wait for a task, depending on
+ * current configuration settings, or returns null if this worker
+ * must exit because of any of:
+ * 1. There are more than maximumPoolSize workers (due to
+ * a call to setMaximumPoolSize).
+ * 2. The pool is stopped.
+ * 3. The pool is shutdown and the queue is empty.
+ * 4. This worker timed out waiting for a task, and timed-out
+ * workers are subject to termination (that is,
+ * {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
+ * both before and after the timed wait.
+ *
+ * @return task, or null if the worker must exit, in which case
+ * workerCount is decremented
+ */
+ private Runnable getTask() {
+ boolean timedOut = false; // Did the last poll() time out?
+
+ retry:
+ for (;;) {
+ int c = ctl.get();
+ int rs = runStateOf(c);
+
+ // Check if queue empty only if necessary.
+ if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+ decrementWorkerCount();
+ return null;
+ }
+
+ boolean timed; // Are workers subject to culling?
+
+ for (;;) {
+ int wc = workerCountOf(c);
+ timed = allowCoreThreadTimeOut || wc > corePoolSize;
+
+ if (wc <= maximumPoolSize && ! (timedOut && timed))
+ break;
+ if (compareAndDecrementWorkerCount(c))
+ return null;
+ c = ctl.get(); // Re-read ctl
+ if (runStateOf(c) != rs)
+ continue retry;
+ // else CAS failed due to workerCount change; retry inner loop
+ }
+
+ try {
+ Runnable r = timed ?
+ (Runnable)workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
+ (Runnable)workQueue.take();
+ if (r != null)
+ return r;
+ timedOut = true;
+ } catch (InterruptedException retry) {
+ timedOut = false;
+ }
+ }
+ }
+
+ /**
+ * Main worker run loop. Repeatedly gets tasks from queue and
+ * executes them, while coping with a number of issues:
+ *
+ * 1. We may start out with an initial task, in which case we
+ * don't need to get the first one. Otherwise, as long as pool is
+ * running, we get tasks from getTask. If it returns null then the
+ * worker exits due to changed pool state or configuration
+ * parameters. Other exits result from exception throws in
+ * external code, in which case completedAbruptly holds, which
+ * usually leads processWorkerExit to replace this thread.
+ *
+ * 2. Before running any task, the lock is acquired to prevent
+ * other pool interrupts while the task is executing, and
+ * clearInterruptsForTaskRun called to ensure that unless pool is
+ * stopping, this thread does not have its interrupt set.
+ *
+ * 3. Each task run is preceded by a call to beforeExecute, which
+ * might throw an exception, in which case we cause thread to die
+ * (breaking loop with completedAbruptly true) without processing
+ * the task.
+ *
+ * 4. Assuming beforeExecute completes normally, we run the task,
+ * gathering any of its thrown exceptions to send to
+ * afterExecute. We separately handle RuntimeException, Error
+ * (both of which the specs guarantee that we trap) and arbitrary
+ * Throwables. Because we cannot rethrow Throwables within
+ * Runnable.run, we wrap them within Errors on the way out (to the
+ * thread's UncaughtExceptionHandler). Any thrown exception also
+ * conservatively causes thread to die.
+ *
+ * 5. After task.run completes, we call afterExecute, which may
+ * also throw an exception, which will also cause thread to
+ * die. According to JLS Sec 14.20, this exception is the one that
+ * will be in effect even if task.run throws.
+ *
+ * The net effect of the exception mechanics is that afterExecute
+ * and the thread's UncaughtExceptionHandler have as accurate
+ * information as we can provide about any problems encountered by
+ * user code.
+ *
+ * @param w the worker
+ */
+ final void runWorker(Worker w) {
+ Runnable task = w.firstTask;
+ w.firstTask = null;
+ boolean completedAbruptly = true;
+ try {
+ while (task != null || (task = getTask()) != null) {
+ w.lock();
+ clearInterruptsForTaskRun();
+ try {
+ beforeExecute(w.thread, task);
+ Throwable thrown = null;
+ try {
+ task.run();
+ } catch (RuntimeException x) {
+ thrown = x; throw x;
+ } catch (Error x) {
+ thrown = x; throw x;
+ } catch (Throwable x) {
+ thrown = x; throw new Error(x);
+ } finally {
+ afterExecute(task, thrown);
+ }
+ } finally {
+ task = null;
+ w.completedTasks++;
+ w.unlock();
+ }
+ }
+ completedAbruptly = false;
+ } finally {
+ processWorkerExit(w, completedAbruptly);
+ }
+ }
+
+ // Public constructors and methods
+
+ /**
+ * Creates a new {@code ThreadPoolExecutor} with the given initial
+ * parameters and default thread factory and rejected execution handler.
+ * It may be more convenient to use one of the {@link Executors} factory
+ * methods instead of this general purpose constructor.
+ *
+ * @param corePoolSize the number of threads to keep in the pool, even
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
+ * @param maximumPoolSize the maximum number of threads to allow in the
+ * pool
+ * @param keepAliveTime when the number of threads is greater than
+ * the core, this is the maximum time that excess idle threads
+ * will wait for new tasks before terminating.
+ * @param unit the time unit for the {@code keepAliveTime} argument
+ * @param workQueue the queue to use for holding tasks before they are
+ * executed. This queue will hold only the {@code Runnable}
+ * tasks submitted by the {@code execute} method.
+ * @throws IllegalArgumentException if one of the following holds:<br>
+ * {@code corePoolSize < 0}<br>
+ * {@code keepAliveTime < 0}<br>
+ * {@code maximumPoolSize <= 0}<br>
+ * {@code maximumPoolSize < corePoolSize}
+ * @throws NullPointerException if {@code workQueue} is null
+ */
+ public ThreadPoolExecutor(int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit,
+ BlockingQueue workQueue) {
+ this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+ Executors.defaultThreadFactory(), defaultHandler);
+ }
+
+ /**
+ * Creates a new {@code ThreadPoolExecutor} with the given initial
+ * parameters and default rejected execution handler.
+ *
+ * @param corePoolSize the number of threads to keep in the pool, even
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
+ * @param maximumPoolSize the maximum number of threads to allow in the
+ * pool
+ * @param keepAliveTime when the number of threads is greater than
+ * the core, this is the maximum time that excess idle threads
+ * will wait for new tasks before terminating.
+ * @param unit the time unit for the {@code keepAliveTime} argument
+ * @param workQueue the queue to use for holding tasks before they are
+ * executed. This queue will hold only the {@code Runnable}
+ * tasks submitted by the {@code execute} method.
+ * @param threadFactory the factory to use when the executor
+ * creates a new thread
+ * @throws IllegalArgumentException if one of the following holds:<br>
+ * {@code corePoolSize < 0}<br>
+ * {@code keepAliveTime < 0}<br>
+ * {@code maximumPoolSize <= 0}<br>
+ * {@code maximumPoolSize < corePoolSize}
+ * @throws NullPointerException if {@code workQueue}
+ * or {@code threadFactory} is null
+ */
+ public ThreadPoolExecutor(int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit,
+ BlockingQueue workQueue,
+ ThreadFactory threadFactory) {
+ this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+ threadFactory, defaultHandler);
+ }
+
+ /**
+ * Creates a new {@code ThreadPoolExecutor} with the given initial
+ * parameters and default thread factory.
+ *
+ * @param corePoolSize the number of threads to keep in the pool, even
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
+ * @param maximumPoolSize the maximum number of threads to allow in the
+ * pool
+ * @param keepAliveTime when the number of threads is greater than
+ * the core, this is the maximum time that excess idle threads
+ * will wait for new tasks before terminating.
+ * @param unit the time unit for the {@code keepAliveTime} argument
+ * @param workQueue the queue to use for holding tasks before they are
+ * executed. This queue will hold only the {@code Runnable}
+ * tasks submitted by the {@code execute} method.
+ * @param handler the handler to use when execution is blocked
+ * because the thread bounds and queue capacities are reached
+ * @throws IllegalArgumentException if one of the following holds:<br>
+ * {@code corePoolSize < 0}<br>
+ * {@code keepAliveTime < 0}<br>
+ * {@code maximumPoolSize <= 0}<br>
+ * {@code maximumPoolSize < corePoolSize}
+ * @throws NullPointerException if {@code workQueue}
+ * or {@code handler} is null
+ */
+ public ThreadPoolExecutor(int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit,
+ BlockingQueue workQueue,
+ RejectedExecutionHandler handler) {
+ this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+ Executors.defaultThreadFactory(), handler);
+ }
+
+ /**
+ * Creates a new {@code ThreadPoolExecutor} with the given initial
+ * parameters.
+ *
+ * @param corePoolSize the number of threads to keep in the pool, even
+ * if they are idle, unless {@code allowCoreThreadTimeOut} is set
+ * @param maximumPoolSize the maximum number of threads to allow in the
+ * pool
+ * @param keepAliveTime when the number of threads is greater than
+ * the core, this is the maximum time that excess idle threads
+ * will wait for new tasks before terminating.
+ * @param unit the time unit for the {@code keepAliveTime} argument
+ * @param workQueue the queue to use for holding tasks before they are
+ * executed. This queue will hold only the {@code Runnable}
+ * tasks submitted by the {@code execute} method.
+ * @param threadFactory the factory to use when the executor
+ * creates a new thread
+ * @param handler the handler to use when execution is blocked
+ * because the thread bounds and queue capacities are reached
+ * @throws IllegalArgumentException if one of the following holds:<br>
+ * {@code corePoolSize < 0}<br>
+ * {@code keepAliveTime < 0}<br>
+ * {@code maximumPoolSize <= 0}<br>
+ * {@code maximumPoolSize < corePoolSize}
+ * @throws NullPointerException if {@code workQueue}
+ * or {@code threadFactory} or {@code handler} is null
+ */
+ public ThreadPoolExecutor(int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit,
+ BlockingQueue workQueue,
+ ThreadFactory threadFactory,
+ RejectedExecutionHandler handler) {
+ if (corePoolSize < 0 ||
+ maximumPoolSize <= 0 ||
+ maximumPoolSize < corePoolSize ||
+ keepAliveTime < 0)
+ throw new IllegalArgumentException();
+ if (workQueue == null || threadFactory == null || handler == null)
+ throw new NullPointerException();
+ this.corePoolSize = corePoolSize;
+ this.maximumPoolSize = maximumPoolSize;
+ this.workQueue = workQueue;
+ this.keepAliveTime = unit.toNanos(keepAliveTime);
+ this.threadFactory = threadFactory;
+ this.handler = handler;
+ }
+
+ /**
+ * Executes the given task sometime in the future. The task
+ * may execute in a new thread or in an existing pooled thread.
+ *
+ * If the task cannot be submitted for execution, either because this
+ * executor has been shutdown or because its capacity has been reached,
+ * the task is handled by the current {@code RejectedExecutionHandler}.
+ *
+ * @param command the task to execute
+ * @throws RejectedExecutionException at discretion of
+ * {@code RejectedExecutionHandler}, if the task
+ * cannot be accepted for execution
+ * @throws NullPointerException if {@code command} is null
+ */
+ public void execute(Runnable command) {
+ if (command == null)
+ throw new NullPointerException();
+ /*
+ * Proceed in 3 steps:
+ *
+ * 1. If fewer than corePoolSize threads are running, try to
+ * start a new thread with the given command as its first
+ * task. The call to addWorker atomically checks runState and
+ * workerCount, and so prevents false alarms that would add
+ * threads when it shouldn't, by returning false.
+ *
+ * 2. If a task can be successfully queued, then we still need
+ * to double-check whether we should have added a thread
+ * (because existing ones died since last checking) or that
+ * the pool shut down since entry into this method. So we
+ * recheck state and if necessary roll back the enqueuing if
+ * stopped, or start a new thread if there are none.
+ *
+ * 3. If we cannot queue task, then we try to add a new
+ * thread. If it fails, we know we are shut down or saturated
+ * and so reject the task.
+ */
+ int c = ctl.get();
+ if (workerCountOf(c) < corePoolSize) {
+ if (addWorker(command, true))
+ return;
+ c = ctl.get();
+ }
+ if (isRunning(c) && workQueue.offer(command)) {
+ int recheck = ctl.get();
+ if (! isRunning(recheck) && remove(command))
+ reject(command);
+ else if (workerCountOf(recheck) == 0)
+ addWorker(null, false);
+ }
+ else if (!addWorker(command, false))
+ reject(command);
+ }
+
+ /**
+ * Initiates an orderly shutdown in which previously submitted
+ * tasks are executed, but no new tasks will be accepted.
+ * Invocation has no additional effect if already shut down.
+ *
+ * @throws SecurityException {@inheritDoc}
+ */
+ public void shutdown() {
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ checkShutdownAccess();
+ advanceRunState(SHUTDOWN);
+ interruptIdleWorkers();
+ onShutdown(); // hook for ScheduledThreadPoolExecutor
+ } finally {
+ mainLock.unlock();
+ }
+ tryTerminate();
+ }
+
+ /**
+ * Attempts to stop all actively executing tasks, halts the
+ * processing of waiting tasks, and returns a list of the tasks
+ * that were awaiting execution. These tasks are drained (removed)
+ * from the task queue upon return from this method.
+ *
+ * <p>There are no guarantees beyond best-effort attempts to stop
+ * processing actively executing tasks. This implementation
+ * cancels tasks via {@link Thread#interrupt}, so any task that
+ * fails to respond to interrupts may never terminate.
+ *
+ * @throws SecurityException {@inheritDoc}
+ */
+ public List shutdownNow() {
+ List tasks;
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ checkShutdownAccess();
+ advanceRunState(STOP);
+ interruptWorkers();
+ tasks = drainQueue();
+ } finally {
+ mainLock.unlock();
+ }
+ tryTerminate();
+ return tasks;
+ }
+
+ public boolean isShutdown() {
+ return ! isRunning(ctl.get());
+ }
+
+ /**
+ * Returns true if this executor is in the process of terminating
+ * after {@link #shutdown} or {@link #shutdownNow} but has not
+ * completely terminated. This method may be useful for
+ * debugging. A return of {@code true} reported a sufficient
+ * period after shutdown may indicate that submitted tasks have
+ * ignored or suppressed interruption, causing this executor not
+ * to properly terminate.
+ *
+ * @return true if terminating but not yet terminated
+ */
+ public boolean isTerminating() {
+ int c = ctl.get();
+ return ! isRunning(c) && runStateLessThan(c, TERMINATED);
+ }
+
+ public boolean isTerminated() {
+ return runStateAtLeast(ctl.get(), TERMINATED);
+ }
+
+ public boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ long nanos = unit.toNanos(timeout);
+ long deadline = Utils.nanoTime() + nanos;
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ if (runStateAtLeast(ctl.get(), TERMINATED))
+ return true;
+ while (nanos > 0) {
+ termination.await(nanos, TimeUnit.NANOSECONDS);
+ if (runStateAtLeast(ctl.get(), TERMINATED))
+ return true;
+ nanos = deadline - Utils.nanoTime();
+ }
+ return false;
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Invokes {@code shutdown} when this executor is no longer
+ * referenced and it has no threads.
+ */
+ protected void finalize() {
+ shutdown();
+ }
+
+ /**
+ * Sets the thread factory used to create new threads.
+ *
+ * @param threadFactory the new thread factory
+ * @throws NullPointerException if threadFactory is null
+ * @see #getThreadFactory
+ */
+ public void setThreadFactory(ThreadFactory threadFactory) {
+ if (threadFactory == null)
+ throw new NullPointerException();
+ this.threadFactory = threadFactory;
+ }
+
+ /**
+ * Returns the thread factory used to create new threads.
+ *
+ * @return the current thread factory
+ * @see #setThreadFactory
+ */
+ public ThreadFactory getThreadFactory() {
+ return threadFactory;
+ }
+
+ /**
+ * Sets a new handler for unexecutable tasks.
+ *
+ * @param handler the new handler
+ * @throws NullPointerException if handler is null
+ * @see #getRejectedExecutionHandler
+ */
+ public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
+ if (handler == null)
+ throw new NullPointerException();
+ this.handler = handler;
+ }
+
+ /**
+ * Returns the current handler for unexecutable tasks.
+ *
+ * @return the current handler
+ * @see #setRejectedExecutionHandler
+ */
+ public RejectedExecutionHandler getRejectedExecutionHandler() {
+ return handler;
+ }
+
+ /**
+ * Sets the core number of threads. This overrides any value set
+ * in the constructor. If the new value is smaller than the
+ * current value, excess existing threads will be terminated when
+ * they next become idle. If larger, new threads will, if needed,
+ * be started to execute any queued tasks.
+ *
+ * @param corePoolSize the new core size
+ * @throws IllegalArgumentException if {@code corePoolSize < 0}
+ * @see #getCorePoolSize
+ */
+ public void setCorePoolSize(int corePoolSize) {
+ if (corePoolSize < 0)
+ throw new IllegalArgumentException();
+ int delta = corePoolSize - this.corePoolSize;
+ this.corePoolSize = corePoolSize;
+ if (workerCountOf(ctl.get()) > corePoolSize)
+ interruptIdleWorkers();
+ else if (delta > 0) {
+ // We don't really know how many new threads are "needed".
+ // As a heuristic, prestart enough new workers (up to new
+ // core size) to handle the current number of tasks in
+ // queue, but stop if queue becomes empty while doing so.
+ int k = Math.min(delta, workQueue.size());
+ while (k-- > 0 && addWorker(null, true)) {
+ if (workQueue.isEmpty())
+ break;
+ }
+ }
+ }
+
+ /**
+ * Returns the core number of threads.
+ *
+ * @return the core number of threads
+ * @see #setCorePoolSize
+ */
+ public int getCorePoolSize() {
+ return corePoolSize;
+ }
+
+ /**
+ * Starts a core thread, causing it to idly wait for work. This
+ * overrides the default policy of starting core threads only when
+ * new tasks are executed. This method will return {@code false}
+ * if all core threads have already been started.
+ *
+ * @return {@code true} if a thread was started
+ */
+ public boolean prestartCoreThread() {
+ return workerCountOf(ctl.get()) < corePoolSize &&
+ addWorker(null, true);
+ }
+
+ /**
+ * Starts all core threads, causing them to idly wait for work. This
+ * overrides the default policy of starting core threads only when
+ * new tasks are executed.
+ *
+ * @return the number of threads started
+ */
+ public int prestartAllCoreThreads() {
+ int n = 0;
+ while (addWorker(null, true))
+ ++n;
+ return n;
+ }
+
+ /**
+ * Returns true if this pool allows core threads to time out and
+ * terminate if no tasks arrive within the keepAlive time, being
+ * replaced if needed when new tasks arrive. When true, the same
+ * keep-alive policy applying to non-core threads applies also to
+ * core threads. When false (the default), core threads are never
+ * terminated due to lack of incoming tasks.
+ *
+ * @return {@code true} if core threads are allowed to time out,
+ * else {@code false}
+ *
+ * @since 1.6
+ */
+ public boolean allowsCoreThreadTimeOut() {
+ return allowCoreThreadTimeOut;
+ }
+
+ /**
+ * Sets the policy governing whether core threads may time out and
+ * terminate if no tasks arrive within the keep-alive time, being
+ * replaced if needed when new tasks arrive. When false, core
+ * threads are never terminated due to lack of incoming
+ * tasks. When true, the same keep-alive policy applying to
+ * non-core threads applies also to core threads. To avoid
+ * continual thread replacement, the keep-alive time must be
+ * greater than zero when setting {@code true}. This method
+ * should in general be called before the pool is actively used.
+ *
+ * @param value {@code true} if should time out, else {@code false}
+ * @throws IllegalArgumentException if value is {@code true}
+ * and the current keep-alive time is not greater than zero
+ *
+ * @since 1.6
+ */
+ public void allowCoreThreadTimeOut(boolean value) {
+ if (value && keepAliveTime <= 0)
+ throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
+ if (value != allowCoreThreadTimeOut) {
+ allowCoreThreadTimeOut = value;
+ if (value)
+ interruptIdleWorkers();
+ }
+ }
+
+ /**
+ * Sets the maximum allowed number of threads. This overrides any
+ * value set in the constructor. If the new value is smaller than
+ * the current value, excess existing threads will be
+ * terminated when they next become idle.
+ *
+ * @param maximumPoolSize the new maximum
+ * @throws IllegalArgumentException if the new maximum is
+ * less than or equal to zero, or
+ * less than the {@linkplain #getCorePoolSize core pool size}
+ * @see #getMaximumPoolSize
+ */
+ public void setMaximumPoolSize(int maximumPoolSize) {
+ if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
+ throw new IllegalArgumentException();
+ this.maximumPoolSize = maximumPoolSize;
+ if (workerCountOf(ctl.get()) > maximumPoolSize)
+ interruptIdleWorkers();
+ }
+
+ /**
+ * Returns the maximum allowed number of threads.
+ *
+ * @return the maximum allowed number of threads
+ * @see #setMaximumPoolSize
+ */
+ public int getMaximumPoolSize() {
+ return maximumPoolSize;
+ }
+
+ /**
+ * Sets the time limit for which threads may remain idle before
+ * being terminated. If there are more than the core number of
+ * threads currently in the pool, after waiting this amount of
+ * time without processing a task, excess threads will be
+ * terminated. This overrides any value set in the constructor.
+ *
+ * @param time the time to wait. A time value of zero will cause
+ * excess threads to terminate immediately after executing tasks.
+ * @param unit the time unit of the {@code time} argument
+ * @throws IllegalArgumentException if {@code time} less than zero or
+ * if {@code time} is zero and {@code allowsCoreThreadTimeOut}
+ * @see #getKeepAliveTime
+ */
+ public void setKeepAliveTime(long time, TimeUnit unit) {
+ if (time < 0)
+ throw new IllegalArgumentException();
+ if (time == 0 && allowsCoreThreadTimeOut())
+ throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
+ long keepAliveTime = unit.toNanos(time);
+ long delta = keepAliveTime - this.keepAliveTime;
+ this.keepAliveTime = keepAliveTime;
+ if (delta < 0)
+ interruptIdleWorkers();
+ }
+
+ /**
+ * Returns the thread keep-alive time, which is the amount of time
+ * that threads in excess of the core pool size may remain
+ * idle before being terminated.
+ *
+ * @param unit the desired time unit of the result
+ * @return the time limit
+ * @see #setKeepAliveTime
+ */
+ public long getKeepAliveTime(TimeUnit unit) {
+ return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
+ }
+
+ /* User-level queue utilities */
+
+ /**
+ * Returns the task queue used by this executor. Access to the
+ * task queue is intended primarily for debugging and monitoring.
+ * This queue may be in active use. Retrieving the task queue
+ * does not prevent queued tasks from executing.
+ *
+ * @return the task queue
+ */
+ public BlockingQueue getQueue() {
+ return workQueue;
+ }
+
+ /**
+ * Removes this task from the executor's internal queue if it is
+ * present, thus causing it not to be run if it has not already
+ * started.
+ *
+ * <p> This method may be useful as one part of a cancellation
+ * scheme. It may fail to remove tasks that have been converted
+ * into other forms before being placed on the internal queue. For
+ * example, a task entered using {@code submit} might be
+ * converted into a form that maintains {@code Future} status.
+ * However, in such cases, method {@link #purge} may be used to
+ * remove those Futures that have been cancelled.
+ *
+ * @param task the task to remove
+ * @return true if the task was removed
+ */
+ public boolean remove(Runnable task) {
+ boolean removed = workQueue.remove(task);
+ tryTerminate(); // In case SHUTDOWN and now empty
+ return removed;
+ }
+
+ /**
+ * Tries to remove from the work queue all {@link Future}
+ * tasks that have been cancelled. This method can be useful as a
+ * storage reclamation operation, that has no other impact on
+ * functionality. Cancelled tasks are never executed, but may
+ * accumulate in work queues until worker threads can actively
+ * remove them. Invoking this method instead tries to remove them now.
+ * However, this method may fail to remove tasks in
+ * the presence of interference by other threads.
+ */
+ public void purge() {
+ final BlockingQueue q = workQueue;
+ try {
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ Runnable r = (Runnable)it.next();
+ if (r instanceof Future && ((Future)r).isCancelled())
+ it.remove();
+ }
+ } catch (ConcurrentModificationException fallThrough) {
+ // Take slow path if we encounter interference during traversal.
+ // Make copy for traversal and call remove for cancelled entries.
+ // The slow path is more likely to be O(N*N).
+ Object[] arr = q.toArray();
+ for (int i=0; i<arr.length; i++) {
+ Object r = arr[i];
+ if (r instanceof Future && ((Future)r).isCancelled())
+ q.remove(r);
+ }
+ }
+
+ tryTerminate(); // In case SHUTDOWN and now empty
+ }
+
+ /* Statistics */
+
+ /**
+ * Returns the current number of threads in the pool.
+ *
+ * @return the number of threads
+ */
+ public int getPoolSize() {
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ // Remove rare and surprising possibility of
+ // isTerminated() && getPoolSize() > 0
+ return runStateAtLeast(ctl.get(), TIDYING) ? 0
+ : workers.size();
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Returns the approximate number of threads that are actively
+ * executing tasks.
+ *
+ * @return the number of threads
+ */
+ public int getActiveCount() {
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ int n = 0;
+ for (Iterator itr = workers.iterator(); itr.hasNext();) {
+ Worker w = (Worker)itr.next();
+ if (w.isLocked())
+ ++n;
+ }
+ return n;
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Returns the largest number of threads that have ever
+ * simultaneously been in the pool.
+ *
+ * @return the number of threads
+ */
+ public int getLargestPoolSize() {
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ return largestPoolSize;
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Returns the approximate total number of tasks that have ever been
+ * scheduled for execution. Because the states of tasks and
+ * threads may change dynamically during computation, the returned
+ * value is only an approximation.
+ *
+ * @return the number of tasks
+ */
+ public long getTaskCount() {
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ long n = completedTaskCount;
+ for (Iterator itr = workers.iterator(); itr.hasNext();) {
+ Worker w = (Worker)itr.next();
+ n += w.completedTasks;
+ if (w.isLocked())
+ ++n;
+ }
+ return n + workQueue.size();
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Returns the approximate total number of tasks that have
+ * completed execution. Because the states of tasks and threads
+ * may change dynamically during computation, the returned value
+ * is only an approximation, but one that does not ever decrease
+ * across successive calls.
+ *
+ * @return the number of tasks
+ */
+ public long getCompletedTaskCount() {
+ final ReentrantLock mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ long n = completedTaskCount;
+ for (Iterator itr = workers.iterator(); itr.hasNext();) {
+ Worker w = (Worker)itr.next();
+ n += w.completedTasks;
+ }
+ return n;
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /* Extension hooks */
+
+ /**
+ * Method invoked prior to executing the given Runnable in the
+ * given thread. This method is invoked by thread {@code t} that
+ * will execute task {@code r}, and may be used to re-initialize
+ * ThreadLocals, or to perform logging.
+ *
+ * <p>This implementation does nothing, but may be customized in
+ * subclasses. Note: To properly nest multiple overridings, subclasses
+ * should generally invoke {@code super.beforeExecute} at the end of
+ * this method.
+ *
+ * @param t the thread that will run task {@code r}
+ * @param r the task that will be executed
+ */
+ protected void beforeExecute(Thread t, Runnable r) { }
+
+ /**
+ * Method invoked upon completion of execution of the given Runnable.
+ * This method is invoked by the thread that executed the task. If
+ * non-null, the Throwable is the uncaught {@code RuntimeException}
+ * or {@code Error} that caused execution to terminate abruptly.
+ *
+ * <p>This implementation does nothing, but may be customized in
+ * subclasses. Note: To properly nest multiple overridings, subclasses
+ * should generally invoke {@code super.afterExecute} at the
+ * beginning of this method.
+ *
+ * <p><b>Note:</b> When actions are enclosed in tasks (such as
+ * {@link FutureTask}) either explicitly or via methods such as
+ * {@code submit}, these task objects catch and maintain
+ * computational exceptions, and so they do not cause abrupt
+ * termination, and the internal exceptions are <em>not</em>
+ * passed to this method. If you would like to trap both kinds of
+ * failures in this method, you can further probe for such cases,
+ * as in this sample subclass that prints either the direct cause
+ * or the underlying exception if a task has been aborted:
+ *
+ * <pre> {@code
+ * class ExtendedExecutor extends ThreadPoolExecutor {
+ * // ...
+ * protected void afterExecute(Runnable r, Throwable t) {
+ * super.afterExecute(r, t);
+ * if (t == null && r instanceof Future<?>) {
+ * try {
+ * Object result = ((Future<?>) r).get();
+ * } catch (CancellationException ce) {
+ * t = ce;
+ * } catch (ExecutionException ee) {
+ * t = ee.getCause();
+ * } catch (InterruptedException ie) {
+ * Thread.currentThread().interrupt(); // ignore/reset
+ * }
+ * }
+ * if (t != null)
+ * System.out.println(t);
+ * }
+ * }}</pre>
+ *
+ * @param r the runnable that has completed
+ * @param t the exception that caused termination, or null if
+ * execution completed normally
+ */
+ protected void afterExecute(Runnable r, Throwable t) { }
+
+ /**
+ * Method invoked when the Executor has terminated. Default
+ * implementation does nothing. Note: To properly nest multiple
+ * overridings, subclasses should generally invoke
+ * {@code super.terminated} within this method.
+ */
+ protected void terminated() { }
+
+ /* Predefined RejectedExecutionHandlers */
+
+ /**
+ * A handler for rejected tasks that runs the rejected task
+ * directly in the calling thread of the {@code execute} method,
+ * unless the executor has been shut down, in which case the task
+ * is discarded.
+ */
+ public static class CallerRunsPolicy implements RejectedExecutionHandler {
+ /**
+ * Creates a {@code CallerRunsPolicy}.
+ */
+ public CallerRunsPolicy() { }
+
+ /**
+ * Executes task r in the caller's thread, unless the executor
+ * has been shut down, in which case the task is discarded.
+ *
+ * @param r the runnable task requested to be executed
+ * @param e the executor attempting to execute this task
+ */
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+ if (!e.isShutdown()) {
+ r.run();
+ }
+ }
+ }
+
+ /**
+ * A handler for rejected tasks that throws a
+ * {@code RejectedExecutionException}.
+ */
+ public static class AbortPolicy implements RejectedExecutionHandler {
+ /**
+ * Creates an {@code AbortPolicy}.
+ */
+ public AbortPolicy() { }
+
+ /**
+ * Always throws RejectedExecutionException.
+ *
+ * @param r the runnable task requested to be executed
+ * @param e the executor attempting to execute this task
+ * @throws RejectedExecutionException always.
+ */
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+ throw new RejectedExecutionException();
+ }
+ }
+
+ /**
+ * A handler for rejected tasks that silently discards the
+ * rejected task.
+ */
+ public static class DiscardPolicy implements RejectedExecutionHandler {
+ /**
+ * Creates a {@code DiscardPolicy}.
+ */
+ public DiscardPolicy() { }
+
+ /**
+ * Does nothing, which has the effect of discarding task r.
+ *
+ * @param r the runnable task requested to be executed
+ * @param e the executor attempting to execute this task
+ */
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+ }
+ }
+
+ /**
+ * A handler for rejected tasks that discards the oldest unhandled
+ * request and then retries {@code execute}, unless the executor
+ * is shut down, in which case the task is discarded.
+ */
+ public static class DiscardOldestPolicy implements RejectedExecutionHandler {
+ /**
+ * Creates a {@code DiscardOldestPolicy} for the given executor.
+ */
+ public DiscardOldestPolicy() { }
+
+ /**
+ * Obtains and ignores the next task that the executor
+ * would otherwise execute, if one is immediately available,
+ * and then retries execution of task r, unless the executor
+ * is shut down, in which case task r is instead discarded.
+ *
+ * @param r the runnable task requested to be executed
+ * @param e the executor attempting to execute this task
+ */
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+ if (!e.isShutdown()) {
+ e.getQueue().poll();
+ e.execute(r);
+ }
+ }
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/TimeUnit.java b/src/actors/scala/actors/threadpool/TimeUnit.java
new file mode 100644
index 0000000000..c443750e33
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/TimeUnit.java
@@ -0,0 +1,407 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+
+/**
+ * A <tt>TimeUnit</tt> represents time durations at a given unit of
+ * granularity and provides utility methods to convert across units,
+ * and to perform timing and delay operations in these units. A
+ * <tt>TimeUnit</tt> does not maintain time information, but only
+ * helps organize and use time representations that may be maintained
+ * separately across various contexts. A nanosecond is defined as one
+ * thousandth of a microsecond, a microsecond as one thousandth of a
+ * millisecond, a millisecond as one thousandth of a second, a minute
+ * as sixty seconds, an hour as sixty minutes, and a day as twenty four
+ * hours.
+ *
+ * <p>A <tt>TimeUnit</tt> is mainly used to inform time-based methods
+ * how a given timing parameter should be interpreted. For example,
+ * the following code will timeout in 50 milliseconds if the {@link
+ * edu.emory.mathcs.backport.java.util.concurrent.locks.Lock lock} is not available:
+ *
+ * <pre> Lock lock = ...;
+ * if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ...
+ * </pre>
+ * while this code will timeout in 50 seconds:
+ * <pre>
+ * Lock lock = ...;
+ * if ( lock.tryLock(50L, TimeUnit.SECONDS) ) ...
+ * </pre>
+ *
+ * Note however, that there is no guarantee that a particular timeout
+ * implementation will be able to notice the passage of time at the
+ * same granularity as the given <tt>TimeUnit</tt>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public abstract class TimeUnit implements java.io.Serializable {
+
+ public static final TimeUnit NANOSECONDS = new TimeUnit(0, "NANOSECONDS") {
+ private final static long serialVersionUID = 535148490883208361L;
+ public long toNanos(long d) { return d; }
+ public long toMicros(long d) { return d/(C1/C0); }
+ public long toMillis(long d) { return d/(C2/C0); }
+ public long toSeconds(long d) { return d/(C3/C0); }
+ public long toMinutes(long d) { return d/(C4/C0); }
+ public long toHours(long d) { return d/(C5/C0); }
+ public long toDays(long d) { return d/(C6/C0); }
+ public long convert(long d, TimeUnit u) { return u.toNanos(d); }
+ int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
+ };
+ public static final TimeUnit MICROSECONDS = new TimeUnit(1, "MICROSECONDS") {
+ private final static long serialVersionUID = 2185906575929579108L;
+ public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); }
+ public long toMicros(long d) { return d; }
+ public long toMillis(long d) { return d/(C2/C1); }
+ public long toSeconds(long d) { return d/(C3/C1); }
+ public long toMinutes(long d) { return d/(C4/C1); }
+ public long toHours(long d) { return d/(C5/C1); }
+ public long toDays(long d) { return d/(C6/C1); }
+ public long convert(long d, TimeUnit u) { return u.toMicros(d); }
+ int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
+ };
+ public static final TimeUnit MILLISECONDS = new TimeUnit(2, "MILLISECONDS") {
+ private final static long serialVersionUID = 9032047794123325184L;
+ public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); }
+ public long toMicros(long d) { return x(d, C2/C1, MAX/(C2/C1)); }
+ public long toMillis(long d) { return d; }
+ public long toSeconds(long d) { return d/(C3/C2); }
+ public long toMinutes(long d) { return d/(C4/C2); }
+ public long toHours(long d) { return d/(C5/C2); }
+ public long toDays(long d) { return d/(C6/C2); }
+ public long convert(long d, TimeUnit u) { return u.toMillis(d); }
+ int excessNanos(long d, long m) { return 0; }
+ };
+ public static final TimeUnit SECONDS = new TimeUnit(3, "SECONDS") {
+ private final static long serialVersionUID = 227755028449378390L;
+ public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); }
+ public long toMicros(long d) { return x(d, C3/C1, MAX/(C3/C1)); }
+ public long toMillis(long d) { return x(d, C3/C2, MAX/(C3/C2)); }
+ public long toSeconds(long d) { return d; }
+ public long toMinutes(long d) { return d/(C4/C3); }
+ public long toHours(long d) { return d/(C5/C3); }
+ public long toDays(long d) { return d/(C6/C3); }
+ public long convert(long d, TimeUnit u) { return u.toSeconds(d); }
+ int excessNanos(long d, long m) { return 0; }
+ };
+ public static final TimeUnit MINUTES = new TimeUnit(4, "MINUTES") {
+ private final static long serialVersionUID = 1827351566402609187L;
+ public long toNanos(long d) { return x(d, C4/C0, MAX/(C4/C0)); }
+ public long toMicros(long d) { return x(d, C4/C1, MAX/(C4/C1)); }
+ public long toMillis(long d) { return x(d, C4/C2, MAX/(C4/C2)); }
+ public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); }
+ public long toMinutes(long d) { return d; }
+ public long toHours(long d) { return d/(C5/C4); }
+ public long toDays(long d) { return d/(C6/C4); }
+ public long convert(long d, TimeUnit u) { return u.toMinutes(d); }
+ int excessNanos(long d, long m) { return 0; }
+ };
+ public static final TimeUnit HOURS = new TimeUnit(5, "HOURS") {
+ private final static long serialVersionUID = -6438436134732089810L;
+ public long toNanos(long d) { return x(d, C5/C0, MAX/(C5/C0)); }
+ public long toMicros(long d) { return x(d, C5/C1, MAX/(C5/C1)); }
+ public long toMillis(long d) { return x(d, C5/C2, MAX/(C5/C2)); }
+ public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); }
+ public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); }
+ public long toHours(long d) { return d; }
+ public long toDays(long d) { return d/(C6/C5); }
+ public long convert(long d, TimeUnit u) { return u.toHours(d); }
+ int excessNanos(long d, long m) { return 0; }
+ };
+ public static final TimeUnit DAYS = new TimeUnit(6, "DAYS") {
+ private final static long serialVersionUID = 567463171959674600L;
+ public long toNanos(long d) { return x(d, C6/C0, MAX/(C6/C0)); }
+ public long toMicros(long d) { return x(d, C6/C1, MAX/(C6/C1)); }
+ public long toMillis(long d) { return x(d, C6/C2, MAX/(C6/C2)); }
+ public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); }
+ public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); }
+ public long toHours(long d) { return x(d, C6/C5, MAX/(C6/C5)); }
+ public long toDays(long d) { return d; }
+ public long convert(long d, TimeUnit u) { return u.toDays(d); }
+ int excessNanos(long d, long m) { return 0; }
+ };
+
+ private static final TimeUnit[] values = new TimeUnit[]
+ { NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS };
+
+ public static TimeUnit[] values() {
+ return (TimeUnit[])values.clone();
+ }
+
+ /**
+ * Returns the enum constant of this type with the specified name. The
+ * string must match <em>exactly</em> an identifier used to declare an
+ * enum constant in this type. (Extraneous whitespace characters are not
+ * permitted.)
+ *
+ * @param name the name of the enum constant to be returned
+ * @return the enum constant with the specified name
+ * @throws IllegalArgumentException
+ * if this enum type has no constant with the specified name
+ */
+ public static TimeUnit valueOf(String name) {
+ for (int i = 0; i < values.length; i++) {
+ if (values[i].name.equals(name)) {
+ return values[i];
+ }
+ }
+ throw new IllegalArgumentException("No enum const TimeUnit." + name);
+ }
+
+ /**
+ * The ordinal of this unit. This is useful both for {@link #ordinal()}
+ * and to maintain serialization consistence with earlier versions.
+ */
+ private final int index;
+
+ /** name of this unit */
+ private final String name;
+
+ /** Internal constructor */
+ TimeUnit(int index, String name) {
+ this.index = index;
+ this.name = name;
+ }
+
+ // Handy constants for conversion methods
+ static final long C0 = 1;
+ static final long C1 = C0 * 1000;
+ static final long C2 = C1 * 1000;
+ static final long C3 = C2 * 1000;
+ static final long C4 = C3 * 60;
+ static final long C5 = C4 * 60;
+ static final long C6 = C5 * 24;
+
+ static final long MAX = Long.MAX_VALUE;
+
+ /**
+ * Scale d by m, checking for overflow.
+ * This has a short name to make above code more readable.
+ */
+ static long x(long d, long m, long over) {
+ if (d > over) return Long.MAX_VALUE;
+ if (d < -over) return Long.MIN_VALUE;
+ return d * m;
+ }
+
+ /**
+ * Convert the given time duration in the given unit to this
+ * unit. Conversions from finer to coarser granularities
+ * truncate, so lose precision. For example converting
+ * <tt>999</tt> milliseconds to seconds results in
+ * <tt>0</tt>. Conversions from coarser to finer granularities
+ * with arguments that would numerically overflow saturate to
+ * <tt>Long.MIN_VALUE</tt> if negative or <tt>Long.MAX_VALUE</tt>
+ * if positive.
+ *
+ * <p>For example, to convert 10 minutes to milliseconds, use:
+ * <tt>TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES)</tt>
+ *
+ * @param sourceDuration the time duration in the given <tt>sourceUnit</tt>
+ * @param sourceUnit the unit of the <tt>sourceDuration</tt> argument
+ * @return the converted duration in this unit,
+ * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
+ * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
+ */
+ public abstract long convert(long sourceDuration, TimeUnit sourceUnit);
+
+ /**
+ * Equivalent to <tt>NANOSECONDS.convert(duration, this)</tt>.
+ * @param duration the duration
+ * @return the converted duration,
+ * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
+ * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
+ * @see #convert
+ */
+ public abstract long toNanos(long duration);
+
+ /**
+ * Equivalent to <tt>MICROSECONDS.convert(duration, this)</tt>.
+ * @param duration the duration
+ * @return the converted duration,
+ * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
+ * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
+ * @see #convert
+ */
+ public abstract long toMicros(long duration);
+
+ /**
+ * Equivalent to <tt>MILLISECONDS.convert(duration, this)</tt>.
+ * @param duration the duration
+ * @return the converted duration,
+ * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
+ * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
+ * @see #convert
+ */
+ public abstract long toMillis(long duration);
+
+ /**
+ * Equivalent to <tt>SECONDS.convert(duration, this)</tt>.
+ * @param duration the duration
+ * @return the converted duration,
+ * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
+ * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
+ * @see #convert
+ */
+ public abstract long toSeconds(long duration);
+
+ /**
+ * Equivalent to <tt>MINUTES.convert(duration, this)</tt>.
+ * @param duration the duration
+ * @return the converted duration,
+ * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
+ * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
+ * @see #convert
+ * @since 1.6
+ */
+ public abstract long toMinutes(long duration);
+
+ /**
+ * Equivalent to <tt>HOURS.convert(duration, this)</tt>.
+ * @param duration the duration
+ * @return the converted duration,
+ * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
+ * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
+ * @see #convert
+ * @since 1.6
+ */
+ public abstract long toHours(long duration);
+
+ /**
+ * Equivalent to <tt>DAYS.convert(duration, this)</tt>.
+ * @param duration the duration
+ * @return the converted duration
+ * @see #convert
+ * @since 1.6
+ */
+ public abstract long toDays(long duration);
+
+ /**
+ * Utility to compute the excess-nanosecond argument to wait,
+ * sleep, join.
+ * @param d the duration
+ * @param m the number of milliseconds
+ * @return the number of nanoseconds
+ */
+ abstract int excessNanos(long d, long m);
+
+ /**
+ * Returns the name of this enum constant, exactly as declared in its enum
+ * declaration. <strong>Most programmers should use the
+ * {@link #toString()} method in preference to this one, as the toString
+ * method may return a more user-friendly name.</strong> This method is
+ * designed primarily for use in specialized situations where correctness
+ * depends on getting the exact name, which will not vary from release to
+ * release.
+ *
+ * @return the name of this enum constant
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Returns the ordinal of this enumeration constant (its position in its
+ * enum declaration, where the initial constant is assigned an ordinal of
+ * zero). Most programmers will have no use for this method. It is
+ * designed for use by sophisticated enum-based data structures, such as
+ * <code>EnumSet</code> and <code>EnumMap</code>.
+ *
+ * @return the ordinal of this enumeration constant
+ */
+ public int ordinal() {
+ return index;
+ }
+
+ /*
+ * Guarantees that deserialized objects will be referentially equal to the
+ * standard enumeration objects.
+ */
+ protected Object readResolve() throws ObjectStreamException {
+ try {
+ return valueOf(name);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidObjectException(name
+ + " is not a valid enum for TimeUnit");
+ }
+ }
+
+ /**
+ * Performs a timed <tt>Object.wait</tt> using this time unit.
+ * This is a convenience method that converts timeout arguments
+ * into the form required by the <tt>Object.wait</tt> method.
+ *
+ * <p>For example, you could implement a blocking <tt>poll</tt>
+ * method (see {@link BlockingQueue#poll BlockingQueue.poll})
+ * using:
+ *
+ * <pre> public synchronized Object poll(long timeout, TimeUnit unit) throws InterruptedException {
+ * while (empty) {
+ * unit.timedWait(this, timeout);
+ * ...
+ * }
+ * }</pre>
+ *
+ * @param obj the object to wait on
+ * @param timeout the maximum time to wait. If less than
+ * or equal to zero, do not wait at all.
+ * @throws InterruptedException if interrupted while waiting.
+ * @see java.lang.Object#wait(long, int)
+ */
+ public void timedWait(Object obj, long timeout)
+ throws InterruptedException {
+ if (timeout > 0) {
+ long ms = toMillis(timeout);
+ int ns = excessNanos(timeout, ms);
+ obj.wait(ms, ns);
+ }
+ }
+
+ /**
+ * Performs a timed <tt>Thread.join</tt> using this time unit.
+ * This is a convenience method that converts time arguments into the
+ * form required by the <tt>Thread.join</tt> method.
+ * @param thread the thread to wait for
+ * @param timeout the maximum time to wait. If less than
+ * or equal to zero, do not wait at all.
+ * @throws InterruptedException if interrupted while waiting.
+ * @see java.lang.Thread#join(long, int)
+ */
+ public void timedJoin(Thread thread, long timeout)
+ throws InterruptedException {
+ if (timeout > 0) {
+ long ms = toMillis(timeout);
+ int ns = excessNanos(timeout, ms);
+ thread.join(ms, ns);
+ }
+ }
+
+ /**
+ * Performs a <tt>Thread.sleep</tt> using this unit.
+ * This is a convenience method that converts time arguments into the
+ * form required by the <tt>Thread.sleep</tt> method.
+ * @param timeout the maximum time to sleep. If less than
+ * or equal to zero, do not sleep at all.
+ * @throws InterruptedException if interrupted while sleeping.
+ * @see java.lang.Thread#sleep
+ */
+ public void sleep(long timeout) throws InterruptedException {
+ if (timeout > 0) {
+ long ms = toMillis(timeout);
+ int ns = excessNanos(timeout, ms);
+ Thread.sleep(ms, ns);
+ }
+ }
+
+ public String toString() {
+ return name;
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/TimeoutException.java b/src/actors/scala/actors/threadpool/TimeoutException.java
new file mode 100644
index 0000000000..c6fdbe5dc4
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/TimeoutException.java
@@ -0,0 +1,38 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool;
+
+/**
+ * Exception thrown when a blocking operation times out. Blocking
+ * operations for which a timeout is specified need a means to
+ * indicate that the timeout has occurred. For many such operations it
+ * is possible to return a value that indicates timeout; when that is
+ * not possible or desirable then <tt>TimeoutException</tt> should be
+ * declared and thrown.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class TimeoutException extends Exception {
+ private static final long serialVersionUID = 1900926677490660714L;
+
+ /**
+ * Constructs a <tt>TimeoutException</tt> with no specified detail
+ * message.
+ */
+ public TimeoutException() {}
+
+ /**
+ * Constructs a <tt>TimeoutException</tt> with the specified detail
+ * message.
+ *
+ * @param message the detail message
+ */
+ public TimeoutException(String message) {
+ super(message);
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/helpers/FIFOWaitQueue.java b/src/actors/scala/actors/threadpool/helpers/FIFOWaitQueue.java
new file mode 100644
index 0000000000..6306faa08f
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/helpers/FIFOWaitQueue.java
@@ -0,0 +1,85 @@
+package scala.actors.threadpool.helpers;
+
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Simple linked list queue used in FIFOSemaphore.
+ * Methods are not synchronized; they depend on synch of callers.
+ * Must be public, since it is used by Semaphore (outside this package).
+ * NOTE: this class is NOT present in java.util.concurrent.
+ **/
+
+public class FIFOWaitQueue extends WaitQueue implements java.io.Serializable {
+
+ private final static long serialVersionUID = 2416444691925378811L;
+
+ protected transient WaitNode head_ = null;
+ protected transient WaitNode tail_ = null;
+
+ public FIFOWaitQueue() {}
+
+ public void insert(WaitNode w) {
+ if (tail_ == null)
+ head_ = tail_ = w;
+ else {
+ tail_.next = w;
+ tail_ = w;
+ }
+ }
+
+ public WaitNode extract() {
+ if (head_ == null)
+ return null;
+ else {
+ WaitNode w = head_;
+ head_ = w.next;
+ if (head_ == null)
+ tail_ = null;
+ w.next = null;
+ return w;
+ }
+ }
+
+ public void putBack(WaitNode w) {
+ w.next = head_;
+ head_ = w;
+ if (tail_ == null)
+ tail_ = w;
+ }
+
+ public boolean hasNodes() {
+ return head_ != null;
+ }
+
+ public int getLength() {
+ int count = 0;
+ WaitNode node = head_;
+ while (node != null) {
+ if (node.waiting) count++;
+ node = node.next;
+ }
+ return count;
+ }
+
+ public Collection getWaitingThreads() {
+ List list = new ArrayList();
+ int count = 0;
+ WaitNode node = head_;
+ while (node != null) {
+ if (node.waiting) list.add(node.owner);
+ node = node.next;
+ }
+ return list;
+ }
+
+ public boolean isWaiting(Thread thread) {
+ if (thread == null) throw new NullPointerException();
+ for (WaitNode node = head_; node != null; node = node.next) {
+ if (node.waiting && node.owner == thread) return true;
+ }
+ return false;
+ }
+
+}
diff --git a/src/actors/scala/actors/threadpool/helpers/NanoTimer.java b/src/actors/scala/actors/threadpool/helpers/NanoTimer.java
new file mode 100644
index 0000000000..f3edf13565
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/helpers/NanoTimer.java
@@ -0,0 +1,29 @@
+/*
+ * Written by Dawid Kurzyniec and released to the public domain, as explained
+ * at http://creativecommons.org/licenses/publicdomain
+ */
+package scala.actors.threadpool.helpers;
+
+/**
+ * Interface to specify custom implementation of precise timer.
+ *
+ * @author Dawid Kurzyniec
+ * @version 1.0
+ */
+public interface NanoTimer {
+ /**
+ * Returns the current value of the most precise available system timer,
+ * in nanoseconds. This method can only be used to measure elapsed time and
+ * is not related to any other notion of system or wall-clock time. The
+ * value returned represents nanoseconds since some fixed but arbitrary
+ * time (perhaps in the future, so values may be negative). This method
+ * provides nanosecond precision, but not necessarily nanosecond accuracy.
+ * No guarantees are made about how frequently values change. Differences
+ * in successive calls that span greater than approximately 292 years
+ * (263 nanoseconds) will not accurately compute elapsed time due to
+ * numerical overflow.
+ *
+ * @return The current value of the system timer, in nanoseconds.
+ */
+ long nanoTime();
+}
diff --git a/src/actors/scala/actors/threadpool/helpers/ThreadHelpers.java b/src/actors/scala/actors/threadpool/helpers/ThreadHelpers.java
new file mode 100644
index 0000000000..13da20c4d6
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/helpers/ThreadHelpers.java
@@ -0,0 +1,66 @@
+/*
+ * Written by Dawid Kurzyniec and released to the public domain, as explained
+ * at http://creativecommons.org/licenses/publicdomain
+ */
+package scala.actors.threadpool.helpers;
+
+/**
+ * Emulation of some new functionality present in java.lang.Thread in J2SE 5.0.
+ *
+ * @author Dawid Kurzyniec
+ * @version 1.0
+ */
+public class ThreadHelpers {
+
+ private ThreadHelpers() {}
+
+ /**
+ * Returns wrapped runnable that ensures that if an exception occurs
+ * during the execution, the specified exception handler is invoked.
+ * @param runnable runnable for which exceptions are to be intercepted
+ * @param handler the exception handler to call when exception occurs
+ * during execution of the given runnable
+ * @return wrapped runnable
+ */
+ public static Runnable assignExceptionHandler(final Runnable runnable,
+ final UncaughtExceptionHandler handler)
+ {
+ if (runnable == null || handler == null) {
+ throw new NullPointerException();
+ }
+ return new Runnable() {
+ public void run() {
+ try {
+ runnable.run();
+ }
+ catch (Throwable error) {
+ try {
+ handler.uncaughtException(Thread.currentThread(), error);
+ }
+ catch (Throwable ignore) {}
+ }
+ }
+ };
+ }
+
+ /**
+ * Abstraction of the exception handler which receives notifications of
+ * exceptions occurred possibly in various parts of the system. Exception
+ * handlers present attractive approach to exception handling in multi-threaded
+ * systems, as they can handle exceptions that occurred in different threads.
+ * <p>
+ * This class is analogous to Thread.UncaughtExceptionHandler in J2SE 5.0.
+ * Obviously you cannot use it the same way, e.g. you cannot assign the
+ * handler to the thread so that it is invoked when thread terminates.
+ * However, it can be {@link ThreadHelpers#assignExceptionHandler emulated}.
+ */
+ public static interface UncaughtExceptionHandler {
+ /**
+ * Notification of the uncaught exception that occurred within specified
+ * thread.
+ * @param thread the thread where the exception occurred
+ * @param error the exception
+ */
+ void uncaughtException(Thread thread, Throwable error);
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/helpers/Utils.java b/src/actors/scala/actors/threadpool/helpers/Utils.java
new file mode 100644
index 0000000000..df1dbd4960
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/helpers/Utils.java
@@ -0,0 +1,343 @@
+/*
+ * Written by Dawid Kurzyniec, based on code written by Doug Lea with assistance
+ * from members of JCP JSR-166 Expert Group. Released to the public domain,
+ * as explained at http://creativecommons.org/licenses/publicdomain.
+ *
+ * Thanks to Craig Mattocks for suggesting to use <code>sun.misc.Perf</code>.
+ */
+
+package scala.actors.threadpool.helpers;
+
+//import edu.emory.mathcs.backport.java.util.*;
+import scala.actors.threadpool.*;
+import scala.actors.threadpool.locks.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.lang.reflect.Array;
+import java.util.Iterator;
+import java.util.Collection;
+
+/**
+ * <p>
+ * This class groups together the functionality of java.util.concurrent that
+ * cannot be fully and reliably implemented in backport, but for which some
+ * form of emulation is possible.
+ * <p>
+ * Currently, this class contains methods related to nanosecond-precision
+ * timing, particularly via the {@link #nanoTime} method. To measure time
+ * accurately, this method by default uses <code>java.sun.Perf</code> on
+ * JDK1.4.2 and it falls back to <code>System.currentTimeMillis</code>
+ * on earlier JDKs.
+ *
+ * @author Dawid Kurzyniec
+ * @version 1.0
+ */
+public final class Utils {
+
+ private final static NanoTimer nanoTimer;
+ private final static String providerProp =
+ "edu.emory.mathcs.backport.java.util.concurrent.NanoTimerProvider";
+
+ static {
+ NanoTimer timer = null;
+ try {
+ String nanoTimerClassName = (String)
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return System.getProperty(providerProp);
+ }
+ });
+ if (nanoTimerClassName != null) {
+ Class cls = Class.forName(nanoTimerClassName);
+ timer = (NanoTimer) cls.newInstance();
+ }
+ }
+ catch (Exception e) {
+ System.err.println("WARNING: unable to load the system-property-defined " +
+ "nanotime provider; switching to the default");
+ e.printStackTrace();
+ }
+
+ if (timer == null) {
+ try {
+ timer = new SunPerfProvider();
+ }
+ catch (Throwable e) {}
+ }
+
+ if (timer == null) {
+ timer = new MillisProvider();
+ }
+
+ nanoTimer = timer;
+ }
+
+ private Utils() {}
+
+ /**
+ * Returns the current value of the most precise available system timer,
+ * in nanoseconds. This method can only be used to measure elapsed time and
+ * is not related to any other notion of system or wall-clock time. The
+ * value returned represents nanoseconds since some fixed but arbitrary
+ * time (perhaps in the future, so values may be negative). This method
+ * provides nanosecond precision, but not necessarily nanosecond accuracy.
+ * No guarantees are made about how frequently values change. Differences
+ * in successive calls that span greater than approximately 292 years
+ * (2^63 nanoseconds) will not accurately compute elapsed time due to
+ * numerical overflow.
+ * <p>
+ * <em>Implementation note:</em>By default, this method uses
+ * <code>sun.misc.Perf</code> on Java 1.4.2, and falls back to
+ * System.currentTimeMillis() emulation on earlier JDKs. Custom
+ * timer can be provided via the system property
+ * <code>edu.emory.mathcs.backport.java.util.concurrent.NanoTimerProvider</code>.
+ * The value of the property should name a class implementing
+ * {@link NanoTimer} interface.
+ * <p>
+ * Note: on JDK 1.4.2, <code>sun.misc.Perf</code> timer seems to have
+ * resolution of the order of 1 microsecond, measured on Linux.
+ *
+ * @return The current value of the system timer, in nanoseconds.
+ */
+ public static long nanoTime() {
+ return nanoTimer.nanoTime();
+ }
+
+ /**
+ * Causes the current thread to wait until it is signalled or interrupted,
+ * or the specified waiting time elapses. This method originally appears
+ * in the {@link Condition} interface, but it was moved to here since it
+ * can only be emulated, with very little accuracy guarantees: the
+ * efficient implementation requires accurate nanosecond timer and native
+ * support for nanosecond-precision wait queues, which are not usually
+ * present in JVMs prior to 1.5. Loss of precision may cause total waiting
+ * times to be systematically shorter than specified when re-waits occur.
+ *
+ * <p>The lock associated with this condition is atomically
+ * released and the current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until <em>one</em> of five things happens:
+ * <ul>
+ * <li>Some other thread invokes the {@link
+ * edu.emory.mathcs.backport.java.util.concurrent.locks.Condition#signal}
+ * method for this
+ * <tt>Condition</tt> and the current thread happens to be chosen as the
+ * thread to be awakened; or
+ * <li>Some other thread invokes the {@link
+ * edu.emory.mathcs.backport.java.util.concurrent.locks.Condition#signalAll}
+ * method for this
+ * <tt>Condition</tt>; or
+ * <li>Some other thread {@link Thread#interrupt interrupts} the current
+ * thread, and interruption of thread suspension is supported; or
+ * <li>The specified waiting time elapses; or
+ * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+ * </ul>
+ *
+ * <p>In all cases, before this method can return the current thread must
+ * re-acquire the lock associated with this condition. When the
+ * thread returns it is <em>guaranteed</em> to hold this lock.
+ *
+ * <p>If the current thread:
+ * <ul>
+ * <li>has its interrupted status set on entry to this method; or
+ * <li>is {@link Thread#interrupt interrupted} while waiting
+ * and interruption of thread suspension is supported,
+ * </ul>
+ * then {@link InterruptedException} is thrown and the current thread's
+ * interrupted status is cleared. It is not specified, in the first
+ * case, whether or not the test for interruption occurs before the lock
+ * is released.
+ *
+ * <p>The method returns an estimate of the number of nanoseconds
+ * remaining to wait given the supplied <tt>nanosTimeout</tt>
+ * value upon return, or a value less than or equal to zero if it
+ * timed out. Accuracy of this estimate is directly dependent on the
+ * accuracy of {@link #nanoTime}. This value can be used to determine
+ * whether and how long to re-wait in cases where the wait returns but an
+ * awaited condition still does not hold. Typical uses of this method take
+ * the following form:
+ *
+ * <pre>
+ * synchronized boolean aMethod(long timeout, TimeUnit unit) {
+ * long nanosTimeout = unit.toNanos(timeout);
+ * while (!conditionBeingWaitedFor) {
+ * if (nanosTimeout &gt; 0)
+ * nanosTimeout = theCondition.awaitNanos(nanosTimeout);
+ * else
+ * return false;
+ * }
+ * // ...
+ * }
+ * </pre>
+ *
+ * <p><b>Implementation Considerations</b>
+ * <p>The current thread is assumed to hold the lock associated with this
+ * <tt>Condition</tt> when this method is called.
+ * It is up to the implementation to determine if this is
+ * the case and if not, how to respond. Typically, an exception will be
+ * thrown (such as {@link IllegalMonitorStateException}) and the
+ * implementation must document that fact.
+ *
+ * <p>A condition implementation can favor responding to an interrupt over
+ * normal method return in response to a signal, or over indicating the
+ * elapse of the specified waiting time. In either case the implementation
+ * must ensure that the signal is redirected to another waiting thread, if
+ * there is one.
+ *
+ * @param cond the condition to wait for
+ * @param nanosTimeout the maximum time to wait, in nanoseconds
+ * @return A value less than or equal to zero if the wait has
+ * timed out; otherwise an estimate, that
+ * is strictly less than the <tt>nanosTimeout</tt> argument,
+ * of the time still remaining when this method returned.
+ *
+ * @throws InterruptedException if the current thread is interrupted (and
+ * interruption of thread suspension is supported).
+ */
+ public static long awaitNanos(Condition cond, long nanosTimeout)
+ throws InterruptedException
+ {
+ if (nanosTimeout <= 0) return nanosTimeout;
+ long now = nanoTime();
+ cond.await(nanosTimeout, TimeUnit.NANOSECONDS);
+ return nanosTimeout - (nanoTime() - now);
+ }
+
+ private static final class SunPerfProvider implements NanoTimer {
+ final Perf perf;
+ final long multiplier, divisor;
+ SunPerfProvider() {
+ perf = (Perf)
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return Perf.getPerf();
+ }
+ });
+ // trying to avoid BOTH overflow and rounding errors
+ long numerator = 1000000000;
+ long denominator = perf.highResFrequency();
+ long gcd = gcd(numerator, denominator);
+ this.multiplier = numerator / gcd;
+ this.divisor = denominator / gcd;
+ }
+ public long nanoTime() {
+ long ctr = perf.highResCounter();
+
+ // anything less sophisticated suffers either from rounding errors
+ // (FP arithmetics, backport v1.0) or overflow, when gcd is small
+ // (a bug in backport v1.0_01 reported by Ramesh Nethi)
+
+ return ((ctr / divisor) * multiplier) +
+ (ctr % divisor) * multiplier / divisor;
+
+ // even the above can theoretically cause problems if your JVM is
+ // running for sufficiently long time, but "sufficiently" means 292
+ // years (worst case), or 30,000 years (common case).
+
+ // Details: when the ticks ctr overflows, there is no way to avoid
+ // discontinuity in computed nanos, even in infinite arithmetics,
+ // unless we count number of overflows that the ctr went through
+ // since the JVM started. This follows from the fact that
+ // (2^64*multiplier/divisor) mod (2^64) > 0 in general case.
+ // Theoretically we could find out the number of overflows by
+ // checking System.currentTimeMillis(), but this is unreliable
+ // since the system time can unpredictably change during the JVM
+ // lifetime.
+ // The time to overflow is 2^63 / ticks frequency. With current
+ // ticks frequencies of several MHz, it gives about 30,000 years
+ // before the problem happens. If ticks frequency reaches 1 GHz, the
+ // time to overflow is 292 years. It is unlikely that the frequency
+ // ever exceeds 1 GHz. We could double the time to overflow
+ // (to 2^64 / frequency) by using unsigned arithmetics, e.g. by
+ // adding the following correction whenever the ticks is negative:
+ // -2*((Long.MIN_VALUE / divisor) * multiplier +
+ // (Long.MIN_VALUE % divisor) * multiplier / divisor)
+ // But, with the worst case of as much as 292 years, it does not
+ // seem justified.
+ }
+ }
+
+ private static final class MillisProvider implements NanoTimer {
+ MillisProvider() {}
+ public long nanoTime() {
+ return System.currentTimeMillis() * 1000000;
+ }
+ }
+
+ private static long gcd(long a, long b) {
+ long r;
+ while (b>0) { r = a % b; a = b; b = r; }
+ return a;
+ }
+
+
+ public static Object[] collectionToArray(Collection c) {
+ // guess the array size; expect to possibly be different
+ int len = c.size();
+ Object[] arr = new Object[len];
+ Iterator itr = c.iterator();
+ int idx = 0;
+ while (true) {
+ while (idx < len && itr.hasNext()) {
+ arr[idx++] = itr.next();
+ }
+ if (!itr.hasNext()) {
+ if (idx == len) return arr;
+ // otherwise have to trim
+ return Arrays.copyOf(arr, idx, Object[].class);
+ }
+ // otherwise, have to grow
+ int newcap = ((arr.length/2)+1)*3;
+ if (newcap < arr.length) {
+ // overflow
+ if (arr.length < Integer.MAX_VALUE) {
+ newcap = Integer.MAX_VALUE;
+ }
+ else {
+ throw new OutOfMemoryError("required array size too large");
+ }
+ }
+ arr = Arrays.copyOf(arr, newcap, Object[].class);
+ len = newcap;
+ }
+ }
+
+ public static Object[] collectionToArray(Collection c, Object[] a) {
+ Class aType = a.getClass();
+ // guess the array size; expect to possibly be different
+ int len = c.size();
+ Object[] arr = (a.length >= len ? a :
+ (Object[])Array.newInstance(aType.getComponentType(), len));
+ Iterator itr = c.iterator();
+ int idx = 0;
+ while (true) {
+ while (idx < len && itr.hasNext()) {
+ arr[idx++] = itr.next();
+ }
+ if (!itr.hasNext()) {
+ if (idx == len) return arr;
+ if (arr == a) {
+ // orig array -> null terminate
+ a[idx] = null;
+ return a;
+ }
+ else {
+ // have to trim
+ return Arrays.copyOf(arr, idx, aType);
+ }
+ }
+ // otherwise, have to grow
+ int newcap = ((arr.length/2)+1)*3;
+ if (newcap < arr.length) {
+ // overflow
+ if (arr.length < Integer.MAX_VALUE) {
+ newcap = Integer.MAX_VALUE;
+ }
+ else {
+ throw new OutOfMemoryError("required array size too large");
+ }
+ }
+ arr = Arrays.copyOf(arr, newcap, aType);
+ len = newcap;
+ }
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/helpers/WaitQueue.java b/src/actors/scala/actors/threadpool/helpers/WaitQueue.java
new file mode 100644
index 0000000000..bcbf29e5c2
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/helpers/WaitQueue.java
@@ -0,0 +1,146 @@
+/*
+ based on file: QueuedSemaphore.java
+ Originally written by Doug Lea and released into the public domain.
+ This may be used for any purposes whatsoever without acknowledgment.
+ Thanks for the assistance and support of Sun Microsystems Labs,
+ and everyone contributing, testing, and using this code.
+ History:
+ Date Who What
+ 11Jun1998 dl Create public version
+ 5Aug1998 dl replaced int counters with longs
+ 24Aug1999 dl release(n): screen arguments
+ */
+
+package scala.actors.threadpool.helpers;
+
+import java.util.Collection;
+import scala.actors.threadpool.*;
+
+/**
+ * Base class for internal queue classes for semaphores, etc.
+ * Relies on subclasses to actually implement queue mechanics.
+ * NOTE: this class is NOT present in java.util.concurrent.
+ **/
+
+public abstract class WaitQueue {
+
+ public abstract void insert(WaitNode w); // assumed not to block
+ public abstract WaitNode extract(); // should return null if empty
+ public abstract void putBack(WaitNode w);
+
+ public abstract boolean hasNodes();
+ public abstract int getLength();
+ public abstract Collection getWaitingThreads();
+ public abstract boolean isWaiting(Thread thread);
+
+ public static interface QueuedSync {
+ // invoked with sync on wait node, (atomically) just before enqueuing
+ boolean recheck(WaitNode node);
+ // invoked with sync on wait node, (atomically) just before signalling
+ void takeOver(WaitNode node);
+ }
+
+ public static class WaitNode {
+ boolean waiting = true;
+ WaitNode next = null;
+ final Thread owner;
+
+ public WaitNode() {
+ this.owner = Thread.currentThread();
+ }
+
+ public Thread getOwner() {
+ return owner;
+ }
+
+ public synchronized boolean signal(QueuedSync sync) {
+ boolean signalled = waiting;
+ if (signalled) {
+ waiting = false;
+ notify();
+ sync.takeOver(this);
+ }
+ return signalled;
+ }
+
+ public synchronized boolean doTimedWait(QueuedSync sync, long nanos)
+ throws InterruptedException
+ {
+ if (sync.recheck(this) || !waiting)
+ return true;
+ else if (nanos <= 0) {
+ waiting = false;
+ return false;
+ }
+ else {
+ long deadline = Utils.nanoTime() + nanos;
+ try {
+ for (; ; ) {
+ TimeUnit.NANOSECONDS.timedWait(this, nanos);
+ if (!waiting) // definitely signalled
+ return true;
+ else {
+ nanos = deadline - Utils.nanoTime();
+ if (nanos <= 0) { // timed out
+ waiting = false;
+ return false;
+ }
+ }
+ }
+ }
+ catch (InterruptedException ex) {
+ if (waiting) { // no notification
+ waiting = false; // invalidate for the signaller
+ throw ex;
+ }
+ else { // thread was interrupted after it was notified
+ Thread.currentThread().interrupt();
+ return true;
+ }
+ }
+ }
+ }
+
+ public synchronized void doWait(QueuedSync sync)
+ throws InterruptedException
+ {
+ if (!sync.recheck(this)) {
+ try {
+ while (waiting) wait();
+ }
+ catch (InterruptedException ex) {
+ if (waiting) { // no notification
+ waiting = false; // invalidate for the signaller
+ throw ex;
+ }
+ else { // thread was interrupted after it was notified
+ Thread.currentThread().interrupt();
+ return;
+ }
+ }
+ }
+ }
+
+ public synchronized void doWaitUninterruptibly(QueuedSync sync) {
+ if (!sync.recheck(this)) {
+ boolean wasInterrupted = Thread.interrupted();
+ try {
+ while (waiting) {
+ try {
+ wait();
+ }
+ catch (InterruptedException ex) {
+ wasInterrupted = true;
+ // no need to notify; if we were signalled, we
+ // must be not waiting, and we'll act like signalled
+ }
+ }
+ }
+ finally {
+ if (wasInterrupted) Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/actors/scala/actors/threadpool/locks/CondVar.java b/src/actors/scala/actors/threadpool/locks/CondVar.java
new file mode 100644
index 0000000000..132e72fe2a
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/locks/CondVar.java
@@ -0,0 +1,190 @@
+/*
+ File: ConditionVariable.java
+ Originally written by Doug Lea and released into the public domain.
+ This may be used for any purposes whatsoever without acknowledgment.
+ Thanks for the assistance and support of Sun Microsystems Labs,
+ and everyone contributing, testing, and using this code.
+ History:
+ Date Who What
+ 11Jun1998 dl Create public version
+ */
+
+package scala.actors.threadpool.locks;
+
+import java.util.Collection;
+import java.util.Date;
+import scala.actors.threadpool.*;
+import scala.actors.threadpool.helpers.*;
+
+class CondVar implements Condition, java.io.Serializable {
+
+ /** The lock **/
+ protected final ExclusiveLock lock;
+
+ /**
+ * Create a new CondVar that relies on the given mutual
+ * exclusion lock.
+ * @param lock A non-reentrant mutual exclusion lock.
+ **/
+
+ CondVar(ExclusiveLock lock) {
+ this.lock = lock;
+ }
+
+ public void awaitUninterruptibly() {
+ int holdCount = lock.getHoldCount();
+ if (holdCount == 0) {
+ throw new IllegalMonitorStateException();
+ }
+ // avoid instant spurious wakeup if thread already interrupted
+ boolean wasInterrupted = Thread.interrupted();
+ try {
+ synchronized (this) {
+ for (int i=holdCount; i>0; i--) lock.unlock();
+ try {
+ wait();
+ }
+ catch (InterruptedException ex) {
+ wasInterrupted = true;
+ // may have masked the signal and there is no way
+ // to tell; we must wake up spuriously
+ }
+ }
+ }
+ finally {
+ for (int i=holdCount; i>0; i--) lock.lock();
+ if (wasInterrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void await() throws InterruptedException {
+ int holdCount = lock.getHoldCount();
+ if (holdCount == 0) {
+ throw new IllegalMonitorStateException();
+ }
+ if (Thread.interrupted()) throw new InterruptedException();
+ try {
+ synchronized (this) {
+ for (int i=holdCount; i>0; i--) lock.unlock();
+ try {
+ wait();
+ }
+ catch (InterruptedException ex) {
+ notify();
+ throw ex;
+ }
+ }
+ }
+ finally {
+ for (int i=holdCount; i>0; i--) lock.lock();
+ }
+ }
+
+ public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
+ int holdCount = lock.getHoldCount();
+ if (holdCount == 0) {
+ throw new IllegalMonitorStateException();
+ }
+ if (Thread.interrupted()) throw new InterruptedException();
+ long nanos = unit.toNanos(timeout);
+ boolean success = false;
+ try {
+ synchronized (this) {
+ for (int i=holdCount; i>0; i--) lock.unlock();
+ try {
+ if (nanos > 0) {
+ long start = Utils.nanoTime();
+ TimeUnit.NANOSECONDS.timedWait(this, nanos);
+ // DK: due to coarse-grained (millis) clock, it seems
+ // preferable to acknowledge timeout (success == false)
+ // when the equality holds (timing is exact)
+ success = Utils.nanoTime() - start < nanos;
+ }
+ }
+ catch (InterruptedException ex) {
+ notify();
+ throw ex;
+ }
+ }
+ }
+ finally {
+ for (int i=holdCount; i>0; i--) lock.lock();
+ }
+ return success;
+ }
+
+// public long awaitNanos(long timeout) throws InterruptedException {
+// throw new UnsupportedOperationException();
+// }
+//
+ public boolean awaitUntil(Date deadline) throws InterruptedException {
+ if (deadline == null) throw new NullPointerException();
+ int holdCount = lock.getHoldCount();
+ if (holdCount == 0) {
+ throw new IllegalMonitorStateException();
+ }
+ long abstime = deadline.getTime();
+ if (Thread.interrupted()) throw new InterruptedException();
+
+ boolean success = false;
+ try {
+ synchronized (this) {
+ for (int i=holdCount; i>0; i--) lock.unlock();
+ try {
+ long start = System.currentTimeMillis();
+ long msecs = abstime - start;
+ if (msecs > 0) {
+ wait(msecs);
+ // DK: due to coarse-grained (millis) clock, it seems
+ // preferable to acknowledge timeout (success == false)
+ // when the equality holds (timing is exact)
+ success = System.currentTimeMillis() - start < msecs;
+ }
+ }
+ catch (InterruptedException ex) {
+ notify();
+ throw ex;
+ }
+ }
+ }
+ finally {
+ for (int i=holdCount; i>0; i--) lock.lock();
+ }
+ return success;
+ }
+
+ public synchronized void signal() {
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ notify();
+ }
+
+ public synchronized void signalAll() {
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ notifyAll();
+ }
+
+ protected ExclusiveLock getLock() { return lock; }
+
+ protected boolean hasWaiters() {
+ throw new UnsupportedOperationException("Use FAIR version");
+ }
+
+ protected int getWaitQueueLength() {
+ throw new UnsupportedOperationException("Use FAIR version");
+ }
+
+ protected Collection getWaitingThreads() {
+ throw new UnsupportedOperationException("Use FAIR version");
+ }
+
+ static interface ExclusiveLock extends Lock {
+ boolean isHeldByCurrentThread();
+ int getHoldCount();
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/locks/Condition.java b/src/actors/scala/actors/threadpool/locks/Condition.java
new file mode 100644
index 0000000000..0553684321
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/locks/Condition.java
@@ -0,0 +1,434 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool.locks;
+
+import scala.actors.threadpool.*;
+import java.util.Date;
+
+/**
+ * {@code Condition} factors out the {@code Object} monitor
+ * methods ({@link Object#wait() wait}, {@link Object#notify notify}
+ * and {@link Object#notifyAll notifyAll}) into distinct objects to
+ * give the effect of having multiple wait-sets per object, by
+ * combining them with the use of arbitrary {@link Lock} implementations.
+ * Where a {@code Lock} replaces the use of {@code synchronized} methods
+ * and statements, a {@code Condition} replaces the use of the Object
+ * monitor methods.
+ *
+ * <p>Conditions (also known as <em>condition queues</em> or
+ * <em>condition variables</em>) provide a means for one thread to
+ * suspend execution (to &quot;wait&quot;) until notified by another
+ * thread that some state condition may now be true. Because access
+ * to this shared state information occurs in different threads, it
+ * must be protected, so a lock of some form is associated with the
+ * condition. The key property that waiting for a condition provides
+ * is that it <em>atomically</em> releases the associated lock and
+ * suspends the current thread, just like {@code Object.wait}.
+ *
+ * <p>A {@code Condition} instance is intrinsically bound to a lock.
+ * To obtain a {@code Condition} instance for a particular {@link Lock}
+ * instance use its {@link Lock#newCondition newCondition()} method.
+ *
+ * <p>As an example, suppose we have a bounded buffer which supports
+ * {@code put} and {@code take} methods. If a
+ * {@code take} is attempted on an empty buffer, then the thread will block
+ * until an item becomes available; if a {@code put} is attempted on a
+ * full buffer, then the thread will block until a space becomes available.
+ * We would like to keep waiting {@code put} threads and {@code take}
+ * threads in separate wait-sets so that we can use the optimization of
+ * only notifying a single thread at a time when items or spaces become
+ * available in the buffer. This can be achieved using two
+ * {@link Condition} instances.
+ * <pre>
+ * class BoundedBuffer {
+ * <b>final Lock lock = new ReentrantLock();</b>
+ * final Condition notFull = <b>lock.newCondition(); </b>
+ * final Condition notEmpty = <b>lock.newCondition(); </b>
+ *
+ * final Object[] items = new Object[100];
+ * int putptr, takeptr, count;
+ *
+ * public void put(Object x) throws InterruptedException {
+ * <b>lock.lock();
+ * try {</b>
+ * while (count == items.length)
+ * <b>notFull.await();</b>
+ * items[putptr] = x;
+ * if (++putptr == items.length) putptr = 0;
+ * ++count;
+ * <b>notEmpty.signal();</b>
+ * <b>} finally {
+ * lock.unlock();
+ * }</b>
+ * }
+ *
+ * public Object take() throws InterruptedException {
+ * <b>lock.lock();
+ * try {</b>
+ * while (count == 0)
+ * <b>notEmpty.await();</b>
+ * Object x = items[takeptr];
+ * if (++takeptr == items.length) takeptr = 0;
+ * --count;
+ * <b>notFull.signal();</b>
+ * return x;
+ * <b>} finally {
+ * lock.unlock();
+ * }</b>
+ * }
+ * }
+ * </pre>
+ *
+ * (The {@link edu.emory.mathcs.backport.java.util.concurrent.ArrayBlockingQueue} class provides
+ * this functionality, so there is no reason to implement this
+ * sample usage class.)
+ *
+ * <p>A {@code Condition} implementation can provide behavior and semantics
+ * that is
+ * different from that of the {@code Object} monitor methods, such as
+ * guaranteed ordering for notifications, or not requiring a lock to be held
+ * when performing notifications.
+ * If an implementation provides such specialized semantics then the
+ * implementation must document those semantics.
+ *
+ * <p>Note that {@code Condition} instances are just normal objects and can
+ * themselves be used as the target in a {@code synchronized} statement,
+ * and can have their own monitor {@link Object#wait wait} and
+ * {@link Object#notify notification} methods invoked.
+ * Acquiring the monitor lock of a {@code Condition} instance, or using its
+ * monitor methods, has no specified relationship with acquiring the
+ * {@link Lock} associated with that {@code Condition} or the use of its
+ * {@linkplain #await waiting} and {@linkplain #signal signalling} methods.
+ * It is recommended that to avoid confusion you never use {@code Condition}
+ * instances in this way, except perhaps within their own implementation.
+ *
+ * <p>Except where noted, passing a {@code null} value for any parameter
+ * will result in a {@link NullPointerException} being thrown.
+ *
+ * <h3>Implementation Considerations</h3>
+ *
+ * <p>When waiting upon a {@code Condition}, a &quot;<em>spurious
+ * wakeup</em>&quot; is permitted to occur, in
+ * general, as a concession to the underlying platform semantics.
+ * This has little practical impact on most application programs as a
+ * {@code Condition} should always be waited upon in a loop, testing
+ * the state predicate that is being waited for. An implementation is
+ * free to remove the possibility of spurious wakeups but it is
+ * recommended that applications programmers always assume that they can
+ * occur and so always wait in a loop.
+ *
+ * <p>The three forms of condition waiting
+ * (interruptible, non-interruptible, and timed) may differ in their ease of
+ * implementation on some platforms and in their performance characteristics.
+ * In particular, it may be difficult to provide these features and maintain
+ * specific semantics such as ordering guarantees.
+ * Further, the ability to interrupt the actual suspension of the thread may
+ * not always be feasible to implement on all platforms.
+ *
+ * <p>Consequently, an implementation is not required to define exactly the
+ * same guarantees or semantics for all three forms of waiting, nor is it
+ * required to support interruption of the actual suspension of the thread.
+ *
+ * <p>An implementation is required to
+ * clearly document the semantics and guarantees provided by each of the
+ * waiting methods, and when an implementation does support interruption of
+ * thread suspension then it must obey the interruption semantics as defined
+ * in this interface.
+ *
+ * <p>As interruption generally implies cancellation, and checks for
+ * interruption are often infrequent, an implementation can favor responding
+ * to an interrupt over normal method return. This is true even if it can be
+ * shown that the interrupt occurred after another action may have unblocked
+ * the thread. An implementation should document this behavior.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Condition {
+
+ /**
+ * Causes the current thread to wait until it is signalled or
+ * {@linkplain Thread#interrupt interrupted}.
+ *
+ * <p>The lock associated with this {@code Condition} is atomically
+ * released and the current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until <em>one</em> of four things happens:
+ * <ul>
+ * <li>Some other thread invokes the {@link #signal} method for this
+ * {@code Condition} and the current thread happens to be chosen as the
+ * thread to be awakened; or
+ * <li>Some other thread invokes the {@link #signalAll} method for this
+ * {@code Condition}; or
+ * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+ * current thread, and interruption of thread suspension is supported; or
+ * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+ * </ul>
+ *
+ * <p>In all cases, before this method can return the current thread must
+ * re-acquire the lock associated with this condition. When the
+ * thread returns it is <em>guaranteed</em> to hold this lock.
+ *
+ * <p>If the current thread:
+ * <ul>
+ * <li>has its interrupted status set on entry to this method; or
+ * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+ * and interruption of thread suspension is supported,
+ * </ul>
+ * then {@link InterruptedException} is thrown and the current thread's
+ * interrupted status is cleared. It is not specified, in the first
+ * case, whether or not the test for interruption occurs before the lock
+ * is released.
+ *
+ * <p><b>Implementation Considerations</b>
+ *
+ * <p>The current thread is assumed to hold the lock associated with this
+ * {@code Condition} when this method is called.
+ * It is up to the implementation to determine if this is
+ * the case and if not, how to respond. Typically, an exception will be
+ * thrown (such as {@link IllegalMonitorStateException}) and the
+ * implementation must document that fact.
+ *
+ * <p>An implementation can favor responding to an interrupt over normal
+ * method return in response to a signal. In that case the implementation
+ * must ensure that the signal is redirected to another waiting thread, if
+ * there is one.
+ *
+ * @throws InterruptedException if the current thread is interrupted
+ * (and interruption of thread suspension is supported)
+ */
+ void await() throws InterruptedException;
+
+ /**
+ * Causes the current thread to wait until it is signalled.
+ *
+ * <p>The lock associated with this condition is atomically
+ * released and the current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until <em>one</em> of three things happens:
+ * <ul>
+ * <li>Some other thread invokes the {@link #signal} method for this
+ * {@code Condition} and the current thread happens to be chosen as the
+ * thread to be awakened; or
+ * <li>Some other thread invokes the {@link #signalAll} method for this
+ * {@code Condition}; or
+ * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+ * </ul>
+ *
+ * <p>In all cases, before this method can return the current thread must
+ * re-acquire the lock associated with this condition. When the
+ * thread returns it is <em>guaranteed</em> to hold this lock.
+ *
+ * <p>If the current thread's interrupted status is set when it enters
+ * this method, or it is {@linkplain Thread#interrupt interrupted}
+ * while waiting, it will continue to wait until signalled. When it finally
+ * returns from this method its interrupted status will still
+ * be set.
+ *
+ * <p><b>Implementation Considerations</b>
+ *
+ * <p>The current thread is assumed to hold the lock associated with this
+ * {@code Condition} when this method is called.
+ * It is up to the implementation to determine if this is
+ * the case and if not, how to respond. Typically, an exception will be
+ * thrown (such as {@link IllegalMonitorStateException}) and the
+ * implementation must document that fact.
+ */
+ void awaitUninterruptibly();
+
+// /**
+// * Causes the current thread to wait until it is signalled or interrupted,
+// * or the specified waiting time elapses.
+// *
+// * <p>The lock associated with this condition is atomically
+// * released and the current thread becomes disabled for thread scheduling
+// * purposes and lies dormant until <em>one</em> of five things happens:
+// * <ul>
+// * <li>Some other thread invokes the {@link #signal} method for this
+// * <tt>Condition</tt> and the current thread happens to be chosen as the
+// * thread to be awakened; or
+// * <li>Some other thread invokes the {@link #signalAll} method for this
+// * <tt>Condition</tt>; or
+// * <li>Some other thread {@link Thread#interrupt interrupts} the current
+// * thread, and interruption of thread suspension is supported; or
+// * <li>The specified waiting time elapses; or
+// * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+// * </ul>
+// *
+// * <p>In all cases, before this method can return the current thread must
+// * re-acquire the lock associated with this condition. When the
+// * thread returns it is <em>guaranteed</em> to hold this lock.
+// *
+// * <p>If the current thread:
+// * <ul>
+// * <li>has its interrupted status set on entry to this method; or
+// * <li>is {@link Thread#interrupt interrupted} while waiting
+// * and interruption of thread suspension is supported,
+// * </ul>
+// * then {@link InterruptedException} is thrown and the current thread's
+// * interrupted status is cleared. It is not specified, in the first
+// * case, whether or not the test for interruption occurs before the lock
+// * is released.
+// *
+// * <p>The method returns an estimate of the number of nanoseconds
+// * remaining to wait given the supplied <tt>nanosTimeout</tt>
+// * value upon return, or a value less than or equal to zero if it
+// * timed out. This value can be used to determine whether and how
+// * long to re-wait in cases where the wait returns but an awaited
+// * condition still does not hold. Typical uses of this method take
+// * the following form:
+// *
+// * <pre>
+// * synchronized boolean aMethod(long timeout, TimeUnit unit) {
+// * long nanosTimeout = unit.toNanos(timeout);
+// * while (!conditionBeingWaitedFor) {
+// * if (nanosTimeout &gt; 0)
+// * nanosTimeout = theCondition.awaitNanos(nanosTimeout);
+// * else
+// * return false;
+// * }
+// * // ...
+// * }
+// * </pre>
+// *
+// * <p> Design note: This method requires a nanosecond argument so
+// * as to avoid truncation errors in reporting remaining times.
+// * Such precision loss would make it difficult for programmers to
+// * ensure that total waiting times are not systematically shorter
+// * than specified when re-waits occur.
+// *
+// * <p><b>Implementation Considerations</b>
+// * <p>The current thread is assumed to hold the lock associated with this
+// * <tt>Condition</tt> when this method is called.
+// * It is up to the implementation to determine if this is
+// * the case and if not, how to respond. Typically, an exception will be
+// * thrown (such as {@link IllegalMonitorStateException}) and the
+// * implementation must document that fact.
+// *
+// * <p>An implementation can favor responding to an interrupt over normal
+// * method return in response to a signal, or over indicating the elapse
+// * of the specified waiting time. In either case the implementation
+// * must ensure that the signal is redirected to another waiting thread, if
+// * there is one.
+// *
+// * @param nanosTimeout the maximum time to wait, in nanoseconds
+// * @return A value less than or equal to zero if the wait has
+// * timed out; otherwise an estimate, that
+// * is strictly less than the <tt>nanosTimeout</tt> argument,
+// * of the time still remaining when this method returned.
+// *
+// * @throws InterruptedException if the current thread is interrupted (and
+// * interruption of thread suspension is supported).
+// */
+// long awaitNanos(long nanosTimeout) throws InterruptedException;
+
+ /**
+ * Causes the current thread to wait until it is signalled or interrupted,
+ * or the specified waiting time elapses. This method is behaviorally
+ * equivalent to:<br>
+ * <pre>
+ * awaitNanos(unit.toNanos(time)) &gt; 0
+ * </pre>
+ * @param time the maximum time to wait
+ * @param unit the time unit of the {@code time} argument
+ * @return {@code false} if the waiting time detectably elapsed
+ * before return from the method, else {@code true}
+ * @throws InterruptedException if the current thread is interrupted
+ * (and interruption of thread suspension is supported)
+ */
+ boolean await(long time, TimeUnit unit) throws InterruptedException;
+
+ /**
+ * Causes the current thread to wait until it is signalled or interrupted,
+ * or the specified deadline elapses.
+ *
+ * <p>The lock associated with this condition is atomically
+ * released and the current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until <em>one</em> of five things happens:
+ * <ul>
+ * <li>Some other thread invokes the {@link #signal} method for this
+ * {@code Condition} and the current thread happens to be chosen as the
+ * thread to be awakened; or
+ * <li>Some other thread invokes the {@link #signalAll} method for this
+ * {@code Condition}; or
+ * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+ * current thread, and interruption of thread suspension is supported; or
+ * <li>The specified deadline elapses; or
+ * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+ * </ul>
+ *
+ * <p>In all cases, before this method can return the current thread must
+ * re-acquire the lock associated with this condition. When the
+ * thread returns it is <em>guaranteed</em> to hold this lock.
+ *
+ *
+ * <p>If the current thread:
+ * <ul>
+ * <li>has its interrupted status set on entry to this method; or
+ * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+ * and interruption of thread suspension is supported,
+ * </ul>
+ * then {@link InterruptedException} is thrown and the current thread's
+ * interrupted status is cleared. It is not specified, in the first
+ * case, whether or not the test for interruption occurs before the lock
+ * is released.
+ *
+ *
+ * <p>The return value indicates whether the deadline has elapsed,
+ * which can be used as follows:
+ * <pre>
+ * synchronized boolean aMethod(Date deadline) {
+ * boolean stillWaiting = true;
+ * while (!conditionBeingWaitedFor) {
+ * if (stillWaiting)
+ * stillWaiting = theCondition.awaitUntil(deadline);
+ * else
+ * return false;
+ * }
+ * // ...
+ * }
+ * </pre>
+ *
+ * <p><b>Implementation Considerations</b>
+ *
+ * <p>The current thread is assumed to hold the lock associated with this
+ * {@code Condition} when this method is called.
+ * It is up to the implementation to determine if this is
+ * the case and if not, how to respond. Typically, an exception will be
+ * thrown (such as {@link IllegalMonitorStateException}) and the
+ * implementation must document that fact.
+ *
+ * <p>An implementation can favor responding to an interrupt over normal
+ * method return in response to a signal, or over indicating the passing
+ * of the specified deadline. In either case the implementation
+ * must ensure that the signal is redirected to another waiting thread, if
+ * there is one.
+ *
+ * @param deadline the absolute time to wait until
+ * @return {@code false} if the deadline has elapsed upon return, else
+ * {@code true}
+ * @throws InterruptedException if the current thread is interrupted
+ * (and interruption of thread suspension is supported)
+ */
+ boolean awaitUntil(Date deadline) throws InterruptedException;
+
+ /**
+ * Wakes up one waiting thread.
+ *
+ * <p>If any threads are waiting on this condition then one
+ * is selected for waking up. That thread must then re-acquire the
+ * lock before returning from {@code await}.
+ */
+ void signal();
+
+ /**
+ * Wakes up all waiting threads.
+ *
+ * <p>If any threads are waiting on this condition then they are
+ * all woken up. Each thread must re-acquire the lock before it can
+ * return from {@code await}.
+ */
+ void signalAll();
+}
diff --git a/src/actors/scala/actors/threadpool/locks/FIFOCondVar.java b/src/actors/scala/actors/threadpool/locks/FIFOCondVar.java
new file mode 100644
index 0000000000..7495a8a884
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/locks/FIFOCondVar.java
@@ -0,0 +1,146 @@
+/*
+ File: ConditionVariable.java
+ Originally written by Doug Lea and released into the public domain.
+ This may be used for any purposes whatsoever without acknowledgment.
+ Thanks for the assistance and support of Sun Microsystems Labs,
+ and everyone contributing, testing, and using this code.
+ History:
+ Date Who What
+ 11Jun1998 dl Create public version
+ */
+
+package scala.actors.threadpool.locks;
+
+import java.util.Collection;
+import java.util.Date;
+import scala.actors.threadpool.*;
+import scala.actors.threadpool.helpers.*;
+
+class FIFOCondVar extends CondVar implements Condition, java.io.Serializable {
+
+ private static final WaitQueue.QueuedSync sync = new WaitQueue.QueuedSync() {
+ public boolean recheck(WaitQueue.WaitNode node) { return false; }
+ public void takeOver(WaitQueue.WaitNode node) {}
+ };
+
+ // wait queue; only accessed when holding the lock
+ private final WaitQueue wq = new FIFOWaitQueue();
+
+ /**
+ * Create a new CondVar that relies on the given mutual exclusion lock.
+ * @param lock A non-reentrant mutual exclusion lock.
+ */
+ FIFOCondVar(ExclusiveLock lock) {
+ super(lock);
+ }
+
+ public void awaitUninterruptibly() {
+ int holdCount = lock.getHoldCount();
+ if (holdCount == 0) {
+ throw new IllegalMonitorStateException();
+ }
+ WaitQueue.WaitNode n = new WaitQueue.WaitNode();
+ wq.insert(n);
+ for (int i=holdCount; i>0; i--) lock.unlock();
+ try {
+ n.doWaitUninterruptibly(sync);
+ }
+ finally {
+ for (int i=holdCount; i>0; i--) lock.lock();
+ }
+ }
+
+ public void await() throws InterruptedException {
+ int holdCount = lock.getHoldCount();
+ if (holdCount == 0) {
+ throw new IllegalMonitorStateException();
+ }
+ if (Thread.interrupted()) throw new InterruptedException();
+ WaitQueue.WaitNode n = new WaitQueue.WaitNode();
+ wq.insert(n);
+ for (int i=holdCount; i>0; i--) lock.unlock();
+ try {
+ n.doWait(sync);
+ }
+ finally {
+ for (int i=holdCount; i>0; i--) lock.lock();
+ }
+ }
+
+ public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
+ int holdCount = lock.getHoldCount();
+ if (holdCount == 0) {
+ throw new IllegalMonitorStateException();
+ }
+ if (Thread.interrupted()) throw new InterruptedException();
+ long nanos = unit.toNanos(timeout);
+ WaitQueue.WaitNode n = new WaitQueue.WaitNode();
+ wq.insert(n);
+ boolean success = false;
+ for (int i=holdCount; i>0; i--) lock.unlock();
+ try {
+ success = n.doTimedWait(sync, nanos);
+ }
+ finally {
+ for (int i=holdCount; i>0; i--) lock.lock();
+ }
+ return success;
+ }
+
+// public long awaitNanos(long timeout) throws InterruptedException {
+// throw new UnsupportedOperationException();
+// }
+//
+ public boolean awaitUntil(Date deadline) throws InterruptedException {
+ if (deadline == null) throw new NullPointerException();
+ long abstime = deadline.getTime();
+ long start = System.currentTimeMillis();
+ long msecs = abstime - start;
+ return await(msecs, TimeUnit.MILLISECONDS);
+ }
+
+ public void signal() {
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ for (;;) {
+ WaitQueue.WaitNode w = wq.extract();
+ if (w == null) return; // no one to signal
+ if (w.signal(sync)) return; // notify if still waiting, else skip
+ }
+ }
+
+ public void signalAll() {
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ for (;;) {
+ WaitQueue.WaitNode w = wq.extract();
+ if (w == null) return; // no more to signal
+ w.signal(sync);
+ }
+ }
+
+ protected boolean hasWaiters() {
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ return wq.hasNodes();
+ }
+
+ protected int getWaitQueueLength() {
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ return wq.getLength();
+ }
+
+ protected Collection getWaitingThreads() {
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ return wq.getWaitingThreads();
+ }
+
+
+}
diff --git a/src/actors/scala/actors/threadpool/locks/Lock.java b/src/actors/scala/actors/threadpool/locks/Lock.java
new file mode 100644
index 0000000000..47a4e8e777
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/locks/Lock.java
@@ -0,0 +1,328 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool.locks;
+
+import scala.actors.threadpool.TimeUnit;
+
+/**
+ * {@code Lock} implementations provide more extensive locking
+ * operations than can be obtained using {@code synchronized} methods
+ * and statements. They allow more flexible structuring, may have
+ * quite different properties, and may support multiple associated
+ * {@link Condition} objects.
+ *
+ * <p>A lock is a tool for controlling access to a shared resource by
+ * multiple threads. Commonly, a lock provides exclusive access to a
+ * shared resource: only one thread at a time can acquire the lock and
+ * all access to the shared resource requires that the lock be
+ * acquired first. However, some locks may allow concurrent access to
+ * a shared resource, such as the read lock of a {@link ReadWriteLock}.
+ *
+ * <p>The use of {@code synchronized} methods or statements provides
+ * access to the implicit monitor lock associated with every object, but
+ * forces all lock acquisition and release to occur in a block-structured way:
+ * when multiple locks are acquired they must be released in the opposite
+ * order, and all locks must be released in the same lexical scope in which
+ * they were acquired.
+ *
+ * <p>While the scoping mechanism for {@code synchronized} methods
+ * and statements makes it much easier to program with monitor locks,
+ * and helps avoid many common programming errors involving locks,
+ * there are occasions where you need to work with locks in a more
+ * flexible way. For example, some algorithms for traversing
+ * concurrently accessed data structures require the use of
+ * &quot;hand-over-hand&quot; or &quot;chain locking&quot;: you
+ * acquire the lock of node A, then node B, then release A and acquire
+ * C, then release B and acquire D and so on. Implementations of the
+ * {@code Lock} interface enable the use of such techniques by
+ * allowing a lock to be acquired and released in different scopes,
+ * and allowing multiple locks to be acquired and released in any
+ * order.
+ *
+ * <p>With this increased flexibility comes additional
+ * responsibility. The absence of block-structured locking removes the
+ * automatic release of locks that occurs with {@code synchronized}
+ * methods and statements. In most cases, the following idiom
+ * should be used:
+ *
+ * <pre><tt> Lock l = ...;
+ * l.lock();
+ * try {
+ * // access the resource protected by this lock
+ * } finally {
+ * l.unlock();
+ * }
+ * </tt></pre>
+ *
+ * When locking and unlocking occur in different scopes, care must be
+ * taken to ensure that all code that is executed while the lock is
+ * held is protected by try-finally or try-catch to ensure that the
+ * lock is released when necessary.
+ *
+ * <p>{@code Lock} implementations provide additional functionality
+ * over the use of {@code synchronized} methods and statements by
+ * providing a non-blocking attempt to acquire a lock ({@link
+ * #tryLock()}), an attempt to acquire the lock that can be
+ * interrupted ({@link #lockInterruptibly}, and an attempt to acquire
+ * the lock that can timeout ({@link #tryLock(long, TimeUnit)}).
+ *
+ * <p>A {@code Lock} class can also provide behavior and semantics
+ * that is quite different from that of the implicit monitor lock,
+ * such as guaranteed ordering, non-reentrant usage, or deadlock
+ * detection. If an implementation provides such specialized semantics
+ * then the implementation must document those semantics.
+ *
+ * <p>Note that {@code Lock} instances are just normal objects and can
+ * themselves be used as the target in a {@code synchronized} statement.
+ * Acquiring the
+ * monitor lock of a {@code Lock} instance has no specified relationship
+ * with invoking any of the {@link #lock} methods of that instance.
+ * It is recommended that to avoid confusion you never use {@code Lock}
+ * instances in this way, except within their own implementation.
+ *
+ * <p>Except where noted, passing a {@code null} value for any
+ * parameter will result in a {@link NullPointerException} being
+ * thrown.
+ *
+ * <h3>Memory Synchronization</h3>
+ *
+ * <p>All {@code Lock} implementations <em>must</em> enforce the same
+ * memory synchronization semantics as provided by the built-in monitor
+ * lock, as described in <a href="http://java.sun.com/docs/books/jls/">
+ * The Java Language Specification, Third Edition (17.4 Memory Model)</a>:
+ * <ul>
+ * <li>A successful {@code lock} operation has the same memory
+ * synchronization effects as a successful <em>Lock</em> action.
+ * <li>A successful {@code unlock} operation has the same
+ * memory synchronization effects as a successful <em>Unlock</em> action.
+ * </ul>
+ *
+ * Unsuccessful locking and unlocking operations, and reentrant
+ * locking/unlocking operations, do not require any memory
+ * synchronization effects.
+ *
+ * <h3>Implementation Considerations</h3>
+ *
+ * <p> The three forms of lock acquisition (interruptible,
+ * non-interruptible, and timed) may differ in their performance
+ * characteristics, ordering guarantees, or other implementation
+ * qualities. Further, the ability to interrupt the <em>ongoing</em>
+ * acquisition of a lock may not be available in a given {@code Lock}
+ * class. Consequently, an implementation is not required to define
+ * exactly the same guarantees or semantics for all three forms of
+ * lock acquisition, nor is it required to support interruption of an
+ * ongoing lock acquisition. An implementation is required to clearly
+ * document the semantics and guarantees provided by each of the
+ * locking methods. It must also obey the interruption semantics as
+ * defined in this interface, to the extent that interruption of lock
+ * acquisition is supported: which is either totally, or only on
+ * method entry.
+ *
+ * <p>As interruption generally implies cancellation, and checks for
+ * interruption are often infrequent, an implementation can favor responding
+ * to an interrupt over normal method return. This is true even if it can be
+ * shown that the interrupt occurred after another action may have unblocked
+ * the thread. An implementation should document this behavior.
+ *
+ * @see ReentrantLock
+ * @see Condition
+ * @see ReadWriteLock
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Lock {
+
+ /**
+ * Acquires the lock.
+ *
+ * <p>If the lock is not available then the current thread becomes
+ * disabled for thread scheduling purposes and lies dormant until the
+ * lock has been acquired.
+ *
+ * <p><b>Implementation Considerations</b>
+ *
+ * <p>A {@code Lock} implementation may be able to detect erroneous use
+ * of the lock, such as an invocation that would cause deadlock, and
+ * may throw an (unchecked) exception in such circumstances. The
+ * circumstances and the exception type must be documented by that
+ * {@code Lock} implementation.
+ */
+ void lock();
+
+ /**
+ * Acquires the lock unless the current thread is
+ * {@linkplain Thread#interrupt interrupted}.
+ *
+ * <p>Acquires the lock if it is available and returns immediately.
+ *
+ * <p>If the lock is not available then the current thread becomes
+ * disabled for thread scheduling purposes and lies dormant until
+ * one of two things happens:
+ *
+ * <ul>
+ * <li>The lock is acquired by the current thread; or
+ * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+ * current thread, and interruption of lock acquisition is supported.
+ * </ul>
+ *
+ * <p>If the current thread:
+ * <ul>
+ * <li>has its interrupted status set on entry to this method; or
+ * <li>is {@linkplain Thread#interrupt interrupted} while acquiring the
+ * lock, and interruption of lock acquisition is supported,
+ * </ul>
+ * then {@link InterruptedException} is thrown and the current thread's
+ * interrupted status is cleared.
+ *
+ * <p><b>Implementation Considerations</b>
+ *
+ * <p>The ability to interrupt a lock acquisition in some
+ * implementations may not be possible, and if possible may be an
+ * expensive operation. The programmer should be aware that this
+ * may be the case. An implementation should document when this is
+ * the case.
+ *
+ * <p>An implementation can favor responding to an interrupt over
+ * normal method return.
+ *
+ * <p>A {@code Lock} implementation may be able to detect
+ * erroneous use of the lock, such as an invocation that would
+ * cause deadlock, and may throw an (unchecked) exception in such
+ * circumstances. The circumstances and the exception type must
+ * be documented by that {@code Lock} implementation.
+ *
+ * @throws InterruptedException if the current thread is
+ * interrupted while acquiring the lock (and interruption
+ * of lock acquisition is supported).
+ */
+ void lockInterruptibly() throws InterruptedException;
+
+ /**
+ * Acquires the lock only if it is free at the time of invocation.
+ *
+ * <p>Acquires the lock if it is available and returns immediately
+ * with the value {@code true}.
+ * If the lock is not available then this method will return
+ * immediately with the value {@code false}.
+ *
+ * <p>A typical usage idiom for this method would be:
+ * <pre>
+ * Lock lock = ...;
+ * if (lock.tryLock()) {
+ * try {
+ * // manipulate protected state
+ * } finally {
+ * lock.unlock();
+ * }
+ * } else {
+ * // perform alternative actions
+ * }
+ * </pre>
+ * This usage ensures that the lock is unlocked if it was acquired, and
+ * doesn't try to unlock if the lock was not acquired.
+ *
+ * @return {@code true} if the lock was acquired and
+ * {@code false} otherwise
+ */
+ boolean tryLock();
+
+ /**
+ * Acquires the lock if it is free within the given waiting time and the
+ * current thread has not been {@linkplain Thread#interrupt interrupted}.
+ *
+ * <p>If the lock is available this method returns immediately
+ * with the value {@code true}.
+ * If the lock is not available then
+ * the current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until one of three things happens:
+ * <ul>
+ * <li>The lock is acquired by the current thread; or
+ * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+ * current thread, and interruption of lock acquisition is supported; or
+ * <li>The specified waiting time elapses
+ * </ul>
+ *
+ * <p>If the lock is acquired then the value {@code true} is returned.
+ *
+ * <p>If the current thread:
+ * <ul>
+ * <li>has its interrupted status set on entry to this method; or
+ * <li>is {@linkplain Thread#interrupt interrupted} while acquiring
+ * the lock, and interruption of lock acquisition is supported,
+ * </ul>
+ * then {@link InterruptedException} is thrown and the current thread's
+ * interrupted status is cleared.
+ *
+ * <p>If the specified waiting time elapses then the value {@code false}
+ * is returned.
+ * If the time is
+ * less than or equal to zero, the method will not wait at all.
+ *
+ * <p><b>Implementation Considerations</b>
+ *
+ * <p>The ability to interrupt a lock acquisition in some implementations
+ * may not be possible, and if possible may
+ * be an expensive operation.
+ * The programmer should be aware that this may be the case. An
+ * implementation should document when this is the case.
+ *
+ * <p>An implementation can favor responding to an interrupt over normal
+ * method return, or reporting a timeout.
+ *
+ * <p>A {@code Lock} implementation may be able to detect
+ * erroneous use of the lock, such as an invocation that would cause
+ * deadlock, and may throw an (unchecked) exception in such circumstances.
+ * The circumstances and the exception type must be documented by that
+ * {@code Lock} implementation.
+ *
+ * @param time the maximum time to wait for the lock
+ * @param unit the time unit of the {@code time} argument
+ * @return {@code true} if the lock was acquired and {@code false}
+ * if the waiting time elapsed before the lock was acquired
+ *
+ * @throws InterruptedException if the current thread is interrupted
+ * while acquiring the lock (and interruption of lock
+ * acquisition is supported)
+ */
+ boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
+
+ /**
+ * Releases the lock.
+ *
+ * <p><b>Implementation Considerations</b>
+ *
+ * <p>A {@code Lock} implementation will usually impose
+ * restrictions on which thread can release a lock (typically only the
+ * holder of the lock can release it) and may throw
+ * an (unchecked) exception if the restriction is violated.
+ * Any restrictions and the exception
+ * type must be documented by that {@code Lock} implementation.
+ */
+ void unlock();
+
+ /**
+ * Returns a new {@link Condition} instance that is bound to this
+ * {@code Lock} instance.
+ *
+ * <p>Before waiting on the condition the lock must be held by the
+ * current thread.
+ * A call to {@link Condition#await()} will atomically release the lock
+ * before waiting and re-acquire the lock before the wait returns.
+ *
+ * <p><b>Implementation Considerations</b>
+ *
+ * <p>The exact operation of the {@link Condition} instance depends on
+ * the {@code Lock} implementation and must be documented by that
+ * implementation.
+ *
+ * @return A new {@link Condition} instance for this {@code Lock} instance
+ * @throws UnsupportedOperationException if this {@code Lock}
+ * implementation does not support conditions
+ */
+ Condition newCondition();
+}
diff --git a/src/actors/scala/actors/threadpool/locks/ReadWriteLock.java b/src/actors/scala/actors/threadpool/locks/ReadWriteLock.java
new file mode 100644
index 0000000000..02983f9bd4
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/locks/ReadWriteLock.java
@@ -0,0 +1,104 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool.locks;
+
+/**
+ * A <tt>ReadWriteLock</tt> maintains a pair of associated {@link
+ * Lock locks}, one for read-only operations and one for writing.
+ * The {@link #readLock read lock} may be held simultaneously by
+ * multiple reader threads, so long as there are no writers. The
+ * {@link #writeLock write lock} is exclusive.
+ *
+ * <p>All <tt>ReadWriteLock</tt> implementations must guarantee that
+ * the memory synchronization effects of <tt>writeLock</tt> operations
+ * (as specified in the {@link Lock} interface) also hold with respect
+ * to the associated <tt>readLock</tt>. That is, a thread successfully
+ * acquiring the read lock will see all updates made upon previous
+ * release of the write lock.
+ *
+ * <p>A read-write lock allows for a greater level of concurrency in
+ * accessing shared data than that permitted by a mutual exclusion lock.
+ * It exploits the fact that while only a single thread at a time (a
+ * <em>writer</em> thread) can modify the shared data, in many cases any
+ * number of threads can concurrently read the data (hence <em>reader</em>
+ * threads).
+ * In theory, the increase in concurrency permitted by the use of a read-write
+ * lock will lead to performance improvements over the use of a mutual
+ * exclusion lock. In practice this increase in concurrency will only be fully
+ * realized on a multi-processor, and then only if the access patterns for
+ * the shared data are suitable.
+ *
+ * <p>Whether or not a read-write lock will improve performance over the use
+ * of a mutual exclusion lock depends on the frequency that the data is
+ * read compared to being modified, the duration of the read and write
+ * operations, and the contention for the data - that is, the number of
+ * threads that will try to read or write the data at the same time.
+ * For example, a collection that is initially populated with data and
+ * thereafter infrequently modified, while being frequently searched
+ * (such as a directory of some kind) is an ideal candidate for the use of
+ * a read-write lock. However, if updates become frequent then the data
+ * spends most of its time being exclusively locked and there is little, if any
+ * increase in concurrency. Further, if the read operations are too short
+ * the overhead of the read-write lock implementation (which is inherently
+ * more complex than a mutual exclusion lock) can dominate the execution
+ * cost, particularly as many read-write lock implementations still serialize
+ * all threads through a small section of code. Ultimately, only profiling
+ * and measurement will establish whether the use of a read-write lock is
+ * suitable for your application.
+ *
+ *
+ * <p>Although the basic operation of a read-write lock is straight-forward,
+ * there are many policy decisions that an implementation must make, which
+ * may affect the effectiveness of the read-write lock in a given application.
+ * Examples of these policies include:
+ * <ul>
+ * <li>Determining whether to grant the read lock or the write lock, when
+ * both readers and writers are waiting, at the time that a writer releases
+ * the write lock. Writer preference is common, as writes are expected to be
+ * short and infrequent. Reader preference is less common as it can lead to
+ * lengthy delays for a write if the readers are frequent and long-lived as
+ * expected. Fair, or &quot;in-order&quot; implementations are also possible.
+ *
+ * <li>Determining whether readers that request the read lock while a
+ * reader is active and a writer is waiting, are granted the read lock.
+ * Preference to the reader can delay the writer indefinitely, while
+ * preference to the writer can reduce the potential for concurrency.
+ *
+ * <li>Determining whether the locks are reentrant: can a thread with the
+ * write lock reacquire it? Can it acquire a read lock while holding the
+ * write lock? Is the read lock itself reentrant?
+ *
+ * <li>Can the write lock be downgraded to a read lock without allowing
+ * an intervening writer? Can a read lock be upgraded to a write lock,
+ * in preference to other waiting readers or writers?
+ *
+ * </ul>
+ * You should consider all of these things when evaluating the suitability
+ * of a given implementation for your application.
+ *
+ * @see ReentrantReadWriteLock
+ * @see Lock
+ * @see ReentrantLock
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ReadWriteLock {
+ /**
+ * Returns the lock used for reading.
+ *
+ * @return the lock used for reading.
+ */
+ Lock readLock();
+
+ /**
+ * Returns the lock used for writing.
+ *
+ * @return the lock used for writing.
+ */
+ Lock writeLock();
+}
diff --git a/src/actors/scala/actors/threadpool/locks/ReentrantLock.java b/src/actors/scala/actors/threadpool/locks/ReentrantLock.java
new file mode 100644
index 0000000000..b42ddd611b
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/locks/ReentrantLock.java
@@ -0,0 +1,959 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool.locks;
+
+import java.util.Collection;
+import scala.actors.threadpool.*;
+import scala.actors.threadpool.helpers.*;
+
+/**
+ * A reentrant mutual exclusion {@link Lock} with the same basic
+ * behavior and semantics as the implicit monitor lock accessed using
+ * {@code synchronized} methods and statements, but with extended
+ * capabilities.
+ *
+ * <p>A {@code ReentrantLock} is <em>owned</em> by the thread last
+ * successfully locking, but not yet unlocking it. A thread invoking
+ * {@code lock} will return, successfully acquiring the lock, when
+ * the lock is not owned by another thread. The method will return
+ * immediately if the current thread already owns the lock. This can
+ * be checked using methods {@link #isHeldByCurrentThread}, and {@link
+ * #getHoldCount}.
+ *
+ * <p>The constructor for this class accepts an optional
+ * <em>fairness</em> parameter. When set {@code true}, under
+ * contention, locks favor granting access to the longest-waiting
+ * thread. Otherwise this lock does not guarantee any particular
+ * access order. Programs using fair locks accessed by many threads
+ * may display lower overall throughput (i.e., are slower; often much
+ * slower) than those using the default setting, but have smaller
+ * variances in times to obtain locks and guarantee lack of
+ * starvation. Note however, that fairness of locks does not guarantee
+ * fairness of thread scheduling. Thus, one of many threads using a
+ * fair lock may obtain it multiple times in succession while other
+ * active threads are not progressing and not currently holding the
+ * lock.
+ * Also note that the untimed {@link #tryLock() tryLock} method does not
+ * honor the fairness setting. It will succeed if the lock
+ * is available even if other threads are waiting.
+ *
+ * <p>It is recommended practice to <em>always</em> immediately
+ * follow a call to {@code lock} with a {@code try} block, most
+ * typically in a before/after construction such as:
+ *
+ * <pre>
+ * class X {
+ * private final ReentrantLock lock = new ReentrantLock();
+ * // ...
+ *
+ * public void m() {
+ * lock.lock(); // block until condition holds
+ * try {
+ * // ... method body
+ * } finally {
+ * lock.unlock()
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ * <p>In addition to implementing the {@link Lock} interface, this
+ * class defines methods {@code isLocked} and
+ * {@code getLockQueueLength}, as well as some associated
+ * {@code protected} access methods that may be useful for
+ * instrumentation and monitoring.
+ *
+ * <p>Serialization of this class behaves in the same way as built-in
+ * locks: a deserialized lock is in the unlocked state, regardless of
+ * its state when serialized.
+ *
+ * <p>This lock supports a maximum of 2147483647 recursive locks by
+ * the same thread. Attempts to exceed this limit result in
+ * {@link Error} throws from locking methods.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @author Dawid Kurzyniec
+ */
+public class ReentrantLock implements Lock, java.io.Serializable,
+ CondVar.ExclusiveLock {
+ private static final long serialVersionUID = 7373984872572414699L;
+
+ private final Sync sync;
+
+ /**
+ * Base of synchronization control for this lock. Subclassed
+ * into fair and nonfair versions below.
+ */
+ static abstract class Sync implements java.io.Serializable {
+ private static final long serialVersionUID = -5179523762034025860L;
+
+ protected transient Thread owner_ = null;
+ protected transient int holds_ = 0;
+
+ protected Sync() {}
+
+ /**
+ * Performs {@link Lock#lock}. The main reason for subclassing
+ * is to allow fast path for nonfair version.
+ */
+ public abstract void lock();
+
+ public abstract void lockInterruptibly() throws InterruptedException;
+
+ final void incHolds() {
+ int nextHolds = ++holds_;
+ if (nextHolds < 0)
+ throw new Error("Maximum lock count exceeded");
+ holds_ = nextHolds;
+ }
+
+ public boolean tryLock() {
+ Thread caller = Thread.currentThread();
+ synchronized (this) {
+ if (owner_ == null) {
+ owner_ = caller;
+ holds_ = 1;
+ return true;
+ }
+ else if (caller == owner_) {
+ incHolds();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public abstract boolean tryLock(long nanos) throws InterruptedException;
+
+ public abstract void unlock();
+
+ public synchronized int getHoldCount() {
+ return isHeldByCurrentThread() ? holds_ : 0;
+ }
+
+ public synchronized boolean isHeldByCurrentThread() {
+ return holds_ > 0 && Thread.currentThread() == owner_;
+ }
+
+ public synchronized boolean isLocked() {
+ return owner_ != null;
+ }
+
+ public abstract boolean isFair();
+
+ protected synchronized Thread getOwner() {
+ return owner_;
+ }
+
+ public boolean hasQueuedThreads() {
+ throw new UnsupportedOperationException("Use FAIR version");
+ }
+
+ public int getQueueLength() {
+ throw new UnsupportedOperationException("Use FAIR version");
+ }
+
+ public Collection getQueuedThreads() {
+ throw new UnsupportedOperationException("Use FAIR version");
+ }
+
+ public boolean isQueued(Thread thread) {
+ throw new UnsupportedOperationException("Use FAIR version");
+ }
+ }
+
+ /**
+ * Sync object for non-fair locks
+ */
+ final static class NonfairSync extends Sync {
+ private static final long serialVersionUID = 7316153563782823691L;
+
+ NonfairSync() {}
+
+ /**
+ * Performs lock. Try immediate barge, backing up to normal
+ * acquire on failure.
+ */
+ public void lock() {
+ Thread caller = Thread.currentThread();
+ synchronized (this) {
+ if (owner_ == null) {
+ owner_ = caller;
+ holds_ = 1;
+ return;
+ }
+ else if (caller == owner_) {
+ incHolds();
+ return;
+ }
+ else {
+ boolean wasInterrupted = Thread.interrupted();
+ try {
+ while (true) {
+ try {
+ wait();
+ }
+ catch (InterruptedException e) {
+ wasInterrupted = true;
+ // no need to notify; if we were signalled, we
+ // will act as signalled, ignoring the
+ // interruption
+ }
+ if (owner_ == null) {
+ owner_ = caller;
+ holds_ = 1;
+ return;
+ }
+ }
+ }
+ finally {
+ if (wasInterrupted) Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ public void lockInterruptibly() throws InterruptedException {
+ if (Thread.interrupted()) throw new InterruptedException();
+ Thread caller = Thread.currentThread();
+ synchronized (this) {
+ if (owner_ == null) {
+ owner_ = caller;
+ holds_ = 1;
+ return;
+ }
+ else if (caller == owner_) {
+ incHolds();
+ return;
+ }
+ else {
+ try {
+ do { wait(); } while (owner_ != null);
+ owner_ = caller;
+ holds_ = 1;
+ return;
+ }
+ catch (InterruptedException ex) {
+ if (owner_ == null) notify();
+ throw ex;
+ }
+ }
+ }
+ }
+
+ public boolean tryLock(long nanos) throws InterruptedException {
+ if (Thread.interrupted()) throw new InterruptedException();
+ Thread caller = Thread.currentThread();
+
+ synchronized (this) {
+ if (owner_ == null) {
+ owner_ = caller;
+ holds_ = 1;
+ return true;
+ }
+ else if (caller == owner_) {
+ incHolds();
+ return true;
+ }
+ else if (nanos <= 0)
+ return false;
+ else {
+ long deadline = Utils.nanoTime() + nanos;
+ try {
+ for (; ; ) {
+ TimeUnit.NANOSECONDS.timedWait(this, nanos);
+ if (caller == owner_) {
+ incHolds();
+ return true;
+ }
+ else if (owner_ == null) {
+ owner_ = caller;
+ holds_ = 1;
+ return true;
+ }
+ else {
+ nanos = deadline - Utils.nanoTime();
+ if (nanos <= 0)
+ return false;
+ }
+ }
+ }
+ catch (InterruptedException ex) {
+ if (owner_ == null) notify();
+ throw ex;
+ }
+ }
+ }
+ }
+
+ public synchronized void unlock() {
+ if (Thread.currentThread() != owner_)
+ throw new IllegalMonitorStateException("Not owner");
+
+ if (--holds_ == 0) {
+ owner_ = null;
+ notify();
+ }
+ }
+
+ public final boolean isFair() {
+ return false;
+ }
+ }
+
+ /**
+ * Sync object for fair locks
+ */
+ final static class FairSync extends Sync implements WaitQueue.QueuedSync {
+ private static final long serialVersionUID = -3000897897090466540L;
+
+ private transient WaitQueue wq_ = new FIFOWaitQueue();
+
+ FairSync() {}
+
+ public synchronized boolean recheck(WaitQueue.WaitNode node) {
+ Thread caller = Thread.currentThread();
+ if (owner_ == null) {
+ owner_ = caller;
+ holds_ = 1;
+ return true;
+ }
+ else if (caller == owner_) {
+ incHolds();
+ return true;
+ }
+ wq_.insert(node);
+ return false;
+ }
+
+ public synchronized void takeOver(WaitQueue.WaitNode node) {
+ // assert (holds_ == 1 && owner_ == Thread.currentThread()
+ owner_ = node.getOwner();
+ }
+
+ public void lock() {
+ Thread caller = Thread.currentThread();
+ synchronized (this) {
+ if (owner_ == null) {
+ owner_ = caller;
+ holds_ = 1;
+ return;
+ }
+ else if (caller == owner_) {
+ incHolds();
+ return;
+ }
+ }
+ WaitQueue.WaitNode n = new WaitQueue.WaitNode();
+ n.doWaitUninterruptibly(this);
+ }
+
+ public void lockInterruptibly() throws InterruptedException {
+ if (Thread.interrupted()) throw new InterruptedException();
+ Thread caller = Thread.currentThread();
+ synchronized (this) {
+ if (owner_ == null) {
+ owner_ = caller;
+ holds_ = 1;
+ return;
+ }
+ else if (caller == owner_) {
+ incHolds();
+ return;
+ }
+ }
+ WaitQueue.WaitNode n = new WaitQueue.WaitNode();
+ n.doWait(this);
+ }
+
+ public boolean tryLock(long nanos) throws InterruptedException {
+ if (Thread.interrupted()) throw new InterruptedException();
+ Thread caller = Thread.currentThread();
+ synchronized (this) {
+ if (owner_ == null) {
+ owner_ = caller;
+ holds_ = 1;
+ return true;
+ }
+ else if (caller == owner_) {
+ incHolds();
+ return true;
+ }
+ }
+ WaitQueue.WaitNode n = new WaitQueue.WaitNode();
+ return n.doTimedWait(this, nanos);
+ }
+
+ protected synchronized WaitQueue.WaitNode getSignallee(Thread caller) {
+ if (caller != owner_)
+ throw new IllegalMonitorStateException("Not owner");
+ // assert (holds_ > 0)
+ if (holds_ >= 2) { // current thread will keep the lock
+ --holds_;
+ return null;
+ }
+ // assert (holds_ == 1)
+ WaitQueue.WaitNode w = wq_.extract();
+ if (w == null) { // if none, clear for new arrivals
+ owner_ = null;
+ holds_ = 0;
+ }
+ return w;
+ }
+
+ public void unlock() {
+ Thread caller = Thread.currentThread();
+ for (;;) {
+ WaitQueue.WaitNode w = getSignallee(caller);
+ if (w == null) return; // no one to signal
+ if (w.signal(this)) return; // notify if still waiting, else skip
+ }
+ }
+
+ public final boolean isFair() {
+ return true;
+ }
+
+ public synchronized boolean hasQueuedThreads() {
+ return wq_.hasNodes();
+ }
+
+ public synchronized int getQueueLength() {
+ return wq_.getLength();
+ }
+
+ public synchronized Collection getQueuedThreads() {
+ return wq_.getWaitingThreads();
+ }
+
+ public synchronized boolean isQueued(Thread thread) {
+ return wq_.isWaiting(thread);
+ }
+
+ private void readObject(java.io.ObjectInputStream in)
+ throws java.io.IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ synchronized (this) {
+ wq_ = new FIFOWaitQueue();
+ }
+ }
+ }
+
+ /**
+ * Creates an instance of {@code ReentrantLock}.
+ * This is equivalent to using {@code ReentrantLock(false)}.
+ */
+ public ReentrantLock() {
+ sync = new NonfairSync();
+ }
+
+ /**
+ * Creates an instance of {@code ReentrantLock} with the
+ * given fairness policy.
+ *
+ * @param fair {@code true} if this lock should use a fair ordering policy
+ */
+ public ReentrantLock(boolean fair) {
+ sync = (fair)? (Sync)new FairSync() : new NonfairSync();
+ }
+
+
+ /**
+ * Acquires the lock.
+ *
+ * <p>Acquires the lock if it is not held by another thread and returns
+ * immediately, setting the lock hold count to one.
+ *
+ * <p>If the current thread already holds the lock then the hold
+ * count is incremented by one and the method returns immediately.
+ *
+ * <p>If the lock is held by another thread then the
+ * current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until the lock has been acquired,
+ * at which time the lock hold count is set to one.
+ */
+ public void lock() {
+ sync.lock();
+ }
+
+ /**
+ * Acquires the lock unless the current thread is
+ * {@linkplain Thread#interrupt interrupted}.
+ *
+ * <p>Acquires the lock if it is not held by another thread and returns
+ * immediately, setting the lock hold count to one.
+ *
+ * <p>If the current thread already holds this lock then the hold count
+ * is incremented by one and the method returns immediately.
+ *
+ * <p>If the lock is held by another thread then the
+ * current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until one of two things happens:
+ *
+ * <ul>
+ *
+ * <li>The lock is acquired by the current thread; or
+ *
+ * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+ * current thread.
+ *
+ * </ul>
+ *
+ * <p>If the lock is acquired by the current thread then the lock hold
+ * count is set to one.
+ *
+ * <p>If the current thread:
+ *
+ * <ul>
+ *
+ * <li>has its interrupted status set on entry to this method; or
+ *
+ * <li>is {@linkplain Thread#interrupt interrupted} while acquiring
+ * the lock,
+ *
+ * </ul>
+ *
+ * then {@link InterruptedException} is thrown and the current thread's
+ * interrupted status is cleared.
+ *
+ * <p>In this implementation, as this method is an explicit
+ * interruption point, preference is given to responding to the
+ * interrupt over normal or reentrant acquisition of the lock.
+ *
+ * @throws InterruptedException if the current thread is interrupted
+ */
+ public void lockInterruptibly() throws InterruptedException {
+ sync.lockInterruptibly();
+ }
+
+ /**
+ * Acquires the lock only if it is not held by another thread at the time
+ * of invocation.
+ *
+ * <p>Acquires the lock if it is not held by another thread and
+ * returns immediately with the value {@code true}, setting the
+ * lock hold count to one. Even when this lock has been set to use a
+ * fair ordering policy, a call to {@code tryLock()} <em>will</em>
+ * immediately acquire the lock if it is available, whether or not
+ * other threads are currently waiting for the lock.
+ * This &quot;barging&quot; behavior can be useful in certain
+ * circumstances, even though it breaks fairness. If you want to honor
+ * the fairness setting for this lock, then use
+ * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) }
+ * which is almost equivalent (it also detects interruption).
+ *
+ * <p> If the current thread already holds this lock then the hold
+ * count is incremented by one and the method returns {@code true}.
+ *
+ * <p>If the lock is held by another thread then this method will return
+ * immediately with the value {@code false}.
+ *
+ * @return {@code true} if the lock was free and was acquired by the
+ * current thread, or the lock was already held by the current
+ * thread; and {@code false} otherwise
+ */
+ public boolean tryLock() {
+ return sync.tryLock();
+ }
+
+ /**
+ * Acquires the lock if it is not held by another thread within the given
+ * waiting time and the current thread has not been
+ * {@linkplain Thread#interrupt interrupted}.
+ *
+ * <p>Acquires the lock if it is not held by another thread and returns
+ * immediately with the value {@code true}, setting the lock hold count
+ * to one. If this lock has been set to use a fair ordering policy then
+ * an available lock <em>will not</em> be acquired if any other threads
+ * are waiting for the lock. This is in contrast to the {@link #tryLock()}
+ * method. If you want a timed {@code tryLock} that does permit barging on
+ * a fair lock then combine the timed and un-timed forms together:
+ *
+ * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
+ * </pre>
+ *
+ * <p>If the current thread
+ * already holds this lock then the hold count is incremented by one and
+ * the method returns {@code true}.
+ *
+ * <p>If the lock is held by another thread then the
+ * current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until one of three things happens:
+ *
+ * <ul>
+ *
+ * <li>The lock is acquired by the current thread; or
+ *
+ * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+ * the current thread; or
+ *
+ * <li>The specified waiting time elapses
+ *
+ * </ul>
+ *
+ * <p>If the lock is acquired then the value {@code true} is returned and
+ * the lock hold count is set to one.
+ *
+ * <p>If the current thread:
+ *
+ * <ul>
+ *
+ * <li>has its interrupted status set on entry to this method; or
+ *
+ * <li>is {@linkplain Thread#interrupt interrupted} while
+ * acquiring the lock,
+ *
+ * </ul>
+ * then {@link InterruptedException} is thrown and the current thread's
+ * interrupted status is cleared.
+ *
+ * <p>If the specified waiting time elapses then the value {@code false}
+ * is returned. If the time is less than or equal to zero, the method
+ * will not wait at all.
+ *
+ * <p>In this implementation, as this method is an explicit
+ * interruption point, preference is given to responding to the
+ * interrupt over normal or reentrant acquisition of the lock, and
+ * over reporting the elapse of the waiting time.
+ *
+ * @param timeout the time to wait for the lock
+ * @param unit the time unit of the timeout argument
+ * @return {@code true} if the lock was free and was acquired by the
+ * current thread, or the lock was already held by the current
+ * thread; and {@code false} if the waiting time elapsed before
+ * the lock could be acquired
+ * @throws InterruptedException if the current thread is interrupted
+ * @throws NullPointerException if the time unit is null
+ *
+ */
+ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
+ return sync.tryLock(unit.toNanos(timeout));
+ }
+
+ /**
+ * Attempts to release this lock.
+ *
+ * <p>If the current thread is the holder of this lock then the hold
+ * count is decremented. If the hold count is now zero then the lock
+ * is released. If the current thread is not the holder of this
+ * lock then {@link IllegalMonitorStateException} is thrown.
+ *
+ * @throws IllegalMonitorStateException if the current thread does not
+ * hold this lock
+ */
+ public void unlock() {
+ sync.unlock();
+ }
+
+ /**
+ * Returns a {@link Condition} instance for use with this
+ * {@link Lock} instance.
+ *
+ * <p>The returned {@link Condition} instance supports the same
+ * usages as do the {@link Object} monitor methods ({@link
+ * Object#wait() wait}, {@link Object#notify notify}, and {@link
+ * Object#notifyAll notifyAll}) when used with the built-in
+ * monitor lock.
+ *
+ * <ul>
+ *
+ * <li>If this lock is not held when any of the {@link Condition}
+ * {@linkplain Condition#await() waiting} or {@linkplain
+ * Condition#signal signalling} methods are called, then an {@link
+ * IllegalMonitorStateException} is thrown.
+ *
+ * <li>When the condition {@linkplain Condition#await() waiting}
+ * methods are called the lock is released and, before they
+ * return, the lock is reacquired and the lock hold count restored
+ * to what it was when the method was called.
+ *
+ * <li>If a thread is {@linkplain Thread#interrupt interrupted}
+ * while waiting then the wait will terminate, an {@link
+ * InterruptedException} will be thrown, and the thread's
+ * interrupted status will be cleared.
+ *
+ * <li> Waiting threads are signalled in FIFO order.
+ *
+ * <li>The ordering of lock reacquisition for threads returning
+ * from waiting methods is the same as for threads initially
+ * acquiring the lock, which is in the default case not specified,
+ * but for <em>fair</em> locks favors those threads that have been
+ * waiting the longest.
+ *
+ * </ul>
+ *
+ * @return the Condition object
+ */
+ public Condition newCondition() {
+ return isFair() ? (Condition)new FIFOCondVar(this) : new CondVar(this);
+ }
+
+ /**
+ * Queries the number of holds on this lock by the current thread.
+ *
+ * <p>A thread has a hold on a lock for each lock action that is not
+ * matched by an unlock action.
+ *
+ * <p>The hold count information is typically only used for testing and
+ * debugging purposes. For example, if a certain section of code should
+ * not be entered with the lock already held then we can assert that
+ * fact:
+ *
+ * <pre>
+ * class X {
+ * ReentrantLock lock = new ReentrantLock();
+ * // ...
+ * public void m() {
+ * assert lock.getHoldCount() == 0;
+ * lock.lock();
+ * try {
+ * // ... method body
+ * } finally {
+ * lock.unlock();
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ * @return the number of holds on this lock by the current thread,
+ * or zero if this lock is not held by the current thread
+ */
+ public int getHoldCount() {
+ return sync.getHoldCount();
+ }
+
+ /**
+ * Queries if this lock is held by the current thread.
+ *
+ * <p>Analogous to the {@link Thread#holdsLock} method for built-in
+ * monitor locks, this method is typically used for debugging and
+ * testing. For example, a method that should only be called while
+ * a lock is held can assert that this is the case:
+ *
+ * <pre>
+ * class X {
+ * ReentrantLock lock = new ReentrantLock();
+ * // ...
+ *
+ * public void m() {
+ * assert lock.isHeldByCurrentThread();
+ * // ... method body
+ * }
+ * }
+ * </pre>
+ *
+ * <p>It can also be used to ensure that a reentrant lock is used
+ * in a non-reentrant manner, for example:
+ *
+ * <pre>
+ * class X {
+ * ReentrantLock lock = new ReentrantLock();
+ * // ...
+ *
+ * public void m() {
+ * assert !lock.isHeldByCurrentThread();
+ * lock.lock();
+ * try {
+ * // ... method body
+ * } finally {
+ * lock.unlock();
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ * @return {@code true} if current thread holds this lock and
+ * {@code false} otherwise
+ */
+ public boolean isHeldByCurrentThread() {
+ return sync.isHeldByCurrentThread();
+ }
+
+ /**
+ * Queries if this lock is held by any thread. This method is
+ * designed for use in monitoring of the system state,
+ * not for synchronization control.
+ *
+ * @return {@code true} if any thread holds this lock and
+ * {@code false} otherwise
+ */
+ public boolean isLocked() {
+ return sync.isLocked();
+ }
+
+ /**
+ * Returns {@code true} if this lock has fairness set true.
+ *
+ * @return {@code true} if this lock has fairness set true
+ */
+ public final boolean isFair() {
+ return sync.isFair();
+ }
+
+ /**
+ * Returns the thread that currently owns this lock, or
+ * {@code null} if not owned. When this method is called by a
+ * thread that is not the owner, the return value reflects a
+ * best-effort approximation of current lock status. For example,
+ * the owner may be momentarily {@code null} even if there are
+ * threads trying to acquire the lock but have not yet done so.
+ * This method is designed to facilitate construction of
+ * subclasses that provide more extensive lock monitoring
+ * facilities.
+ *
+ * @return the owner, or {@code null} if not owned
+ */
+ protected Thread getOwner() {
+ return sync.getOwner();
+ }
+
+ /**
+ * Queries whether any threads are waiting to acquire this lock. Note that
+ * because cancellations may occur at any time, a {@code true}
+ * return does not guarantee that any other thread will ever
+ * acquire this lock. This method is designed primarily for use in
+ * monitoring of the system state.
+ *
+ * @return {@code true} if there may be other threads waiting to
+ * acquire the lock
+ */
+ public final boolean hasQueuedThreads() {
+ return sync.hasQueuedThreads();
+ }
+
+
+ /**
+ * Queries whether the given thread is waiting to acquire this
+ * lock. Note that because cancellations may occur at any time, a
+ * {@code true} return does not guarantee that this thread
+ * will ever acquire this lock. This method is designed primarily for use
+ * in monitoring of the system state.
+ *
+ * @param thread the thread
+ * @return {@code true} if the given thread is queued waiting for this lock
+ * @throws NullPointerException if the thread is null
+ */
+ public final boolean hasQueuedThread(Thread thread) {
+ return sync.isQueued(thread);
+ }
+
+
+ /**
+ * Returns an estimate of the number of threads waiting to
+ * acquire this lock. The value is only an estimate because the number of
+ * threads may change dynamically while this method traverses
+ * internal data structures. This method is designed for use in
+ * monitoring of the system state, not for synchronization
+ * control.
+ *
+ * @return the estimated number of threads waiting for this lock
+ */
+ public final int getQueueLength() {
+ return sync.getQueueLength();
+ }
+
+ /**
+ * Returns a collection containing threads that may be waiting to
+ * acquire this lock. Because the actual set of threads may change
+ * dynamically while constructing this result, the returned
+ * collection is only a best-effort estimate. The elements of the
+ * returned collection are in no particular order. This method is
+ * designed to facilitate construction of subclasses that provide
+ * more extensive monitoring facilities.
+ *
+ * @return the collection of threads
+ */
+ protected Collection getQueuedThreads() {
+ return sync.getQueuedThreads();
+ }
+
+ /**
+ * Queries whether any threads are waiting on the given condition
+ * associated with this lock. Note that because timeouts and
+ * interrupts may occur at any time, a {@code true} return does
+ * not guarantee that a future {@code signal} will awaken any
+ * threads. This method is designed primarily for use in
+ * monitoring of the system state.
+ *
+ * @param condition the condition
+ * @return {@code true} if there are any waiting threads
+ * @throws IllegalMonitorStateException if this lock is not held
+ * @throws IllegalArgumentException if the given condition is
+ * not associated with this lock
+ * @throws NullPointerException if the condition is null
+ */
+ public boolean hasWaiters(Condition condition) {
+ return asCondVar(condition).hasWaiters();
+ }
+
+ /**
+ * Returns an estimate of the number of threads waiting on the
+ * given condition associated with this lock. Note that because
+ * timeouts and interrupts may occur at any time, the estimate
+ * serves only as an upper bound on the actual number of waiters.
+ * This method is designed for use in monitoring of the system
+ * state, not for synchronization control.
+ *
+ * @param condition the condition
+ * @return the estimated number of waiting threads
+ * @throws IllegalMonitorStateException if this lock is not held
+ * @throws IllegalArgumentException if the given condition is
+ * not associated with this lock
+ * @throws NullPointerException if the condition is null
+ */
+ public int getWaitQueueLength(Condition condition) {
+ return asCondVar(condition).getWaitQueueLength();
+ }
+
+ /**
+ * Returns a collection containing those threads that may be
+ * waiting on the given condition associated with this lock.
+ * Because the actual set of threads may change dynamically while
+ * constructing this result, the returned collection is only a
+ * best-effort estimate. The elements of the returned collection
+ * are in no particular order. This method is designed to
+ * facilitate construction of subclasses that provide more
+ * extensive condition monitoring facilities.
+ *
+ * @param condition the condition
+ * @return the collection of threads
+ * @throws IllegalMonitorStateException if this lock is not held
+ * @throws IllegalArgumentException if the given condition is
+ * not associated with this lock
+ * @throws NullPointerException if the condition is null
+ */
+ protected Collection getWaitingThreads(Condition condition) {
+ return asCondVar(condition).getWaitingThreads();
+ }
+
+ /**
+ * Returns a string identifying this lock, as well as its lock state.
+ * The state, in brackets, includes either the String {@code "Unlocked"}
+ * or the String {@code "Locked by"} followed by the
+ * {@linkplain Thread#getName name} of the owning thread.
+ *
+ * @return a string identifying this lock, as well as its lock state
+ */
+ public String toString() {
+ Thread o = getOwner();
+ return super.toString() + ((o == null) ?
+ "[Unlocked]" :
+ "[Locked by thread " + o.getName() + "]");
+ }
+
+ private CondVar asCondVar(Condition condition) {
+ if (condition == null)
+ throw new NullPointerException();
+ if (!(condition instanceof CondVar))
+ throw new IllegalArgumentException("not owner");
+ CondVar condVar = (CondVar)condition;
+ if (condVar.lock != this)
+ throw new IllegalArgumentException("not owner");
+ return condVar;
+ }
+}
diff --git a/src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java b/src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java
new file mode 100644
index 0000000000..6411bbea01
--- /dev/null
+++ b/src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java
@@ -0,0 +1,1339 @@
+/*
+ * 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/licenses/publicdomain
+ */
+
+package scala.actors.threadpool.locks;
+
+import java.util.HashMap;
+import scala.actors.threadpool.*;
+import scala.actors.threadpool.helpers.*;
+
+/**
+ * An implementation of {@link ReadWriteLock} supporting similar
+ * semantics to {@link ReentrantLock}.
+ * <p>This class has the following properties:
+ *
+ * <ul>
+ * <li><b>Acquisition order</b>
+ *
+ * <p>The order of entry
+ * to the read and write lock is unspecified, subject to reentrancy
+ * constraints. A nonfair lock that is continously contended may
+ * indefinitely postpone one or more reader or writer threads, but
+ * will normally have higher throughput than a fair lock.
+ * <p>
+ *
+ * DEPARTURE FROM java.util.concurrent: this implementation impose
+ * a writer-preferrence and thus its acquisition order may be different
+ * than in java.util.concurrent.
+ *
+ * <li><b>Reentrancy</b>
+ *
+ * <p>This lock allows both readers and writers to reacquire read or
+ * write locks in the style of a {@link ReentrantLock}. Non-reentrant
+ * readers are not allowed until all write locks held by the writing
+ * thread have been released.
+ *
+ * <p>Additionally, a writer can acquire the read lock, but not
+ * vice-versa. Among other applications, reentrancy can be useful
+ * when write locks are held during calls or callbacks to methods that
+ * perform reads under read locks. If a reader tries to acquire the
+ * write lock it will never succeed.
+ *
+ * <li><b>Lock downgrading</b>
+ * <p>Reentrancy also allows downgrading from the write lock to a read lock,
+ * by acquiring the write lock, then the read lock and then releasing the
+ * write lock. However, upgrading from a read lock to the write lock is
+ * <b>not</b> possible.
+ *
+ * <li><b>Interruption of lock acquisition</b>
+ * <p>The read lock and write lock both support interruption during lock
+ * acquisition.
+ *
+ * <li><b>{@link Condition} support</b>
+ * <p>The write lock provides a {@link Condition} implementation that
+ * behaves in the same way, with respect to the write lock, as the
+ * {@link Condition} implementation provided by
+ * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}.
+ * This {@link Condition} can, of course, only be used with the write lock.
+ *
+ * <p>The read lock does not support a {@link Condition} and
+ * {@code readLock().newCondition()} throws
+ * {@code UnsupportedOperationException}.
+ *
+ * <li><b>Instrumentation</b>
+ * <p>This class supports methods to determine whether locks
+ * are held or contended. These methods are designed for monitoring
+ * system state, not for synchronization control.
+ * </ul>
+ *
+ * <p>Serialization of this class behaves in the same way as built-in
+ * locks: a deserialized lock is in the unlocked state, regardless of
+ * its state when serialized.
+ *
+ * <p><b>Sample usages</b>. Here is a code sketch showing how to exploit
+ * reentrancy to perform lock downgrading after updating a cache (exception
+ * handling is elided for simplicity):
+ * <pre>
+ * class CachedData {
+ * Object data;
+ * volatile boolean cacheValid;
+ * ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ *
+ * void processCachedData() {
+ * rwl.readLock().lock();
+ * if (!cacheValid) {
+ * // Must release read lock before acquiring write lock
+ * rwl.readLock().unlock();
+ * rwl.writeLock().lock();
+ * // Recheck state because another thread might have acquired
+ * // write lock and changed state before we did.
+ * if (!cacheValid) {
+ * data = ...
+ * cacheValid = true;
+ * }
+ * // Downgrade by acquiring read lock before releasing write lock
+ * rwl.readLock().lock();
+ * rwl.writeLock().unlock(); // Unlock write, still hold read
+ * }
+ *
+ * use(data);
+ * rwl.readLock().unlock();
+ * }
+ * }
+ * </pre>
+ *
+ * ReentrantReadWriteLocks can be used to improve concurrency in some
+ * uses of some kinds of Collections. This is typically worthwhile
+ * only when the collections are expected to be large, accessed by
+ * more reader threads than writer threads, and entail operations with
+ * overhead that outweighs synchronization overhead. For example, here
+ * is a class using a TreeMap that is expected to be large and
+ * concurrently accessed.
+ *
+ * <pre>{@code
+ * class RWDictionary {
+ * private final Map<String, Data> m = new TreeMap<String, Data>();
+ * private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ * private final Lock r = rwl.readLock();
+ * private final Lock w = rwl.writeLock();
+ *
+ * public Data get(String key) {
+ * r.lock();
+ * try { return m.get(key); }
+ * finally { r.unlock(); }
+ * }
+ * public String[] allKeys() {
+ * r.lock();
+ * try { return m.keySet().toArray(); }
+ * finally { r.unlock(); }
+ * }
+ * public Data put(String key, Data value) {
+ * w.lock();
+ * try { return m.put(key, value); }
+ * finally { w.unlock(); }
+ * }
+ * public void clear() {
+ * w.lock();
+ * try { m.clear(); }
+ * finally { w.unlock(); }
+ * }
+ * }}</pre>
+ *
+ * <h3>Implementation Notes</h3>
+ *
+ * <p>This lock supports a maximum of 65535 recursive write locks
+ * and 65535 read locks. Attempts to exceed these limits result in
+ * {@link Error} throws from locking methods.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ *
+ */
+public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
+ private static final long serialVersionUID = -3463448656717690166L;
+
+ final ReadLock readerLock_ = new ReadLock(this);
+ final WriteLock writerLock_ = new WriteLock(this);
+
+ final Sync sync;
+
+ /**
+ * Creates a new {@code ReentrantReadWriteLock} with
+ * default (nonfair) ordering properties.
+ */
+ public ReentrantReadWriteLock() {
+ this.sync = new NonfairSync();
+ }
+
+ public Lock writeLock() { return writerLock_; }
+ public Lock readLock() { return readerLock_; }
+
+ /**
+ * Synchronization implementation for ReentrantReadWriteLock.
+ * Subclassed into fair and nonfair versions.
+ */
+ private abstract static class Sync implements java.io.Serializable {
+
+ private static final int NONE = 0;
+ private static final int READER = 1;
+ private static final int WRITER = 2;
+
+ transient int activeReaders_ = 0;
+ transient Thread activeWriter_ = null;
+ transient int waitingReaders_ = 0;
+ transient int waitingWriters_ = 0;
+
+ /** Number of acquires on write lock by activeWriter_ thread **/
+ transient int writeHolds_ = 0;
+
+ /** Number of acquires on read lock by any reader thread **/
+ transient HashMap readers_ = new HashMap();
+
+ /** cache/reuse the special Integer value one to speed up readlocks **/
+ static final Integer IONE = new Integer(1);
+
+ Sync() {}
+
+ /*
+ Each of these variants is needed to maintain atomicity
+ of wait counts during wait loops. They could be
+ made faster by manually inlining each other. We hope that
+ compilers do this for us though.
+ */
+
+ synchronized boolean startReadFromNewReader() {
+ boolean pass = startRead();
+ if (!pass) ++waitingReaders_;
+ return pass;
+ }
+
+ synchronized boolean startWriteFromNewWriter() {
+ boolean pass = startWrite();
+ if (!pass) ++waitingWriters_;
+ return pass;
+ }
+
+ synchronized boolean startReadFromWaitingReader() {
+ boolean pass = startRead();
+ if (pass) --waitingReaders_;
+ return pass;
+ }
+
+ synchronized boolean startWriteFromWaitingWriter() {
+ boolean pass = startWrite();
+ if (pass) --waitingWriters_;
+ return pass;
+ }
+
+ /*
+ A bunch of small synchronized methods are needed
+ to allow communication from the Lock objects
+ back to this object, that serves as controller
+ */
+
+ synchronized void cancelledWaitingReader() { --waitingReaders_; }
+ synchronized void cancelledWaitingWriter() { --waitingWriters_; }
+
+ boolean allowReader() {
+ return (activeWriter_ == null && waitingWriters_ == 0) ||
+ activeWriter_ == Thread.currentThread();
+ }
+
+ synchronized boolean startRead() {
+ Thread t = Thread.currentThread();
+ Object c = readers_.get(t);
+ if (c != null) { // already held -- just increment hold count
+ readers_.put(t, new Integer( ( (Integer) (c)).intValue() + 1));
+ ++activeReaders_;
+ return true;
+ }
+ else if (allowReader()) {
+ readers_.put(t, IONE);
+ ++activeReaders_;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ synchronized boolean startWrite() {
+ if (activeWriter_ == Thread.currentThread()) { // already held; re-acquire
+ ++writeHolds_;
+ return true;
+ }
+ else if (writeHolds_ == 0) {
+ if (activeReaders_ == 0 ||
+ (readers_.size() == 1 &&
+ readers_.get(Thread.currentThread()) != null)) {
+ activeWriter_ = Thread.currentThread();
+ writeHolds_ = 1;
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+
+ synchronized int endRead() {
+ Thread t = Thread.currentThread();
+ Object c = readers_.get(t);
+ if (c == null)
+ throw new IllegalMonitorStateException();
+ --activeReaders_;
+ if (c != IONE) { // more than one hold; decrement count
+ int h = ( (Integer) (c)).intValue() - 1;
+ Integer ih = (h == 1) ? IONE : new Integer(h);
+ readers_.put(t, ih);
+ return NONE;
+ }
+ else {
+ readers_.remove(t);
+
+ if (writeHolds_ > 0) // a write lock is still held by current thread
+ return NONE;
+ else if (activeReaders_ == 0 && waitingWriters_ > 0)
+ return WRITER;
+ else
+ return NONE;
+ }
+ }
+
+ synchronized int endWrite() {
+ if (activeWriter_ != Thread.currentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ --writeHolds_;
+ if (writeHolds_ > 0) // still being held
+ return NONE;
+ else {
+ activeWriter_ = null;
+ if (waitingReaders_ > 0 && allowReader())
+ return READER;
+ else if (waitingWriters_ > 0)
+ return WRITER;
+ else
+ return NONE;
+ }
+ }
+
+ synchronized Thread getOwner() {
+ return activeWriter_;
+ }
+
+ synchronized int getReadLockCount() {
+ return activeReaders_;
+ }
+
+ synchronized boolean isWriteLocked() {
+ return activeWriter_ != null;
+ }
+
+ synchronized boolean isWriteLockedByCurrentThread() {
+ return activeWriter_ == Thread.currentThread();
+ }
+
+ synchronized int getWriteHoldCount() {
+ return isWriteLockedByCurrentThread() ? writeHolds_ : 0;
+ }
+
+ synchronized int getReadHoldCount() {
+ if (activeReaders_ == 0) return 0;
+ Thread t = Thread.currentThread();
+ Integer i = (Integer)readers_.get(t);
+ return (i == null) ? 0 : i.intValue();
+ }
+
+ final synchronized boolean hasQueuedThreads() {
+ return waitingWriters_ > 0 || waitingReaders_ > 0;
+ }
+
+ final synchronized int getQueueLength() {
+ return waitingWriters_ + waitingReaders_;
+ }
+
+ private void readObject(java.io.ObjectInputStream in)
+ throws java.io.IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ // readers_ is transient, need to reinitialize. Let's flush the memory
+ // and ensure visibility by synchronizing (all other accesses to
+ // readers_ are also synchronized on "this")
+ synchronized (this) {
+ readers_ = new HashMap();
+ }
+ }
+ }
+
+ /**
+ * Nonfair version of Sync
+ */
+ private static class NonfairSync extends Sync {
+ NonfairSync() {}
+ }
+
+ /**
+ * The lock returned by method {@link ReentrantReadWriteLock#readLock}.
+ */
+ public static class ReadLock implements Lock, java.io.Serializable {
+
+ private static final long serialVersionUID = -5992448646407690164L;
+
+ final ReentrantReadWriteLock lock;
+
+ /**
+ * Constructor for use by subclasses
+ *
+ * @param lock the outer lock object
+ * @throws NullPointerException if the lock is null
+ */
+ protected ReadLock(ReentrantReadWriteLock lock) {
+ if (lock == null) throw new NullPointerException();
+ this.lock = lock;
+ }
+
+ /**
+ * Acquires the read lock.
+ *
+ * <p>Acquires the read lock if the write lock is not held by
+ * another thread and returns immediately.
+ *
+ * <p>If the write lock is held by another thread then
+ * the current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until the read lock has been acquired.
+ */
+ public void lock() {
+ synchronized (this) {
+ if (lock.sync.startReadFromNewReader()) return;
+ boolean wasInterrupted = Thread.interrupted();
+ try {
+ while (true) {
+ try {
+ ReadLock.this.wait();
+ }
+ catch (InterruptedException ex) {
+ wasInterrupted = true;
+ // no need to propagate the potentially masked
+ // signal, since readers are always notified all
+ }
+ if (lock.sync.startReadFromWaitingReader()) return;
+ }
+ }
+ finally {
+ if (wasInterrupted) Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Acquires the read lock unless the current thread is
+ * {@linkplain Thread#interrupt interrupted}.
+ *
+ * <p>Acquires the read lock if the write lock is not held
+ * by another thread and returns immediately.
+ *
+ * <p>If the write lock is held by another thread then the
+ * current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until one of two things happens:
+ *
+ * <ul>
+ *
+ * <li>The read lock is acquired by the current thread; or
+ *
+ * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+ * the current thread.
+ *
+ * </ul>
+ *
+ * <p>If the current thread:
+ *
+ * <ul>
+ *
+ * <li>has its interrupted status set on entry to this method; or
+ *
+ * <li>is {@linkplain Thread#interrupt interrupted} while
+ * acquiring the read lock,
+ *
+ * </ul>
+ *
+ * then {@link InterruptedException} is thrown and the current
+ * thread's interrupted status is cleared.
+ *
+ * <p>In this implementation, as this method is an explicit
+ * interruption point, preference is given to responding to
+ * the interrupt over normal or reentrant acquisition of the
+ * lock.
+ *
+ * @throws InterruptedException if the current thread is interrupted
+ */
+ public void lockInterruptibly() throws InterruptedException {
+ if (Thread.interrupted()) throw new InterruptedException();
+ InterruptedException ie = null;
+ synchronized (this) {
+ if (!lock.sync.startReadFromNewReader()) {
+ for (; ; ) {
+ try {
+ ReadLock.this.wait();
+ if (lock.sync.startReadFromWaitingReader())
+ return;
+ }
+ catch (InterruptedException ex) {
+ lock.sync.cancelledWaitingReader();
+ ie = ex;
+ break;
+ }
+ }
+ }
+ }
+ if (ie != null) {
+ // fall through outside synch on interrupt.
+ // This notification is not really needed here,
+ // but may be in plausible subclasses
+ lock.writerLock_.signalWaiters();
+ throw ie;
+ }
+ }
+
+ /**
+ * Acquires the read lock only if the write lock is not held by
+ * another thread at the time of invocation.
+ *
+ * <p>Acquires the read lock if the write lock is not held by
+ * another thread and returns immediately with the value
+ * {@code true}. Even when this lock has been set to use a
+ * fair ordering policy, a call to {@code tryLock()}
+ * <em>will</em> immediately acquire the read lock if it is
+ * available, whether or not other threads are currently
+ * waiting for the read lock. This &quot;barging&quot; behavior
+ * can be useful in certain circumstances, even though it
+ * breaks fairness. If you want to honor the fairness setting
+ * for this lock, then use {@link #tryLock(long, TimeUnit)
+ * tryLock(0, TimeUnit.SECONDS) } which is almost equivalent
+ * (it also detects interruption).
+ *
+ * <p>If the write lock is held by another thread then
+ * this method will return immediately with the value
+ * {@code false}.
+ *
+ * @return {@code true} if the read lock was acquired
+ */
+ public boolean tryLock() {
+ return lock.sync.startRead();
+ }
+
+ /**
+ * Acquires the read lock if the write lock is not held by
+ * another thread within the given waiting time and the
+ * current thread has not been {@linkplain Thread#interrupt
+ * interrupted}.
+ *
+ * <p>Acquires the read lock if the write lock is not held by
+ * another thread and returns immediately with the value
+ * {@code true}. If this lock has been set to use a fair
+ * ordering policy then an available lock <em>will not</em> be
+ * acquired if any other threads are waiting for the
+ * lock. This is in contrast to the {@link #tryLock()}
+ * method. If you want a timed {@code tryLock} that does
+ * permit barging on a fair lock then combine the timed and
+ * un-timed forms together:
+ *
+ * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
+ * </pre>
+ *
+ * <p>If the write lock is held by another thread then the
+ * current thread becomes disabled for thread scheduling
+ * purposes and lies dormant until one of three things happens:
+ *
+ * <ul>
+ *
+ * <li>The read lock is acquired by the current thread; or
+ *
+ * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+ * the current thread; or
+ *
+ * <li>The specified waiting time elapses.
+ *
+ * </ul>
+ *
+ * <p>If the read lock is acquired then the value {@code true} is
+ * returned.
+ *
+ * <p>If the current thread:
+ *
+ * <ul>
+ *
+ * <li>has its interrupted status set on entry to this method; or
+ *
+ * <li>is {@linkplain Thread#interrupt interrupted} while
+ * acquiring the read lock,
+ *
+ * </ul> then {@link InterruptedException} is thrown and the
+ * current thread's interrupted status is cleared.
+ *
+ * <p>If the specified waiting time elapses then the value
+ * {@code false} is returned. If the time is less than or
+ * equal to zero, the method will not wait at all.
+ *
+ * <p>In this implementation, as this method is an explicit
+ * interruption point, preference is given to responding to
+ * the interrupt over normal or reentrant acquisition of the
+ * lock, and over reporting the elapse of the waiting time.
+ *
+ * @param timeout the time to wait for the read lock
+ * @param unit the time unit of the timeout argument
+ * @return {@code true} if the read lock was acquired
+ * @throws InterruptedException if the current thread is interrupted
+ * @throws NullPointerException if the time unit is null
+ *
+ */
+ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
+ if (Thread.interrupted()) throw new InterruptedException();
+ InterruptedException ie = null;
+ long nanos = unit.toNanos(timeout);
+ synchronized (this) {
+ if (nanos <= 0)
+ return lock.sync.startRead();
+ else if (lock.sync.startReadFromNewReader())
+ return true;
+ else {
+ long deadline = Utils.nanoTime() + nanos;
+ for (; ; ) {
+ try {
+ TimeUnit.NANOSECONDS.timedWait(ReadLock.this, nanos);
+ }
+ catch (InterruptedException ex) {
+ lock.sync.cancelledWaitingReader();
+ ie = ex;
+ break;
+ }
+ if (lock.sync.startReadFromWaitingReader())
+ return true;
+ else {
+ nanos = deadline - Utils.nanoTime();
+ if (nanos <= 0) {
+ lock.sync.cancelledWaitingReader();
+ break;
+ }
+ }
+ }
+ }
+ }
+ // safeguard on interrupt or timeout:
+ lock.writerLock_.signalWaiters();
+ if (ie != null)
+ throw ie;
+ else
+ return false; // timed out
+ }
+
+ /**
+ * Attempts to release this lock.
+ *
+ * <p> If the number of readers is now zero then the lock
+ * is made available for write lock attempts.
+ */
+ public void unlock() {
+ switch (lock.sync.endRead()) {
+ case Sync.NONE: return;
+ case Sync.READER: lock.readerLock_.signalWaiters(); return;
+ case Sync.WRITER: lock.writerLock_.signalWaiters(); return;
+ }
+ }
+
+ /**
+ * Throws {@code UnsupportedOperationException} because
+ * {@code ReadLocks} do not support conditions.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public Condition newCondition() {
+ throw new UnsupportedOperationException();
+ }
+
+ synchronized void signalWaiters() {
+ notifyAll();
+ }
+
+ /**
+ * Returns a string identifying this lock, as well as its lock state.
+ * The state, in brackets, includes the String {@code "Read locks ="}
+ * followed by the number of held read locks.
+ *
+ * @return a string identifying this lock, as well as its lock state
+ */
+ public String toString() {
+ int r = lock.getReadLockCount();
+ return super.toString() +
+ "[Read locks = " + r + "]";
+ }
+
+ }
+
+ /**
+ * The lock returned by method {@link ReentrantReadWriteLock#writeLock}.
+ */
+ public static class WriteLock implements Lock, CondVar.ExclusiveLock,
+ java.io.Serializable {
+
+ private static final long serialVersionUID = -4992448646407690164L;
+ final ReentrantReadWriteLock lock;
+
+ /**
+ * Constructor for use by subclasses
+ *
+ * @param lock the outer lock object
+ * @throws NullPointerException if the lock is null
+ */
+ protected WriteLock(ReentrantReadWriteLock lock) {
+ if (lock == null) throw new NullPointerException();
+ this.lock = lock;
+ }
+
+ /**
+ * Acquires the write lock.
+ *
+ * <p>Acquires the write lock if neither the read nor write lock
+ * are held by another thread
+ * and returns immediately, setting the write lock hold count to
+ * one.
+ *
+ * <p>If the current thread already holds the write lock then the
+ * hold count is incremented by one and the method returns
+ * immediately.
+ *
+ * <p>If the lock is held by another thread then the current
+ * thread becomes disabled for thread scheduling purposes and
+ * lies dormant until the write lock has been acquired, at which
+ * time the write lock hold count is set to one.
+ */
+ public void lock() {
+ synchronized (this) {
+ if (lock.sync.startWriteFromNewWriter()) return;
+ boolean wasInterrupted = Thread.interrupted();
+ try {
+ while (true) {
+ try {
+ WriteLock.this.wait();
+ }
+ catch (InterruptedException ex) {
+ wasInterrupted = true;
+ // no need to notify; if we were notified,
+ // we will act as notified, and succeed in
+ // startWrite and return
+ }
+ if (lock.sync.startWriteFromWaitingWriter()) return;
+ }
+ }
+ finally {
+ if (wasInterrupted) Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Acquires the write lock unless the current thread is
+ * {@linkplain Thread#interrupt interrupted}.
+ *
+ * <p>Acquires the write lock if neither the read nor write lock
+ * are held by another thread
+ * and returns immediately, setting the write lock hold count to
+ * one.
+ *
+ * <p>If the current thread already holds this lock then the
+ * hold count is incremented by one and the method returns
+ * immediately.
+ *
+ * <p>If the lock is held by another thread then the current
+ * thread becomes disabled for thread scheduling purposes and
+ * lies dormant until one of two things happens:
+ *
+ * <ul>
+ *
+ * <li>The write lock is acquired by the current thread; or
+ *
+ * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+ * the current thread.
+ *
+ * </ul>
+ *
+ * <p>If the write lock is acquired by the current thread then the
+ * lock hold count is set to one.
+ *
+ * <p>If the current thread:
+ *
+ * <ul>
+ *
+ * <li>has its interrupted status set on entry to this method;
+ * or
+ *
+ * <li>is {@linkplain Thread#interrupt interrupted} while
+ * acquiring the write lock,
+ *
+ * </ul>
+ *
+ * then {@link InterruptedException} is thrown and the current
+ * thread's interrupted status is cleared.
+ *
+ * <p>In this implementation, as this method is an explicit
+ * interruption point, preference is given to responding to
+ * the interrupt over normal or reentrant acquisition of the
+ * lock.
+ *
+ * @throws InterruptedException if the current thread is interrupted
+ */
+ public void lockInterruptibly() throws InterruptedException {
+ if (Thread.interrupted()) throw new InterruptedException();
+ InterruptedException ie = null;
+ synchronized (this) {
+ if (!lock.sync.startWriteFromNewWriter()) {
+ for (; ; ) {
+ try {
+ WriteLock.this.wait();
+ if (lock.sync.startWriteFromWaitingWriter())
+ return;
+ }
+ catch (InterruptedException ex) {
+ lock.sync.cancelledWaitingWriter();
+ WriteLock.this.notify();
+ ie = ex;
+ break;
+ }
+ }
+ }
+ }
+ if (ie != null) {
+ // Fall through outside synch on interrupt.
+ // On exception, we may need to signal readers.
+ // It is not worth checking here whether it is strictly necessary.
+ lock.readerLock_.signalWaiters();
+ throw ie;
+ }
+ }
+
+ /**
+ * Acquires the write lock only if it is not held by another thread
+ * at the time of invocation.
+ *
+ * <p>Acquires the write lock if neither the read nor write lock
+ * are held by another thread
+ * and returns immediately with the value {@code true},
+ * setting the write lock hold count to one. Even when this lock has
+ * been set to use a fair ordering policy, a call to
+ * {@code tryLock()} <em>will</em> immediately acquire the
+ * lock if it is available, whether or not other threads are
+ * currently waiting for the write lock. This &quot;barging&quot;
+ * behavior can be useful in certain circumstances, even
+ * though it breaks fairness. If you want to honor the
+ * fairness setting for this lock, then use {@link
+ * #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) }
+ * which is almost equivalent (it also detects interruption).
+ *
+ * <p> If the current thread already holds this lock then the
+ * hold count is incremented by one and the method returns
+ * {@code true}.
+ *
+ * <p>If the lock is held by another thread then this method
+ * will return immediately with the value {@code false}.
+ *
+ * @return {@code true} if the lock was free and was acquired
+ * by the current thread, or the write lock was already held
+ * by the current thread; and {@code false} otherwise.
+ */
+ public boolean tryLock() {
+ return lock.sync.startWrite();
+ }
+
+ /**
+ * Acquires the write lock if it is not held by another thread
+ * within the given waiting time and the current thread has
+ * not been {@linkplain Thread#interrupt interrupted}.
+ *
+ * <p>Acquires the write lock if neither the read nor write lock
+ * are held by another thread
+ * and returns immediately with the value {@code true},
+ * setting the write lock hold count to one. If this lock has been
+ * set to use a fair ordering policy then an available lock
+ * <em>will not</em> be acquired if any other threads are
+ * waiting for the write lock. This is in contrast to the {@link
+ * #tryLock()} method. If you want a timed {@code tryLock}
+ * that does permit barging on a fair lock then combine the
+ * timed and un-timed forms together:
+ *
+ * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
+ * </pre>
+ *
+ * <p>If the current thread already holds this lock then the
+ * hold count is incremented by one and the method returns
+ * {@code true}.
+ *
+ * <p>If the lock is held by another thread then the current
+ * thread becomes disabled for thread scheduling purposes and
+ * lies dormant until one of three things happens:
+ *
+ * <ul>
+ *
+ * <li>The write lock is acquired by the current thread; or
+ *
+ * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+ * the current thread; or
+ *
+ * <li>The specified waiting time elapses
+ *
+ * </ul>
+ *
+ * <p>If the write lock is acquired then the value {@code true} is
+ * returned and the write lock hold count is set to one.
+ *
+ * <p>If the current thread:
+ *
+ * <ul>
+ *
+ * <li>has its interrupted status set on entry to this method;
+ * or
+ *
+ * <li>is {@linkplain Thread#interrupt interrupted} while
+ * acquiring the write lock,
+ *
+ * </ul>
+ *
+ * then {@link InterruptedException} is thrown and the current
+ * thread's interrupted status is cleared.
+ *
+ * <p>If the specified waiting time elapses then the value
+ * {@code false} is returned. If the time is less than or
+ * equal to zero, the method will not wait at all.
+ *
+ * <p>In this implementation, as this method is an explicit
+ * interruption point, preference is given to responding to
+ * the interrupt over normal or reentrant acquisition of the
+ * lock, and over reporting the elapse of the waiting time.
+ *
+ * @param timeout the time to wait for the write lock
+ * @param unit the time unit of the timeout argument
+ *
+ * @return {@code true} if the lock was free and was acquired
+ * by the current thread, or the write lock was already held by the
+ * current thread; and {@code false} if the waiting time
+ * elapsed before the lock could be acquired.
+ *
+ * @throws InterruptedException if the current thread is interrupted
+ * @throws NullPointerException if the time unit is null
+ *
+ */
+ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
+ if (Thread.interrupted()) throw new InterruptedException();
+ InterruptedException ie = null;
+ long nanos = unit.toNanos(timeout);
+ synchronized (this) {
+ if (nanos <= 0)
+ return lock.sync.startWrite();
+ else if (lock.sync.startWriteFromNewWriter())
+ return true;
+ else {
+ long deadline = Utils.nanoTime() + nanos;
+ for (; ; ) {
+ try {
+ TimeUnit.NANOSECONDS.timedWait(WriteLock.this, nanos);
+ }
+ catch (InterruptedException ex) {
+ lock.sync.cancelledWaitingWriter();
+ WriteLock.this.notify();
+ ie = ex;
+ break;
+ }
+ if (lock.sync.startWriteFromWaitingWriter())
+ return true;
+ else {
+ nanos = deadline - Utils.nanoTime();
+ if (nanos <= 0) {
+ lock.sync.cancelledWaitingWriter();
+ WriteLock.this.notify();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ lock.readerLock_.signalWaiters();
+ if (ie != null)
+ throw ie;
+ else
+ return false; // timed out
+ }
+
+ /**
+ * Attempts to release this lock.
+ *
+ * <p>If the current thread is the holder of this lock then
+ * the hold count is decremented. If the hold count is now
+ * zero then the lock is released. If the current thread is
+ * not the holder of this lock then {@link
+ * IllegalMonitorStateException} is thrown.
+ *
+ * @throws IllegalMonitorStateException if the current thread does not
+ * hold this lock.
+ */
+ public void unlock() {
+ switch (lock.sync.endWrite()) {
+ case Sync.NONE: return;
+ case Sync.READER: lock.readerLock_.signalWaiters(); return;
+ case Sync.WRITER: lock.writerLock_.signalWaiters(); return;
+ }
+ }
+
+ /**
+ * Returns a {@link Condition} instance for use with this
+ * {@link Lock} instance.
+ * <p>The returned {@link Condition} instance supports the same
+ * usages as do the {@link Object} monitor methods ({@link
+ * Object#wait() wait}, {@link Object#notify notify}, and {@link
+ * Object#notifyAll notifyAll}) when used with the built-in
+ * monitor lock.
+ *
+ * <ul>
+ *
+ * <li>If this write lock is not held when any {@link
+ * Condition} method is called then an {@link
+ * IllegalMonitorStateException} is thrown. (Read locks are
+ * held independently of write locks, so are not checked or
+ * affected. However it is essentially always an error to
+ * invoke a condition waiting method when the current thread
+ * has also acquired read locks, since other threads that
+ * could unblock it will not be able to acquire the write
+ * lock.)
+ *
+ * <li>When the condition {@linkplain Condition#await() waiting}
+ * methods are called the write lock is released and, before
+ * they return, the write lock is reacquired and the lock hold
+ * count restored to what it was when the method was called.
+ *
+ * <li>If a thread is {@linkplain Thread#interrupt interrupted} while
+ * waiting then the wait will terminate, an {@link
+ * InterruptedException} will be thrown, and the thread's
+ * interrupted status will be cleared.
+ *
+ * <li> Waiting threads are signalled in FIFO order.
+ *
+ * <li>The ordering of lock reacquisition for threads returning
+ * from waiting methods is the same as for threads initially
+ * acquiring the lock, which is in the default case not specified,
+ * but for <em>fair</em> locks favors those threads that have been
+ * waiting the longest.
+ *
+ * </ul>
+ *
+ * @return the Condition object
+ */
+ public Condition newCondition() {
+ return new CondVar(this);
+ }
+
+ synchronized void signalWaiters() {
+ notify();
+ }
+
+ /**
+ * Returns a string identifying this lock, as well as its lock
+ * state. The state, in brackets includes either the String
+ * {@code "Unlocked"} or the String {@code "Locked by"}
+ * followed by the {@linkplain Thread#getName name} of the owning thread.
+ *
+ * @return a string identifying this lock, as well as its lock state
+ */
+ public String toString() {
+ Thread o = lock.getOwner();
+ return super.toString() + ((o == null) ?
+ "[Unlocked]" :
+ "[Locked by thread " + o.getName() + "]");
+ }
+
+ /**
+ * Queries if this write lock is held by the current thread.
+ * Identical in effect to {@link
+ * ReentrantReadWriteLock#isWriteLockedByCurrentThread}.
+ *
+ * @return {@code true} if the current thread holds this lock and
+ * {@code false} otherwise
+ * @since 1.6
+ */
+ public boolean isHeldByCurrentThread() {
+ return lock.sync.isWriteLockedByCurrentThread();
+ }
+
+ /**
+ * Queries the number of holds on this write lock by the current
+ * thread. A thread has a hold on a lock for each lock action
+ * that is not matched by an unlock action. Identical in effect
+ * to {@link ReentrantReadWriteLock#getWriteHoldCount}.
+ *
+ * @return the number of holds on this lock by the current thread,
+ * or zero if this lock is not held by the current thread
+ * @since 1.6
+ */
+ public int getHoldCount() {
+ return lock.sync.getWriteHoldCount();
+ }
+
+ }
+
+ // Instrumentation and status
+
+ /**
+ * Returns {@code true} if this lock has fairness set true.
+ *
+ * @return {@code true} if this lock has fairness set true
+ */
+ public final boolean isFair() {
+ return false;
+ }
+
+ /**
+ * Returns the thread that currently owns the write lock, or
+ * {@code null} if not owned. When this method is called by a
+ * thread that is not the owner, the return value reflects a
+ * best-effort approximation of current lock status. For example,
+ * the owner may be momentarily {@code null} even if there are
+ * threads trying to acquire the lock but have not yet done so.
+ * This method is designed to facilitate construction of
+ * subclasses that provide more extensive lock monitoring
+ * facilities.
+ *
+ * @return the owner, or {@code null} if not owned
+ */
+ protected Thread getOwner() {
+ return sync.getOwner();
+ }
+
+ /**
+ * Queries the number of read locks held for this lock. This
+ * method is designed for use in monitoring system state, not for
+ * synchronization control.
+ * @return the number of read locks held.
+ */
+ public int getReadLockCount() {
+ return sync.getReadLockCount();
+ }
+
+ /**
+ * Queries if the write lock is held by any thread. This method is
+ * designed for use in monitoring system state, not for
+ * synchronization control.
+ *
+ * @return {@code true} if any thread holds the write lock and
+ * {@code false} otherwise
+ */
+ public boolean isWriteLocked() {
+ return sync.isWriteLocked();
+ }
+
+ /**
+ * Queries if the write lock is held by the current thread.
+ *
+ * @return {@code true} if the current thread holds the write lock and
+ * {@code false} otherwise
+ */
+ public boolean isWriteLockedByCurrentThread() {
+ return sync.isWriteLockedByCurrentThread();
+ }
+
+ /**
+ * Queries the number of reentrant write holds on this lock by the
+ * current thread. A writer thread has a hold on a lock for
+ * each lock action that is not matched by an unlock action.
+ *
+ * @return the number of holds on the write lock by the current thread,
+ * or zero if the write lock is not held by the current thread
+ */
+ public int getWriteHoldCount() {
+ return sync.getWriteHoldCount();
+ }
+
+ /**
+ * Queries the number of reentrant read holds on this lock by the
+ * current thread. A reader thread has a hold on a lock for
+ * each lock action that is not matched by an unlock action.
+ *
+ * @return the number of holds on the read lock by the current thread,
+ * or zero if the read lock is not held by the current thread
+ * @since 1.6
+ */
+ public int getReadHoldCount() {
+ return sync.getReadHoldCount();
+ }
+
+
+// /**
+// * Returns a collection containing threads that may be waiting to
+// * acquire the write lock. Because the actual set of threads may
+// * change dynamically while constructing this result, the returned
+// * collection is only a best-effort estimate. The elements of the
+// * returned collection are in no particular order. This method is
+// * designed to facilitate construction of subclasses that provide
+// * more extensive lock monitoring facilities.
+// * @return the collection of threads
+// */
+// protected Collection getQueuedWriterThreads() {
+// return sync.getExclusiveQueuedThreads();
+// }
+//
+// /**
+// * Returns a collection containing threads that may be waiting to
+// * acquire the read lock. Because the actual set of threads may
+// * change dynamically while constructing this result, the returned
+// * collection is only a best-effort estimate. The elements of the
+// * returned collection are in no particular order. This method is
+// * designed to facilitate construction of subclasses that provide
+// * more extensive lock monitoring facilities.
+// * @return the collection of threads
+// */
+// protected Collection getQueuedReaderThreads() {
+// return sync.getSharedQueuedThreads();
+// }
+//
+ /**
+ * Queries whether any threads are waiting to acquire the read or
+ * write lock. Note that because cancellations may occur at any
+ * time, a {@code true} return does not guarantee that any other
+ * thread will ever acquire a lock. This method is designed
+ * primarily for use in monitoring of the system state.
+ *
+ * @return {@code true} if there may be other threads waiting to
+ * acquire the lock
+ */
+ public final boolean hasQueuedThreads() {
+ return sync.hasQueuedThreads();
+ }
+//
+// /**
+// * Queries whether the given thread is waiting to acquire either
+// * the read or write lock. Note that because cancellations may
+// * occur at any time, a <tt>true</tt> return does not guarantee
+// * that this thread will ever acquire a lock. This method is
+// * designed primarily for use in monitoring of the system state.
+// *
+// * @param thread the thread
+// * @return true if the given thread is queued waiting for this lock.
+// * @throws NullPointerException if thread is null
+// */
+// public final boolean hasQueuedThread(Thread thread) {
+// return sync.isQueued(thread);
+// }
+
+ /**
+ * Returns an estimate of the number of threads waiting to acquire
+ * either the read or write lock. The value is only an estimate
+ * because the number of threads may change dynamically while this
+ * method traverses internal data structures. This method is
+ * designed for use in monitoring of the system state, not for
+ * synchronization control.
+ *
+ * @return the estimated number of threads waiting for this lock
+ */
+ public final int getQueueLength() {
+ return sync.getQueueLength();
+ }
+
+// /**
+// * Returns a collection containing threads that may be waiting to
+// * acquire either the read or write lock. Because the actual set
+// * of threads may change dynamically while constructing this
+// * result, the returned collection is only a best-effort estimate.
+// * The elements of the returned collection are in no particular
+// * order. This method is designed to facilitate construction of
+// * subclasses that provide more extensive monitoring facilities.
+// * @return the collection of threads
+// */
+// protected Collection getQueuedThreads() {
+// return sync.getQueuedThreads();
+// }
+//
+// /**
+// * Queries whether any threads are waiting on the given condition
+// * associated with the write lock. Note that because timeouts and
+// * interrupts may occur at any time, a <tt>true</tt> return does
+// * not guarantee that a future <tt>signal</tt> will awaken any
+// * threads. This method is designed primarily for use in
+// * monitoring of the system state.
+// * @param condition the condition
+// * @return <tt>true</tt> if there are any waiting threads.
+// * @throws IllegalMonitorStateException if this lock
+// * is not held
+// * @throws IllegalArgumentException if the given condition is
+// * not associated with this lock
+// * @throws NullPointerException if condition null
+// */
+// public boolean hasWaiters(Condition condition) {
+// if (condition == null)
+// throw new NullPointerException();
+// if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+// throw new IllegalArgumentException("not owner");
+// return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
+// }
+
+// /**
+// * Returns an estimate of the number of threads waiting on the
+// * given condition associated with the write lock. Note that because
+// * timeouts and interrupts may occur at any time, the estimate
+// * serves only as an upper bound on the actual number of waiters.
+// * This method is designed for use in monitoring of the system
+// * state, not for synchronization control.
+// * @param condition the condition
+// * @return the estimated number of waiting threads.
+// * @throws IllegalMonitorStateException if this lock
+// * is not held
+// * @throws IllegalArgumentException if the given condition is
+// * not associated with this lock
+// * @throws NullPointerException if condition null
+// */
+// public int getWaitQueueLength(Condition condition) {
+// if (condition == null)
+// throw new NullPointerException();
+// if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+// throw new IllegalArgumentException("not owner");
+// return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
+// }
+//
+// /**
+// * Returns a collection containing those threads that may be
+// * waiting on the given condition associated with the write lock.
+// * Because the actual set of threads may change dynamically while
+// * constructing this result, the returned collection is only a
+// * best-effort estimate. The elements of the returned collection
+// * are in no particular order. This method is designed to
+// * facilitate construction of subclasses that provide more
+// * extensive condition monitoring facilities.
+// * @param condition the condition
+// * @return the collection of threads
+// * @throws IllegalMonitorStateException if this lock
+// * is not held
+// * @throws IllegalArgumentException if the given condition is
+// * not associated with this lock
+// * @throws NullPointerException if condition null
+// */
+// protected Collection getWaitingThreads(Condition condition) {
+// if (condition == null)
+// throw new NullPointerException();
+// if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+// throw new IllegalArgumentException("not owner");
+// return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
+// }
+
+ /**
+ * Returns a string identifying this lock, as well as its lock state.
+ * The state, in brackets, includes the String {@code "Write locks ="}
+ * followed by the number of reentrantly held write locks, and the
+ * String {@code "Read locks ="} followed by the number of held
+ * read locks.
+ *
+ * @return a string identifying this lock, as well as its lock state
+ */
+ public String toString() {
+ return super.toString() +
+ "[Write locks = " + getWriteHoldCount() +
+ ", Read locks = " + getReadLockCount() + "]";
+ }
+}