Skip to content
Snippets Groups Projects
Unverified Commit 0b26e374 authored by Anton Georgiev's avatar Anton Georgiev Committed by GitHub
Browse files

Merge pull request #12842 from defnull/v2.3.x-release

fix(common-web): Sub-processes hang if output buffers fill up
parents b54e4a6c 500a1e6f
No related branches found
No related tags found
No related merge requests found
...@@ -19,66 +19,76 @@ ...@@ -19,66 +19,76 @@
package org.bigbluebutton.presentation.imp; package org.bigbluebutton.presentation.imp;
import java.util.Timer; import java.io.File;
import java.util.TimerTask; import java.io.IOException;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* A wrapper class the executes an external command. * A wrapper class the executes an external command.
*
* See http://kylecartmell.com/?p=9
* *
* @author Richard Alam * @author Richard Alam
* * @author Marcel Hellkamp
*/ */
public class ExternalProcessExecutor { public class ExternalProcessExecutor {
private static Logger log = LoggerFactory.getLogger(ExternalProcessExecutor.class); private static Logger log = LoggerFactory.getLogger(ExternalProcessExecutor.class);
// Replace with ProcessBuilder.Redirect.DISCARD in java 9+
public boolean exec(String COMMAND, long timeoutMillis) { private static File DISCARD = new File(
Timer timer = new Timer(false); System.getProperty("os.name").startsWith("Windows") ? "NUL" : "/dev/null");
Process p = null;
try {
InterruptTimerTask interrupter = new InterruptTimerTask(Thread.currentThread());
timer.schedule(interrupter, timeoutMillis);
p = Runtime.getRuntime().exec(COMMAND);
int result = p.waitFor();
if (result == 0) {
return true;
} else {
return false;
}
} catch(Exception e) { /**
log.info("TIMEDOUT excuting : {}", COMMAND); * Run COMMAND for at most timeoutMillis while ignoring any output.
if (p != null) { *
p.destroy(); * @deprecated The COMMAND string is split on whitespace to create an argument
} * list. This won't work for arguments that contain whitespace. Use
} finally { * {@link #exec(List, Duration)} instead.
timer.cancel(); // If the process returns within the timeout period, we have to stop the interrupter *
// so that it does not unexpectedly interrupt some other code later. * @param COMMAND A single command or whitespace separated list of
* arguments.
Thread.interrupted(); // We need to clear the interrupt flag on the current thread just in case * @param timeoutMillis Timeout in milliseconds.
// interrupter executed after waitFor had already returned but before timer.cancel * @return true if the command terminated in time with an exit value of 0.
// took effect. */
// @Deprecated
// Oh, and there's also Sun bug 6420270 to worry about here. public boolean exec(String COMMAND, long timeoutMillis) {
} return exec(Arrays.asList(COMMAND.split("[ \\t\\n\\r\\f]+")), Duration.ofMillis(timeoutMillis));
return false;
} }
class InterruptTimerTask extends TimerTask { /**
private Thread thread; * Run a command for a limited amount of time while ignoring any output.
*
* @param cmd List containing the program and its arguments.
* @param timeout Maximum execution time.
* @return true if the command terminated in time with an exit value of 0.
*/
public boolean exec(List<String> cmd, Duration timeout) {
public InterruptTimerTask(Thread t) { ProcessBuilder pb = new ProcessBuilder(cmd);
this.thread = t; pb.redirectError(DISCARD);
} pb.redirectOutput(DISCARD);
public void run() { Process proc;
thread.interrupt(); try {
} proc = pb.start();
} catch (IOException e) {
log.error("Failed to execute: {}", String.join(" ", cmd), e);
return false;
}
try {
if (!proc.waitFor(timeout.toMillis(), TimeUnit.MILLISECONDS)) {
log.warn("TIMEDOUT excuting: {}", String.join(" ", cmd));
proc.destroy();
}
return !proc.isAlive() && proc.exitValue() == 0;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
proc.destroy();
return false;
}
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment