diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java index 793c65dbafdf21ccbce6b88a4fc868c5d56baa8e..804c838232cb4569c843cd91ed9a93e941624491 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java @@ -27,6 +27,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.file.FileSystems; import java.nio.file.Path; +import java.util.concurrent.TimeUnit; import com.oracle.truffle.r.runtime.REnvVars; import com.oracle.truffle.r.runtime.RVersionNumber; @@ -50,6 +51,8 @@ public class GnuROneShotRSession implements RSession { private static final String[] GNUR_COMMANDLINE = new String[]{"R", "--vanilla", "--slave", "--silent"}; private static final String FASTR_TESTGEN_GNUR = "FASTR_TESTGEN_GNUR"; private static final String NATIVE_PROJECT = "com.oracle.truffle.r.native"; + private static final int DEFAULT_TIMEOUT_MINS = 5; + private static int timeoutMins = DEFAULT_TIMEOUT_MINS; //@formatter:off protected static final String GNUR_OPTIONS = @@ -65,6 +68,14 @@ public class GnuROneShotRSession implements RSession { protected static byte[] QUIT = "q()\n".getBytes(); protected Process createGnuR() throws IOException { + String timeout = System.getenv("FASTR_TESTGEN_TIMEOUT"); + if (timeout != null) { + try { + timeoutMins = Integer.parseInt(timeout); + } catch (NumberFormatException ex) { + System.err.println("ignoring invalid value for FASTR_TESTGEN_TIMEOUT"); + } + } String testGenGnuR = System.getenv(FASTR_TESTGEN_GNUR); if (testGenGnuR != null) { if (testGenGnuR.length() == 0 || testGenGnuR.equals("internal")) { @@ -93,24 +104,21 @@ public class GnuROneShotRSession implements RSession { } @Override - public String eval(String expression, ContextInfo contextInfo, boolean longTimeout) { + public String eval(String expression, ContextInfo contextInfo, boolean longTimeout) throws Throwable { if (expression.contains("library(") && !TestBase.generatingExpected()) { System.out.println("=============================================="); System.out.println("LIBRARY LOADING WHILE CREATING EXPECTED OUTPUT"); System.out.println("creating expected output for these tests only works during test output"); System.out.println("generation (mx rtestgen), and will otherwise create corrupted output."); } - try { - Process p = createGnuR(); - InputStream gnuRoutput = p.getInputStream(); - OutputStream gnuRinput = p.getOutputStream(); - send(gnuRinput, expression.getBytes(), NL, QUIT); - p.waitFor(); - return readAvailable(gnuRoutput); - } catch (IOException | InterruptedException ex) { - System.err.print("exception: " + ex); - return null; + Process p = createGnuR(); + InputStream gnuRoutput = p.getInputStream(); + OutputStream gnuRinput = p.getOutputStream(); + send(gnuRinput, expression.getBytes(), NL, QUIT); + if (!p.waitFor(timeoutMins, TimeUnit.MINUTES)) { + throw new RuntimeException(String.format("GNU R process timed out on: '%s'\n", expression)); } + return readAvailable(gnuRoutput); } protected void send(OutputStream gnuRinput, byte[]... data) throws IOException { @@ -125,8 +133,4 @@ public class GnuROneShotRSession implements RSession { return "GnuR one-shot"; } - public static void main(String[] args) { - String testGenGnuR = System.getenv(FASTR_TESTGEN_GNUR); - System.out.printf("%s='%s'%n", FASTR_TESTGEN_GNUR, testGenGnuR); - } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java index e42c022411ae2fccc7273fc42ac9d5be625249ff..954a0b268d3a2eb928b8ac6d781caea86e670596 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java @@ -34,6 +34,9 @@ public interface RSession { * If {@code contextInfo is non-null} it is used for the evaluation, else the choice is left to * the implementation. If the implementation uses timeouts, {@code longTimeout} indicates that * this evaluation is expected to take (much) longer than normal. + * + * This result will always be non-null or an exception will be thrown in, say, a timeout + * occurring. */ String eval(String expression, ContextInfo contextInfo, boolean longTimeout) throws Throwable;