| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 class _ProcessStartStatus { | 5 class _ProcessStartStatus { |
| 6 int _errorCode; // Set to OS error code if process start failed. | 6 int _errorCode; // Set to OS error code if process start failed. |
| 7 String _errorMessage; // Set to OS error message if process start failed. | 7 String _errorMessage; // Set to OS error message if process start failed. |
| 8 } | 8 } |
| 9 | 9 |
| 10 | 10 |
| 11 class _Process implements Process { | 11 class _Process implements Process { |
| 12 | 12 |
| 13 _Process(String path, List<String> arguments) { | 13 _Process.start(String path, List<String> arguments) { |
| 14 if (path is !String) { | 14 if (path is !String) { |
| 15 throw new ProcessException("Path is not a String: $path"); | 15 throw new ProcessException("Path is not a String: $path"); |
| 16 } | 16 } |
| 17 _path = path; | 17 _path = path; |
| 18 | 18 |
| 19 if (arguments is !List) { | 19 if (arguments is !List) { |
| 20 throw new ProcessException("Arguments is not a List: $arguments"); | 20 throw new ProcessException("Arguments is not a List: $arguments"); |
| 21 } | 21 } |
| 22 int len = arguments.length; | 22 int len = arguments.length; |
| 23 _arguments = new ObjectArray<String>(len); | 23 _arguments = new ObjectArray<String>(len); |
| 24 for (int i = 0; i < len; i++) { | 24 for (int i = 0; i < len; i++) { |
| 25 var arg = arguments[i]; | 25 var arg = arguments[i]; |
| 26 if (arg is !String) { | 26 if (arg is !String) { |
| 27 throw new ProcessException("Non-string argument: $arg"); | 27 throw new ProcessException("Non-string argument: $arg"); |
| 28 } | 28 } |
| 29 _arguments[i] = arguments[i]; | 29 _arguments[i] = arguments[i]; |
| 30 } | 30 } |
| 31 | 31 |
| 32 _in = new _Socket._internalReadOnly(); // stdout coming from process. | 32 _in = new _Socket._internalReadOnly(); // stdout coming from process. |
| 33 _out = new _Socket._internalWriteOnly(); // stdin going to process. | 33 _out = new _Socket._internalWriteOnly(); // stdin going to process. |
| 34 _err = new _Socket._internalReadOnly(); // stderr coming from process. | 34 _err = new _Socket._internalReadOnly(); // stderr coming from process. |
| 35 _exitHandler = new _Socket._internalReadOnly(); | 35 _exitHandler = new _Socket._internalReadOnly(); |
| 36 _closed = false; | 36 _closed = false; |
| 37 _killed = false; | 37 _killed = false; |
| 38 _started = false; | 38 _started = false; |
| 39 _exitHandlerCallback = null; | 39 _exitHandlerCallback = null; |
| 40 // TODO(ager): Make the actual process starting really async instead of |
| 41 // simulating it with a timer. |
| 42 new Timer((Timer ignore) => start(), 0); |
| 40 } | 43 } |
| 41 | 44 |
| 42 int _intFromBytes(List<int> bytes, int offset) { | 45 int _intFromBytes(List<int> bytes, int offset) { |
| 43 return (bytes[offset] + | 46 return (bytes[offset] + |
| 44 (bytes[offset + 1] << 8) + | 47 (bytes[offset + 1] << 8) + |
| 45 (bytes[offset + 2] << 16) + | 48 (bytes[offset + 2] << 16) + |
| 46 (bytes[offset + 3] << 24)); | 49 (bytes[offset + 3] << 24)); |
| 47 } | 50 } |
| 48 | 51 |
| 49 void start() { | 52 void start() { |
| 50 var status = new _ProcessStartStatus(); | 53 var status = new _ProcessStartStatus(); |
| 51 bool success = _start( | 54 bool success = _start( |
| 52 _path, _arguments, _in, _out, _err, _exitHandler, status); | 55 _path, _arguments, _in, _out, _err, _exitHandler, status); |
| 53 if (!success) { | 56 if (!success) { |
| 54 close(); | 57 close(); |
| 55 throw new ProcessException(status._errorMessage, status._errorCode); | 58 if (_errorHandler !== null) { |
| 59 _errorHandler(new ProcessException(status._errorMessage, |
| 60 status._errorCode)); |
| 61 } |
| 56 } | 62 } |
| 57 _started = true; | 63 _started = true; |
| 58 | 64 |
| 59 // Make sure to activate socket handlers now that the file | 65 // Make sure to activate socket handlers now that the file |
| 60 // descriptors have been set. | 66 // descriptors have been set. |
| 61 _in._activateHandlers(); | 67 _in._activateHandlers(); |
| 62 _out._activateHandlers(); | 68 _out._activateHandlers(); |
| 63 _err._activateHandlers(); | 69 _err._activateHandlers(); |
| 64 | 70 |
| 65 // Setup an exit handler to handle internal cleanup and possible | 71 // Setup an exit handler to handle internal cleanup and possible |
| 66 // callback when a process terminates. | 72 // callback when a process terminates. |
| 67 _exitHandler.dataHandler = () { | 73 _exitHandler.dataHandler = () { |
| 68 final int EXIT_DATA_SIZE = 12; | 74 final int EXIT_DATA_SIZE = 12; |
| 69 List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE); | 75 List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE); |
| 70 InputStream input = _exitHandler.inputStream; | 76 InputStream input = _exitHandler.inputStream; |
| 71 int exitDataRead = 0; | 77 int exitDataRead = 0; |
| 72 | 78 |
| 73 int exitCode(List<int> ints) { | 79 int exitCode(List<int> ints) { |
| 74 var code = _intFromBytes(ints, 4); | 80 var code = _intFromBytes(ints, 4); |
| 75 var negative = _intFromBytes(ints, 8); | 81 var negative = _intFromBytes(ints, 8); |
| 76 assert(negative == 0 || negative == 1); | 82 assert(negative == 0 || negative == 1); |
| 77 return (negative == 0) ? code : -code; | 83 return (negative == 0) ? code : -code; |
| 84 } |
| 85 |
| 86 int exitPid(List<int> ints) { |
| 87 return _intFromBytes(ints, 0); |
| 88 } |
| 89 |
| 90 void handleExit() { |
| 91 _processExit(exitPid(exitDataBuffer)); |
| 92 if (_exitHandlerCallback !== null) { |
| 93 _exitHandlerCallback(exitCode(exitDataBuffer)); |
| 78 } | 94 } |
| 95 } |
| 79 | 96 |
| 80 int exitPid(List<int> ints) { | 97 void exitData() { |
| 81 return _intFromBytes(ints, 0); | 98 exitDataRead += input.readInto( |
| 82 } | 99 exitDataBuffer, exitDataRead, EXIT_DATA_SIZE - exitDataRead); |
| 100 if (exitDataRead == EXIT_DATA_SIZE) handleExit(); |
| 101 } |
| 83 | 102 |
| 84 void handleExit() { | 103 input.dataHandler = exitData; |
| 85 _processExit(exitPid(exitDataBuffer)); | 104 }; |
| 86 if (_exitHandlerCallback !== null) { | |
| 87 _exitHandlerCallback(exitCode(exitDataBuffer)); | |
| 88 } | |
| 89 } | |
| 90 | 105 |
| 91 void exitData() { | 106 if (_startHandler !== null) { |
| 92 exitDataRead += input.readInto( | 107 _startHandler(); |
| 93 exitDataBuffer, exitDataRead, EXIT_DATA_SIZE - exitDataRead); | 108 } |
| 94 if (exitDataRead == EXIT_DATA_SIZE) handleExit(); | |
| 95 } | |
| 96 | |
| 97 input.dataHandler = exitData; | |
| 98 }; | |
| 99 } | 109 } |
| 100 | 110 |
| 101 bool _start(String path, | 111 bool _start(String path, |
| 102 List<String> arguments, | 112 List<String> arguments, |
| 103 Socket input, | 113 Socket input, |
| 104 Socket output, | 114 Socket output, |
| 105 Socket error, | 115 Socket error, |
| 106 Socket exitHandler, | 116 Socket exitHandler, |
| 107 _ProcessStartStatus status) native "Process_Start"; | 117 _ProcessStartStatus status) native "Process_Start"; |
| 108 | 118 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 122 return _err.inputStream; | 132 return _err.inputStream; |
| 123 } | 133 } |
| 124 | 134 |
| 125 OutputStream get stdin() { | 135 OutputStream get stdin() { |
| 126 if (_closed) { | 136 if (_closed) { |
| 127 throw new ProcessException("Process closed"); | 137 throw new ProcessException("Process closed"); |
| 128 } | 138 } |
| 129 return _out.outputStream; | 139 return _out.outputStream; |
| 130 } | 140 } |
| 131 | 141 |
| 132 bool kill() { | 142 void kill() { |
| 133 if (_closed && _pid === null) { | 143 if (_closed && _pid === null && _errorHandler !== null) { |
| 134 throw new ProcessException("Process closed"); | 144 _errorHandler(new ProcessException("Process closed")); |
| 135 } | 145 } |
| 136 if (_killed) { | 146 if (_killed) { |
| 137 return true; | 147 return true; |
| 138 } | 148 } |
| 149 // TODO(ager): Make the actual kill operation asynchronous. |
| 139 if (_kill(_pid)) { | 150 if (_kill(_pid)) { |
| 140 _killed = true; | 151 _killed = true; |
| 141 return true; | 152 return true; |
| 142 } | 153 } |
| 143 return false; | 154 if (_errorHandler !== null) { |
| 155 _errorHandler(new ProcessException("Could not kill process")); |
| 156 } |
| 144 } | 157 } |
| 145 | 158 |
| 146 void _kill(int pid) native "Process_Kill"; | 159 void _kill(int pid) native "Process_Kill"; |
| 147 | 160 |
| 148 void close() { | 161 void close() { |
| 149 if (_closed) { | 162 if (_closed) { |
| 150 throw new ProcessException("Process closed"); | 163 throw new ProcessException("Process closed"); |
| 151 } | 164 } |
| 152 _in.close(); | 165 _in.close(); |
| 153 _out.close(); | 166 _out.close(); |
| 154 _err.close(); | 167 _err.close(); |
| 155 _exitHandler.close(); | 168 _exitHandler.close(); |
| 156 _closed = true; | 169 _closed = true; |
| 157 } | 170 } |
| 158 | 171 |
| 159 void set exitHandler(void callback(int exitCode)) { | 172 void set exitHandler(void callback(int exitCode)) { |
| 160 if (_closed) { | 173 if (_closed) { |
| 161 throw new ProcessException("Process closed"); | 174 throw new ProcessException("Process closed"); |
| 162 } | 175 } |
| 163 if (_killed) { | 176 if (_killed) { |
| 164 throw new ProcessException("Process killed"); | 177 throw new ProcessException("Process killed"); |
| 165 } | 178 } |
| 166 _exitHandlerCallback = callback; | 179 _exitHandlerCallback = callback; |
| 167 } | 180 } |
| 168 | 181 |
| 182 void set errorHandler(void callback(ProcessException exception)) { |
| 183 _errorHandler = callback; |
| 184 } |
| 185 |
| 186 void set startHandler(void callback()) { |
| 187 _startHandler = callback; |
| 188 } |
| 189 |
| 169 String _path; | 190 String _path; |
| 170 ObjectArray<String> _arguments; | 191 ObjectArray<String> _arguments; |
| 171 Socket _in; | 192 Socket _in; |
| 172 Socket _out; | 193 Socket _out; |
| 173 Socket _err; | 194 Socket _err; |
| 174 Socket _exitHandler; | 195 Socket _exitHandler; |
| 175 int _pid; | 196 int _pid; |
| 176 bool _closed; | 197 bool _closed; |
| 177 bool _killed; | 198 bool _killed; |
| 178 bool _started; | 199 bool _started; |
| 179 var _exitHandlerCallback; | 200 Function _exitHandlerCallback; |
| 201 Function _errorHandler; |
| 202 Function _startHandler; |
| 180 } | 203 } |
| OLD | NEW |