2021-02-02 11:40:07 +08:00
|
|
|
From 20109e1a7f9941662abd5069d30ad693c181f415 Mon Sep 17 00:00:00 2001
|
|
|
|
|
Date: Fri, 22 Jan 2021 11:33:53 +0800
|
|
|
|
|
Subject: Backport of JDK-8191483
|
2020-01-20 12:09:52 +08:00
|
|
|
|
|
|
|
|
summary: AbstractQueuedSynchronizer cancel/cancel race
|
|
|
|
|
LLT:
|
|
|
|
|
Bug url: https://bugs.openjdk.java.net/browse/JDK-8191483
|
|
|
|
|
---
|
|
|
|
|
.../locks/AbstractQueuedLongSynchronizer.java | 34 +++++++++++--------
|
|
|
|
|
.../locks/AbstractQueuedSynchronizer.java | 34 +++++++++++--------
|
|
|
|
|
2 files changed, 40 insertions(+), 28 deletions(-)
|
|
|
|
|
|
|
|
|
|
diff --git a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
|
2021-02-02 11:40:07 +08:00
|
|
|
index 47fdbfb94..8699fc9b8 100644
|
2020-01-20 12:09:52 +08:00
|
|
|
--- a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
|
|
|
|
|
+++ b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
|
|
|
|
|
@@ -531,7 +531,9 @@ public abstract class AbstractQueuedLongSynchronizer
|
|
|
|
|
|
|
|
|
|
// predNext is the apparent node to unsplice. CASes below will
|
|
|
|
|
// fail if not, in which case, we lost race vs another cancel
|
|
|
|
|
- // or signal, so no further action is necessary.
|
|
|
|
|
+ // or signal, so no further action is necessary, although with
|
|
|
|
|
+ // a possibility that a cancelled node may transiently remain
|
|
|
|
|
+ // reachable.
|
|
|
|
|
Node predNext = pred.next;
|
|
|
|
|
|
|
|
|
|
// Can use unconditional write instead of CAS here.
|
|
|
|
|
@@ -1131,13 +1133,13 @@ public abstract class AbstractQueuedLongSynchronizer
|
|
|
|
|
* at any time, a {@code true} return does not guarantee that any
|
|
|
|
|
* other thread will ever acquire.
|
|
|
|
|
*
|
|
|
|
|
- * <p>In this implementation, this operation returns in
|
|
|
|
|
- * constant time.
|
|
|
|
|
- *
|
|
|
|
|
* @return {@code true} if there may be other threads waiting to acquire
|
|
|
|
|
*/
|
|
|
|
|
public final boolean hasQueuedThreads() {
|
|
|
|
|
- return head != tail;
|
|
|
|
|
+ for (Node p = tail, h = head; p != h && p != null; p = p.prev)
|
|
|
|
|
+ if (p.waitStatus <= 0)
|
|
|
|
|
+ return true;
|
|
|
|
|
+ return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -1288,17 +1290,21 @@ public abstract class AbstractQueuedLongSynchronizer
|
|
|
|
|
* @since 1.7
|
|
|
|
|
*/
|
|
|
|
|
public final boolean hasQueuedPredecessors() {
|
|
|
|
|
- // The correctness of this depends on head being initialized
|
|
|
|
|
- // before tail and on head.next being accurate if the current
|
|
|
|
|
- // thread is first in queue.
|
|
|
|
|
- Node t = tail; // Read fields in reverse initialization order
|
|
|
|
|
- Node h = head;
|
|
|
|
|
- Node s;
|
|
|
|
|
- return h != t &&
|
|
|
|
|
- ((s = h.next) == null || s.thread != Thread.currentThread());
|
|
|
|
|
+ Node h, s;
|
|
|
|
|
+ if ((h = head) != null) {
|
|
|
|
|
+ if ((s = h.next) == null || s.waitStatus > 0) {
|
|
|
|
|
+ s = null; // traverse in case of concurrent cancellation
|
|
|
|
|
+ for (Node p = tail; p != h && p != null; p = p.prev) {
|
|
|
|
|
+ if (p.waitStatus <= 0)
|
|
|
|
|
+ s = p;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (s != null && s.thread != Thread.currentThread())
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// Instrumentation and monitoring methods
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
diff --git a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
|
2021-02-02 11:40:07 +08:00
|
|
|
index dce35765d..9088e5894 100644
|
2020-01-20 12:09:52 +08:00
|
|
|
--- a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
|
|
|
|
|
+++ b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
|
|
|
|
|
@@ -753,7 +753,9 @@ public abstract class AbstractQueuedSynchronizer
|
|
|
|
|
|
|
|
|
|
// predNext is the apparent node to unsplice. CASes below will
|
|
|
|
|
// fail if not, in which case, we lost race vs another cancel
|
|
|
|
|
- // or signal, so no further action is necessary.
|
|
|
|
|
+ // or signal, so no further action is necessary, although with
|
|
|
|
|
+ // a possibility that a cancelled node may transiently remain
|
|
|
|
|
+ // reachable.
|
|
|
|
|
Node predNext = pred.next;
|
|
|
|
|
|
|
|
|
|
// Can use unconditional write instead of CAS here.
|
|
|
|
|
@@ -1353,13 +1355,13 @@ public abstract class AbstractQueuedSynchronizer
|
|
|
|
|
* at any time, a {@code true} return does not guarantee that any
|
|
|
|
|
* other thread will ever acquire.
|
|
|
|
|
*
|
|
|
|
|
- * <p>In this implementation, this operation returns in
|
|
|
|
|
- * constant time.
|
|
|
|
|
- *
|
|
|
|
|
* @return {@code true} if there may be other threads waiting to acquire
|
|
|
|
|
*/
|
|
|
|
|
public final boolean hasQueuedThreads() {
|
|
|
|
|
- return head != tail;
|
|
|
|
|
+ for (Node p = tail, h = head; p != h && p != null; p = p.prev)
|
|
|
|
|
+ if (p.waitStatus <= 0)
|
|
|
|
|
+ return true;
|
|
|
|
|
+ return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -1510,17 +1512,21 @@ public abstract class AbstractQueuedSynchronizer
|
|
|
|
|
* @since 1.7
|
|
|
|
|
*/
|
|
|
|
|
public final boolean hasQueuedPredecessors() {
|
|
|
|
|
- // The correctness of this depends on head being initialized
|
|
|
|
|
- // before tail and on head.next being accurate if the current
|
|
|
|
|
- // thread is first in queue.
|
|
|
|
|
- Node t = tail; // Read fields in reverse initialization order
|
|
|
|
|
- Node h = head;
|
|
|
|
|
- Node s;
|
|
|
|
|
- return h != t &&
|
|
|
|
|
- ((s = h.next) == null || s.thread != Thread.currentThread());
|
|
|
|
|
+ Node h, s;
|
|
|
|
|
+ if ((h = head) != null) {
|
|
|
|
|
+ if ((s = h.next) == null || s.waitStatus > 0) {
|
|
|
|
|
+ s = null; // traverse in case of concurrent cancellation
|
|
|
|
|
+ for (Node p = tail; p != h && p != null; p = p.prev) {
|
|
|
|
|
+ if (p.waitStatus <= 0)
|
|
|
|
|
+ s = p;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (s != null && s.thread != Thread.currentThread())
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// Instrumentation and monitoring methods
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
--
|
2021-02-02 11:40:07 +08:00
|
|
|
2.19.0
|
2020-01-20 12:09:52 +08:00
|
|
|
|