|
32 | 32 | import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
|
33 | 33 | import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
|
34 | 34 |
|
35 |
| -import java.io.BufferedReader; |
36 | 35 | import java.io.Console;
|
37 | 36 | import java.io.IOException;
|
38 | 37 | import java.io.InputStream;
|
39 |
| -import java.io.InputStreamReader; |
40 | 38 | import java.io.OutputStream;
|
| 39 | +import java.lang.ProcessBuilder.Redirect; |
41 | 40 | import java.math.BigInteger;
|
42 | 41 | import java.nio.ByteBuffer;
|
43 | 42 | import java.nio.channels.NonWritableChannelException;
|
|
88 | 87 | import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
|
89 | 88 | import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
|
90 | 89 | import com.oracle.graal.python.nodes.util.CastToIndexNode;
|
| 90 | +import com.oracle.graal.python.runtime.PythonContext; |
91 | 91 | import com.oracle.graal.python.runtime.PythonCore;
|
92 | 92 | import com.oracle.graal.python.runtime.exception.PException;
|
93 | 93 | import com.oracle.graal.python.runtime.exception.PythonErrorType;
|
|
96 | 96 | import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
97 | 97 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
98 | 98 | import com.oracle.truffle.api.TruffleFile;
|
| 99 | +import com.oracle.truffle.api.TruffleLanguage.Env; |
99 | 100 | import com.oracle.truffle.api.dsl.Cached;
|
100 | 101 | import com.oracle.truffle.api.dsl.Fallback;
|
101 | 102 | import com.oracle.truffle.api.dsl.GenerateNodeFactory;
|
@@ -1043,48 +1044,65 @@ abstract static class SystemNode extends PythonBuiltinNode {
|
1043 | 1044 | static final String[] shell = System.getProperty("os.name").toLowerCase().startsWith("windows") ? new String[]{"cmd.exe", "/c"}
|
1044 | 1045 | : new String[]{(System.getenv().getOrDefault("SHELL", "sh")), "-c"};
|
1045 | 1046 |
|
1046 |
| - class StreamGobbler extends Thread { |
1047 |
| - static final int bufsize = 4096; |
1048 |
| - InputStream is; |
1049 |
| - OutputStream type; |
1050 |
| - private char[] buf; |
1051 |
| - |
1052 |
| - StreamGobbler(InputStream is, OutputStream outputStream) { |
1053 |
| - this.is = is; |
1054 |
| - this.type = outputStream; |
1055 |
| - this.buf = new char[bufsize]; |
| 1047 | + static class PipePump extends Thread { |
| 1048 | + private final InputStream in; |
| 1049 | + private final OutputStream out; |
| 1050 | + private final byte[] buffer; |
| 1051 | + private boolean finish; |
| 1052 | + |
| 1053 | + public PipePump(InputStream in, OutputStream out) { |
| 1054 | + this.in = in; |
| 1055 | + this.out = out; |
| 1056 | + this.buffer = new byte[8192]; |
| 1057 | + this.finish = false; |
1056 | 1058 | }
|
1057 | 1059 |
|
1058 | 1060 | @Override
|
1059 |
| - @TruffleBoundary |
1060 | 1061 | public void run() {
|
1061 | 1062 | try {
|
1062 |
| - InputStreamReader isr = new InputStreamReader(is); |
1063 |
| - BufferedReader br = new BufferedReader(isr); |
1064 |
| - int readSz = 0; |
1065 |
| - while ((readSz = br.read(buf, 0, bufsize)) > 0) { |
1066 |
| - type.write(new String(buf).getBytes(), 0, readSz); |
| 1063 | + while (!Thread.interrupted() && !finish) { |
| 1064 | + int read = in.read(buffer, 0, in.available()); |
| 1065 | + if (read == -1) { |
| 1066 | + return; |
| 1067 | + } |
| 1068 | + out.write(buffer, 0, read); |
1067 | 1069 | }
|
1068 |
| - } catch (IOException ioe) { |
| 1070 | + } catch (IOException e) { |
1069 | 1071 | }
|
1070 | 1072 | }
|
| 1073 | + |
| 1074 | + public void finish() { |
| 1075 | + Thread.yield(); |
| 1076 | + finish = true; |
| 1077 | + } |
1071 | 1078 | }
|
1072 | 1079 |
|
1073 | 1080 | @TruffleBoundary
|
1074 | 1081 | @Specialization
|
1075 | 1082 | int system(String cmd) {
|
1076 |
| - if (!getContext().isExecutableAccessAllowed()) { |
| 1083 | + PythonContext context = getContext(); |
| 1084 | + if (!context.isExecutableAccessAllowed()) { |
1077 | 1085 | return -1;
|
1078 | 1086 | }
|
1079 | 1087 | String[] command = new String[]{shell[0], shell[1], cmd};
|
| 1088 | + Env env = context.getEnv(); |
1080 | 1089 | try {
|
1081 |
| - Runtime rt = Runtime.getRuntime(); |
1082 |
| - Process proc = rt.exec(command); |
1083 |
| - StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), getContext().getStandardErr()); |
1084 |
| - StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), getContext().getStandardOut()); |
1085 |
| - errorGobbler.start(); |
1086 |
| - outputGobbler.start(); |
1087 |
| - return proc.waitFor(); |
| 1090 | + ProcessBuilder pb = new ProcessBuilder(command); |
| 1091 | + pb.redirectInput(Redirect.PIPE); |
| 1092 | + pb.redirectOutput(Redirect.PIPE); |
| 1093 | + pb.redirectError(Redirect.PIPE); |
| 1094 | + Process proc = pb.start(); |
| 1095 | + PipePump stdin = new PipePump(env.in(), proc.getOutputStream()); |
| 1096 | + PipePump stdout = new PipePump(proc.getInputStream(), env.out()); |
| 1097 | + PipePump stderr = new PipePump(proc.getErrorStream(), env.err()); |
| 1098 | + stdin.start(); |
| 1099 | + stdout.start(); |
| 1100 | + stderr.start(); |
| 1101 | + int exitStatus = proc.waitFor(); |
| 1102 | + stdin.finish(); |
| 1103 | + stdout.finish(); |
| 1104 | + stderr.finish(); |
| 1105 | + return exitStatus; |
1088 | 1106 | } catch (IOException | InterruptedException e) {
|
1089 | 1107 | return -1;
|
1090 | 1108 | }
|
|
0 commit comments