| Index: runtime/bin/process_patch.dart | 
| diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart | 
| index edc29e294c144f62518e7a32dd1fdb5dc0226fe6..29913b126ae02e81645e3ed34159bc7588b674b4 100644 | 
| --- a/runtime/bin/process_patch.dart | 
| +++ b/runtime/bin/process_patch.dart | 
| @@ -25,7 +25,7 @@ patch class Process { | 
| /* patch */ static Future<ProcessResult> run(String executable, | 
| List<String> arguments, | 
| [ProcessOptions options]) { | 
| -    return new _NonInteractiveProcess(executable, arguments, options)._result; | 
| +    return _runNonInteractiveProcess(executable, arguments, options); | 
| } | 
| } | 
|  | 
| @@ -88,13 +88,15 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { | 
| }); | 
| } | 
|  | 
| -    _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(); | 
| +    // stdin going to process. | 
| +    _stdin = new _Socket._writePipe(); | 
| +    // stdout coming from process. | 
| +    _stdout = new _Socket._readPipe(); | 
| +    // stderr coming from process. | 
| +    _stderr = new _Socket._readPipe(); | 
| +    _exitHandler = new _Socket._readPipe(); | 
| _ended = false; | 
| _started = false; | 
| -    _onExit = null; | 
| } | 
|  | 
| String _windowsArgumentEscape(String argument) { | 
| @@ -160,16 +162,12 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { | 
| _arguments, | 
| _workingDirectory, | 
| _environment, | 
| -                                  _in, | 
| -                                  _out, | 
| -                                  _err, | 
| -                                  _exitHandler, | 
| +                                  _stdin._nativeSocket, | 
| +                                  _stdout._nativeSocket, | 
| +                                  _stderr._nativeSocket, | 
| +                                  _exitHandler._nativeSocket, | 
| status); | 
| if (!success) { | 
| -        _in.close(); | 
| -        _out.close(); | 
| -        _err.close(); | 
| -        _exitHandler.close(); | 
| completer.completeError( | 
| new ProcessException(_path, | 
| _arguments, | 
| @@ -179,23 +177,12 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { | 
| } | 
| _started = true; | 
|  | 
| -      _in._closed = false; | 
| -      _out._closed = false; | 
| -      _err._closed = false; | 
| -      _exitHandler._closed = false; | 
| - | 
| -      // 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. | 
| int exitDataRead = 0; | 
| final int EXIT_DATA_SIZE = 8; | 
| List<int> exitDataBuffer = new List<int>.fixedLength(EXIT_DATA_SIZE); | 
| -      _exitHandler.inputStream.onData = () { | 
| +      _exitHandler.listen((data) { | 
|  | 
| int exitCode(List<int> ints) { | 
| var code = _intFromBytes(ints, 0); | 
| @@ -206,18 +193,17 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { | 
|  | 
| void handleExit() { | 
| _ended = true; | 
| -          _exitCode = exitCode(exitDataBuffer); | 
| -          if (_onExit != null) _onExit(_exitCode); | 
| -          _out.close(); | 
| +          _exitCode.complete(exitCode(exitDataBuffer)); | 
| +          // Kill stdin, helping hand if the user forgot to do it. | 
| +          _stdin.destroy(); | 
| } | 
|  | 
| -        exitDataRead += _exitHandler.inputStream.readInto( | 
| -            exitDataBuffer, exitDataRead, EXIT_DATA_SIZE - exitDataRead); | 
| +        exitDataBuffer.setRange(exitDataRead, data.length, data); | 
| +        exitDataRead += data.length; | 
| if (exitDataRead == EXIT_DATA_SIZE) { | 
| -          _exitHandler.close(); | 
| handleExit(); | 
| } | 
| -      }; | 
| +      }); | 
|  | 
| completer.complete(this); | 
| }); | 
| @@ -228,24 +214,29 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { | 
| List<String> arguments, | 
| String workingDirectory, | 
| List<String> environment, | 
| -                    Socket input, | 
| -                    Socket output, | 
| -                    Socket error, | 
| -                    Socket exitHandler, | 
| +                    _NativeSocket stdin, | 
| +                    _NativeSocket stdout, | 
| +                    _NativeSocket stderr, | 
| +                    _NativeSocket exitHandler, | 
| _ProcessStartStatus status) native "Process_Start"; | 
|  | 
| -  InputStream get stdout { | 
| -    return _in.inputStream; | 
| +  Stream<List<int>> get stdout { | 
| +    // TODO(ajohnsen): Get stream object only. | 
| +    return _stdout; | 
| } | 
|  | 
| -  InputStream get stderr { | 
| -    return _err.inputStream; | 
| +  Stream<List<int>> get stderr { | 
| +    // TODO(ajohnsen): Get stream object only. | 
| +    return _stderr; | 
| } | 
|  | 
| -  OutputStream get stdin { | 
| -    return _out.outputStream; | 
| +  IOSink get stdin { | 
| +    // TODO(ajohnsen): Get consumer object only. | 
| +    return _stdin; | 
| } | 
|  | 
| +  Future<int> get exitCode => _exitCode.future; | 
| + | 
| bool kill([ProcessSignal signal = ProcessSignal.SIGTERM]) { | 
| if (signal is! ProcessSignal) { | 
| throw new ArgumentError( | 
| @@ -258,24 +249,18 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { | 
|  | 
| bool _kill(Process p, int signal) native "Process_Kill"; | 
|  | 
| -  void set onExit(void callback(int exitCode)) { | 
| -    if (_ended) callback(_exitCode); | 
| -    _onExit = callback; | 
| -  } | 
| - | 
| String _path; | 
| List<String> _arguments; | 
| String _workingDirectory; | 
| List<String> _environment; | 
| -  // Private methods of _Socket are used by _in, _out, and _err. | 
| -  _Socket _in; | 
| -  _Socket _out; | 
| -  _Socket _err; | 
| +  // Private methods of Socket are used by _in, _out, and _err. | 
| +  Socket _stdin; | 
| +  Socket _stdout; | 
| +  Socket _stderr; | 
| Socket _exitHandler; | 
| -  int _exitCode; | 
| bool _ended; | 
| bool _started; | 
| -  Function _onExit; | 
| +  final Completer<int> _exitCode = new Completer<int>(); | 
| } | 
|  | 
|  | 
| @@ -283,88 +268,59 @@ class _ProcessImpl extends NativeFieldWrapperClass1 implements Process { | 
| // that buffers output so it can be delivered when the process exits. | 
| // _NonInteractiveProcess is used to implement the Process.run | 
| // method. | 
| -class _NonInteractiveProcess { | 
| -  _NonInteractiveProcess(String path, | 
| -                         List<String> arguments, | 
| -                         ProcessOptions options) { | 
| -    _completer = new Completer<ProcessResult>(); | 
| -    // Extract output encoding options and verify arguments. | 
| -    var stdoutEncoding = Encoding.SYSTEM; | 
| -    var stderrEncoding = Encoding.SYSTEM; | 
| -    if (options != null) { | 
| -      if (options.stdoutEncoding != null) { | 
| -        stdoutEncoding = options.stdoutEncoding; | 
| -        if (stdoutEncoding is !Encoding) { | 
| -          throw new ArgumentError( | 
| -              'stdoutEncoding option is not an encoding: $stdoutEncoding'); | 
| -        } | 
| -      } | 
| -      if (options.stderrEncoding != null) { | 
| -        stderrEncoding = options.stderrEncoding; | 
| -        if (stderrEncoding is !Encoding) { | 
| -          throw new ArgumentError( | 
| -              'stderrEncoding option is not an encoding: $stderrEncoding'); | 
| -        } | 
| +Future<ProcessResult> _runNonInteractiveProcess(String path, | 
| +                                                List<String> arguments, | 
| +                                                ProcessOptions options) { | 
| +  // Extract output encoding options and verify arguments. | 
| +  var stdoutEncoding = Encoding.SYSTEM; | 
| +  var stderrEncoding = Encoding.SYSTEM; | 
| +  if (options != null) { | 
| +    if (options.stdoutEncoding != null) { | 
| +      stdoutEncoding = options.stdoutEncoding; | 
| +      if (stdoutEncoding is !Encoding) { | 
| +        throw new ArgumentError( | 
| +            'stdoutEncoding option is not an encoding: $stdoutEncoding'); | 
| } | 
| } | 
| - | 
| -    // Start the underlying process. | 
| -    var processFuture = new _ProcessImpl(path, arguments, options)._start(); | 
| - | 
| -    processFuture.then((Process p) { | 
| -      // Make sure the process stdin is closed. | 
| -      p.stdin.close(); | 
| - | 
| -      // Setup process exit handling. | 
| -      p.onExit = (exitCode) { | 
| -        _exitCode = exitCode; | 
| -        _checkDone(); | 
| -      }; | 
| - | 
| -      // Setup stdout handling. | 
| -      _stdoutBuffer = new StringBuffer(); | 
| -      var stdoutStream = new StringInputStream(p.stdout, stdoutEncoding); | 
| -      stdoutStream.onData = () { | 
| -        var data = stdoutStream.read(); | 
| -        if (data != null) _stdoutBuffer.add(data); | 
| -      }; | 
| -      stdoutStream.onClosed = () { | 
| -        _stdoutClosed = true; | 
| -        _checkDone(); | 
| -      }; | 
| - | 
| -      // Setup stderr handling. | 
| -      _stderrBuffer = new StringBuffer(); | 
| -      var stderrStream = new StringInputStream(p.stderr, stderrEncoding); | 
| -      stderrStream.onData = () { | 
| -        var data = stderrStream.read(); | 
| -        if (data != null) _stderrBuffer.add(data); | 
| -      }; | 
| -      stderrStream.onClosed = () { | 
| -        _stderrClosed = true; | 
| -        _checkDone(); | 
| -      }; | 
| -    }).catchError((error) { | 
| -      _completer.completeError(error.error); | 
| -    }); | 
| -  } | 
| - | 
| -  void _checkDone() { | 
| -    if (_exitCode != null && _stderrClosed && _stdoutClosed) { | 
| -      _completer.complete(new _ProcessResult(_exitCode, | 
| -                                             _stdoutBuffer.toString(), | 
| -                                             _stderrBuffer.toString())); | 
| +    if (options.stderrEncoding != null) { | 
| +      stderrEncoding = options.stderrEncoding; | 
| +      if (stderrEncoding is !Encoding) { | 
| +        throw new ArgumentError( | 
| +            'stderrEncoding option is not an encoding: $stderrEncoding'); | 
| +      } | 
| } | 
| } | 
|  | 
| -  Future<ProcessResult> get _result => _completer.future; | 
| - | 
| -  Completer<ProcessResult> _completer; | 
| -  StringBuffer _stdoutBuffer; | 
| -  StringBuffer _stderrBuffer; | 
| -  int _exitCode; | 
| -  bool _stdoutClosed = false; | 
| -  bool _stderrClosed = false; | 
| +  // Start the underlying process. | 
| +  return Process.start(path, arguments, options).then((Process p) { | 
| +    // Make sure the process stdin is closed. | 
| +    p.stdin.close(); | 
| + | 
| +    // Setup stdout handling. | 
| +    Future<StringBuffer> stdout = p.stdout | 
| +        .transform(new StringDecoder(stdoutEncoding)) | 
| +        .reduce( | 
| +            new StringBuffer(), | 
| +            (buf, data) { | 
| +              buf.add(data); | 
| +              return buf; | 
| +            }); | 
| + | 
| +    Future<StringBuffer> stderr = p.stderr | 
| +        .transform(new StringDecoder(stderrEncoding)) | 
| +        .reduce( | 
| +            new StringBuffer(), | 
| +            (buf, data) { | 
| +              buf.add(data); | 
| +              return buf; | 
| +            }); | 
| + | 
| +    return Future.wait([p.exitCode, stdout, stderr]).then((result) { | 
| +      return new _ProcessResult(result[0], | 
| +                                result[1].toString(), | 
| +                                result[2].toString()); | 
| +    }); | 
| +  }); | 
| } | 
|  | 
|  | 
|  |