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;
|
package dorkbox.executor;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.FileDescriptor;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FilterInputStream;
|
import java.io.FilterInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import dorkbox.console.Console;
|
import dorkbox.console.Console;
|
||||||
import dorkbox.console.input.Terminal;
|
|
||||||
|
|
||||||
public
|
public
|
||||||
class ProcessProxy extends Thread {
|
class ProcessStreamProxy extends Thread {
|
||||||
|
|
||||||
private final InputStream is;
|
private final InputStream is;
|
||||||
private final OutputStream os;
|
private final OutputStream os;
|
||||||
|
|
||||||
private final boolean isSystemIn;
|
|
||||||
|
|
||||||
private final CountDownLatch startUpLatch = new CountDownLatch(1);
|
private final CountDownLatch startUpLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch shutDownLatch = new CountDownLatch(1);
|
private final CountDownLatch shutDownLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
// when reading from the stdin and outputting to the process
|
// when reading from the stdin and outputting to the process
|
||||||
public
|
public
|
||||||
ProcessProxy(String processName, InputStream inputStreamFromConsole, OutputStream outputStreamToProcess) {
|
ProcessStreamProxy(String processName, InputStream inputStreamFromConsole, OutputStream outputStreamToProcess) {
|
||||||
boolean isSystemIn = false;
|
|
||||||
|
|
||||||
// basic check to see if we are System.in
|
// basic check to see if we are System.in
|
||||||
if (inputStreamFromConsole.equals(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 {
|
try {
|
||||||
Field in = FilterInputStream.class.getDeclaredField("in");
|
Field in = FilterInputStream.class.getDeclaredField("in");
|
||||||
in.setAccessible(true);
|
in.setAccessible(true);
|
||||||
|
@ -59,17 +53,14 @@ class ProcessProxy extends Thread {
|
||||||
unwrapped = in.get(unwrapped);
|
unwrapped = in.get(unwrapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
isSystemIn = unwrapped instanceof FileInputStream;
|
if (unwrapped instanceof FileInputStream && ((FileInputStream) unwrapped).getFD().equals(FileDescriptor.in)) {
|
||||||
if (isSystemIn) {
|
// 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 = (InputStream) unwrapped;
|
inputStreamFromConsole = Console.inputStream();
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} 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.is = inputStreamFromConsole;
|
||||||
this.os = outputStreamToProcess;
|
this.os = outputStreamToProcess;
|
||||||
|
|
||||||
|
@ -95,9 +86,14 @@ class ProcessProxy extends Thread {
|
||||||
|
|
||||||
public
|
public
|
||||||
void close() {
|
void close() {
|
||||||
// this.interrupt();
|
|
||||||
running.set(false);
|
running.set(false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
shutDownLatch.await();
|
shutDownLatch.await();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
@ -105,101 +101,44 @@ class ProcessProxy extends Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
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);
|
running.set(true);
|
||||||
|
|
||||||
final OutputStream os = this.os;
|
|
||||||
// final BufferedReader reader = this.reader;
|
|
||||||
final long timeout = 200L;
|
|
||||||
|
|
||||||
startUpLatch.countDown();
|
startUpLatch.countDown();
|
||||||
|
|
||||||
|
|
||||||
|
final InputStream is = this.is;
|
||||||
|
final OutputStream os = this.os;
|
||||||
|
int readInt;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// this thread will read until there is no more data to read. (this is generally what you want)
|
// 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)
|
// the stream will be closed when the process closes it (usually on exit)
|
||||||
int readInt;
|
|
||||||
|
|
||||||
if (os == null) {
|
if (os == null) {
|
||||||
while (!reader.ready()) {
|
//noinspection StatementWithEmptyBody
|
||||||
Thread.sleep(timeout);
|
while (is.read() != -1 && running.get()) {
|
||||||
|
// just read so it won't block or backup.
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// just read so it won't block.
|
|
||||||
reader.readLine();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
while (running.get()) {
|
while ((readInt = is.read()) != -1 && running.get()) {
|
||||||
try {
|
os.write(readInt);
|
||||||
while (!reader.ready()) {
|
|
||||||
Thread.sleep(timeout);
|
|
||||||
|
|
||||||
if (!running.get()) {
|
// flush the output on new line. (same for both windows '\r\n' and linux '\n')
|
||||||
if (isSystemIn) {
|
if (readInt == '\n') {
|
||||||
System.err.println("DONE sysin " + this);
|
os.flush();
|
||||||
// should attempt to process anything more.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// should process whatever is left.
|
synchronized (os) {
|
||||||
System.err.println("DONE a " + this);
|
os.notifyAll();
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignored) {
|
||||||
ignore.printStackTrace();
|
|
||||||
} finally {
|
} finally {
|
||||||
System.err.println("DONE c " + this);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// this.reader.close();
|
// this.reader.close();
|
||||||
if (os != null) {
|
if (os != null) {
|
Loading…
Reference in New Issue
Block a user