Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java89
1 files changed, 87 insertions, 2 deletions
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java
index 330e661e4..3a1ae19a0 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java
@@ -17,10 +17,13 @@ package org.eclipse.debug.internal.core;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IStreamListener;
import org.eclipse.debug.core.model.IFlushableStreamMonitor;
@@ -33,6 +36,19 @@ import org.eclipse.debug.core.model.IFlushableStreamMonitor;
* and input stream.
*/
public class OutputStreamMonitor implements IFlushableStreamMonitor {
+
+ /**
+ * VM property which indicates maximum wait time (in milliseconds) for
+ * reading to finish, when calling {@link #getContents()}.
+ */
+ private static final String MAX_WAIT_TIME_FOR_STREAM_READING_PROPERTY = "org.eclipse.debug.core.msMaxWaitTimeForStreamMonitorReading"; //$NON-NLS-1$
+
+ /**
+ * Wait max n milliseconds for the thread to finish reading when calling
+ * {@link #getContents()}.
+ */
+ private static final long MAX_WAIT_TIME_FOR_STREAM_READING = maxWaitTimeForStreamReading();
+
/**
* The stream being monitored (connected system out or err).
*/
@@ -70,11 +86,19 @@ public class OutputStreamMonitor implements IFlushableStreamMonitor {
*/
private boolean fKilled= false;
- private long lastSleep;
+ /**
+ * Last time we've read something from the stream
+ */
+ private long lastSleep;
private String fEncoding;
/**
+ * Indicates whether the monitor is done reading from the stream.
+ */
+ private final AtomicBoolean fReadingDone;
+
+ /**
* Creates an output stream monitor on the
* given stream (connected to system out or err).
*
@@ -85,6 +109,7 @@ public class OutputStreamMonitor implements IFlushableStreamMonitor {
fStream = new BufferedInputStream(stream, 8192);
fEncoding = encoding;
fContents= new StringBuilder();
+ fReadingDone = new AtomicBoolean(false);
}
/* (non-Javadoc)
@@ -126,9 +151,22 @@ public class OutputStreamMonitor implements IFlushableStreamMonitor {
*/
@Override
public synchronized String getContents() {
+ boolean doneReading = waitForReadingToFinish(MAX_WAIT_TIME_FOR_STREAM_READING);
+ if (!doneReading) {
+ logWarning("OutputStreamMonitor::startMonitoring() was unable to start reading stream after " + MAX_WAIT_TIME_FOR_STREAM_READING + " ms."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
return fContents.toString();
}
+ private void read() {
+ fReadingDone.set(false);
+ try {
+ readInternal();
+ } finally {
+ fReadingDone.set(true);
+ }
+ }
+
/**
* Continually reads from the stream.
* <p>
@@ -137,7 +175,7 @@ public class OutputStreamMonitor implements IFlushableStreamMonitor {
* to implement <code>Runnable</code> without publicly
* exposing a <code>run</code> method.
*/
- private void read() {
+ private void readInternal() {
lastSleep = System.currentTimeMillis();
long currentTime = lastSleep;
byte[] bytes= new byte[BUFFER_SIZE];
@@ -244,6 +282,53 @@ public class OutputStreamMonitor implements IFlushableStreamMonitor {
return new ContentNotifier();
}
+ /**
+ * Blocking call to make sure the stream reading thread is done (and so
+ * {@link #readInternal()} was called).
+ *
+ * @param timeout max time to wait for reading the entire stream
+ *
+ * @return {@code true} if the stream reading is done
+ */
+ protected boolean waitForReadingToFinish(long timeout) {
+ final long start = System.currentTimeMillis();
+ while (!fReadingDone.get() && System.currentTimeMillis() - start < timeout) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ break;
+ }
+ }
+ return fReadingDone.get();
+ }
+
+ private static long maxWaitTimeForStreamReading() {
+ long maxTime = 10_000;
+ String systemPropertyValue = System.getProperty(MAX_WAIT_TIME_FOR_STREAM_READING_PROPERTY);
+ if (systemPropertyValue != null) {
+ try {
+ maxTime = Long.parseLong(systemPropertyValue);
+ } catch (NumberFormatException e) {
+ logError("Failed to read default value for max stream monitor read time: " + MAX_WAIT_TIME_FOR_STREAM_READING_PROPERTY, e); //$NON-NLS-1$
+ }
+ }
+ return maxTime;
+ }
+
+ private static void logWarning(String warningMessage) {
+ log(IStatus.WARNING, warningMessage, null);
+ }
+
+ private static void logError(String errorMessage, Exception e) {
+ log(IStatus.ERROR, errorMessage, e);
+ }
+
+ private static void log(int statusCode, String errorMessage, Exception e) {
+ IStatus errorStatus = new Status(statusCode, DebugPlugin.getUniqueIdentifier(), errorMessage, e);
+ DebugPlugin.log(errorStatus);
+ }
+
class ContentNotifier implements ISafeRunnable {
private IStreamListener fListener;

Back to the top