提交 d3205370 编写于 作者: J jgodinez

8001038: Resourcefully handle resources

Reviewed-by: prr, bae
Contributed-by: jia-hong.chen@oracle.com
上级 9a1ff143
......@@ -873,6 +873,33 @@ public class Font implements java.io.Serializable
public static Font createFont(int fontFormat, InputStream fontStream)
throws java.awt.FontFormatException, java.io.IOException {
if (hasTempPermission()) {
return createFont0(fontFormat, fontStream, null);
}
// Otherwise, be extra conscious of pending temp file creation and
// resourcefully handle the temp file resources, among other things.
CreatedFontTracker tracker = CreatedFontTracker.getTracker();
boolean acquired = false;
try {
acquired = tracker.acquirePermit();
if (!acquired) {
throw new IOException("Timed out waiting for resources.");
}
return createFont0(fontFormat, fontStream, tracker);
} catch (InterruptedException e) {
throw new IOException("Problem reading font data.");
} finally {
if (acquired) {
tracker.releasePermit();
}
}
}
private static Font createFont0(int fontFormat, InputStream fontStream,
CreatedFontTracker tracker)
throws java.awt.FontFormatException, java.io.IOException {
if (fontFormat != Font.TRUETYPE_FONT &&
fontFormat != Font.TYPE1_FONT) {
throw new IllegalArgumentException ("font format not recognized");
......@@ -886,9 +913,11 @@ public class Font implements java.io.Serializable
}
}
);
if (tracker != null) {
tracker.add(tFile);
}
int totalSize = 0;
CreatedFontTracker tracker = null;
try {
final OutputStream outStream =
AccessController.doPrivileged(
......@@ -898,8 +927,8 @@ public class Font implements java.io.Serializable
}
}
);
if (!hasTempPermission()) {
tracker = CreatedFontTracker.getTracker();
if (tracker != null) {
tracker.set(tFile, outStream);
}
try {
byte[] buf = new byte[8192];
......@@ -940,6 +969,9 @@ public class Font implements java.io.Serializable
Font font = new Font(tFile, fontFormat, true, tracker);
return font;
} finally {
if (tracker != null) {
tracker.remove(tFile);
}
if (!copiedFontData) {
if (tracker != null) {
tracker.subBytes(totalSize);
......
......@@ -25,13 +25,22 @@
package sun.font;
import java.io.File;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import sun.awt.AppContext;
public class CreatedFontTracker {
public static final int MAX_FILE_SIZE = 32 * 1024 * 1024;
public static final int MAX_TOTAL_BYTES = 10 * MAX_FILE_SIZE;
static int numBytes;
static CreatedFontTracker tracker;
int numBytes;
public static synchronized CreatedFontTracker getTracker() {
if (tracker == null) {
......@@ -40,6 +49,10 @@ public class CreatedFontTracker {
return tracker;
}
private CreatedFontTracker() {
numBytes = 0;
}
public synchronized int getNumBytes() {
return numBytes;
}
......@@ -51,4 +64,108 @@ public class CreatedFontTracker {
public synchronized void subBytes(int sz) {
numBytes -= sz;
}
/**
* Returns an AppContext-specific counting semaphore.
*/
private static synchronized Semaphore getCS() {
final AppContext appContext = AppContext.getAppContext();
Semaphore cs = (Semaphore) appContext.get(CreatedFontTracker.class);
if (cs == null) {
// Make a semaphore with 5 permits that obeys the first-in first-out
// granting of permits.
cs = new Semaphore(5, true);
appContext.put(CreatedFontTracker.class, cs);
}
return cs;
}
public boolean acquirePermit() throws InterruptedException {
// This does a timed-out wait.
return getCS().tryAcquire(120, TimeUnit.SECONDS);
}
public void releasePermit() {
getCS().release();
}
public void add(File file) {
TempFileDeletionHook.add(file);
}
public void set(File file, OutputStream os) {
TempFileDeletionHook.set(file, os);
}
public void remove(File file) {
TempFileDeletionHook.remove(file);
}
/**
* Helper class for cleanup of temp files created while processing fonts.
* Note that this only applies to createFont() from an InputStream object.
*/
private static class TempFileDeletionHook {
private static HashMap<File, OutputStream> files = new HashMap<>();
private static Thread t = null;
static void init() {
if (t == null) {
// Add a shutdown hook to remove the temp file.
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
/* The thread must be a member of a thread group
* which will not get GCed before VM exit.
* Make its parent the top-level thread group.
*/
ThreadGroup tg =
Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
t = new Thread(tg, new Runnable() {
public void run() {
runHooks();
}
});
t.setContextClassLoader(null);
Runtime.getRuntime().addShutdownHook(t);
return null;
}
});
}
}
private TempFileDeletionHook() {}
static synchronized void add(File file) {
init();
files.put(file, null);
}
static synchronized void set(File file, OutputStream os) {
files.put(file, os);
}
static synchronized void remove(File file) {
files.remove(file);
}
static synchronized void runHooks() {
if (files.isEmpty()) {
return;
}
for (Map.Entry<File, OutputStream> entry : files.entrySet()) {
// Close the associated output stream, and then delete the file.
try {
if (entry.getValue() != null) {
entry.getValue().close();
}
} catch (Exception e) {}
entry.getKey().delete();
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册