lots of work to clean up console lockup issues (fixes #4825)

This commit is contained in:
Ben Fry
2017-05-03 20:40:36 -04:00
parent f9071c01d4
commit a9de2e3d53
5 changed files with 120 additions and 64 deletions
+14 -18
View File
@@ -30,7 +30,7 @@ import java.util.Date;
/**
* Message console that sits below the editing area.
* Non-GUI handling of System.out and System.err redirection.
* <p />
* Be careful when debugging this class, because if it's throwing exceptions,
* don't take over System.err, and debug while watching just System.out
@@ -43,9 +43,6 @@ import java.util.Date;
* get along with one another. Use 'ant run' to work on encoding-related issues.
*/
public class Console {
// PrintStream sketchOut;
// PrintStream sketchErr;
// Single static instance shared because there's only one real System.out.
// Within the input handlers, the currentConsole variable will be used to
// echo things to the correct location.
@@ -72,6 +69,13 @@ public class Console {
static public void startup() {
if (systemOut != null) {
// TODO fix this dreadful style choice in how the Console is initialized
// (This is not good code.. startup() should gracefully deal with this.
// It's just a low priority relative to the likelihood of trouble.)
new Exception("startup() called more than once").printStackTrace(systemErr);
return;
}
systemOut = System.out;
systemErr = System.err;
@@ -115,8 +119,6 @@ public class Console {
File errFile = new File(consoleDir, stamp + ".err");
stderrFile = new FileOutputStream(errFile);
// consoleOut = new PrintStream(new EditorConsoleStream(false, null));
// consoleErr = new PrintStream(new EditorConsoleStream(true, null));
consoleOut = new PrintStream(new ConsoleStream(false));
consoleErr = new PrintStream(new ConsoleStream(true));
@@ -144,20 +146,14 @@ public class Console {
}
// public Console() {
// sketchOut = new PrintStream(new EditorConsoleStream(false, this));
// sketchErr = new PrintStream(new EditorConsoleStream(true, this));
// }
static public void systemOut(String what) {
systemOut.println(what);
}
// public PrintStream getOut() {
// return sketchOut;
// }
// public PrintStream getErr() {
// return sketchErr;
// }
static public void systemErr(String what) {
systemErr.println(what);
}
/**
@@ -7,13 +7,13 @@
*/
/*
* Copyright (c) 1997-2001 by Sun Microsystems, Inc. All Rights Reserved.
*
*
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
* modify and redistribute this software in source and binary code form,
* provided that i) this copyright notice and license appear on all copies of
* the software; and ii) Licensee does not utilize the software in a manner
* which is disparaging to Sun.
*
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
@@ -25,7 +25,7 @@
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
*
* This software is not designed or intended for use in on-line control of
* aircraft, air traffic, aircraft navigation or aircraft communications; or in
* the design, construction, operation or maintenance of any nuclear
@@ -50,7 +50,7 @@ public class StreamRedirectThread extends Thread {
private static final int BUFFER_SIZE = 2048;
/**
* Set up for copy.
* @param name Name of the thread
@@ -63,15 +63,15 @@ public class StreamRedirectThread extends Thread {
this.out = new OutputStreamWriter(out);
setPriority(Thread.MAX_PRIORITY-1);
}
public StreamRedirectThread(String name, Reader in, Writer out) {
super(name);
this.in = in;
this.out = out;
setPriority(Thread.MAX_PRIORITY-1);
}
/**
* Copy.
@@ -80,16 +80,15 @@ public class StreamRedirectThread extends Thread {
try {
char[] cbuf = new char[BUFFER_SIZE];
int count;
//System.out.println("opening streamredirectthread");
while ((count = in.read(cbuf, 0, BUFFER_SIZE)) >= 0) {
out.write(cbuf, 0, count);
// had to add the flush() here.. maybe shouldn't be using writer? [fry]
out.flush();
}
//System.out.println("exiting streamredirectthread");
out.flush();
} catch(IOException exc) {
System.err.println("Child I/O Transfer - " + exc);
} catch (IOException exc) {
processing.app.Console.systemErr("Child I/O Transfer - " + exc);
}
}
}
+88 -31
View File
@@ -32,8 +32,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import javax.swing.*;
import javax.swing.border.MatteBorder;
@@ -46,16 +45,6 @@ import processing.app.Preferences;
/**
* Message console that sits below the editing area.
* <p />
* Be careful when debugging this class, because if it's throwing exceptions,
* don't take over System.err, and debug while watching just System.out
* or just call println() or whatever directly to systemOut or systemErr.
* <p />
* Also note that encodings will not work properly when run from Eclipse. This
* means that if you use non-ASCII characters in a println() or some such,
* the characters won't print properly in the Processing and/or Eclipse console.
* It seems that Eclipse's console-grabbing and that of Processing don't
* get along with one another. Use 'ant run' to work on encoding-related issues.
*/
public class EditorConsole extends JScrollPane {
Editor editor;
@@ -69,6 +58,7 @@ public class EditorConsole extends JScrollPane {
MutableAttributeSet errStyle;
int maxLineCount;
int maxCharCount;
PrintStream sketchOut;
PrintStream sketchErr;
@@ -79,9 +69,10 @@ public class EditorConsole extends JScrollPane {
public EditorConsole(Editor editor) {
this.editor = editor;
maxLineCount = Preferences.getInteger("console.length");
maxLineCount = Preferences.getInteger("console.lines");
maxCharCount = Preferences.getInteger("console.chars");
consoleDoc = new BufferedStyledDocument(10000, maxLineCount);
consoleDoc = new BufferedStyledDocument(10000, maxLineCount, maxCharCount);
consoleTextPane = new JTextPane(consoleDoc);
consoleTextPane.setEditable(false);
@@ -98,7 +89,7 @@ public class EditorConsole extends JScrollPane {
protected void flush() {
// only if new text has been added
if (consoleDoc.hasAppendage) {
if (consoleDoc.hasAppendage()) {
// insert the text that's been added in the meantime
consoleDoc.insertAll();
// always move to the end of the text as it's added
@@ -150,8 +141,7 @@ public class EditorConsole extends JScrollPane {
*/
protected void updateAppearance() {
String fontFamily = Preferences.get("editor.font.family");
int fontSize =
Toolkit.zoom(Preferences.getInteger("console.font.size"));
int fontSize = Toolkit.zoom(Preferences.getInteger("console.font.size"));
StyleConstants.setFontFamily(stdStyle, fontFamily);
StyleConstants.setFontSize(stdStyle, fontSize);
StyleConstants.setFontFamily(errStyle, fontFamily);
@@ -232,7 +222,7 @@ public class EditorConsole extends JScrollPane {
}
synchronized public void message(String what, boolean err) {
public void message(String what, boolean err) {
if (err && (what.contains("invalid context 0x0") || (what.contains("invalid drawable")))) {
// Respectfully declining... This is a quirk of more recent releases of
// Java on Mac OS X, but is widely reported as the source of any other
@@ -302,22 +292,32 @@ public class EditorConsole extends JScrollPane {
* swing event thread, so they need to be synchronized
*/
class BufferedStyledDocument extends DefaultStyledDocument {
List<ElementSpec> elements = new ArrayList<>();
int maxLineLength, maxLineCount;
//List<ElementSpec> elements = new ArrayList<>();
LinkedBlockingQueue<ElementSpec> elements;
// AtomicInteger queuedLineCount = new AtomicInteger();
int maxLineLength, maxLineCount, maxCharCount;
int currentLineLength = 0;
boolean needLineBreak = false;
boolean hasAppendage = false;
// boolean hasAppendage = false;
final Object insertLock = new Object();
public BufferedStyledDocument(int maxLineLength, int maxLineCount) {
public BufferedStyledDocument(int maxLineLength, int maxLineCount,
int maxCharCount) {
this.maxLineLength = maxLineLength;
this.maxLineCount = maxLineCount;
this.maxCharCount = maxCharCount;
elements = new LinkedBlockingQueue<>();
}
// monitor this so that it's only updated when needed (otherwise console
// updates every 250 ms when an app isn't even running.. see bug 180)
public boolean hasAppendage() {
return elements.size() > 0;
}
/** buffer a string for insertion at the end of the DefaultStyledDocument */
public synchronized void appendString(String str, AttributeSet a) {
// do this so that it's only updated when needed (otherwise console
// updates every 250 ms when an app isn't even running.. see bug 180)
hasAppendage = true;
public void appendString(String str, AttributeSet a) {
// hasAppendage = true;
// process each line of the string
while (str.length() > 0) {
@@ -326,6 +326,7 @@ class BufferedStyledDocument extends DefaultStyledDocument {
if (needLineBreak || currentLineLength > maxLineLength) {
elements.add(new ElementSpec(a, ElementSpec.EndTagType));
elements.add(new ElementSpec(a, ElementSpec.StartTagType));
// queuedLineCount.incrementAndGet();
currentLineLength = 0;
}
@@ -341,15 +342,42 @@ class BufferedStyledDocument extends DefaultStyledDocument {
needLineBreak = true;
str = str.substring(str.indexOf('\n') + 1); // eat the line
}
/*
while (queuedLineCount.get() > maxLineCount) {
Console.systemOut("too many: " + queuedLineCount);
ElementSpec elem = elements.remove();
if (elem.getType() == ElementSpec.EndTagType) {
queuedLineCount.decrementAndGet();
}
}
*/
}
if (elements.size() > 1000) {
insertAll();
}
}
/** insert the buffered strings */
public synchronized void insertAll() {
ElementSpec[] elementArray = new ElementSpec[elements.size()];
elements.toArray(elementArray);
public void insertAll() {
/*
// each line is ~3 elements
int tooMany = elements.size() - maxLineCount*3;
if (tooMany > 0) {
try {
remove(0, getLength()); // clear the document first
} catch (BadLocationException ble) {
ble.printStackTrace();
}
Console.systemOut("skipping " + elements.size());
for (int i = 0; i < tooMany; i++) {
elements.remove();
}
}
*/
ElementSpec[] elementArray = elements.toArray(new ElementSpec[0]);
try {
/*
// check how many lines have been used so far
// if too many, shave off a few lines from the beginning
Element element = super.getDefaultRootElement();
@@ -366,13 +394,42 @@ class BufferedStyledDocument extends DefaultStyledDocument {
// remove to the end of the 200th line
super.remove(0, endOffset);
}
super.insert(super.getLength(), elementArray);
*/
synchronized (insertLock) {
checkLength();
insert(getLength(), elementArray);
checkLength();
}
} catch (BadLocationException e) {
// ignore the error otherwise this will cause an infinite loop
// maybe not a good idea in the long run?
}
elements.clear();
hasAppendage = false;
// hasAppendage = false;
}
private void checkLength() throws BadLocationException {
// set a limit on the number of characters in the console
int docLength = getLength();
if (docLength > maxCharCount) {
remove(0, docLength - maxCharCount);
}
// check how many lines have been used so far
// if too many, shave off a few lines from the beginning
Element element = super.getDefaultRootElement();
int lineCount = element.getElementCount();
int overage = lineCount - maxLineCount;
if (overage > 0) {
// if 1200 lines, and 1000 lines is max,
// find the position of the end of the 200th line
//systemOut.println("overage is " + overage);
Element lineElement = element.getElement(overage);
if (lineElement != null) {
int endOffset = lineElement.getEndOffset();
// remove to the end of the 200th line
super.remove(0, endOffset);
}
}
}
}
+2 -1
View File
@@ -184,7 +184,8 @@ console.auto_clear = true
# set the maximum number of lines remembered by the console
# the default is 500, lengthen at your own peril
console.length = 500
console.lines = 500
console.chars = 40000
# Any additional Java options when running.
# If you change this and can't run things, it's your own durn fault.
+6 -3
View File
@@ -1,4 +1,10 @@
0261 (3.3.4 or 3.4)
X redo console handling to not use Timer, fixing freeze-up problems
o https://github.com/processing/processing/pull/4935
X https://github.com/processing/processing/issues/4825
_ should ant run launch the .app so that launchsvcs stuff works properly?
_ sketch.properties not being written if initial mode is p5.js?
_ what to double-click when opening p5 projects
@@ -39,9 +45,6 @@ _ super easy given current code implementation, might help usability
contrib
_ redo console handling to not use Timer, fixing freeze-up problems
_ https://github.com/processing/processing/pull/4935
_ https://github.com/processing/processing/issues/4825
_ Make the change detector not reload the sketch
_ https://github.com/processing/processing/pull/5021
_ https://github.com/processing/processing/issues/4713