/* * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
inputWriter = new PrintWriter(jdb.getOutputStream(), true);
} catch (Throwable ex) { // terminate jdb if something went wrong
jdb.destroy(); throw ex;
}
}
privatefinal Process jdb; privatefinal OutputHandler outputHandler = new OutputHandler(); privatefinal PrintWriter inputWriter; privatefinal List<String> jdbOutput = new LinkedList<>();
privatestaticfinal String lineSeparator = System.getProperty("line.separator"); // wait time before check jdb output (in ms) privatestaticfinallong sleepTime = 1000; // max time to wait for jdb output (in ms) privatestaticfinallong timeout = Utils.adjustTimeout(60000);
// pattern for message of a breakpoint hit publicstaticfinal String BREAKPOINT_HIT = "Breakpoint hit:"; // pattern for message of an application exit publicstaticfinal String APPLICATION_EXIT = "The application exited"; // pattern for message of an application disconnect publicstaticfinal String APPLICATION_DISCONNECTED = "The application has been disconnected";
// waits until the process shutdown or crash publicboolean waitFor(long timeout, TimeUnit unit) { try { return jdb.waitFor(Utils.adjustTimeout(timeout), unit);
} catch (InterruptedException e) { returnfalse;
}
}
publicvoid shutdown() { // shutdown jdb if (jdb.isAlive()) { try {
quit(); // wait some time after the command for the process termination
waitFor(10, TimeUnit.SECONDS);
} finally { if (jdb.isAlive()) {
jdb.destroy();
}
}
}
}
// waits until string {@pattern} appears in the jdb output, within the last {@code lines} lines. /* Comment from original /test/jdk/com/sun/jdi/ShellScaffold.sh # Now we have to wait for the next jdb prompt. We wait for a pattern # to appear in the last line of jdb output. Normally, the prompt is # # 1) ^main[89] @ # or # 1) ^[89] @ # for virtual threads # # where ^ means start of line, and @ means end of file with no end of line # and 89 is the current command counter. But we have complications e.g., # the following jdb output can appear: # # 2) a[89] = 10 # # The above form is an array assignment and not a prompt. # # 3) ^main[89] main[89] ... # # This occurs if the next cmd is one that causes no jdb output, e.g., # 'trace methods'. # # 4) ^main[89] [main[89]] .... > @ # # jdb prints a > as a prompt after something like a cont. # Thus, even though the above is the last 'line' in the file, it # isn't the next prompt we are waiting for after the cont completes. # HOWEVER, sometimes we see this for a cont command: # # ^main[89] $ # <lines output for hitting a bkpt> # # 5) ^main[89] > @ # # i.e., the > prompt comes out AFTER the prompt we we need to wait for.
*/ // compile regexp once privatefinalstatic String promptPattern = "[a-zA-Z0-9_-]*>?\\[[1-9][0-9]*\\] [ >]*$"; finalstatic Pattern PROMPT_REGEXP = Pattern.compile(promptPattern);
// jdb prompt when debuggee is not started and is not suspended after breakpoint privatestaticfinal String SIMPLE_PROMPT = "> "; public List<String> waitForSimplePrompt(int lines, boolean allowExit) { return waitForPrompt(lines, allowExit, Pattern.compile(SIMPLE_PROMPT));
}
private List<String> waitForPrompt(int lines, boolean allowExit, Pattern promptRegexp) { long startTime = System.currentTimeMillis(); while (System.currentTimeMillis() - startTime < timeout) { try { Thread.sleep(sleepTime);
} catch (InterruptedException e) { // ignore
} synchronized (outputHandler) { if (!outputHandler.updated()) { try {
outputHandler.wait(sleepTime);
} catch (InterruptedException e) { // ignore
}
} else { // if something appeared in the jdb output, reset the timeout
startTime = System.currentTimeMillis();
}
}
List<String> reply = outputHandler.get(); if ((promptRegexp.flags() & Pattern.MULTILINE) > 0) {
String replyString = reply.stream().collect(Collectors.joining(lineSeparator)); if (promptRegexp.matcher(replyString).find()) {
logJdb(reply); return outputHandler.reset();
}
} else { for (String line : reply.subList(Math.max(0, reply.size() - lines), reply.size())) { if (promptRegexp.matcher(line).find()) {
logJdb(reply); return outputHandler.reset();
}
}
} if (!jdb.isAlive()) { // ensure we get the whole output
reply = outputHandler.reset();
logJdb(reply); if (!allowExit) { thrownew RuntimeException("waitForPrompt timed out after " + (timeout/1000)
+ " seconds, looking for '" + promptRegexp.pattern() + "', in " + lines + " lines");
} return reply;
}
} // timeout
logJdb(outputHandler.get()); thrownew RuntimeException("waitForPrompt timed out after " + (timeout/1000)
+ " seconds, looking for '" + promptRegexp.pattern() + "', in " + lines + " lines");
}
public List<String> command(JdbCommand cmd) { if (!jdb.isAlive()) { if (cmd.allowExit) { // return remaining output return outputHandler.reset();
} thrownew RuntimeException("Attempt to send command '" + cmd.cmd + "' to terminated jdb");
}
log("> " + cmd.cmd);
inputWriter.println(cmd.cmd);
if (inputWriter.checkError()) { thrownew RuntimeException("Unexpected IO error while writing command '" + cmd.cmd + "' to jdb stdin stream");
}
// returns the whole jdb output as a string public String getJdbOutput() { return jdbOutput.stream().collect(Collectors.joining(lineSeparator));
}
// handler for out/err of the pdb process privateclass OutputHandler extends OutputStream { // there are 2 buffers: // outStream - data from the process stdout/stderr after last get() call // cachedData - data collected at get(), cleared by reset()
privatefinal ByteArrayOutputStream outStream = new ByteArrayOutputStream(); // if the last line in the reply had EOL, the list's last element is empty privatefinal List<String> cachedData = new ArrayList<>();
@Override publicsynchronizedvoid write(int b) throws IOException {
outStream.write((byte)(b & 0xFF));
notifyAll();
}
@Override publicsynchronizedvoid write(byte b[], int off, int len) throws IOException {
outStream.write(b, off, len);
notifyAll();
}
// gets output after the last {@ reset}. // returned data becomes invalid after {@reset}. publicsynchronized List<String> get() { if (updated()) { // we don't want to discard empty lines
String[] newLines = outStream.toString().split("\\R", -1); if (!cachedData.isEmpty()) { // concat the last line if previous data had no EOL
newLines[0] = cachedData.remove(cachedData.size()-1) + newLines[0];
}
cachedData.addAll(Arrays.asList(newLines));
outStream.reset();
} return Collections.unmodifiableList(cachedData);
}
// clears last replay (does not touch replyStream) // returns list as the last get() publicsynchronized List<String> reset() {
List<String> result = new ArrayList<>(cachedData);
cachedData.clear(); return result;
}
// tests if there are some new data after the last lastReply() call publicsynchronizedboolean updated() { return outStream.size() > 0;
}
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.