From ee968be141f92b43f5ed6ec8ece3f5adfc2fd6e6 Mon Sep 17 00:00:00 2001 From: nathan Date: Tue, 28 Nov 2017 21:07:11 +0100 Subject: [PATCH] Fixed issues with reading from System.in and blocking reads. --- ...cessProxy.java => ProcessStreamProxy.java} | 121 +++++------------- 1 file changed, 30 insertions(+), 91 deletions(-) rename src/dorkbox/executor/{ProcessProxy.java => ProcessStreamProxy.java} (51%) diff --git a/src/dorkbox/executor/ProcessProxy.java b/src/dorkbox/executor/ProcessStreamProxy.java similarity index 51% rename from src/dorkbox/executor/ProcessProxy.java rename to src/dorkbox/executor/ProcessStreamProxy.java index 6e433de..9373278 100644 --- a/src/dorkbox/executor/ProcessProxy.java +++ b/src/dorkbox/executor/ProcessStreamProxy.java @@ -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) {