Added a potential fix for infinite loop in LinkedTransferQueue.clean()

This commit is contained in:
Trustin Lee 2008-11-13 14:11:59 +00:00
parent 92bbc4acec
commit b876bd8cec

View File

@ -95,6 +95,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> implements Blocking
/** The number of CPUs, for spin control */ /** The number of CPUs, for spin control */
private static final int NCPUS = Runtime.getRuntime().availableProcessors(); private static final int NCPUS = Runtime.getRuntime().availableProcessors();
private static final QNode UNDEFINED = new QNode(null, false);
/** /**
* The number of times to spin before blocking in timed waits. * The number of times to spin before blocking in timed waits.
* The value is empirically derived -- it works well across a * The value is empirically derived -- it works well across a
@ -345,7 +347,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> implements Blocking
* Gets rid of cancelled node s with original predecessor pred. * Gets rid of cancelled node s with original predecessor pred.
* @return null (to simplify use by callers) * @return null (to simplify use by callers)
*/ */
Object clean(QNode pred, QNode s) { Object clean(final QNode pred, final QNode s) {
Thread w = s.waiter; Thread w = s.waiter;
if (w != null) { // Wake up thread if (w != null) { // Wake up thread
s.waiter = null; s.waiter = null;
@ -354,6 +356,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> implements Blocking
} }
} }
QNode olddp = UNDEFINED;
for (;;) { for (;;) {
if (pred.next != s) { if (pred.next != s) {
return null; return null;
@ -382,6 +385,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> implements Blocking
return null; return null;
} }
} }
boolean stateUnchanged = true;
QNode dp = cleanMe.get(); QNode dp = cleanMe.get();
if (dp != null) { // Try unlinking previous cancelled node if (dp != null) { // Try unlinking previous cancelled node
QNode d = dp.next; QNode d = dp.next;
@ -389,15 +394,22 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> implements Blocking
if (d == null || // d is gone or if (d == null || // d is gone or
d == dp || // d is off list or d == dp || // d is off list or
d.get() != d || // d not cancelled or d.get() != d || // d not cancelled or
d != t && // d not tail and d != t && // d not tail and
(dn = d.next) != null && // has successor (dn = d.next) != null && // has successor
dn != d && // that is on list dn != d && // that is on list
dp.casNext(d, dn)) { dp.casNext(d, dn)) {
cleanMe.compareAndSet(dp, null); cleanMe.compareAndSet(dp, null);
stateUnchanged = false;
} }
if (dp == pred) { if (dp == pred) {
return null; // s is already saved node return null; // s is already saved node
} }
if (stateUnchanged && olddp == dp) {
return null; // infinite loop expected - bail out
} else {
olddp = dp;
}
} }
else if (cleanMe.compareAndSet(null, pred)) { else if (cleanMe.compareAndSet(null, pred)) {
return null; // Postpone cleaning s return null; // Postpone cleaning s