JBR-3916 Deadlock in pGetBounds() on Linux

The deadlock occurred because one thread was holding the AWT lock and
waiting for boundsCacheLock in resetBoundsCache() and the other vice
versa stuck in pGetBounds() owning boundsCacheLock and waiting for the
AWT lock.

The solution is to get rid of boundsCacheLock altogether. It was
introduced in order to never return null from getBoundsCached() so that
resetBoundsCache() wouldn't interfere. But the same effect can be
achieved by simply using a local variable to hold a copy of the current
bounds. The worst case scenario now is that two threads update
boundsCached immediately one after another (if they both have observed
the null value there at about the same time), but that's harmless as
pGetBounds() grabs the AWT lock when necessary.

(cherry picked from commit dc6ad31524)
This commit is contained in:
Maxim Kartashev
2021-10-26 17:50:03 +03:00
committed by jbrbot
parent 9e4d1b1bf0
commit b5736ebcde

View File

@@ -148,22 +148,23 @@ public final class X11GraphicsDevice extends GraphicsDevice
return rect;
}
private Rectangle boundsCached;
private final Object boundsCacheLock = new Object();
private volatile Rectangle boundsCached;
private Rectangle getBoundsCached() {
synchronized (boundsCacheLock) {
if (boundsCached == null) {
boundsCached = getBoundsImpl();
}
return boundsCached;
// A local copy is needed in order to avoid races with other
// threads doing resetBoundsCache(). We may not return null.
final Rectangle localBoundsCached = boundsCached;
if (localBoundsCached == null) {
final Rectangle newBounds = getBoundsImpl();
boundsCached = newBounds;
return newBounds;
} else {
return localBoundsCached;
}
}
public void resetBoundsCache() {
synchronized (boundsCacheLock) {
boundsCached = null;
}
boundsCached = null;
}
public Rectangle getBounds() {