--- jsr166/src/jsr166y/LinkedTransferQueue.java 2009/11/02 00:28:28 1.61 +++ jsr166/src/jsr166y/LinkedTransferQueue.java 2009/11/02 15:32:00 1.65 @@ -479,13 +479,12 @@ public class LinkedTransferQueue exte } /* - * Possible values for "how" argument in xfer method. Beware that - * the order of assigned numerical values matters. + * Possible values for "how" argument in xfer method. */ - private static final int NOW = 0; // for untimed poll, tryTransfer - private static final int ASYNC = 1; // for offer, put, add - private static final int SYNC = 2; // for transfer, take - private static final int TIMEOUT = 3; // for timed poll, tryTransfer + private static final int NOW = 0; // for untimed poll, tryTransfer + private static final int ASYNC = 1; // for offer, put, add + private static final int SYNC = 2; // for transfer, take + private static final int TIMED = 3; // for timed poll, tryTransfer @SuppressWarnings("unchecked") static E cast(Object item) { @@ -498,8 +497,8 @@ public class LinkedTransferQueue exte * * @param e the item or null for take * @param haveData true if this is a put, else a take - * @param how NOW, ASYNC, SYNC, or TIMEOUT - * @param nanos timeout in nanosecs, used only if mode is TIMEOUT + * @param how NOW, ASYNC, SYNC, or TIMED + * @param nanos timeout in nanosecs, used only if mode is TIMED * @return an item if matched, else e * @throws NullPointerException if haveData mode but e is null */ @@ -537,14 +536,14 @@ public class LinkedTransferQueue exte p = (p != n) ? n : (h = head); // Use head if p offlist } - if (how >= ASYNC) { // No matches available + if (how != NOW) { // No matches available if (s == null) s = new Node(e, haveData); Node pred = tryAppend(s, haveData); if (pred == null) continue retry; // lost race vs opposite mode - if (how >= SYNC) - return awaitMatch(s, pred, e, how, nanos); + if (how != ASYNC) + return awaitMatch(s, pred, e, (how == TIMED), nanos); } return e; // not waiting } @@ -593,12 +592,12 @@ public class LinkedTransferQueue exte * predecessor, or null if unknown (the null case does not occur * in any current calls but may in possible future extensions) * @param e the comparison value for checking match - * @param how either SYNC or TIMEOUT - * @param nanos timeout value + * @param timed if true, wait only until timeout elapses + * @param nanos timeout in nanosecs, used only if timed is true * @return matched item, or e if unmatched on interrupt or timeout */ - private E awaitMatch(Node s, Node pred, E e, int how, long nanos) { - long lastTime = (how == TIMEOUT) ? System.nanoTime() : 0L; + private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) { + long lastTime = timed ? System.nanoTime() : 0L; Thread w = Thread.currentThread(); int spins = -1; // initialized after first item and cancel checks ThreadLocalRandom randomYields = null; // bound if needed @@ -610,7 +609,7 @@ public class LinkedTransferQueue exte s.forgetContents(); // avoid garbage return this.cast(item); } - if ((w.isInterrupted() || (how == TIMEOUT && nanos <= 0)) && + if ((w.isInterrupted() || (timed && nanos <= 0)) && s.casItem(e, s)) { // cancel unsplice(pred, s); return e; @@ -629,7 +628,7 @@ public class LinkedTransferQueue exte else if (s.waiter == null) { s.waiter = w; // request unpark then recheck } - else if (how == TIMEOUT) { + else if (timed) { long now = System.nanoTime(); if ((nanos -= now - lastTime) > 0) LockSupport.parkNanos(this, nanos); @@ -683,15 +682,23 @@ public class LinkedTransferQueue exte /* -------------- Traversal methods -------------- */ /** + * Returns the successor of p, or the head node if p.next has been + * linked to self, which will only be true if traversing with a + * stale pointer that is now off the list. + */ + final Node succ(Node p) { + Node next = p.next; + return (p == next) ? head : next; + } + + /** * Returns the first unmatched node of the given mode, or null if * none. Used by methods isEmpty, hasWaitingConsumer. */ - private Node firstOfMode(boolean data) { - for (Node p = head; p != null; ) { + private Node firstOfMode(boolean isData) { + for (Node p = head; p != null; p = succ(p)) { if (!p.isMatched()) - return (p.isData == data) ? p : null; - Node n = p.next; - p = (n != p) ? n : head; + return (p.isData == isData) ? p : null; } return null; } @@ -701,13 +708,14 @@ public class LinkedTransferQueue exte * null if none. Used by peek. */ private E firstDataItem() { - for (Node p = head; p != null; ) { - boolean isData = p.isData; + for (Node p = head; p != null; p = succ(p)) { Object item = p.item; - if (item != p && (item != null) == isData) - return isData ? this.cast(item) : null; - Node n = p.next; - p = (n != p) ? n : head; + if (p.isData) { + if (item != null && item != p) + return this.cast(item); + } + else if (item == null) + return null; } return null; } @@ -748,10 +756,8 @@ public class LinkedTransferQueue exte private void advance(Node prev) { lastPred = lastRet; lastRet = prev; - Node p; - if (prev == null || (p = prev.next) == prev) - p = head; - while (p != null) { + for (Node p = (prev == null) ? head : succ(prev); + p != null; p = succ(p)) { Object item = p.item; if (p.isData) { if (item != null && item != p) { @@ -762,8 +768,6 @@ public class LinkedTransferQueue exte } else if (item == null) break; - Node n = p.next; - p = (n != p) ? n : head; } nextNode = null; } @@ -1037,7 +1041,7 @@ public class LinkedTransferQueue exte */ public boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException { - if (xfer(e, true, TIMEOUT, unit.toNanos(timeout)) == null) + if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null) return true; if (!Thread.interrupted()) return false; @@ -1053,7 +1057,7 @@ public class LinkedTransferQueue exte } public E poll(long timeout, TimeUnit unit) throws InterruptedException { - E e = xfer(null, false, TIMEOUT, unit.toNanos(timeout)); + E e = xfer(null, false, TIMED, unit.toNanos(timeout)); if (e != null || !Thread.interrupted()) return e; throw new InterruptedException();