Skip to content

Commit 01ea6a5

Browse files
sjuddglide-copybara-robot
authored andcommitted
Avoid deadlock between SingleRequest and RequestFutureTarget.
Clearing the Request object outside of RequestFutureTarget's lock should prevent the RequestFutureTarget -> Request path, which will eliminate the deadlock. Since a new Request object is created for each subsequent load, there isn't any risk that clearing the Request outside of the lock will end up clearing a new or restarted request. PiperOrigin-RevId: 261721324
1 parent b2a46ef commit 01ea6a5

File tree

1 file changed

+35
-11
lines changed

1 file changed

+35
-11
lines changed

library/src/main/java/com/bumptech/glide/request/RequestFutureTarget.java

+35-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.bumptech.glide.request;
22

33
import android.graphics.drawable.Drawable;
4+
import androidx.annotation.GuardedBy;
45
import androidx.annotation.NonNull;
56
import androidx.annotation.Nullable;
67
import androidx.annotation.VisibleForTesting;
@@ -57,12 +58,26 @@ public class RequestFutureTarget<R> implements FutureTarget<R>, RequestListener<
5758
private final boolean assertBackgroundThread;
5859
private final Waiter waiter;
5960

60-
@Nullable private R resource;
61-
@Nullable private Request request;
61+
@GuardedBy("this")
62+
@Nullable
63+
private R resource;
64+
65+
@GuardedBy("this")
66+
@Nullable
67+
private Request request;
68+
69+
@GuardedBy("this")
6270
private boolean isCancelled;
71+
72+
@GuardedBy("this")
6373
private boolean resultReceived;
74+
75+
@GuardedBy("this")
6476
private boolean loadFailed;
65-
@Nullable private GlideException exception;
77+
78+
@GuardedBy("this")
79+
@Nullable
80+
private GlideException exception;
6681

6782
/** Constructor for a RequestFutureTarget. Should not be used directly. */
6883
public RequestFutureTarget(int width, int height) {
@@ -77,15 +92,24 @@ public RequestFutureTarget(int width, int height) {
7792
}
7893

7994
@Override
80-
public synchronized boolean cancel(boolean mayInterruptIfRunning) {
81-
if (isDone()) {
82-
return false;
95+
public boolean cancel(boolean mayInterruptIfRunning) {
96+
Request toClear = null;
97+
synchronized (this) {
98+
if (isDone()) {
99+
return false;
100+
}
101+
102+
isCancelled = true;
103+
waiter.notifyAll(this);
104+
if (mayInterruptIfRunning) {
105+
toClear = request;
106+
request = null;
107+
}
83108
}
84-
isCancelled = true;
85-
waiter.notifyAll(this);
86-
if (mayInterruptIfRunning && request != null) {
87-
request.clear();
88-
request = null;
109+
110+
// Avoid deadlock by clearing outside of the lock (b/138335419)
111+
if (toClear != null) {
112+
toClear.clear();
89113
}
90114
return true;
91115
}

0 commit comments

Comments
 (0)