Files
sdk/runtime/bin/process_impl.dart
T
sgjesse@google.com d7c8c1f1e4 Fix a number of issues with the process handling
1. Ignore the signal SIGPIPE on Linux and Mac OS

When reading from or writing to a closed pipe the signal SIGPIPE
is raised. The default handling of this is to terminate the
program. When signal SIGPIPE is ignored the read and write
returns EPIPE.

2. Wrong return type for stdio getter

3. When there is an error on a socket mark it as closed

4. Mark the pipe used for process exit status as a one way pipe

5. Add tests to test stdin, stdout and stderr in Dart scripts

R=ager@google.com

BUG=dart:536, dart:454
TEST=

Review URL: http://codereview.chromium.org//8662006

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@1793 260f80e4-7a28-3924-810f-c04153c831b5
2011-11-23 14:49:18 +00:00

181 lines
4.8 KiB
Dart

// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class _ProcessStartStatus {
int _errorCode; // Set to OS error code if process start failed.
String _errorMessage; // Set to OS error message if process start failed.
}
class _Process implements Process {
_Process(String path, List<String> arguments) {
if (path is !String) {
throw new ProcessException("Path is not a String: $path");
}
_path = path;
if (arguments is !List) {
throw new ProcessException("Arguments is not a List: $arguments");
}
int len = arguments.length;
_arguments = new ObjectArray<String>(len);
for (int i = 0; i < len; i++) {
var arg = arguments[i];
if (arg is !String) {
throw new ProcessException("Non-string argument: $arg");
}
_arguments[i] = arguments[i];
}
_in = new _Socket._internalReadOnly(); // stdout coming from process.
_out = new _Socket._internalWriteOnly(); // stdin going to process.
_err = new _Socket._internalReadOnly(); // stderr coming from process.
_exitHandler = new _Socket._internalReadOnly();
_closed = false;
_killed = false;
_started = false;
_exitHandlerCallback = null;
}
int _intFromBytes(List<int> bytes, int offset) {
return (bytes[offset] +
(bytes[offset + 1] << 8) +
(bytes[offset + 2] << 16) +
(bytes[offset + 3] << 24));
}
void start() {
var status = new _ProcessStartStatus();
bool success = _start(
_path, _arguments, _in, _out, _err, _exitHandler, status);
if (!success) {
close();
throw new ProcessException(status._errorMessage, status._errorCode);
}
_started = true;
// Make sure to activate socket handlers now that the file
// descriptors have been set.
_in._activateHandlers();
_out._activateHandlers();
_err._activateHandlers();
// Setup an exit handler to handle internal cleanup and possible
// callback when a process terminates.
_exitHandler.dataHandler = () {
final int EXIT_DATA_SIZE = 12;
List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE);
InputStream input = _exitHandler.inputStream;
int exitDataRead = 0;
int exitCode(List<int> ints) {
var code = _intFromBytes(ints, 4);
var negative = _intFromBytes(ints, 8);
assert(negative == 0 || negative == 1);
return (negative == 0) ? code : -code;
}
int exitPid(List<int> ints) {
return _intFromBytes(ints, 0);
}
void handleExit() {
_processExit(exitPid(exitDataBuffer));
if (_exitHandlerCallback !== null) {
_exitHandlerCallback(exitCode(exitDataBuffer));
}
}
void exitData() {
exitDataRead += input.readInto(
exitDataBuffer, exitDataRead, EXIT_DATA_SIZE - exitDataRead);
if (exitDataRead == EXIT_DATA_SIZE) handleExit();
}
input.dataHandler = exitData;
};
}
bool _start(String path,
List<String> arguments,
Socket input,
Socket output,
Socket error,
Socket exitHandler,
_ProcessStartStatus status) native "Process_Start";
void _processExit(int pid) native "Process_Exit";
InputStream get stdout() {
if (_closed) {
throw new ProcessException("Process closed");
}
return _in.inputStream;
}
InputStream get stderr() {
if (_closed) {
throw new ProcessException("Process closed");
}
return _err.inputStream;
}
OutputStream get stdin() {
if (_closed) {
throw new ProcessException("Process closed");
}
return _out.outputStream;
}
bool kill() {
if (_closed && _pid === null) {
throw new ProcessException("Process closed");
}
if (_killed) {
return true;
}
if (_kill(_pid)) {
_killed = true;
return true;
}
return false;
}
void _kill(int pid) native "Process_Kill";
void close() {
if (_closed) {
throw new ProcessException("Process closed");
}
_in.close();
_out.close();
_err.close();
_exitHandler.close();
_closed = true;
}
void set exitHandler(void callback(int exitCode)) {
if (_closed) {
throw new ProcessException("Process closed");
}
if (_killed) {
throw new ProcessException("Process killed");
}
_exitHandlerCallback = callback;
}
String _path;
ObjectArray<String> _arguments;
Socket _in;
Socket _out;
Socket _err;
Socket _exitHandler;
int _pid;
bool _closed;
bool _killed;
bool _started;
var _exitHandlerCallback;
}