Fixed issues with reading from System.in and blocking reads.
This commit is contained in:
parent
d9b565edde
commit
ee968be141
|
@ -15,40 +15,34 @@
|
|||
*/
|
||||
package dorkbox.executor;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import dorkbox.console.Console;
|
||||
import dorkbox.console.input.Terminal;
|
||||
|
||||
public
|
||||
class ProcessProxy extends Thread {
|
||||
class ProcessStreamProxy extends Thread {
|
||||
|
||||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
|
||||
private final boolean isSystemIn;
|
||||
|
||||
private final CountDownLatch startUpLatch = new CountDownLatch(1);
|
||||
private final CountDownLatch shutDownLatch = new CountDownLatch(1);
|
||||
|
||||
// when reading from the stdin and outputting to the process
|
||||
public
|
||||
ProcessProxy(String processName, InputStream inputStreamFromConsole, OutputStream outputStreamToProcess) {
|
||||
boolean isSystemIn = false;
|
||||
|
||||
ProcessStreamProxy(String processName, InputStream inputStreamFromConsole, OutputStream outputStreamToProcess) {
|
||||
// basic check to see if we are System.in
|
||||
if (inputStreamFromConsole.equals(System.in)) {
|
||||
|
||||
// more exact check: basically unwrap everything and see if it's a FileInputStream
|
||||
// more exact check: basically unwrap everything and see if it's a FileInputStream (which it should be)
|
||||
try {
|
||||
Field in = FilterInputStream.class.getDeclaredField("in");
|
||||
in.setAccessible(true);
|
||||
|
@ -59,17 +53,14 @@ class ProcessProxy extends Thread {
|
|||
unwrapped = in.get(unwrapped);
|
||||
}
|
||||
|
||||
isSystemIn = unwrapped instanceof FileInputStream;
|
||||
if (isSystemIn) {
|
||||
inputStreamFromConsole = (InputStream) unwrapped;
|
||||
if (unwrapped instanceof FileInputStream && ((FileInputStream) unwrapped).getFD().equals(FileDescriptor.in)) {
|
||||
// if we are actually System.in, we want to use the Console.in INSTEAD, because it will let us do things we could otherwise not do.
|
||||
inputStreamFromConsole = Console.inputStream();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
// if we are actually System.in, we want to use the Console.in INSTEAD, because it will let us do things we could otherwise not do.
|
||||
this.isSystemIn = isSystemIn;
|
||||
|
||||
this.is = inputStreamFromConsole;
|
||||
this.os = outputStreamToProcess;
|
||||
|
||||
|
@ -95,9 +86,14 @@ class ProcessProxy extends Thread {
|
|||
|
||||
public
|
||||
void close() {
|
||||
// this.interrupt();
|
||||
running.set(false);
|
||||
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
shutDownLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
|
@ -105,101 +101,44 @@ class ProcessProxy extends Thread {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
// if we are system in, we can ONLY read the line input, unless the Console project is present!
|
||||
if (isSystemIn) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// we rely on buferredReader.ready(), so that we can know if there is input or not (and read/block/etc if necessary)
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(this.is));
|
||||
|
||||
|
||||
Terminal in = Console.in();
|
||||
|
||||
|
||||
|
||||
running.set(true);
|
||||
|
||||
final OutputStream os = this.os;
|
||||
// final BufferedReader reader = this.reader;
|
||||
final long timeout = 200L;
|
||||
|
||||
startUpLatch.countDown();
|
||||
|
||||
|
||||
final InputStream is = this.is;
|
||||
final OutputStream os = this.os;
|
||||
int readInt;
|
||||
|
||||
try {
|
||||
// this thread will read until there is no more data to read. (this is generally what you want)
|
||||
// the stream will be closed when the process closes it (usually on exit)
|
||||
int readInt;
|
||||
|
||||
if (os == null) {
|
||||
while (!reader.ready()) {
|
||||
Thread.sleep(timeout);
|
||||
|
||||
if (!running.get()) {
|
||||
if (isSystemIn) {
|
||||
System.err.println("DONE sysin " + this);
|
||||
// should attempt to process anything more.
|
||||
return;
|
||||
}
|
||||
|
||||
// should process whatever is left.
|
||||
System.err.println("DONE a " + this);
|
||||
break;
|
||||
}
|
||||
//noinspection StatementWithEmptyBody
|
||||
while (is.read() != -1 && running.get()) {
|
||||
// just read so it won't block or backup.
|
||||
}
|
||||
|
||||
// just read so it won't block.
|
||||
reader.readLine();
|
||||
}
|
||||
else {
|
||||
while (running.get()) {
|
||||
try {
|
||||
while (!reader.ready()) {
|
||||
Thread.sleep(timeout);
|
||||
while ((readInt = is.read()) != -1 && running.get()) {
|
||||
os.write(readInt);
|
||||
|
||||
if (!running.get()) {
|
||||
if (isSystemIn) {
|
||||
System.err.println("DONE sysin " + this);
|
||||
// should attempt to process anything more.
|
||||
return;
|
||||
}
|
||||
// flush the output on new line. (same for both windows '\r\n' and linux '\n')
|
||||
if (readInt == '\n') {
|
||||
os.flush();
|
||||
|
||||
// should process whatever is left.
|
||||
System.err.println("DONE a " + this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
|
||||
|
||||
while ((readInt = reader.read()) != -1) {
|
||||
System.err.println(".");
|
||||
os.write(readInt);
|
||||
|
||||
// flush the output on new line. (same for both windows '\r\n' and linux '\n')
|
||||
if (readInt == '\n') {
|
||||
os.flush();
|
||||
|
||||
synchronized (os) {
|
||||
os.notifyAll();
|
||||
}
|
||||
synchronized (os) {
|
||||
os.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
ignore.printStackTrace();
|
||||
} catch (Exception ignored) {
|
||||
} finally {
|
||||
System.err.println("DONE c " + this);
|
||||
|
||||
try {
|
||||
// this.reader.close();
|
||||
if (os != null) {
|
Loading…
Reference in New Issue