summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-08-24 23:10:15 +0000
committereea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-08-24 23:10:15 +0000
commite4012b2dc8297540c9501a10daa8b8746d55297e (patch)
treeef60f5324a9022443eb683594e2d415ea46d08eb
parentf69420de3b964a4f1de9b9c310ca9ced2461e24e (diff)
downloadATCD-e4012b2dc8297540c9501a10daa8b8746d55297e.tar.gz
Updated source files for Concurrency.
-rw-r--r--java/JACE/Concurrency/AbstractLock.java269
-rw-r--r--java/JACE/Concurrency/Condition.java124
-rw-r--r--java/JACE/Concurrency/LockAdapter.java262
-rw-r--r--java/JACE/Concurrency/LockException.java28
-rw-r--r--java/JACE/Concurrency/Mutex.java239
-rw-r--r--java/JACE/Concurrency/RWMutex.java268
-rw-r--r--java/JACE/Concurrency/RenewObject.java36
-rw-r--r--java/JACE/Concurrency/Semaphore.java263
-rw-r--r--java/JACE/Concurrency/ThreadManager.java113
-rw-r--r--java/JACE/Concurrency/Token.java301
-rw-r--r--java/JACE/Concurrency/WaitObject.java39
-rw-r--r--java/JACE/Concurrency/package.html15
12 files changed, 1957 insertions, 0 deletions
diff --git a/java/JACE/Concurrency/AbstractLock.java b/java/JACE/Concurrency/AbstractLock.java
new file mode 100644
index 00000000000..c8afaf789ae
--- /dev/null
+++ b/java/JACE/Concurrency/AbstractLock.java
@@ -0,0 +1,269 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.Concurrency
+ *
+ * = FILENAME
+ * Lock.java
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+package JACE.Concurrency;
+
+import JACE.ASX.*;
+
+/**
+ * Interface for any Java ACE synchronization mechanism.
+ * <P>
+ * Defines the interface for Token, Mutex, RWMutex, Semaphore,
+ * and the RemoteLock proxies in the Token service, as well as
+ * the possible constant return values.
+ * <P>
+ * Methods which take TimeValue timeouts can throw
+ * JACE.ASX.TimeoutExceptions. The locks should continue to
+ * function properly after a thread times out or is interrupted.
+ * <em>Also note that the timeouts are absolute time-of-day
+ * values, not relative times.</em>
+ * <P>
+ * An AbstractLock.FAILURE can be returned for an undefined type of
+ * failure.
+ * <P>
+ * You can assume that
+ * AbstractLock.FAILURE < AbstractLock.SUCCESS < AbstractLock.SLEEPHOOK
+ * <P>
+ * Any method can throw a LockException, providing a way to return
+ * unusual error cases in future types of locks (such as the Token
+ * service).
+ * <P>
+ * It is safe to call release () in a finally block, since it will
+ * return FAILURE if the accessing thread is not the owner.
+ *
+ */
+public interface AbstractLock
+{
+ /**
+ * Generic failure indication, used as a return value.
+ */
+ public static final int FAILURE = -1;
+
+ /**
+ * Success indication, used as a return value.
+ */
+ int SUCCESS = 0;
+
+ /**
+ * Success indication, but notes that the thread had to sleep
+ * to complete it (and it called the sleep hook). Used as a
+ * return value.
+ */
+ int SLEEPHOOK = 1;
+
+
+ /**
+ * Acquire ownership of the lock, blocking indefinitely if necessary.
+ * <P>
+ *@return AbstractLock.FAILURE or AbstractLock.SUCCESS
+ *@exception LockException special exception defined by a later
+ * implementation
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ */
+ public int acquire () throws LockException, InterruptedException;
+
+ /**
+ * Acquire ownership of the lock by the given absolute time time-out.
+ * A value of null for the timeout parameter results in a blocking
+ * acquire.
+ * A value of TimeValue.zero throws a TimeoutException if the
+ * acquire would block.
+ * <P>
+ *@param timeout absolute time by which the lock must be acquired
+ *@return appropriate Lock return value (AbstractLock.FAILURE,
+ * AbstractLock.SUCCESS or AbstractLock.SLEEPHOOK)
+ *@exception LockException special exception defined by a later
+ * implementation
+ *@exception JACE.ASX.TimeoutException thrown when the lock is not
+ * obtained by the desired time
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ *@see AbstractLock#tryAcquire
+ */
+ public int acquire (TimeValue timeout)
+ throws LockException, TimeoutException, InterruptedException;
+
+ /**
+ * Acquire a read lock, blocking indefinitely if necessary. This can
+ * be used to implement Reader-Writer locks in which multiple readers
+ * may have simultaneous access.
+ * <P>
+ *@return AbstractLock.FAILURE or AbstractLock.SUCCESS
+ *@exception LockException special exception defined by a later
+ * implementation
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ */
+ public int acquireRead () throws LockException, InterruptedException;
+
+ /**
+ * Acquire a read lock by the given absolute time time-out. This can
+ * be used to implement Reader-Writer locks in which multiple readers
+ * may have simultaneous access.
+ * <P>
+ *@param timeout absolute time by which the lock must be acquired
+ *@return appropriate lock return value (AbstractLock.FAILURE,
+ * AbstractLock.SUCCESS or AbstractLock.SLEEPHOOK)
+ *@exception LockException special exception defined by a later
+ * implementation
+ *@exception JACE.ASX.TimeoutException thrown when the lock is not
+ * obtained by the desired time
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ *@see AbstractLock#tryAcquireRead
+ */
+ public int acquireRead (TimeValue timeout)
+ throws LockException, TimeoutException, InterruptedException;
+
+ /**
+ * Acquire a write lock, blocking indefinitely if necessary. This can
+ * be used to implement Reader-Writer locks in which a writer has
+ * exclusive access.
+ * <P>
+ *@return AbstractLock.FAILURE or AbstractLock.SUCCESS
+ *@exception LockException special exception defined by a later
+ * implementation
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ */
+ public int acquireWrite () throws LockException, InterruptedException;
+
+ /**
+ * Acquire a write lock by the given absolute time time-out. This can
+ * be used to implement Reader-Writer locks in which a writer has
+ * exclusive access.
+ * <P>
+ *@param timeout absolute time by which the lock must be acquired
+ *@return appropriate AbstractLock return value (AbstractLock.FAILURE,
+ * AbstractLock.SUCCESS or AbstractLock.SLEEPHOOK)
+ *@exception LockException special exception defined by a later
+ * implementation
+ *@exception JACE.ASX.TimeoutException thrown when the lock is not
+ * obtained by the desired time
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ *@see AbstractLock#tryAcquireWrite
+ */
+ public int acquireWrite (TimeValue timeout)
+ throws LockException, TimeoutException, InterruptedException;
+
+ /**
+ * Give up the lock to some number of waiting threads (if any), then
+ * reacquire, blocking indefinitely if necessary.
+ * <P>
+ * An optimized method that efficiently reacquires the token if no
+ * other threads are waiting. This is useful for situations where
+ * you don't want to degrade the quality of service if there are
+ * other threads waiting to get the token.
+ * <P>
+ *@param requeuePosition position in the waiters queue to insert
+ * this thread. If this value is -1 and there are other
+ * threads waiting to obtain the token, this thread is queued
+ * at the end. If this value is greater than -1, then it
+ * indicates how many entries to skip over before inserting
+ * our thread into the queue. (For example, if it is 0,
+ * this thread is put at the front of the queue.) If this
+ * value is greater than the number of waiters, this thread is
+ * simply put at the end of the current waiters queue.
+ *@return AbstractLock.FAILURE or AbstractLock.SUCCESS
+ *@exception LockException special exception defined by a later
+ * implementation
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ */
+ public int renew (int requeuePosition) throws LockException,
+ InterruptedException;
+
+ /**
+ * Give up the lock to some waiting threads (if any), then reacquire
+ * by the given absolute time time-out.
+ * <P>
+ * An optimized method that efficiently reacquires the token if no
+ * other threads are waiting. This is useful for situations where
+ * you don't want to degrade the quality of service if there are
+ * other threads waiting to get the token.
+ * <P>
+ * A value of null for the timeout should indicate a blocking renew.
+ * <P>
+ *@param requeuePosition position in the waiters queue to insert
+ * this thread. If this value is -1 and there are other
+ * threads waiting to obtain the token, this thread is queued
+ * at the end. If this value is greater than -1, then it
+ * indicates how many entries to skip over before inserting
+ * our thread into the queue. (For example, if it is 0,
+ * this thread is put at the front of the queue.) If this
+ * value is greater than the number of waiters, this thread is
+ * simply put at the end of the current waiters queue.
+ *
+ *@param timeout absolute time by which the lock must be reacquired
+ *
+ *@return appropriate AbstractLock return value
+ * (AbstractLock.FAILURE or AbstractLock.SUCCESS)
+ *@exception LockException special exception defined by a later
+ * implementation
+ *@exception JACE.ASX.TimeoutException thrown when the lock is not
+ * obtained by the desired time
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ */
+ public int renew (int requeuePosition, TimeValue timeout)
+ throws LockException, TimeoutException, InterruptedException;
+
+ /**
+ * Try to acquire the lock without blocking.
+ * <P>
+ *@return appropriate AbstractLock return value
+ * (AbstractLock.FAILURE or AbstractLock.SUCCESS)
+ *@exception LockException special exception defined by a later
+ * implementation
+ */
+ public int tryAcquire () throws LockException;
+
+ /**
+ * Try to acquire a read lock without blocking.
+ * <P>
+ *@see #acquireRead
+ *@return appropriate AbstractLock return value
+ * (AbstractLock.FAILURE or AbstractLock.SUCCESS)
+ *@exception LockException special exception defined by a later
+ * implementation
+ */
+ public int tryAcquireRead () throws LockException;
+
+ /**
+ * Try to acquire a write lock without blocking.
+ *<P>
+ *@see #acquireWrite
+ *@return appropriate AbstractLock return value
+ * (AbstractLock.FAILURE or AbstractLock.SUCCESS)
+ *@exception LockException special exception defined by a later
+ * implementation
+ */
+ public int tryAcquireWrite () throws LockException;
+
+ /**
+ * Method that is called before a thread goes to sleep in an
+ * acquire. This should be overridden by a subclass to define
+ * the appropriate behavior.
+ */
+ public void sleepHook ();
+
+ /**
+ * Release ownership of this lock.
+ * <P>
+ *@return appropriate AbstractLock return value
+ * (AbstractLock.FAILURE or AbstractLock.SUCCESS)
+ *@exception LockException special exception defined by a later
+ * implementation
+ */
+ public int release () throws LockException;
+}
diff --git a/java/JACE/Concurrency/Condition.java b/java/JACE/Concurrency/Condition.java
new file mode 100644
index 00000000000..1889f6e1edf
--- /dev/null
+++ b/java/JACE/Concurrency/Condition.java
@@ -0,0 +1,124 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.Concurrency
+ *
+ * = FILENAME
+ * Condition.java
+ *
+ *@author Irfan Pyarali
+ *
+ *************************************************/
+package JACE.Concurrency;
+
+import JACE.ASX.TimeoutException;
+import JACE.ASX.TimeValue;
+
+/**
+ * Abstraction for <em>traditional</em>
+ * condition variable
+ * <P>
+ * This condition variable allows the use of one
+ * mutex between multiple conditions.
+ * This implementation is based on the C++ version of ACE.
+ */
+public class Condition
+{
+ /**
+ * Default constructor
+ *@param Mutex for synchronization
+ */
+ public Condition (Mutex mutex)
+ {
+ mutex_ = mutex;
+ }
+
+ /**
+ * Wait for condition to become signaled.
+ *@exception InterruptedException exception during wait
+ */
+ public void Wait ()
+ throws InterruptedException
+ {
+ waiters_++;
+
+ try
+ {
+ mutex_.release();
+ synchronized (waitObject_) {
+ waitObject_.wait ();
+ }
+ mutex_.acquire ();
+ }
+ finally
+ {
+ waiters_--;
+ }
+ }
+
+ /**
+ * TimedWait for condition to become signaled. Note that the
+ * given TimeValue is an absolute time, not a relative time.
+ *
+ *@param tv Absolute time to wait until before timing out
+ *@exception TimeoutException wait timed out exception
+ *@exception InterruptedException exception during wait
+ */
+ public void Wait (TimeValue tv)
+ throws TimeoutException, InterruptedException
+ {
+ waiters_++;
+
+ try
+ {
+ mutex_.release();
+
+ synchronized (waitObject_) {
+ long start = System.currentTimeMillis();
+ long waitTime = tv.getMilliTime() - start;
+ if (waitTime < 1)
+ throw new TimeoutException ();
+ waitObject_.wait (waitTime);
+ }
+
+ mutex_.acquire (tv);
+ }
+ finally
+ {
+ waiters_--;
+ }
+ }
+
+ /**
+ * Signal condition. Wake one waiter (if any).
+ */
+ public void signal ()
+ {
+ synchronized (waitObject_) {
+ waitObject_.notify ();
+ }
+ }
+
+ /**
+ * Signal condition. Wake up all waiters (if any).
+ */
+ public void broadcast ()
+ {
+ synchronized (waitObject_) {
+ waitObject_.notifyAll ();
+ }
+ }
+
+ /**
+ * Accessor to lock
+ *@return Mutex
+ */
+ public Mutex mutex ()
+ {
+ return mutex_;
+ }
+
+ private int waiters_;
+ private Object waitObject_ = new Object ();
+ private Mutex mutex_;
+}
diff --git a/java/JACE/Concurrency/LockAdapter.java b/java/JACE/Concurrency/LockAdapter.java
new file mode 100644
index 00000000000..db2e9de05c7
--- /dev/null
+++ b/java/JACE/Concurrency/LockAdapter.java
@@ -0,0 +1,262 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.Concurrency
+ *
+ * = FILENAME
+ * Lock.java
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+package JACE.Concurrency;
+
+import JACE.ASX.*;
+
+/**
+ * Abstract adapter class which provides useful default implementations
+ * for several methods in the AbstractLock interface, as well as
+ * protected helper functions for making sure only the owner
+ * can perform certain operations.
+ *
+ *@see JACE.Concurrency.AbstractLock
+ */
+public abstract class LockAdapter implements AbstractLock
+{
+ /**
+ * Default implementation that calls acquire (TimeValue) with a null
+ * timeout.
+ *
+ *@see AbstractLock#acquire
+ */
+ public int acquire () throws InterruptedException
+ {
+ try {
+ return acquire (null);
+ } catch (TimeoutException e) {
+ // This should never happen
+ return AbstractLock.FAILURE;
+ }
+ }
+
+ /**
+ * Acquire ownership of the lock by the given absolute time time-out.
+ * A value of null for the timeout parameter results in a blocking
+ * acquire.
+ * A value of TimeValue.zero throws a TimeoutException if the
+ * acquire would block.
+ * <P>
+ *@param timeout absolute time by which the lock must be acquired
+ *@return appropriate Lock return value (AbstractLock.FAILURE,
+ * AbstractLock.SUCCESS or AbstractLock.SLEEPHOOK)
+ *@exception JACE.ASX.TimeoutException thrown when the lock is not
+ * obtained by the desired time
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ *@see AbstractLock#tryAcquire
+ */
+ public abstract int acquire (TimeValue timeout)
+ throws TimeoutException, InterruptedException;
+
+ /**
+ * Default implementation that calls acquireRead (TimeValue) with a
+ * null timeout.
+ *
+ *@see AbstractLock#acquireRead
+ */
+ public int acquireRead () throws InterruptedException
+ {
+ try {
+ return acquireRead (null);
+ } catch (TimeoutException e) {
+ // This should never happen
+ }
+
+ return AbstractLock.FAILURE;
+ }
+
+ /**
+ * Default implementation that calls acquire (TimeValue).
+ *
+ *@see AbstractLock#acquireRead(TimeValue)
+ */
+ public int acquireRead (TimeValue timeout)
+ throws TimeoutException, InterruptedException
+ {
+ return acquire (timeout);
+ }
+
+ /**
+ * Default implementation that calls acquire with a null
+ * timeout.
+ *
+ *@see AbstractLock#acquireWrite
+ */
+ public int acquireWrite () throws InterruptedException
+ {
+ try {
+ return acquire (null);
+ } catch (TimeoutException e) {
+ // This should never happen
+ }
+
+ return AbstractLock.FAILURE;
+ }
+
+ /**
+ * Default implementation that calls acquire (TimeValue).
+ *
+ *@see AbstractLock#acquireWrite(TimeValue)
+ */
+ public int acquireWrite (TimeValue timeout)
+ throws TimeoutException, InterruptedException
+ {
+ return acquire (timeout);
+ }
+
+ /**
+ * Default implementation that calls renew (int, TimeValue) with
+ * a null timeout.
+ *
+ *@see AbstractLock#renew(int)
+ */
+ public int renew (int requeuePosition) throws InterruptedException
+ {
+ try
+ {
+ return renew (requeuePosition, null);
+ } catch (TimeoutException e) {
+ // Note that this should never happen since we requested a
+ // blocking acquire.
+ return AbstractLock.FAILURE;
+ }
+ }
+
+ /**
+ * Give up the lock to some waiting threads (if any), then reacquire
+ * by the given absolute time time-out.
+ * <P>
+ * An optimized method that efficiently reacquires the token if no
+ * other threads are waiting. This is useful for situations where
+ * you don't want to degrade the quality of service if there are
+ * other threads waiting to get the token.
+ * <P>
+ * A value of null for the timeout should indicate a blocking renew.
+ * <P>
+ *@param requeuePosition position in the waiters queue to insert
+ * this thread. If this value is -1 and there are other
+ * threads waiting to obtain the token, this thread is queued
+ * at the end. If this value is greater than -1, then it
+ * indicates how many entries to skip over before inserting
+ * our thread into the queue. (For example, if it is 0,
+ * this thread is put at the front of the queue.) If this
+ * value is greater than the number of waiters, this thread is
+ * simply put at the end of the current waiters queue.
+ *
+ *@param timeout absolute time by which the lock must be reacquired
+ *
+ *@return appropriate AbstractLock return value
+ * (AbstractLock.FAILURE or AbstractLock.SUCCESS)
+ *@exception JACE.ASX.TimeoutException thrown when the lock is not
+ * obtained by the desired time
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ */
+ public abstract int renew (int requeuePosition,
+ TimeValue timeout)
+ throws TimeoutException,
+ InterruptedException;
+
+ /**
+ * Default implementation that calls tryAcquire ().
+ *
+ *@see AbstractLock#tryAcquireRead
+ */
+ public int tryAcquireRead ()
+ {
+ return tryAcquire ();
+ }
+
+ /**
+ * Default implementation that calls tryAcquire ().
+ *
+ *@see AbstractLock#tryAcquireWrite
+ */
+ public int tryAcquireWrite ()
+ {
+ return tryAcquire ();
+ }
+ /**
+ * Try to acquire the lock without blocking.
+ * <P>
+ *@return appropriate AbstractLock return value
+ * (AbstractLock.FAILURE or AbstractLock.SUCCESS)
+ */
+ public abstract int tryAcquire ();
+
+ /**
+ * Default implementation as a no-op.
+ *
+ *@see AbstractLock#sleepHook
+ */
+ public void sleepHook ()
+ {
+ }
+
+ /**
+ * Release ownership of this lock.
+ * <P>
+ *@return appropriate AbstractLock return value
+ * (AbstractLock.FAILURE or AbstractLock.SUCCESS)
+ */
+ public abstract int release ();
+
+ /**
+ * Obtains an Object which uniquely identifies the current accessor
+ * (usually a thread). This is used to make sure only an owner can
+ * perform certain operations like release. Subclasses can redefine
+ * the behavior as necessary, such as in the Token service where it is
+ * defined to be the client ID sent by the proxy.
+ * <P>
+ * When using Java 1.2 or later, it might be more efficient to use
+ * ThreadLocal and an Integer for the ID. The current default
+ * implementation returns the Thread.currentThread () reference.
+ *
+ *@return Object representing a unique ID for this accessor
+ */
+ protected Object accessorID ()
+ {
+ return Thread.currentThread();
+ }
+
+ /**
+ * Check to see if the current accessor is the (or a) owner of this
+ * lock.
+ */
+ protected boolean isOwner()
+ {
+ return accessorID().equals(this.owner_);
+ }
+
+ /**
+ * Set the current accessor to be the (or a) owner of this lock.
+ */
+ protected void setOwner()
+ {
+ this.owner_ = accessorID();
+ }
+
+ /**
+ * Make sure that this accessor is no longer the (or a) owner of this
+ * lock.
+ */
+ protected void clearOwner()
+ {
+ this.owner_ = null;
+ }
+
+ /**
+ * Reference to the accessorID of the owner.
+ */
+ private Object owner_;
+}
diff --git a/java/JACE/Concurrency/LockException.java b/java/JACE/Concurrency/LockException.java
new file mode 100644
index 00000000000..dff4c09c626
--- /dev/null
+++ b/java/JACE/Concurrency/LockException.java
@@ -0,0 +1,28 @@
+package JACE.Concurrency;
+
+/**
+ * Base class for possible exceptions thrown from Lock
+ * mechanisms. This can be used by later Lock
+ * implementations to signal special types of exceptions, such
+ * as a remote failure, etc.
+ * <P>
+ */
+public class LockException extends java.lang.Exception
+{
+ /**
+ * Default constructor
+ */
+ public LockException () { }
+
+ /**
+ * Constructor with a string message that will be returned
+ * via the getMessage() method on Exception.
+ * <P>
+ *@see java.lang.Exception#getMessage
+ */
+ public LockException (String message)
+ {
+ super(message);
+ }
+}
+
diff --git a/java/JACE/Concurrency/Mutex.java b/java/JACE/Concurrency/Mutex.java
new file mode 100644
index 00000000000..856fdbd79eb
--- /dev/null
+++ b/java/JACE/Concurrency/Mutex.java
@@ -0,0 +1,239 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.Concurrency
+ *
+ * = FILENAME
+ * Mutex.java
+ *
+ *@author Prashant Jain
+ *@author Everett Anderson
+ *
+ *************************************************/
+package JACE.Concurrency;
+
+import java.util.*;
+import JACE.ASX.*;
+
+/**
+ * Value added abstraction for mutex variable creation.
+ *
+ * A mutex whose operations do not block forever and can time out.
+ * <P>
+ * <EM>This class does not support recursive semantics.</EM>
+ */
+public class Mutex extends LockAdapter
+{
+ /**
+ * Acquire ownership of the lock, blocking indefinitely if necessary.
+ * <P>
+ *@return AbstractLock.FAILURE or AbstractLock.SUCCESS
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ */
+ public synchronized int acquire () throws InterruptedException
+ {
+ if (this.monitor_.condition ()) {
+ this.monitor_.condition (false);
+ setOwner ();
+ return AbstractLock.SUCCESS;
+ }
+
+ this.numberOfWaiters_++;
+ try {
+ sleepHook ();
+ this.monitor_.timedWait ();
+ } finally {
+ this.numberOfWaiters_--;
+ }
+ this.monitor_.condition (false);
+ setOwner();
+
+ return AbstractLock.SLEEPHOOK;
+ }
+
+ public int renew (int requeuePosition,
+ TimeValue timeout)
+ throws InterruptedException,
+ TimeoutException
+ {
+ RenewObject rwo;
+
+ synchronized (this) {
+
+ if (!this.isOwner ())
+ return AbstractLock.FAILURE;
+
+ if (numberOfWaiters_ == 0 || requeuePosition == 0)
+ return AbstractLock.SUCCESS;
+
+ if (requeuePosition < 0 || requeuePosition > numberOfWaiters_)
+ requeuePosition = numberOfWaiters_;
+
+ rwo = new RenewObject (requeuePosition);
+
+ this.release ();
+ this.renewers_.addElement (rwo);
+ }
+
+ // We can't have the method synchronized, or synchronize on (this)
+ // in here because then the Thread that was woken up won't be able
+ // to continue its acquire.
+ //
+ // Normally when an exception occurs in timedWait, this thread just
+ // needs to remove itself from the renewers queue.
+ //
+ // However, the following situation exists:
+ // Thread A is the current owner, and is doing processing in release()
+ // This thread generates a timeout exception in timedWait
+ // Thread A signals this thread to wake up and take ownership, and
+ // removes it from the queue.
+ // This thread never takes ownership -- the exception keeps going up.
+ //
+ // This could lead to other renewers waiting in limbo forever.
+ //
+ // Solution: If this thread has an exception and it looks like it
+ // has been proclaimed the owner, then it calls release and lets
+ // the exception continue.
+
+ boolean exceptionOccured = true;
+ try {
+ synchronized (rwo) {
+ rwo.timedWait (timeout);
+
+ exceptionOccured = false;
+ }
+ } finally {
+ if (exceptionOccured) {
+ synchronized (this) {
+ if (!renewers_.removeElement (rwo)) {
+ setOwner ();
+ release ();
+ }
+ }
+ }
+ }
+
+ synchronized (this) {
+ setOwner ();
+ }
+
+ // By this point, we should know that we have the lock. The condition
+ // flag is never set to true in the release() call from the Thread
+ // that gave us control.
+
+ return AbstractLock.SUCCESS;
+ }
+
+ public synchronized int tryAcquire () {
+ if (this.monitor_.condition ()) {
+ this.monitor_.condition (false);
+ setOwner();
+ return AbstractLock.SUCCESS;
+ } else
+ return AbstractLock.FAILURE;
+ }
+
+ public synchronized int acquire (TimeValue tv)
+ throws TimeoutException, InterruptedException
+ {
+ if (this.monitor_.condition ()) {
+ this.monitor_.condition (false);
+ setOwner ();
+ return AbstractLock.SUCCESS;
+ }
+
+ this.numberOfWaiters_++;
+ try {
+ sleepHook ();
+ this.monitor_.timedWait (tv);
+ } finally {
+ this.numberOfWaiters_--;
+ }
+ this.monitor_.condition (false);
+ setOwner();
+
+ return AbstractLock.SLEEPHOOK;
+ }
+
+ /**
+ * Checks any objects in the renewers queue, giving one of them
+ * the lock if it is appropriate. Assumes the synchronization
+ * lock is already held.
+ *
+ *@return true if a renewer was signaled, else false
+ */
+ protected boolean signalNextRenewer ()
+ {
+ // First find the renewer with the minimum yieldTo count, processing
+ // all of them along the way.
+ if (this.renewers_.size() > 0) {
+
+ RenewObject renewer = (RenewObject)renewers_.
+ elementAt (renewers_.size () - 1);
+
+ renewer.decrementYieldTo ();
+
+ for (int i = this.renewers_.size() - 2; i >=0; i--) {
+
+ RenewObject rwo = (RenewObject)renewers_.elementAt (i);
+
+ rwo.decrementYieldTo ();
+
+ renewer = renewer.min (rwo);
+ }
+
+ // If the renewer with the minimum yieldTo count has yielded to
+ // enough threads, or if there are no waiting threads, it should
+ // be signaled (thus, it wakes up and obtains the lock again).
+
+ if (renewer.condition () || numberOfWaiters_ == 0) {
+ // Note that we leave monitor_.condition in the false state so
+ // we are assured that only the renewer (and not another
+ // Thread that does an acquire) will gain control. This
+ // is important since the renew method can't be synchronized
+ // in its current implementation.
+ renewers_.removeElement(renewer);
+
+ synchronized (renewer) {
+ renewer.signal ();
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public synchronized int release ()
+ {
+ if (!isOwner())
+ return AbstractLock.FAILURE;
+
+ if (!signalNextRenewer ()) {
+ // Do a normal release if there are no threads waiting to renew
+ // or no such threads are ready to renew.
+ this.monitor_.condition (true);
+ this.monitor_.signal ();
+ }
+
+ return AbstractLock.SUCCESS;
+ }
+
+ /**
+ * Monitor used to signal whether or not this Mutex is available.
+ */
+ protected WaitObject monitor_ = new WaitObject (true, this);
+ // The monitor (adapter) to wait on
+
+ /**
+ * Queue of waiting renewers.
+ */
+ protected Vector renewers_ = new Vector ();
+
+ /**
+ * Number of waiting threads.
+ */
+ protected int numberOfWaiters_ = 0;
+}
diff --git a/java/JACE/Concurrency/RWMutex.java b/java/JACE/Concurrency/RWMutex.java
new file mode 100644
index 00000000000..abb30ce3bc8
--- /dev/null
+++ b/java/JACE/Concurrency/RWMutex.java
@@ -0,0 +1,268 @@
+package JACE.Concurrency;
+
+import java.util.*;
+import JACE.ASX.*;
+
+/**
+ * A read/write lock allows multiple
+ * readers or a single writer to access the guarded element.
+ * <P>
+ * <EM>This class does not support recursive semantics.</EM>
+ */
+public class RWMutex extends LockAdapter
+{
+ public synchronized int tryAcquire ()
+ {
+ if (referenceCount_ == 0) {
+ referenceCount_ = -1;
+ setOwner ();
+ return AbstractLock.SUCCESS;
+ } else
+ return AbstractLock.FAILURE;
+ }
+
+ public synchronized int tryAcquireRead ()
+ {
+ if (referenceCount_ > -1 && waiters_.size () == 0) {
+ referenceCount_++;
+ setOwner ();
+ return AbstractLock.SUCCESS;
+ } else
+ return AbstractLock.FAILURE;
+ }
+
+ public int acquire(TimeValue timeout)
+ throws TimeoutException, InterruptedException
+ {
+ return acquireWrite(timeout);
+ }
+
+ public void waitUntilIsOwner (RWWaitObject waitObj, TimeValue timeout)
+ throws TimeoutException, InterruptedException
+ {
+ boolean exceptionOccured = true;
+ try {
+ sleepHook ();
+ synchronized (waitObj) {
+ waitObj.timedWait (timeout);
+ }
+ exceptionOccured = false;
+ } finally {
+
+ synchronized (this) {
+
+ if (exceptionOccured) {
+ if (!waiters_.removeElement (waitObj)) {
+ setOwner ();
+ release ();
+ }
+ } else
+ setOwner();
+ }
+ }
+ }
+
+ public int acquireRead(TimeValue timeout)
+ throws TimeoutException, InterruptedException
+ {
+ RWWaitObject waitObj = null;
+
+ synchronized (this) {
+
+ if (referenceCount_ > -1 && waiters_.size () == 0) {
+ referenceCount_++;
+ setOwner ();
+ return AbstractLock.SUCCESS;
+ }
+
+ waitObj = new RWWaitObject (true);
+
+ waiters_.addElement (waitObj);
+ }
+
+ waitUntilIsOwner (waitObj, timeout);
+
+ return AbstractLock.SLEEPHOOK;
+ }
+
+ public int acquireWrite(TimeValue timeout)
+ throws TimeoutException, InterruptedException
+ {
+ RWWaitObject waitObj = null;
+
+ synchronized (this) {
+
+ if (referenceCount_ == 0) {
+ referenceCount_ = -1;
+ setOwner ();
+ return AbstractLock.SUCCESS;
+ }
+
+ waitObj = new RWWaitObject (false);
+
+ waiters_.addElement (waitObj);
+ }
+
+ waitUntilIsOwner (waitObj, timeout);
+
+ // When the writer gets here, it has been cleared to go by
+ // whatever thread specifically gave control to this writer in
+ // release. The referenceCount_ and numberOfWaitingWriters_
+ // variables are also adjusted by the releasing thread since
+ // it already has a synchronization lock. Not doing that,
+ // and then having another synchronized (this) block in here
+ // could lead to a situation in which another thread sneaks
+ // in inbetween when this thread leaves timedWait and goes to
+ // adjust them.
+
+ return AbstractLock.SLEEPHOOK;
+ }
+
+
+ public synchronized int release ()
+ {
+ if (!isOwner ())
+ return AbstractLock.FAILURE;
+
+ clearOwner ();
+
+ // Releasing a reader.
+ if (referenceCount_ > 0) {
+ referenceCount_--;
+
+ if (referenceCount_ != 0)
+ return AbstractLock.SUCCESS;
+
+ } else {
+ // releasing a writer
+ referenceCount_ = 0;
+ }
+
+ if (waiters_.size () == 0)
+ return AbstractLock.SUCCESS;
+
+ if (releaseFirstReaders () == 0) {
+ RWWaitObject waitObj = (RWWaitObject)waiters_.firstElement ();
+ waiters_.removeElementAt (0);
+
+ referenceCount_ = -1;
+
+ waitObj.condition (true);
+ synchronized (waitObj) {
+ waitObj.signal ();
+ }
+ }
+
+ return AbstractLock.SUCCESS;
+ }
+
+ // Releases all waiting readers up to the first waiting writer
+ // or the end of the queue. Returns the number of readers
+ // released.
+ protected int releaseFirstReaders ()
+ {
+ int releasedReaders = 0;
+
+ do {
+
+ RWWaitObject waitObj = (RWWaitObject)waiters_.firstElement ();
+ if (!waitObj.isReader ())
+ break;
+
+ waiters_.removeElementAt (0);
+
+ referenceCount_++;
+ releasedReaders++;
+
+ waitObj.condition (true);
+ synchronized (waitObj) {
+ waitObj.signal ();
+ }
+
+ } while (waiters_.size () > 0);
+
+ return releasedReaders;
+ }
+
+ public int renew (int requeuePosition,
+ JACE.ASX.TimeValue timeout)
+ throws InterruptedException,
+ TimeoutException
+ {
+ RWWaitObject waitObj = null;
+
+ synchronized (this) {
+
+ if (!isOwner ())
+ return AbstractLock.FAILURE;
+
+ if (requeuePosition == 0 || waiters_.size () == 0)
+ return AbstractLock.SUCCESS;
+
+ waitObj = new RWWaitObject (referenceCount_ > 0);
+
+ if (requeuePosition < 0 || requeuePosition > waiters_.size ()) {
+ requeuePosition = waiters_.size ();
+ }
+
+ waiters_.insertElementAt (waitObj, requeuePosition);
+
+ release ();
+ }
+
+ waitUntilIsOwner (waitObj, timeout);
+
+ // When the writer gets here, it has been cleared to go by
+ // whatever thread specifically gave control to this writer in
+ // release. The referenceCount_ and numberOfWaitingWriters_
+ // variables are also adjusted by the releasing thread since
+ // it already has a synchronization lock. Not doing that,
+ // and then having another synchronized (this) block in here
+ // could lead to a situation in which another thread sneaks
+ // in inbetween when this thread leaves timedWait and goes to
+ // adjust them.
+
+ return AbstractLock.SUCCESS;
+ }
+
+ static class RWWaitObject extends WaitObject
+ {
+ public RWWaitObject (boolean isReader)
+ {
+ isReader_ = isReader;
+ }
+
+ public boolean isReader ()
+ {
+ return isReader_;
+ }
+
+ private boolean isReader_ = false;
+ }
+
+ protected boolean isOwner ()
+ {
+ return owners_.containsKey (accessorID());
+ }
+
+ protected void setOwner ()
+ {
+ owners_.put (accessorID(), this);
+ }
+
+ protected void clearOwner ()
+ {
+ owners_.remove (accessorID());
+ }
+
+ private Vector waiters_ = new Vector ();
+
+ private int referenceCount_ = 0;
+ // Value is -1 if writer has the lock, else this keeps track of the
+ // number of readers holding the lock.
+
+ private Hashtable owners_ = new Hashtable ();
+
+ private int nestingLevel_ = 0;
+}
+
diff --git a/java/JACE/Concurrency/RenewObject.java b/java/JACE/Concurrency/RenewObject.java
new file mode 100644
index 00000000000..b690958968a
--- /dev/null
+++ b/java/JACE/Concurrency/RenewObject.java
@@ -0,0 +1,36 @@
+package JACE.Concurrency;
+
+import JACE.ASX.TimedWait;
+
+class RenewObject extends TimedWait
+{
+ public RenewObject (int maxYieldTo)
+ {
+ yieldTo_ = maxYieldTo;
+ }
+
+ public boolean condition ()
+ {
+ return yieldTo_ <= 0;
+ }
+
+ public void decrementYieldTo()
+ {
+ this.yieldTo_--;
+ }
+
+ public int yieldTo ()
+ {
+ return this.yieldTo_;
+ }
+
+ public RenewObject min (RenewObject other)
+ {
+ if (other.yieldTo_ < this.yieldTo_)
+ return other;
+ else
+ return this;
+ }
+
+ private int yieldTo_;
+}
diff --git a/java/JACE/Concurrency/Semaphore.java b/java/JACE/Concurrency/Semaphore.java
new file mode 100644
index 00000000000..5e558035aee
--- /dev/null
+++ b/java/JACE/Concurrency/Semaphore.java
@@ -0,0 +1,263 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.Concurrency
+ *
+ * = FILENAME
+ * Semaphore.java
+ *
+ *@author Prashant Jain
+ *
+ *************************************************/
+package JACE.Concurrency;
+
+import java.util.*;
+import JACE.ASX.*;
+
+/**
+ * Implementation of Dijkstra's counting semaphore in java.
+ * <P>
+ * <EM>This class does not support recursive semantics.</EM>
+ */
+public class Semaphore extends LockAdapter
+{
+ static class TimedWaitSAdapter extends JACE.ASX.TimedWait
+ {
+ TimedWaitSAdapter (Object obj)
+ {
+ super (obj);
+ }
+
+ // Check to see if there are any semaphores available.
+ public boolean condition ()
+ {
+ return this.count_ > 0;
+ }
+
+ // Increment the count by one
+ public void increment ()
+ {
+ this.count_++;
+ }
+
+ // Decrement the count by one
+ public void decrement ()
+ {
+ this.count_--;
+ }
+
+ // Set the count
+ public void count (int c)
+ {
+ this.count_ = c;
+ }
+
+ public int count ()
+ {
+ return this.count_;
+ }
+
+ private int count_ = 0;
+ }
+
+ /**
+ * Create a Semaphore.
+ *@param count semaphore count
+ */
+ public Semaphore (int c)
+ {
+ this.monitor_.count (c);
+ this.owners_ = new Hashtable (c);
+ }
+
+ /**
+ * Create a binary Semaphore.
+ */
+ public Semaphore ()
+ {
+ this.monitor_.count (1);
+ this.owners_ = new Hashtable (1);
+ }
+
+ public synchronized int tryAcquire ()
+ {
+ if (this.monitor_.condition ()) {
+ this.monitor_.decrement ();
+ setOwner ();
+ return AbstractLock.SUCCESS;
+ } else
+ return AbstractLock.FAILURE;
+ }
+
+ /**
+ * Acquire the Semaphore. Throws a TimeoutException if the semaphore
+ * isn't acquired before the given absolute time.
+ *@param tv time (TimeValue) to wait until before throwing a
+ * TimeoutException (unless the semaphore is acquired before that)
+ *@exception TimeoutException wait timed out exception
+ *@exception InterruptedException exception during wait
+ */
+ public synchronized int acquire (TimeValue tv)
+ throws TimeoutException, InterruptedException
+ {
+ if (this.monitor_.condition ()) {
+ this.monitor_.decrement ();
+ setOwner ();
+ return AbstractLock.SUCCESS;
+ }
+
+ numberOfWaiters_++;
+
+ try {
+ sleepHook ();
+ this.monitor_.timedWait (tv);
+ } finally {
+ numberOfWaiters_--;
+ }
+
+ this.monitor_.decrement ();
+ setOwner ();
+
+ return AbstractLock.SLEEPHOOK;
+ }
+
+ public synchronized int release ()
+ {
+ if (!isOwner ())
+ return AbstractLock.FAILURE;
+
+ if (!signalNextRenewer ()) {
+ this.monitor_.increment ();
+ this.monitor_.signal ();
+ clearOwner ();
+ }
+
+ return AbstractLock.SUCCESS;
+ }
+
+ /**
+ * Checks any objects in the renewers queue, giving one of them
+ * the lock if it is appropriate. Assumes the synchronization
+ * lock is already held.
+ *
+ *@return true if a renewer was signaled, else false
+ */
+ protected boolean signalNextRenewer ()
+ {
+ // First find the renewer with the minimum yieldTo count, processing
+ // all of them along the way.
+ if (this.renewers_.size() > 0) {
+
+ RenewObject renewer = (RenewObject)renewers_.
+ elementAt (renewers_.size () - 1);
+
+ renewer.decrementYieldTo ();
+
+ for (int i = this.renewers_.size() - 2; i >=0; i--) {
+
+ RenewObject rwo = (RenewObject)renewers_.elementAt (i);
+
+ rwo.decrementYieldTo ();
+
+ renewer = renewer.min (rwo);
+ }
+
+ // If the renewer with the minimum yieldTo count has yielded to
+ // enough threads, or if there are no waiting threads, it should
+ // be signaled (thus, it wakes up and obtains the lock again).
+
+ if (renewer.condition () || numberOfWaiters_ == 0) {
+ // Note that we leave monitor_.inUse in the true state so
+ // we are assured that only the renewer (and not another
+ // Thread that does an acquire) will gain control. This
+ // is important since the renew method can't be synchronized
+ // in its current implementation.
+ renewers_.removeElement(renewer);
+
+ synchronized (renewer) {
+ renewer.signal ();
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public int renew (int requeuePosition,
+ JACE.ASX.TimeValue timeout)
+ throws InterruptedException,
+ TimeoutException
+ {
+ RenewObject rwo;
+
+ synchronized (this) {
+
+ if (!this.isOwner ())
+ return AbstractLock.FAILURE;
+
+ if (numberOfWaiters_ == 0 ||
+ requeuePosition == 0 ||
+ this.monitor_.condition ())
+ return AbstractLock.SUCCESS;
+
+ if (requeuePosition < 0 || requeuePosition > numberOfWaiters_)
+ requeuePosition = numberOfWaiters_;
+
+ rwo = new RenewObject (requeuePosition);
+
+ this.release ();
+ this.renewers_.addElement (rwo);
+ }
+
+ boolean exceptionOccured = true;
+ try {
+ synchronized (rwo) {
+ rwo.timedWait (timeout);
+
+ exceptionOccured = false;
+ }
+ } finally {
+ synchronized (this) {
+
+ if (exceptionOccured) {
+ if (!renewers_.removeElement (rwo)) {
+ setOwner ();
+ release ();
+ }
+ } else {
+ setOwner();
+ }
+ }
+ }
+
+ // By this point, we should know that we have the lock. The inUse
+ // flag is never set to false in the release() call from the Thread
+ // that gave us control. That thread also set the owner value.
+
+ return AbstractLock.SUCCESS;
+ }
+
+ protected boolean isOwner ()
+ {
+ return owners_.containsKey (accessorID());
+ }
+
+ protected void setOwner ()
+ {
+ owners_.put (accessorID(), this);
+ }
+
+ protected void clearOwner ()
+ {
+ owners_.remove (accessorID());
+ }
+
+ private TimedWaitSAdapter monitor_ = new TimedWaitSAdapter (this);
+ // The monitor (adapter) to wait on
+
+ private Hashtable owners_;
+ private Vector renewers_ = new Vector ();
+ private int numberOfWaiters_ = 0;
+}
diff --git a/java/JACE/Concurrency/ThreadManager.java b/java/JACE/Concurrency/ThreadManager.java
new file mode 100644
index 00000000000..d23e2410676
--- /dev/null
+++ b/java/JACE/Concurrency/ThreadManager.java
@@ -0,0 +1,113 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.Concurrency
+ *
+ * = FILENAME
+ * ThreadManager.java
+ *
+ *@author Prashant Jain
+ *
+ *************************************************/
+package JACE.Concurrency;
+
+import java.util.*;
+import JACE.OS.*;
+
+/**
+ * Wrapper for a ThreadGroup which provides additional methods for
+ * creating a certain number of Runnable instances.
+ */
+public class ThreadManager
+{
+ /**
+ * Default constructor
+ */
+ public ThreadManager ()
+ {
+ this (ACE.DEFAULT_THREAD_GROUP_NAME);
+ }
+
+ /**
+ * Create a Thread Manager.
+ *@param groupName name of the thread group that the Thread Manager
+ * will manage
+ */
+ public ThreadManager (String groupName)
+ {
+ this.thrGrp_ = new ThreadGroup (groupName);
+ if (this.thrGrp_ == null)
+ ACE.ERROR ("Thread group create failed");
+ }
+
+ /**
+ * Create a new thread.
+ *@param thr the caller whose run method will be invoked when the
+ * thread has been spawned
+ *@param daemon flag indicating whether the thread should be
+ * spawned off as a daemon thread
+ */
+ public void spawn (Runnable thr,
+ boolean daemon)
+ {
+ Thread t = new Thread (this.thrGrp_, thr);
+ if (daemon) // Set the thread to be a daemon thread
+ t.setDaemon (true);
+ t.start ();
+ }
+
+ /**
+ * Create a new thread and also give it a name.
+ *@param thr the caller whose run method will be invoked when the
+ * thread has been spawned
+ *@param threadName the name of the new thread
+ *@param daemon flag indicating whether the thread should be
+ * spawned off as a daemon thread
+ */
+ public void spawn (Runnable thr,
+ String threadName,
+ boolean daemon)
+ {
+ Thread t = new Thread (this.thrGrp_, thr, threadName);
+ if (daemon) // Set the thread to be a daemon thread
+ t.setDaemon (true);
+ t.start ();
+ }
+
+
+ /**
+ * Create <n> new threads.
+ *@param n the number of threads to spawn
+ *@param thr the caller whose run method will be invoked by each of
+ * the <n> threads
+ *@param daemon flag indicating whether the threads should be
+ * spawned off as daemon threads
+ */
+ public void spawnN (int n,
+ Runnable thr,
+ boolean daemon)
+ {
+ // Spawn off all the threads.
+ for (int i = 0; i < n; i++)
+ {
+ this.spawn (thr, daemon);
+ }
+ }
+
+ /**
+ * Get the thread group containing all the threads. Note that the
+ * thread group can be used to get information regarding number of
+ * active threads as well as to suspend/resume all the threads in
+ * the group.
+ *@return the thread group that contains all the threads managed by
+ * the Thread Manager
+ */
+ public ThreadGroup thrGrp ()
+ {
+ return this.thrGrp_;
+ }
+
+ private ThreadGroup thrGrp_;
+ // Thread Group that contains all the spawned threads
+
+}
diff --git a/java/JACE/Concurrency/Token.java b/java/JACE/Concurrency/Token.java
new file mode 100644
index 00000000000..c9080b47fbe
--- /dev/null
+++ b/java/JACE/Concurrency/Token.java
@@ -0,0 +1,301 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.Concurrency
+ *
+ * = FILENAME
+ * Token.java
+ *
+ *@author Prashant Jain
+ *
+ *************************************************/
+package JACE.Concurrency;
+
+import java.util.*;
+import JACE.ASX.*;
+
+import JACE.OS.*;
+
+/**
+ * Class that acquires, renews, and releases a synchronization
+ * token that is serviced in strict FIFO ordering.
+ * <P>
+ * This is a general-purpose synchronization mechanism that offers
+ * several benefits. For example, it implements "recursive mutex"
+ * semantics, where a thread that owns the token can reacquire it
+ * without deadlocking. In addition, threads that are blocked
+ * awaiting the token are serviced in strict FIFO order as other
+ * threads release the token. The solution makes use of the
+ * Specific Notification pattern presented by Tom Cargill in
+ * "Specific Notification for Java Thread Synchronization," PLoP96.
+ *
+ * <P>
+ * This class DOES support recursive semantics.
+ */
+public class Token extends LockAdapter
+{
+ /**
+ * Acquire ownership of the lock, blocking indefinitely if necessary.
+ * <P>
+ *@return AbstractLock.FAILURE or AbstractLock.SUCCESS
+ *@exception InterruptedException indicates another thread has
+ * interrupted this one during wait
+ */
+ public int acquire () throws InterruptedException
+ {
+ try
+ {
+ return this.acquire (null);
+ }
+ catch (TimeoutException e)
+ {
+ // This really shouldn't happen since we are supposed to
+ // block.
+ return AbstractLock.FAILURE;
+ }
+ }
+
+ /**
+ * Acquire the token by the given absolute time time-out. The
+ * method uses synchronized blocks internally to avoid race conditions.
+ *@param timeout time to wait until before throwing a
+ * TimeoutException (unless the token is acquired before that).
+ * Performs a blocking acquire if the given timeout is null.
+ *@return AbstractLock.SUCCESS if acquires without calling <sleepHook>
+ * AbstractLock.SLEEPHOOK if <sleepHook> is called.
+ * AbstractLock.FAILURE if failure occurs
+ *@exception TimeoutException if time-out occurs
+ *@exception InterruptedException exception during wait
+ */
+ public int acquire (TimeValue timeout) throws TimeoutException,
+ InterruptedException
+ {
+ int result = AbstractLock.SUCCESS;
+ WaitObject snl = new WaitObject ();
+ boolean mustWait;
+ synchronized (snl)
+ {
+ synchronized (this)
+ {
+ mustWait = !this.snq_.isEmpty ();
+
+ if (mustWait && isOwner ())
+ {
+ // I am the one who has the token. So just increment
+ // the nesting level
+ this.nestingLevel_++;
+ return AbstractLock.SUCCESS;
+ }
+ // Add local lock to the queue
+ this.snq_.addElement (snl);
+ }
+ if (mustWait)
+ {
+ result = AbstractLock.SLEEPHOOK;
+ sleepHook();
+
+ boolean exceptionOccured = true;
+ try {
+ snl.timedWait(timeout);
+ exceptionOccured = false;
+ } finally {
+ if (exceptionOccured) {
+ synchronized (this) {
+ if (!snq_.removeElement (snl)) {
+ setOwner ();
+ release ();
+ }
+ }
+ }
+ }
+ }
+
+ // Set the owner of the token
+ synchronized (this) {
+ setOwner();
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Try to acquire the token. Implements a non-blocking acquire.
+ *
+ *@return AbstractLock.SUCCESS if acquires
+ * AbstractLock.FAILURE if failure occurs
+ */
+ public synchronized int tryAcquire ()
+ {
+ int result = AbstractLock.SUCCESS;
+
+ if (this.snq_.isEmpty ())
+ {
+ // No one has the token, so acquire it
+ this.snq_.addElement (new WaitObject ());
+
+ setOwner();
+ }
+ else if (isOwner())
+ {
+ this.nestingLevel_++;
+ }
+ // Someone else has the token.
+ else
+ {
+ // Would have to block to acquire the token, so return
+ // failure.
+ result = AbstractLock.FAILURE;
+ }
+ return result;
+ }
+
+ /**
+ * An optimized method that efficiently reacquires the token if no
+ * other threads are waiting. This is useful for situations where
+ * you don't want to degrade the quality of service if there are
+ * other threads waiting to get the token. If the given TimeValue
+ * is null, it's the same as calling renew(int requeuePosition).
+ *@param requeuePosition Position in the queue where to insert the
+ * lock. If requeuePosition == -1 and there are other threads
+ * waiting to obtain the token we are queued at the end of the list
+ * of waiters. If requeuePosition > -1 then it indicates how many
+ * entries to skip over before inserting our thread into the list of
+ * waiters (e.g.,requeuePosition == 0 means "insert at front of the
+ * queue").
+ *@param timeout Throw a TimeoutException if the token isn't renewed
+ * before this absolute time timeout.
+ *@return AbstractLock.SUCCESS if renewed the lock
+ * AbstractLock.FAILURE if failure occurs
+ *@exception TimeoutException exception if timeout occurs
+ *@exception InterruptedException exception during wait
+ */
+ public int renew (int requeuePosition, TimeValue timeout)
+ throws TimeoutException, InterruptedException
+ {
+ WaitObject snl = null;
+ int saveNestingLevel = 0;
+
+ synchronized (this)
+ {
+ if (!isOwner ())
+ return AbstractLock.FAILURE;
+
+ // Check if there is a thread waiting to acquire the token. If
+ // not or if requeuePosition == 0, then we don't do anything
+ // and we simply keep the token.
+ if (this.snq_.size () > 1 && requeuePosition != 0)
+ {
+ // Save the nesting level
+ saveNestingLevel = this.nestingLevel_;
+ this.nestingLevel_ = 0;
+
+ // Reinsert ourselves at requeuePosition in the queue
+ snl = (WaitObject) this.snq_.firstElement ();
+ this.snq_.removeElementAt (0);
+
+ if (requeuePosition < 0)
+ this.snq_.addElement (snl); // Insert at end
+ else
+ this.snq_.insertElementAt (snl, Math.min(requeuePosition,
+ this.snq_.size()));
+
+ synchronized (this.snq_.firstElement ())
+ {
+ // Notify the first waiting thread in the queue
+ WaitObject obj = (WaitObject) this.snq_.firstElement ();
+ // Set its condition to be true so that it falls out
+ // of the for loop
+ obj.condition (true);
+ // Now signal the thread
+ obj.signal ();
+ }
+ }
+ }
+
+ // Check if we reinserted the lock in the queue and therefore need
+ // to do a wait
+ if (snl != null)
+ {
+ synchronized (snl)
+ {
+ // Set the condition to be false so that we can begin the
+ // wait
+ snl.condition (false);
+ // Wait until the given absolute time (or until notified
+ // if the timeout is null)
+
+ boolean exceptionOccured = true;
+ try {
+
+ snl.timedWait (timeout);
+
+ exceptionOccured = false;
+
+ } finally {
+ if (exceptionOccured) {
+ synchronized (this) {
+ if (!snq_.removeElement (snl)) {
+ setOwner ();
+ release ();
+ }
+ }
+ }
+ }
+ }
+
+ synchronized (this) {
+ // Restore the nesting level and current owner of the lock
+ this.nestingLevel_ = saveNestingLevel;
+
+ // Set the owner of the token
+ setOwner();
+ }
+ }
+
+ return AbstractLock.SUCCESS;
+ }
+
+ /**
+ * Release the token. It is safe for non-owners to call
+ * this.
+ *@return AbstractLock.SUCCESS on success
+ * AbstractLock.FAILURE on failure (for instance, a non-owner
+ * calling release)
+ */
+ public synchronized int release ()
+ {
+ if (!isOwner())
+ return AbstractLock.FAILURE;
+
+ // Check if nestingLevel > 0 and if so, decrement it
+ if (this.nestingLevel_ > 0)
+ this.nestingLevel_--;
+ else
+ {
+ clearOwner ();
+ this.snq_.removeElementAt (0);
+ if (!this.snq_.isEmpty ())
+ {
+ synchronized (this.snq_.firstElement ())
+ {
+ // Notify the first waiting thread in the queue
+ WaitObject obj = (WaitObject) this.snq_.firstElement ();
+ // Set its condition to be true so that it falls out
+ // of the for loop
+ obj.condition (true);
+ // Now signal the thread
+ obj.signal ();
+ }
+ }
+ }
+
+ return AbstractLock.SUCCESS;
+ }
+
+ private Vector snq_ = new Vector ();
+ // Vector of lock objects
+
+ private int nestingLevel_ = 0;
+ // Current Nesting Level
+}
diff --git a/java/JACE/Concurrency/WaitObject.java b/java/JACE/Concurrency/WaitObject.java
new file mode 100644
index 00000000000..b7c8cbc7191
--- /dev/null
+++ b/java/JACE/Concurrency/WaitObject.java
@@ -0,0 +1,39 @@
+package JACE.Concurrency;
+
+import JACE.ASX.TimedWait;
+
+class WaitObject extends TimedWait
+{
+ public WaitObject ()
+ {
+ super ();
+ }
+
+ public WaitObject (Object obj)
+ {
+ super (obj);
+ }
+
+ public WaitObject (boolean initialState)
+ {
+ condition_ = initialState;
+ }
+
+ public WaitObject (boolean initialState, Object obj)
+ {
+ super (obj);
+ condition_ = initialState;
+ }
+
+ public boolean condition ()
+ {
+ return this.condition_;
+ }
+
+ public void condition (boolean c)
+ {
+ this.condition_ = c;
+ }
+
+ private boolean condition_ = false;
+}
diff --git a/java/JACE/Concurrency/package.html b/java/JACE/Concurrency/package.html
new file mode 100644
index 00000000000..ceadb36f662
--- /dev/null
+++ b/java/JACE/Concurrency/package.html
@@ -0,0 +1,15 @@
+<!-- $Id$ -->
+<HTML>
+<BODY>
+Collection of concurrency mechanisms and a Thread manager.
+<P>
+JACE concurrency mechanisms now inherit from a common base class,
+AbstractLock. This allows users to write code without regard to
+whether a lock is local or remote.
+
+@see JACE.netsvcs.Token.RemoteLock
+@see <a href="http://www.cs.wustl.edu/~schmidt/ACE-papers.html#concurrency">Documents on ACE concurrency components</a>
+</BODY>
+</HTML>
+
+