outofmemory exception handling, command line option for setting the process affinity and priority, some functions was executed on a different thread when parallel option was disabled

This commit is contained in:
Honfika
2013-10-16 18:21:25 +02:00
parent fa0bee22a3
commit d73f2bf3ac
5 changed files with 163 additions and 75 deletions

View File

@@ -127,6 +127,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -650,37 +651,61 @@ public class SWF {
return ret;
}
public List<File> exportActionScript3(AbortRetryIgnoreHandler handler, String outdir, ExportMode exportMode, boolean parallel) {
ExecutorService executor = Executors.newFixedThreadPool(parallel ? 20 : 1);
List<Future<File>> futureResults = new ArrayList<>();
AtomicInteger cnt = new AtomicInteger(1);
List<ABCContainerTag> abcTags = new ArrayList<>();
public List<File> exportActionScript3(final AbortRetryIgnoreHandler handler, final String outdir, final ExportMode exportMode, final boolean parallel) {
final AtomicInteger cnt = new AtomicInteger(1);
final List<ABCContainerTag> abcTags = new ArrayList<>();
for (Tag t : tags) {
if (t instanceof ABCContainerTag) {
abcTags.add((ABCContainerTag) t);
}
}
List<MyEntry<ClassPath, ScriptPack>> packs = getAS3Packs();
for (MyEntry<ClassPath, ScriptPack> item : packs) {
Future<File> future = executor.submit(new ExportPackTask(handler, cnt, packs.size(), item.key, item.value, outdir, abcTags, exportMode, parallel));
futureResults.add(future);
}
List<File> ret = new ArrayList<>();
for (int f = 0; f < futureResults.size(); f++) {
final List<File> ret = new ArrayList<>();
final List<MyEntry<ClassPath, ScriptPack>> packs = getAS3Packs();
if (!parallel || packs.size() < 2) {
try {
ret.add(futureResults.get(f).get());
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, "Error during ABC export", ex);
Helper.timedCall(new Callable<Void>() {
@Override
public Void call() throws Exception {
for (MyEntry<ClassPath, ScriptPack> item : packs) {
ExportPackTask task = new ExportPackTask(handler, cnt, packs.size(), item.key, item.value, outdir, abcTags, exportMode, parallel);
try {
ret.add(task.call());
} catch (Exception ex) {
Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, "Error during ABC export", ex);
}
}
return null;
}
}, Configuration.DECOMPILATION_TIMEOUT, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT) + " ActionScript export limit reached", ex);
}
} else {
ExecutorService executor = Executors.newFixedThreadPool(20);
List<Future<File>> futureResults = new ArrayList<>();
for (MyEntry<ClassPath, ScriptPack> item : packs) {
Future<File> future = executor.submit(new ExportPackTask(handler, cnt, packs.size(), item.key, item.value, outdir, abcTags, exportMode, parallel));
futureResults.add(future);
}
for (int f = 0; f < futureResults.size(); f++) {
try {
ret.add(futureResults.get(f).get());
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, "Error during ABC export", ex);
}
}
try {
executor.shutdown();
executor.awaitTermination(Configuration.DECOMPILATION_TIMEOUT, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT) + " ActionScript export limit reached", ex);
}
}
try {
executor.shutdown();
executor.awaitTermination(Configuration.DECOMPILATION_TIMEOUT, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT) + " ActionScript export limit reached", ex);
}
return ret;
}

View File

@@ -64,6 +64,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -606,7 +607,7 @@ public class SWFInputStream extends InputStream {
/**
* Reads list of tags from the stream. Reading ends with End tag(=0) or end
* of the stream. Optinally can skip AS1/2 tags when file is AS3
* of the stream. Optionally can skip AS1/2 tags when file is AS3
*
* @param swf
* @param level
@@ -633,10 +634,11 @@ public class SWFInputStream extends InputStream {
*/
public List<Tag> readTagList(SWF swf, int level, boolean parallel, boolean skipUnusualTags, boolean parseTags) throws IOException {
ExecutorService executor = null;
List<Future<Tag>> futureResults = new ArrayList<>();
if (parallel) {
executor = Executors.newFixedThreadPool(20);
futureResults = new ArrayList<>();
}
List<Future<Tag>> futureResults = new ArrayList<>();
List<Tag> tags = new ArrayList<>();
Tag tag;
Tag previousTag = null;
@@ -659,7 +661,7 @@ public class SWFInputStream extends InputStream {
}
tag.previousTag = previousTag;
previousTag = tag;
boolean doParse = false;
boolean doParse;
if (!skipUnusualTags) {
doParse = true;
} else {
@@ -718,7 +720,7 @@ public class SWFInputStream extends InputStream {
for (Future<Tag> future : futureResults) {
try {
tags.add(future.get());
} catch (Exception e) {
} catch (InterruptedException | ExecutionException e) {
Logger.getLogger(SWFInputStream.class.getName()).log(Level.SEVERE, "Error during tag reading", e);
}
}
@@ -1005,21 +1007,6 @@ public class SWFInputStream extends InputStream {
return ret;
}
/**
* Reads one Tag from the stream
*
* @param swf
* @param level
* @param pos
* @param parallel
* @param skipUnusualTags
* @return Tag or null when End tag
* @throws IOException
*/
public Tag readTag(SWF swf, int level, long pos, boolean parallel, boolean skipUnusualTags) throws IOException {
return readTag(swf, level, pos, true, parallel, skipUnusualTags);
}
/**
* Reads one Tag from the stream with optional resolving (= reading tag
* content)

View File

@@ -135,40 +135,38 @@ public class Traits implements Serializable {
}
public HilightedTextWriter convert(Trait parent, String path, List<ABCContainerTag> abcTags, ABC abc, boolean isStatic, ExportMode exportMode, boolean makePackages, int scriptIndex, int classIndex, HilightedTextWriter writer, List<String> fullyQualifiedNames, boolean parallel) {
ExecutorService executor = null;
List<Future<String>> futureResults = null;
List<TraitConvertTask> traitConvertTasks = null;
if (parallel) {
executor = Executors.newFixedThreadPool(20);
futureResults = new ArrayList<>();
} else {
traitConvertTasks = new ArrayList<>();
}
for (int t = 0; t < traits.length; t++) {
HilightedTextWriter writer2 = new HilightedTextWriter(writer.getIsHighlighted(), writer.getIndent());
TraitConvertTask task = new TraitConvertTask(traits[t], parent, makePackages, path, abcTags, abc, isStatic, exportMode, scriptIndex, classIndex, writer2, fullyQualifiedNames, t, parallel);
if (parallel) {
Future<String> future = executor.submit(task);
futureResults.add(future);
} else {
traitConvertTasks.add(task);
}
}
int taskCount = parallel ? futureResults.size() : traitConvertTasks.size();
for (int f = 0; f < taskCount; f++) {
if (f > 0) {
if (!parallel || traits.length < 2) {
for (int t = 0; t < traits.length; t++) {
if (t > 0) {
writer.newLine();
}
TraitConvertTask task = new TraitConvertTask(traits[t], parent, makePackages, path, abcTags, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, t, parallel);
task.call();
writer.newLine();
}
try {
String taskResult = parallel ? futureResults.get(f).get() : traitConvertTasks.get(f).call();
writer.appendWithoutIndent(taskResult);
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(Traits.class.getName()).log(Level.SEVERE, "Error during traits converting", ex);
} else {
ExecutorService executor = Executors.newFixedThreadPool(20);
List<Future<String>> futureResults = null;
futureResults = new ArrayList<>();
for (int t = 0; t < traits.length; t++) {
HilightedTextWriter writer2 = new HilightedTextWriter(writer.getIsHighlighted(), writer.getIndent());
TraitConvertTask task = new TraitConvertTask(traits[t], parent, makePackages, path, abcTags, abc, isStatic, exportMode, scriptIndex, classIndex, writer2, fullyQualifiedNames, t, parallel);
Future<String> future = executor.submit(task);
futureResults.add(future);
}
for (int f = 0; f < futureResults.size(); f++) {
if (f > 0) {
writer.newLine();
}
try {
String taskResult = futureResults.get(f).get();
writer.appendWithoutIndent(taskResult);
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(Traits.class.getName()).log(Level.SEVERE, "Error during traits converting", ex);
}
}
}
if (parallel) {
executor.shutdown();
}
return writer;

View File

@@ -281,12 +281,16 @@ public class Main {
if (Main.inputStream instanceof FileInputStream) {
Main.inputStream.close();
}
} catch (OutOfMemoryError ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
View.showMessageDialog(null, "Cannot load SWF file. Out of memory.");
loadingDialog.setVisible(false);
swf = null;
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
View.showMessageDialog(null, "Cannot load SWF file.");
loadingDialog.setVisible(false);
swf = null;
//return false;
}
try {
@@ -966,6 +970,65 @@ public class Main {
}
pos++;
} else if (args[pos].equals("-affinity")) {
parameterProcessed = true;
pos++;
if (Platform.isWindows()) {
if (args.length <= pos) {
System.err.println("affinity parameter expected");
badArguments();
}
try {
int affinityMask = Integer.parseInt(args[pos]);
Kernel32.INSTANCE.SetProcessAffinityMask(Kernel32.INSTANCE.GetCurrentProcess(), affinityMask);
} catch (NumberFormatException nex) {
System.err.println("Bad affinityMask value");
}
pos++;
} else {
System.err.println("Process affinity setting is only available on Windows platform.");
}
} else if (args[pos].equals("-priority")) {
parameterProcessed = true;
pos++;
if (Platform.isWindows()) {
if (args.length <= pos) {
System.err.println("priority parameter expected");
badArguments();
}
String priority = args[pos];
int priorityClass = 0;
switch (priority) {
case "low":
priorityClass = Kernel32.IDLE_PRIORITY_CLASS;
break;
case "belownormal":
priorityClass = Kernel32.BELOW_NORMAL_PRIORITY_CLASS;
break;
case "normal":
priorityClass = Kernel32.NORMAL_PRIORITY_CLASS;
break;
case "abovenormal":
priorityClass = Kernel32.ABOVE_NORMAL_PRIORITY_CLASS;
break;
case "high":
priorityClass = Kernel32.HIGH_PRIORITY_CLASS;
break;
case "realtime":
priorityClass = Kernel32.REALTIME_PRIORITY_CLASS;
break;
default:
System.err.println("Bad affinityMask value");
}
if (priorityClass != 0) {
Kernel32.INSTANCE.SetPriorityClass(Kernel32.INSTANCE.GetCurrentProcess(), priorityClass);
}
pos++;
} else {
System.err.println("Process priority setting is only available on Windows platform.");
}
}
}
if (args[pos].equals("-removefromcontextmenu")) {
@@ -1119,7 +1182,7 @@ public class Main {
default:
exportOK = false;
}
} catch (Exception ex) {
} catch (OutOfMemoryError | Exception ex) {
exportOK = false;
System.err.print("FAIL: Exporting Failed on Exception - ");
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);

View File

@@ -109,7 +109,18 @@ public interface Kernel32 extends WinNT {
// Define the well known values for CreateNamedPipe nMaxInstances
//
public static final int PIPE_UNLIMITED_INSTANCES = 255;
//
// Define the values for process priority
//
public static final int ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000;
public static final int BELOW_NORMAL_PRIORITY_CLASS = 0x00004000;
public static final int HIGH_PRIORITY_CLASS = 0x00000080;
public static final int IDLE_PRIORITY_CLASS = 0x00000040;
public static final int NORMAL_PRIORITY_CLASS = 0x00000020;
public static final int PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000;
public static final int PROCESS_MODE_BACKGROUND_END = 0x00200000;
public static final int REALTIME_PRIORITY_CLASS = 0x00000100;
// __out
// HANDLE
// WINAPI
@@ -172,6 +183,10 @@ public interface Kernel32 extends WinNT {
*/
HANDLE GetCurrentProcess();
int SetProcessAffinityMask(HANDLE hProcess, int mask);
int SetPriorityClass(HANDLE hProcess, int dwPriorityClass);
/**
* This function returns a handle to an existing process object.
*