EVALUATION
This bug was actually fixed (inadvertently)
in mustang b49 as part of the changes for
6237968: Add AbstractQueuedLongSynchronizer, providing support for 64 bits of synchronization state
+ /**
+ * Returns true if given node is on this condition queue.
+ * Call only when holding lock.
+ */
+ private boolean isOnConditionQueue(Node node) {
+ return node.next != null || node == lastWaiter;
+ }
+
+ /**
+ * Unlinks a cancelled waiter node from condition queue. This
+ * is called when cancellation occurred during condition wait,
+ * not lock wait, and is called only after lock has been
+ * re-acquired by a cancelled waiter and the node is not known
+ * to already have been dequeued. It is needed to avoid
+ * garbage retention in the absence of signals. So even though
+ * it may require a full traversal, it comes into play only
+ * when timeouts or cancellations occur in the absence of
+ * signals.
+ */
+ private void unlinkCancelledWaiter(Node node) {
+ Node t = firstWaiter;
+ Node trail = null;
+ while (t != null) {
+ if (t == node) {
+ Node next = t.nextWaiter;
+ if (trail == null)
+ firstWaiter = next;
+ else
+ trail.nextWaiter = next;
+ if (lastWaiter == node)
+ lastWaiter = trail;
+ break;
+ }
+ trail = t;
+ t = t.nextWaiter;
+ }
+ }
+
// public methods
/**
* Moves the longest-waiting thread, if one exists, from the
* wait queue for this condition to the wait queue for the
* owning lock.
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
@@ -1780,14 +1823,16 @@
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
+ if (isOnConditionQueue(node))
+ unlinkCancelledWaiter(node);
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
/**
* Implements timed condition wait.
* <ol>
@@ -1820,14 +1865,16 @@
long now = System.nanoTime();
nanosTimeout -= now - lastTime;
lastTime = now;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
+ if (isOnConditionQueue(node))
+ unlinkCancelledWaiter(node);
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return nanosTimeout - (System.nanoTime() - lastTime);
}
/**
* Implements absolute timed condition wait.
@@ -1861,14 +1908,16 @@
}
LockSupport.parkUntil(this, abstime);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
+ if (isOnConditionQueue(node))
+ unlinkCancelledWaiter(node);
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
/**
* Implements timed condition wait.
@@ -1906,14 +1955,16 @@
break;
long now = System.nanoTime();
nanosTimeout -= now - lastTime;
lastTime = now;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
+ if (isOnConditionQueue(node))
+ unlinkCancelledWaiter(node);
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
// support for instrumentation
|