JRE-193 UI freeze and 12/second thread dumps

Moved CStrikeDisposer dispose code to AppKit

(cherry picked from commit 28774d6878)
This commit is contained in:
Alexey Ushakov
2021-04-14 22:34:22 +03:00
committed by alexey.ushakov@jetbrains.com
parent 0b27afa493
commit 79d3896473
2 changed files with 84 additions and 34 deletions

View File

@@ -25,6 +25,8 @@
package sun.font;
import sun.lwawt.macosx.concurrent.Dispatch;
import java.awt.Rectangle;
import java.awt.geom.*;
import java.util.HashMap;
@@ -366,7 +368,7 @@ public final class CStrike extends PhysicalStrike {
private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
// rdar://problem/5204197
private boolean disposed = false;
private final AtomicBoolean disposed = new AtomicBoolean(false);
private final long[] firstLayerCache;
private SparseBitShiftingTwoLayerArray secondLayerCache;
@@ -429,41 +431,64 @@ public final class CStrike extends PhysicalStrike {
}
public synchronized void dispose() {
// rdar://problem/5204197
// Note that sun.font.Font2D.getStrike() actively disposes
// cleared strikeRef. We need to check the disposed flag to
// prevent double frees of native resources.
if (disposed) {
return;
}
final Runnable command = () -> {
// rdar://problem/5204197
// Note that sun.font.Font2D.getStrike() actively disposes
// cleared strikeRef. We need to check the disposed flag to
// prevent double frees of native resources.
if (disposed.compareAndSet(false, true)) {
super.dispose();
super.dispose();
// clean out the first array
disposeLongArray(firstLayerCache);
// clean out the first array
disposeLongArray(firstLayerCache);
// clean out the two layer arrays
if (secondLayerCache != null) {
final long[][] secondLayerLongArrayArray = secondLayerCache.cache;
for (int i = 0; i < secondLayerLongArrayArray.length; i++) {
final long[] longArray = secondLayerLongArrayArray[i];
if (longArray != null) disposeLongArray(longArray);
}
}
// clean out the two layer arrays
if (secondLayerCache != null) {
final long[][] secondLayerLongArrayArray = secondLayerCache.cache;
for (final long[] longArray : secondLayerLongArrayArray) {
if (longArray != null) disposeLongArray(longArray);
}
}
// clean up everyone else
if (generalCache != null) {
for (long longValue : generalCache.values()) {
if (longValue != -1 && longValue != 0) {
removeGlyphInfoFromCache(longValue);
StrikeCache.freeLongPointer(longValue);
// clean up everyone else
if (generalCache != null) {
for (long longValue : generalCache.values()) {
if (longValue != -1 && longValue != 0) {
removeGlyphInfoFromCache(longValue);
StrikeCache.freeLongPointer(longValue);
}
}
}
if (generalCache != null) {
for (Long aLong : generalCache.values()) {
final long longValue = aLong;
if (longValue != -1 && longValue != 0) {
removeGlyphInfoFromCache(longValue);
StrikeCache.freeLongPointer(longValue);
}
}
}
}
}
};
// rdar://problem/5204197
// Finally, set the flag.
disposed = true;
// Move disposal code to AppKit thread in order to avoid the
// following deadlock:
// 1) CGLGraphicsConfig.getCGLConfigInfo (called from Java2D
// disposal thread) takes RenderQueue.lock
// 2) CGLLayer.drawInCGLContext is invoked on AppKit thread and
// blocked on RenderQueue.lock
// 1) invokes native block on AppKit and wait
//
// If dispatch instance is not available, run the code on
// disposal thread as before
final Dispatch dispatch = Dispatch.getInstance();
if (!CThreading.isAppKit() && dispatch != null)
dispatch.getNonBlockingMainQueueExecutor().execute(command);
else
command.run();
}
private static void disposeLongArray(final long[] longArray) {

View File

@@ -25,6 +25,11 @@
package sun.font;
import sun.lwawt.macosx.concurrent.Dispatch;
import sun.lwawt.macosx.CThreading;
import java.util.concurrent.atomic.AtomicBoolean;
/*
* This keeps track of data that needs to be cleaned up once a
* strike is freed.
@@ -49,6 +54,7 @@ package sun.font;
class CStrikeDisposer extends FontStrikeDisposer {
long pNativeScalerContext;
private final AtomicBoolean disposed = new AtomicBoolean(false);
public CStrikeDisposer(Font2D font2D, FontStrikeDesc desc,
long pContext, int[] images)
@@ -76,12 +82,31 @@ class CStrikeDisposer extends FontStrikeDisposer {
}
public synchronized void dispose() {
if (!disposed) {
if (pNativeScalerContext != 0L) {
freeNativeScalerContext(pNativeScalerContext);
final Runnable command = () -> {
if (disposed.compareAndSet(false, true)) {
if (pNativeScalerContext != 0L) {
freeNativeScalerContext(pNativeScalerContext);
}
super.dispose();
}
super.dispose();
}
};
// Move disposal code to AppKit thread in order to avoid the
// following deadlock:
// 1) CGLGraphicsConfig.getCGLConfigInfo (called from Java2D
// disposal thread) takes RenderQueue.lock
// 2) CGLLayer.drawInCGLContext is invoked on AppKit thread and
// blocked on RenderQueue.lock
// 1) invokes native block on AppKit and wait
//
// If dispatch instance is not available, run the code on
// disposal thread as before
final Dispatch dispatch = Dispatch.getInstance();
if (!CThreading.isAppKit() && dispatch != null)
dispatch.getNonBlockingMainQueueExecutor().execute(command);
else
command.run();
}
private native void freeNativeScalerContext(long pContext);