You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2019/08/09 13:02:19 UTC
[httpcomponents-core] 01/01: HTTPCORE-588: race condition in
ComplexCancellable that can lead to operational dependency not being
correctly cancelled
This is an automated email from the ASF dual-hosted git repository.
olegk pushed a commit to branch HTTPCORE-588
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git
commit 1e9d57e176b142ed05f48928e36c04149c1f9385
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Fri Aug 9 12:22:24 2019 +0200
HTTPCORE-588: race condition in ComplexCancellable that can lead to operational dependency not being correctly cancelled
---
.../hc/core5/concurrent/ComplexCancellable.java | 28 ++++++++++------------
1 file changed, 13 insertions(+), 15 deletions(-)
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/concurrent/ComplexCancellable.java b/httpcore5/src/main/java/org/apache/hc/core5/concurrent/ComplexCancellable.java
index d306d6a..1b43219 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/concurrent/ComplexCancellable.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/concurrent/ComplexCancellable.java
@@ -26,8 +26,7 @@
*/
package org.apache.hc.core5.concurrent;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicMarkableReference;
import org.apache.hc.core5.util.Args;
@@ -40,37 +39,36 @@ import org.apache.hc.core5.util.Args;
*/
public final class ComplexCancellable implements CancellableDependency {
- private final AtomicReference<Cancellable> dependencyRef;
- private final AtomicBoolean cancelled;
+ private final AtomicMarkableReference<Cancellable> dependencyRef;
public ComplexCancellable() {
- this.dependencyRef = new AtomicReference<>(null);
- this.cancelled = new AtomicBoolean(false);
+ this.dependencyRef = new AtomicMarkableReference<>(null, false);
}
@Override
public boolean isCancelled() {
- return cancelled.get();
+ return dependencyRef.isMarked();
}
@Override
public void setDependency(final Cancellable dependency) {
Args.notNull(dependency, "dependency");
- if (!cancelled.get()) {
- dependencyRef.set(dependency);
- } else {
+ final Cancellable actualDependency = dependencyRef.getReference();
+ if (!dependencyRef.compareAndSet(actualDependency, dependency, false, false)) {
dependency.cancel();
}
}
@Override
public boolean cancel() {
- if (cancelled.compareAndSet(false, true)) {
- final Cancellable dependency = dependencyRef.getAndSet(null);
- if (dependency != null) {
- dependency.cancel();
+ while (!dependencyRef.isMarked()) {
+ final Cancellable actualDependency = dependencyRef.getReference();
+ if (dependencyRef.compareAndSet(actualDependency, actualDependency, false, true)) {
+ if (actualDependency != null) {
+ actualDependency.cancel();
+ }
+ return true;
}
- return true;
}
return false;
}