From 34a34c9e1d6002300a30d9d939d93a2d313743f5 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Tue, 17 Nov 2015 20:05:31 +0300 Subject: [PATCH] util: redirect stderr to stdout to spawn fewer threads; reuse BaseOutputReader (IDEA-CR-6825) --- .../src/com/intellij/util/EnvironmentUtil.java | 81 +++++++--------------- 1 file changed, 24 insertions(+), 57 deletions(-) diff --git a/platform/util/src/com/intellij/util/EnvironmentUtil.java b/platform/util/src/com/intellij/util/EnvironmentUtil.java index 089e230..e3aec2e 100644 --- a/platform/util/src/com/intellij/util/EnvironmentUtil.java +++ b/platform/util/src/com/intellij/util/EnvironmentUtil.java @@ -26,6 +26,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.concurrency.FixedFuture; +import com.intellij.util.io.BaseOutputReader; import com.intellij.util.text.CaseInsensitiveStringHashingStrategy; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; @@ -167,17 +168,17 @@ public class EnvironmentUtil { String[] command = {shell, "-l", "-i", "-c", ("'" + reader.getAbsolutePath() + "' '" + envFile.getAbsolutePath() + "'")}; LOG.info("loading shell env: " + StringUtil.join(command, " ")); - Process process = Runtime.getRuntime().exec(command); - StreamGobbler stdoutGobbler = new StreamGobbler(process.getInputStream(), "stdout"); - stdoutGobbler.start(); - StreamGobbler stderrGobbler = new StreamGobbler(process.getErrorStream(), "stderr"); - stderrGobbler.start(); + ProcessBuilder processBuilder = new ProcessBuilder(command); + processBuilder.redirectErrorStream(true); + Process process = processBuilder.start(); + + StreamGobbler gobbler = new StreamGobbler(process.getInputStream()); int rv = waitAndTerminateAfter(process, SHELL_ENV_READING_TIMEOUT); - stdoutGobbler.logIfNotEmpty(); - stderrGobbler.logIfNotEmpty(); + gobbler.stop(); String lines = FileUtil.loadFile(envFile); if (rv != 0 || lines.isEmpty()) { + LOG.info("shell process output: " + StringUtil.trimEnd(gobbler.getText(), '\n')); throw new Exception("rv:" + rv + " text:" + lines.length()); } return parseEnv(lines); @@ -300,67 +301,33 @@ public class EnvironmentUtil { } } - private static class StreamGobbler implements Runnable { - private final BufferedReader myReader; - private final String myStreamType; - private final StringBuffer myBuffer = new StringBuffer(); - private final Semaphore myFinishSemaphore = new Semaphore(0); + private static class StreamGobbler extends BaseOutputReader { - public StreamGobbler(@NotNull InputStream stream, @NotNull String streamType) { - myReader = new BufferedReader(new InputStreamReader(stream)); - myStreamType = streamType; - } + private final StringBuffer myBuffer; - public void start() { - Thread thread = new Thread(this, "shell process " + myStreamType + " reader"); - thread.start(); + public StreamGobbler(@NotNull InputStream stream) { + super(stream, CharsetToolkit.getDefaultSystemCharset()); + myBuffer = new StringBuffer(); + start("stdout/stderr streams of shell env loading process"); } + @NotNull @Override - public void run() { - int ch; - try { - while ((ch = myReader.read()) != -1) { - myBuffer.append((char)ch); - } - } - catch (IOException e) { - LOG.warn("Error reading shell process " + myStreamType, e); - } - finally { - myFinishSemaphore.release(1); - close(); - } + protected Future executeOnPooledThread(@NotNull Runnable runnable) { + ExecutorService executor = ConcurrencyUtil.newSingleThreadExecutor("shell process streams gobbler"); + Future future = executor.submit(runnable); + executor.shutdown(); + return future; } - private void close() { - try { - myReader.close(); - } - catch (IOException e) { - LOG.warn("Error closing shell process " + myStreamType, e); - } + @Override + protected void onTextAvailable(@NotNull String text) { + myBuffer.append(text); } @NotNull - private String getText() { - try { - if (!myFinishSemaphore.tryAcquire(1, 2, TimeUnit.SECONDS)) { - LOG.warn("closing shell process " + myStreamType + " forcibly"); - close(); - } - } - catch (InterruptedException e) { - LOG.info(e); - } + public String getText() { return myBuffer.toString(); } - - public void logIfNotEmpty() { - String text = getText(); - if (!text.isEmpty()) { - LOG.info("shell process " + myStreamType + ":" + StringUtil.trimEnd(text, '\n')); - } - } } } -- 1.8.2.1