| 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 return; |
| 62 } |
| 56 } | 63 } |
| 57 _started = true; | 64 _started = true; |
| 58 | 65 |
| 59 // Make sure to activate socket handlers now that the file | 66 // Make sure to activate socket handlers now that the file |
| 60 // descriptors have been set. | 67 // descriptors have been set. |
| 61 _in._activateHandlers(); | 68 _in._activateHandlers(); |
| 62 _out._activateHandlers(); | 69 _out._activateHandlers(); |
| 63 _err._activateHandlers(); | 70 _err._activateHandlers(); |
| 64 | 71 |
| 65 // Setup an exit handler to handle internal cleanup and possible | 72 // Setup an exit handler to handle internal cleanup and possible |
| 66 // callback when a process terminates. | 73 // callback when a process terminates. |
| 67 _exitHandler.dataHandler = () { | 74 _exitHandler.dataHandler = () { |
| 68 final int EXIT_DATA_SIZE = 12; | 75 final int EXIT_DATA_SIZE = 12; |
| 69 List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE); | 76 List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE); |
| 70 InputStream input = _exitHandler.inputStream; | 77 InputStream input = _exitHandler.inputStream; |
| 71 int exitDataRead = 0; | 78 int exitDataRead = 0; |
| 72 | 79 |
| 73 int exitCode(List<int> ints) { | 80 int exitCode(List<int> ints) { |
| 74 var code = _intFromBytes(ints, 4); | 81 var code = _intFromBytes(ints, 4); |
| 75 var negative = _intFromBytes(ints, 8); | 82 var negative = _intFromBytes(ints, 8); |
| 76 assert(negative == 0 || negative == 1); | 83 assert(negative == 0 || negative == 1); |
| 77 return (negative == 0) ? code : -code; | 84 return (negative == 0) ? code : -code; |
| 85 } |
| 86 |
| 87 int exitPid(List<int> ints) { |
| 88 return _intFromBytes(ints, 0); |
| 89 } |
| 90 |
| 91 void handleExit() { |
| 92 _processExit(exitPid(exitDataBuffer)); |
| 93 if (_exitHandlerCallback !== null) { |
| 94 _exitHandlerCallback(exitCode(exitDataBuffer)); |
| 78 } | 95 } |
| 96 } |
| 79 | 97 |
| 80 int exitPid(List<int> ints) { | 98 void exitData() { |
| 81 return _intFromBytes(ints, 0); | 99 exitDataRead += input.readInto( |
| 82 } | 100 exitDataBuffer, exitDataRead, EXIT_DATA_SIZE - exitDataRead); |
| 101 if (exitDataRead == EXIT_DATA_SIZE) handleExit(); |
| 102 } |
| 83 | 103 |
| 84 void handleExit() { | 104 input.dataHandler = exitData; |
| 85 _processExit(exitPid(exitDataBuffer)); | 105 }; |
| 86 if (_exitHandlerCallback !== null) { | |
| 87 _exitHandlerCallback(exitCode(exitDataBuffer)); | |
| 88 } | |
| 89 } | |
| 90 | 106 |
| 91 void exitData() { | 107 if (_startHandler !== null) { |
| 92 exitDataRead += input.readInto( | 108 _startHandler(); |
| 93 exitDataBuffer, exitDataRead, EXIT_DATA_SIZE - exitDataRead); | 109 } |
| 94 if (exitDataRead == EXIT_DATA_SIZE) handleExit(); | |
| 95 } | |
| 96 | |
| 97 input.dataHandler = exitData; | |
| 98 }; | |
| 99 } | 110 } |
| 100 | 111 |
| 101 bool _start(String path, | 112 bool _start(String path, |
| 102 List<String> arguments, | 113 List<String> arguments, |
| 103 Socket input, | 114 Socket input, |
| 104 Socket output, | 115 Socket output, |
| 105 Socket error, | 116 Socket error, |
| 106 Socket exitHandler, | 117 Socket exitHandler, |
| 107 _ProcessStartStatus status) native "Process_Start"; | 118 _ProcessStartStatus status) native "Process_Start"; |
| 108 | 119 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 122 return _err.inputStream; | 133 return _err.inputStream; |
| 123 } | 134 } |
| 124 | 135 |
| 125 OutputStream get stdin() { | 136 OutputStream get stdin() { |
| 126 if (_closed) { | 137 if (_closed) { |
| 127 throw new ProcessException("Process closed"); | 138 throw new ProcessException("Process closed"); |
| 128 } | 139 } |
| 129 return _out.outputStream; | 140 return _out.outputStream; |
| 130 } | 141 } |
| 131 | 142 |
| 132 bool kill() { | 143 void kill() { |
| 133 if (_closed && _pid === null) { | 144 if (_closed && _pid === null && _errorHandler !== null) { |
| 134 throw new ProcessException("Process closed"); | 145 _errorHandler(new ProcessException("Process closed")); |
| 146 return; |
| 135 } | 147 } |
| 136 if (_killed) { | 148 if (_killed) { |
| 137 return true; | 149 return; |
| 138 } | 150 } |
| 151 // TODO(ager): Make the actual kill operation asynchronous. |
| 139 if (_kill(_pid)) { | 152 if (_kill(_pid)) { |
| 140 _killed = true; | 153 _killed = true; |
| 141 return true; | 154 return; |
| 142 } | 155 } |
| 143 return false; | 156 if (_errorHandler !== null) { |
| 157 _errorHandler(new ProcessException("Could not kill process")); |
| 158 return; |
| 159 } |
| 144 } | 160 } |
| 145 | 161 |
| 146 void _kill(int pid) native "Process_Kill"; | 162 void _kill(int pid) native "Process_Kill"; |
| 147 | 163 |
| 148 void close() { | 164 void close() { |
| 149 if (_closed) { | 165 if (_closed) { |
| 150 throw new ProcessException("Process closed"); | 166 throw new ProcessException("Process closed"); |
| 151 } | 167 } |
| 152 _in.close(); | 168 _in.close(); |
| 153 _out.close(); | 169 _out.close(); |
| 154 _err.close(); | 170 _err.close(); |
| 155 _exitHandler.close(); | 171 _exitHandler.close(); |
| 156 _closed = true; | 172 _closed = true; |
| 157 } | 173 } |
| 158 | 174 |
| 159 void set exitHandler(void callback(int exitCode)) { | 175 void set exitHandler(void callback(int exitCode)) { |
| 160 if (_closed) { | 176 if (_closed) { |
| 161 throw new ProcessException("Process closed"); | 177 throw new ProcessException("Process closed"); |
| 162 } | 178 } |
| 163 if (_killed) { | 179 if (_killed) { |
| 164 throw new ProcessException("Process killed"); | 180 throw new ProcessException("Process killed"); |
| 165 } | 181 } |
| 166 _exitHandlerCallback = callback; | 182 _exitHandlerCallback = callback; |
| 167 } | 183 } |
| 168 | 184 |
| 185 void set errorHandler(void callback(ProcessException exception)) { |
| 186 _errorHandler = callback; |
| 187 } |
| 188 |
| 189 void set startHandler(void callback()) { |
| 190 _startHandler = callback; |
| 191 } |
| 192 |
| 169 String _path; | 193 String _path; |
| 170 ObjectArray<String> _arguments; | 194 ObjectArray<String> _arguments; |
| 171 Socket _in; | 195 Socket _in; |
| 172 Socket _out; | 196 Socket _out; |
| 173 Socket _err; | 197 Socket _err; |
| 174 Socket _exitHandler; | 198 Socket _exitHandler; |
| 175 int _pid; | 199 int _pid; |
| 176 bool _closed; | 200 bool _closed; |
| 177 bool _killed; | 201 bool _killed; |
| 178 bool _started; | 202 bool _started; |
| 179 var _exitHandlerCallback; | 203 Function _exitHandlerCallback; |
| 204 Function _errorHandler; |
| 205 Function _startHandler; |
| 180 } | 206 } |
| OLD | NEW |