Added a potential fix for infinite loop in LinkedTransferQueue.clean()
This commit is contained in:
parent
92bbc4acec
commit
b876bd8cec
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user