blob: 34caa9ac7820750aba15aae5fd60cd540a415c2a [file] [log] [blame]
package org.eclipse.cdt.internal.core;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
/**
* Bundled state of a launched process including the threads linking the process in/output
* to console documents.
*/
public class ProcessClosure {
/**
* Thread which continuously reads from a input stream and pushes the read data
* to an output stream which is immediately flushed afterwards.
*/
protected static class ReaderThread extends Thread {
private InputStream fInputStream;
private OutputStream fOutputStream;
private boolean fFinished = false;
private String lineSeparator;
/*
* outputStream can be null
*/
public ReaderThread(ThreadGroup group, String name, InputStream in, OutputStream out) {
super(group, name);
fOutputStream= out;
fInputStream= in;
setDaemon(true);
lineSeparator = (String) System.getProperty("line.separator");
}
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(fInputStream));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fOutputStream));
String line;
while ((line = reader.readLine()) != null) {
line += lineSeparator;
char[] array = line.toCharArray();
writer.write(array, 0, array.length);
writer.flush();
}
} catch (IOException x) {
// ignore
} finally {
try {
fInputStream.close();
} catch (IOException e) {
// ignore
}
try {
fOutputStream.close();
} catch (IOException e) {
// ignore
}
complete();
}
}
public synchronized boolean finished() {
return fFinished;
}
public synchronized void waitFor() {
while (!fFinished) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
public synchronized void complete() {
fFinished = true;
notify();
}
}
protected static int fCounter= 0;
protected Process fProcess;
protected OutputStream fOutput;
protected OutputStream fError;
protected ReaderThread fOutputReader;
protected ReaderThread fErrorReader;
/**
* Creates a process closure and connects the launched process with
* a console document.
* @param outputStream prcess stdout is written to this stream. Can be <code>null</code>, if
* not interested in reading the output
* @param errorStream prcess stderr is written to this stream. Can be <code>null</code>, if
* not interested in reading the output
*/
public ProcessClosure(Process process, OutputStream outputStream, OutputStream errorStream) {
fProcess= process;
fOutput= outputStream;
fError= errorStream;
}
/**
* Live links the launched process with the configured in/out streams using
* reader threads.
*/
public void runNonBlocking() {
ThreadGroup group= new ThreadGroup("CBuilder" + fCounter++);
InputStream stdin= fProcess.getInputStream();
InputStream stderr= fProcess.getErrorStream();
fOutputReader= new ReaderThread(group, "OutputReader", stdin, fOutput);
fErrorReader= new ReaderThread(group, "ErrorReader", stderr, fError);
fOutputReader.start();
fErrorReader.start();
}
public void runBlocking() {
runNonBlocking();
boolean finished = false;
while (!finished) {
try {
fProcess.waitFor();
} catch (InterruptedException e) {
//System.err.println("Closure exception " +e);
}
try {
fProcess.exitValue();
finished = true;
} catch (IllegalThreadStateException e) {
//System.err.println("Closure exception " +e);
}
}
// @@@FIXME: Windows 2000 is screwed; double-check using output threads
if (!fOutputReader.finished()) {
fOutputReader.waitFor();
}
if (!fErrorReader.finished()) {
fErrorReader.waitFor();
}
// it seems that thread termination and stream closing is working without
// any help
fProcess= null;
fOutputReader= null;
fErrorReader= null;
}
public boolean isAlive() {
if (fProcess != null) {
if (fOutputReader.isAlive() || fErrorReader.isAlive()) {
return true;
} else {
fProcess= null;
fOutputReader= null;
fErrorReader= null;
}
}
return false;
}
/**
* Forces the termination the launched process
*/
public void terminate() {
if (fProcess != null) {
fProcess.destroy();
fProcess= null;
}
}
}