summaryrefslogtreecommitdiff
path: root/java/src
diff options
context:
space:
mode:
authoreea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-07-08 22:16:46 +0000
committereea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-07-08 22:16:46 +0000
commite75e64e6b93800116de5e7da5f16a87006d20b22 (patch)
tree44ea3c9fd203fce5d7c12d752fdc75c5cd1b9d01 /java/src
parent4c8e64c42a2a50576b94bcdcaab3af11ef69106e (diff)
downloadATCD-e75e64e6b93800116de5e7da5f16a87006d20b22.tar.gz
*** NOTE:
Changed the semantics of Condition, TimedWait, MessageQueue, Task, Mutex, Semaphore, and Token to use absolute times for their timeouts. Changed the semantics of EventHandler, ServiceObject, and SvcHandler such that handleTimeout receives a TimeValue representing when the event occured. Changed TimerQueue internally to reflect the above changes. Also made better checks in Token and Mutex so that non-owners can call release without adverse effects. I plan to try to do this with Semaphore and RWMutex as well. Fixed several bugs in Token tryacquire and renew. Added relativeTimeOfDay methods to TimeValue.
Diffstat (limited to 'java/src')
-rw-r--r--java/src/Condition.java12
-rw-r--r--java/src/EventHandler.java2
-rw-r--r--java/src/MessageQueue.java35
-rw-r--r--java/src/Mutex.java31
-rw-r--r--java/src/Semaphore.java8
-rw-r--r--java/src/ServiceObject.java2
-rw-r--r--java/src/StreamHead.java2
-rw-r--r--java/src/StreamTail.java4
-rw-r--r--java/src/SvcHandler.java2
-rw-r--r--java/src/Task.java12
-rw-r--r--java/src/TimeValue.java32
-rw-r--r--java/src/TimedWait.java32
-rw-r--r--java/src/TimerQueue.java29
-rw-r--r--java/src/Token.java209
14 files changed, 249 insertions, 163 deletions
diff --git a/java/src/Condition.java b/java/src/Condition.java
index 59a97c9a1a7..d0b5e10a84e 100644
--- a/java/src/Condition.java
+++ b/java/src/Condition.java
@@ -62,12 +62,15 @@ public class Condition
}
/**
- * TimedWait for condition to become signaled.
+ * 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
+ throws TimeoutException, InterruptedException
{
waiters_++;
@@ -75,13 +78,8 @@ public class Condition
{
mutex_.release();
- TimeValue start = TimeValue.getTimeOfDay ();
-
semaphore_.acquire (tv);
- TimeValue now = TimeValue.getTimeOfDay ();
- tv.minusEquals (TimeValue.minus (now, start));
-
mutex_.acquire (tv);
}
finally
diff --git a/java/src/EventHandler.java b/java/src/EventHandler.java
index 25057a459c8..f02c53684fd 100644
--- a/java/src/EventHandler.java
+++ b/java/src/EventHandler.java
@@ -43,7 +43,7 @@ public interface EventHandler
{
/**
* Called when timer expires.
- *@param tv Time Value for which timer was set
+ *@param tv Time Value at which the event occured
*@param obj An arbitrary object that was passed to the Timer Queue
* (Asynchronous Completion Token)
*/
diff --git a/java/src/MessageQueue.java b/java/src/MessageQueue.java
index e25fdc65238..8c8dab1a0fe 100644
--- a/java/src/MessageQueue.java
+++ b/java/src/MessageQueue.java
@@ -108,10 +108,11 @@ public class MessageQueue
return 0;
}
+ // ************ Note! ***********
// = For enqueue, enqueueHead, enqueueTail, and dequeueHead if
- // timeout is specified, the caller will wait for amount of time in
+ // timeout is specified, the caller will wait until the *absolute time*
// tv. Calls will return, however, when queue is closed,
- // deactivated, or if the time specified in tv elapses.
+ // deactivated, or if it is past the time tv
/**
* Enqueue a <MessageBlock> into the <MessageQueue> in accordance
@@ -130,11 +131,10 @@ public class MessageQueue
/**
* Enqueue a <MessageBlock> into the <MessageQueue> in accordance
* with its <msgPriority> (0 is lowest priority). Note that the
- * call will return if <timeout> amount of time expires or if the
- * queue has been deactivated.
+ * call will return if the queue has been deactivated or it is
+ * later than the specified absolute time value.
*@param newItem item to enqueue onto the Message Queue
- *@param tv amount of time (TimeValue) to wait before returning
- * (unless operation completes before)
+ *@param tv absolute TimeValue to timeout after
*@return -1 on failure, else the number of items still on the
* queue.
*@exception java.lang.InterruptedException Interrupted while accessing queue
@@ -182,11 +182,11 @@ public class MessageQueue
/**
* Enqueue a <MessageBlock> at the end of the <MessageQueue>. Note
- * that the call will return if <timeout> amount of time expires or
+ * that the call will return when it's later than the given TimeValue or
* if the queue has been deactivated.
*@param newItem item to enqueue onto the Message Queue
- *@param tv amount of time (TimeValue) to wait before returning
- * (unless operation completes before)
+ *@param tv absolute TimeValue to wait until before returning (unless
+ * the operation compeltes before this time)
*@return -1 on failure, else the number of items still on the queue.
*@exception java.lang.InterruptedException Interrupted while accessing queue
*/
@@ -232,12 +232,12 @@ public class MessageQueue
}
/**
- * Enqueue a <MessageBlock> at the head of the <MessageQueue>. Note
- * that the call will return if <timeout> amount of time expires or
+ * Enqueue a <MessageBlock> at the head of the <MessageQueue>. Note
+ * that the call will return when it's later than the given TimeValue or
* if the queue has been deactivated.
*@param newItem item to enqueue onto the Message Queue
- *@param tv amount of time (TimeValue) to wait before returning
- * (unless operation completes before)
+ *@param tv absolute TimeValue to wait until before returning (unless
+ * the operation completes before that time)
*@return -1 on failure, else the number of items still on the queue.
*@exception java.lang.InterruptedException Interrupted while accessing queue
*/
@@ -284,12 +284,15 @@ public class MessageQueue
/**
* Dequeue and return the <MessageBlock> at the head of the
- * <MessageQueue>. Note that the call will return if <timeout>
- * amount of time expires or if the queue has been deactivated.
+ * <MessageQueue>. Note that the call when return if the queue has
+ * been deactivated or when the current time is later than the given
+ * time value.
+ *@param tv absolute time timeout (blocks indefinitely if null)
*@return null on failure, else the <MessageBlock> at the head of queue.
*@exception InterruptedException Interrupted while accessing queue
*/
- public synchronized MessageBlock dequeueHead (TimeValue tv) throws InterruptedException
+ public synchronized MessageBlock dequeueHead (TimeValue tv)
+ throws InterruptedException
{
MessageBlock result = null;
if (this.deactivated_)
diff --git a/java/src/Mutex.java b/java/src/Mutex.java
index 8daab4ff9eb..1b796062ae8 100644
--- a/java/src/Mutex.java
+++ b/java/src/Mutex.java
@@ -61,13 +61,15 @@ public class Mutex
{
this.monitor_.timedWait ();
this.monitor_.inUse (true);
+ setOwner();
}
/**
- * Acquire the mutex. Note that the call will return if <timeout>
- * amount of time expires.
- *@param tv amount of time (TimeValue) to wait before returning
- * (unless operation completes before)
+ * Acquire the mutex.
+ * Throws a TimeoutException if the mutex isn't acquired before the
+ * given absolute time timeout.
+ *@param tv time (TimeValue) to wait until before throwing a
+ * TimeoutException (unless the mutex is acquired before that)
*@exception TimeoutException wait timed out exception
*@exception InterruptedException exception during wait
*/
@@ -76,17 +78,32 @@ public class Mutex
{
this.monitor_.timedWait (tv);
this.monitor_.inUse (true);
+ setOwner();
}
/**
- * Release the mutex.
+ * Release the mutex. This is safe for non-owners to call.
*/
public synchronized void release ()
{
- this.monitor_.inUse (false);
- this.monitor_.signal ();
+ if (isOwner()) {
+ this.monitor_.inUse (false);
+ this.monitor_.signal ();
+ }
}
private TimedWaitMAdapter monitor_ = new TimedWaitMAdapter (this);
// The monitor (adapter) to wait on
+
+ // Keep track of the owner. Allow subclasses to redefine this
+ // behavior
+ private Object owner_ = null;
+
+ protected void setOwner() {
+ this.owner_ = Thread.currentThread().toString();
+ }
+
+ protected boolean isOwner() {
+ return Thread.currentThread().toString().equals(this.owner_);
+ }
}
diff --git a/java/src/Semaphore.java b/java/src/Semaphore.java
index 4762712d722..6c5427bb0c0 100644
--- a/java/src/Semaphore.java
+++ b/java/src/Semaphore.java
@@ -75,10 +75,10 @@ public class Semaphore
}
/**
- * Acquire the Semaphore. Note that the call will return if <timeout>
- * amount of time expires.
- *@param tv amount of time (TimeValue) to wait before returning
- * (unless operation completes before)
+ * 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
*/
diff --git a/java/src/ServiceObject.java b/java/src/ServiceObject.java
index 1c420c08f3b..faf5a28daa4 100644
--- a/java/src/ServiceObject.java
+++ b/java/src/ServiceObject.java
@@ -50,7 +50,7 @@ public class ServiceObject implements EventHandler
/**
* Called when timer expires. Overwrite this method to do
* anything useful.
- *@param tv Time Value for which timer was set
+ *@param tv Time Value for when timer expired
*@param obj An arbitrary object that was passed to the Timer Queue
* (Asynchronous Completion Token)
*@return -1
diff --git a/java/src/StreamHead.java b/java/src/StreamHead.java
index 37d9c2af0c3..dfc198f86e2 100644
--- a/java/src/StreamHead.java
+++ b/java/src/StreamHead.java
@@ -72,7 +72,7 @@ public class StreamHead extends Task
f &= ~TaskFlags.ACE_FLUSHR;
}
if ((f & TaskFlags.ACE_FLUSHW) != 0)
- return this.reply (mb, new TimeValue ());
+ return this.reply (mb, null);
return 0;
}
diff --git a/java/src/StreamTail.java b/java/src/StreamTail.java
index 44f9dde6634..26f05d167e8 100644
--- a/java/src/StreamTail.java
+++ b/java/src/StreamTail.java
@@ -60,7 +60,7 @@ public class StreamTail extends Task
default:
mb.msgType (MessageType.MB_IOCNAK);
}
- return this.reply (mb, new TimeValue ());
+ return this.reply (mb, null);
}
// Perform flush algorithm as though we were the driver
@@ -77,7 +77,7 @@ public class StreamTail extends Task
if ((f & TaskFlags.ACE_FLUSHR) != 0)
{
this.sibling ().flush (TaskFlags.ACE_FLUSHALL);
- return this.reply (mb, new TimeValue ());
+ return this.reply (mb, null);
}
return 0;
}
diff --git a/java/src/SvcHandler.java b/java/src/SvcHandler.java
index cb9af5a3334..17bac41a62d 100644
--- a/java/src/SvcHandler.java
+++ b/java/src/SvcHandler.java
@@ -72,7 +72,7 @@ public abstract class SvcHandler extends Task
/**
* Provide a default implementation to simplify ancestors.
- *@param tv Time Value for which timer was set
+ *@param tv Time Value when the event occured
*@param obj An arbitrary object that was passed to the Timer Queue
* (Asynchronous Completion Token)
*/
diff --git a/java/src/Task.java b/java/src/Task.java
index 24ed6a7eb07..1d0f2894c8d 100644
--- a/java/src/Task.java
+++ b/java/src/Task.java
@@ -71,7 +71,7 @@ public abstract class Task implements Runnable, EventHandler
* Transfer a message into the queue to handle immediate
* processing.
*@param mb Message Block to handle immediately
- *@param tv amount of time to wait for
+ *@param tv Latest time to wait until (absolute time)
*/
public abstract int put (MessageBlock mb, TimeValue tv);
@@ -232,7 +232,7 @@ public abstract class Task implements Runnable, EventHandler
/**
* Insert message into the message queue.
*@param mb Message Block to insert into the Message Queue
- *@param tv amount of time to wait for
+ *@param tv time to wait until (absolute time)
*@exception java.lang.InterruptedException Interrupted while accessing queue
*/
protected int putq (MessageBlock mb, TimeValue tv) throws InterruptedException
@@ -243,7 +243,7 @@ public abstract class Task implements Runnable, EventHandler
/**
* Extract the first message from the queue. Note that the call is blocking.
*@return the first Message Block from the Message Queue.
- *@param tv amount of time to wait for
+ *@param tv Latest time to wait until (absolute time)
*@exception java.lang.InterruptedException Interrupted while accessing queue
*/
protected MessageBlock getq (TimeValue tv) throws InterruptedException
@@ -254,7 +254,7 @@ public abstract class Task implements Runnable, EventHandler
/**
* Return a message back to the queue.
*@param mb Message Block to return back to the Message Queue
- *@param tv amount of time to wait for
+ *@param tv Latest time to wait until (absolute time)
*@exception java.lang.InterruptedException Interrupted while accessing queue
*/
protected int ungetq (MessageBlock mb, TimeValue tv) throws InterruptedException
@@ -265,7 +265,7 @@ public abstract class Task implements Runnable, EventHandler
/**
* Transfer message to the adjacent ACETask in an ACEStream.
*@param mb Message Block to transfer to the adjacent Task
- *@param tv amount of time to wait for
+ *@param tv Latest time to wait until (absolute time)
*@return -1 if there is no adjacent Task, else the return value of
* trying to put the Message Block on that Task's Message Queue.
*/
@@ -278,7 +278,7 @@ public abstract class Task implements Runnable, EventHandler
* Turn the message back around. Puts the message in the sibling's
* Message Queue.
*@param mb Message Block to put into sibling's Message Queue
- *@param tv amount of time to wait for
+ *@param tv Latest time to wait until (absolute time)
*@return -1 if there is no adjacent Task to the sibling, else the
* return value of trying to put the Message Block on sibling's
* Message Queue.
diff --git a/java/src/TimeValue.java b/java/src/TimeValue.java
index 280f45ab0f1..26391b61c6c 100644
--- a/java/src/TimeValue.java
+++ b/java/src/TimeValue.java
@@ -17,7 +17,8 @@ public class TimeValue
public final static TimeValue zero = new TimeValue (0,0);
/**
- * Default constructor
+ * Default constructor. This creates a TimeValue that is
+ * equal to TimeValue.zero.
*/
public TimeValue ()
{
@@ -94,7 +95,7 @@ public class TimeValue
/**
* Get current time.
- *@return the current system time
+ *@return the current system time as a new TimeValue
*/
public static TimeValue getTimeOfDay ()
{
@@ -102,6 +103,33 @@ public class TimeValue
}
/**
+ * Return a new TimeValue that represents the current system time
+ * of day offset by the given number of seconds and nanoseconds.
+ *@param sec Number of seconds to offset by
+ *@param nanos Number of nanoseconds to offset by
+ *@see JACE.ASX.TimeValue;
+ *@return TimeValue for the system time plus the given offset
+ */
+ public static TimeValue relativeTimeOfDay(long sec, int nanos)
+ {
+ return new TimeValue(System.currentTimeMillis() / 1000 + sec,
+ nanos);
+ }
+
+ /**
+ * Return a new TimeValue that represents the current system time
+ * of day offset by the given TimeValue.
+ *@param tv TimeValue to offset by
+ *@see JACE.ASX.TimeValue;
+ *@return TimeValue for the system time plus the given offset
+ */
+ public static TimeValue relativeTimeOfDay(TimeValue offset)
+ {
+ return new TimeValue(System.currentTimeMillis() + offset.sec(),
+ offset.nanos());
+ }
+
+ /**
* Compare two Time Values for equality.
*@param tv Time Value to compare with
*@return true if the two Time Values are equal, false otherwise
diff --git a/java/src/TimedWait.java b/java/src/TimedWait.java
index e8402e96991..e8a7eb2d408 100644
--- a/java/src/TimedWait.java
+++ b/java/src/TimedWait.java
@@ -70,7 +70,10 @@ public abstract class TimedWait
* this method is final to ensure that no one overrides it.
* IMPORTANT: This method assumes it is called with the object_'s
* monitor lock already held.
- *@param tv Amount of time to do wait for.
+ * If the specified wait time is zero, this checks the condition,
+ * then returns on success or throws a TimeoutException on failure.
+ *@param tv Absolute time to wait until before throwing an exception
+ * if the condition isn't satisfied
*@exception java.lang.InterruptedException Interrupted during wait
*@exception JACE.ASX.TimeoutException Reached timeout specified
*/
@@ -78,13 +81,23 @@ public abstract class TimedWait
throws InterruptedException,
TimeoutException
{
+ if (tv == null) {
+ this.timedWait();
+ return;
+ }
+
// Acquire the monitor lock.
if (!condition ())
{
- // Only attempt to perform the timed wait if the condition isn't
- // true initially.
- long start = System.currentTimeMillis ();
- long waitTime = tv.getMilliTime ();
+ long start = System.currentTimeMillis();
+ long waitTime = tv.getMilliTime() - start;
+
+ // Safety check since there is a possibility that it is
+ // exactly the same time as the tv. That would cause
+ // waitTime to be 0, and since Java's wait(timeout) blocks
+ // when timeout is 0, it would mean trouble.
+ if (waitTime < 1)
+ throw new TimeoutException();
for (;;) {
// Wait until we are notified.
@@ -92,16 +105,17 @@ public abstract class TimedWait
// Recheck the condition.
if (!condition ()) {
- long now = System.currentTimeMillis ();
- long timeSoFar = now - start;
+ long now = System.currentTimeMillis();
+ long timeSoFar = now - start;
+
// Timed out!
- if (timeSoFar >= tv.getMilliTime ())
+ if (now >= tv.getMilliTime ())
throw new TimeoutException ();
else
// We still have some time left to wait, so adjust the
// wait_time.
- waitTime = tv.getMilliTime () - timeSoFar;
+ waitTime -= timeSoFar;
}
else
break; // Condition became true.
diff --git a/java/src/TimerQueue.java b/java/src/TimerQueue.java
index e3aa30d9472..a374a9603cd 100644
--- a/java/src/TimerQueue.java
+++ b/java/src/TimerQueue.java
@@ -40,7 +40,7 @@ class TimerNode
// Argument to pass to <handleTimeout>.
public TimeValue timerValue_;
- // Time until the timer expires.
+ // Time when the timer expires. (absolute time)
public TimeValue interval_;
// If this is a periodic timer this holds the time until the next
@@ -124,29 +124,26 @@ public class TimerQueue implements Runnable
this.eventLoopRunning_ = true;
TimeValue timeout = null;
- TimeValue earliest = null;
for (;;)
{
synchronized (this.obj_)
{
- earliest = this.earliestTime ();
- if (earliest != null)
- timeout = TimeValue.minus (earliest, TimeValue.getTimeOfDay ());
- else
- timeout = new TimeValue ();
+ timeout = this.earliestTime ();
+
try
{
// Extract the earliest time from the queue and do a timed wait
+ // Note that this does a blocking wait if timeout is null
this.obj_.timedWait (timeout);
- // We have been notified. Check to see if we need to
- // restart the wait with a different timeout
+ // We have been notified.
if (this.reset_)
{
this.reset_ = false;
this.obj_.condition (false);
- timeout = TimeValue.minus (this.earliestTime (), TimeValue.getTimeOfDay ());
+ // Don't need to change the timer since it's an absolute
+ // time value.
}
}
catch (TimeoutException e)
@@ -196,7 +193,7 @@ public class TimerQueue implements Runnable
*@param handler Event Handler that is to be scheduled with the timer
*@param obj Object that is passed back to the Event Handler when
* timeout occurs (Asynchronous Completion Token)
- *@param delta amount of time for which to schedule the timer
+ *@param delta amount of time for which to schedule the timer (relative time)
*@return id of the timer scheduled
*/
public int scheduleTimer (EventHandler handler,
@@ -217,23 +214,25 @@ public class TimerQueue implements Runnable
*@param handler Event Handler that is to be scheduled with the timer
*@param arg Object that is passed back to the Event Handler when
* timeout occurs (Asynchronous Completion Token)
- *@param timeout amount of time for which to schedule the timer
+ *@param delta amount of time for which to schedule the timer (relative time)
*@param interval amount of time to use to reschedule the timer
*@return id of the timer scheduled
*/
public int scheduleTimer (EventHandler handler,
Object arg,
- TimeValue timeout,
+ TimeValue delta,
TimeValue interval)
{
// Increment the sequence number (it will wrap around).
this.timerId_++;
- ACE.DEBUG("scheduleTimer (" + this.timerId_ + "): " + timeout + ", " + interval);
+ ACE.DEBUG("scheduleTimer (" + this.timerId_ + "): " +
+ delta + ", " + interval);
+ // futureTime is the current time of day plus the given delta
+ TimeValue futureTime = TimeValue.relativeTimeOfDay (delta);
- TimeValue futureTime = TimeValue.plus (timeout, TimeValue.getTimeOfDay ());
TimerNode node = new TimerNode (handler,
arg,
futureTime,
diff --git a/java/src/Token.java b/java/src/Token.java
index a17be013ad5..ec6abb42343 100644
--- a/java/src/Token.java
+++ b/java/src/Token.java
@@ -52,6 +52,7 @@ class WaitObject extends TimedWait
*/
public class Token
{
+
/**
* Acquire the token. Note that this will block. The method uses
* synchronized blocks internally to avoid race conditions.
@@ -64,7 +65,7 @@ public class Token
{
try
{
- return this.acquire (new TimeValue ());
+ return this.acquire (null);
}
catch (TimeoutException e)
{
@@ -75,17 +76,20 @@ public class Token
}
/**
- * Acquire the token. Wait for timeout amount of time. The method
- * uses synchronized blocks internally to avoid race conditions.
- *@param timeout Amount of time to wait for in trying to acquire the
- * token.
+ * Acquire the token.
+ * Throws a TimeoutException if the token isn't acquired before the
+ * given absolute time timeout.
+ *@param timeout time (TimeValue) 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 0 if acquires without calling <sleepHook>
* 1 if <sleepHook> is called.
* -1 if failure occurs
*@exception TimeoutException exception if timeout occurs
*@exception InterruptedException exception during wait
*/
- public int acquire (TimeValue timeout) throws InterruptedException, TimeoutException
+ public int acquire (TimeValue timeout)
+ throws InterruptedException, TimeoutException
{
int result = 0;
WaitObject snl = new WaitObject ();
@@ -95,26 +99,26 @@ public class Token
synchronized (this)
{
mustWait = !this.snq_.isEmpty ();
- if (mustWait &&
- Thread.currentThread ().toString ().compareTo (this.owner_) == 0)
+
+ if (mustWait && isOwner ())
{
// I am the one who has the token. So just increment
// the nesting level
this.nestingLevel_++;
- return result;
+ return 0;
}
// Add local lock to the queue
this.snq_.addElement (snl);
}
if (mustWait)
- {
+ {
result = 1;
- // Call sleep hook
- sleepHook ();
- snl.timedWait (timeout); // Do a blocking wait
- }
+ sleepHook();
+ snl.timedWait(timeout);
+ }
+
// Set the owner of the token
- this.owner_ = Thread.currentThread ().toString ();
+ setOwner();
}
return result;
}
@@ -122,29 +126,29 @@ public class Token
/**
* Try to acquire the token. Implements a non-blocking acquire.
*@return 0 if acquires without calling <sleepHook>
- * 1 if <sleepHook> is called.
* -1 if failure occurs
*/
public synchronized int tryAcquire ()
{
int result = 0;
- if (!this.snq_.isEmpty ())
+
+ if (this.snq_.isEmpty ())
{
// No one has the token, so acquire it
this.snq_.addElement (new WaitObject ());
+
+ setOwner();
}
- // Check if I am the one holding the token.
- else if (Thread.currentThread ().toString ().compareTo (this.owner_) == 0)
+ else if (isOwner())
{
this.nestingLevel_++;
}
// Someone else has the token.
else
{
- // Will have to block to acquire the token, so call
- // sleepHook and return
- sleepHook ();
- result = 1;
+ // Would have to block to acquire the token, so return
+ // failure.
+ result = -1;
}
return result;
}
@@ -163,7 +167,8 @@ public class Token
* 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.
+ * other threads waiting to get the token. This blocks until it
+ * can regain the token.
*@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
@@ -177,7 +182,7 @@ public class Token
{
try
{
- this.renew (requeuePosition, new TimeValue ());
+ this.renew (requeuePosition, null);
}
catch (TimeoutException e)
{
@@ -190,7 +195,8 @@ public class Token
* 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.
+ * 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
@@ -198,8 +204,8 @@ public class Token
* 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 Amount of time to wait for in trying to acquire the
- * token.
+ *@param timeout Throw a TimeoutException if the token isn't renewed
+ * before this absolute time timeout.
*@exception TimeoutException exception if timeout occurs
*@exception InterruptedException exception during wait
*/
@@ -210,81 +216,100 @@ public class Token
int saveNestingLevel = 0;
synchronized (this)
- {
- // 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, requeuePosition);
-
- 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 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);
- // Do a blocking wait
+ {
+ 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)
snl.timedWait (timeout);
- }
- // Restore the nesting level and current owner of the lock
- this.nestingLevel_ = saveNestingLevel;
- this.owner_ = Thread.currentThread ().toString ();
- }
+ }
+ // Restore the nesting level and current owner of the lock
+ this.nestingLevel_ = saveNestingLevel;
+
+ // Set the owner of the token
+ setOwner();
+ }
}
/**
- * Release the token.
+ * Release the token. It is safe for non-owners to call
+ * this.
*/
public synchronized void release ()
{
+ if (!isOwner())
+ return;
+
// Check if nestingLevel > 0 and if so, decrement it
if (this.nestingLevel_ > 0)
- this.nestingLevel_--;
+ this.nestingLevel_--;
else
- {
- 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 ();
- }
- }
- }
+ {
+ 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 ();
+ }
+ }
+ }
+ }
+
+ // The next two methods allow subclasses to change the behavior of the
+ // checking and setting the Object owner_ member variable. The default
+ // is to use the current Thread's toString() as the Object.
+ protected void setOwner() {
+ this.owner_ = Thread.currentThread().toString();
+ }
+
+ protected boolean isOwner() {
+ return Thread.currentThread().toString().equals(this.owner_);
}
private Vector snq_ = new Vector ();
@@ -293,6 +318,8 @@ public class Token
private int nestingLevel_ = 0;
// Current Nesting Level
- private String owner_ = null;
- // Current owner of the token.
+ private Object owner_ = null;
+ // Current owner of the token. The setOwner() and isOwner()
+ // methods provide subclasses with the ability to change the
+ // behavior. The default is to use the Thread.toString().
}