Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(989)

Side by Side Diff: runtime/bin/process_patch.dart

Issue 798743004: Add support for starting a detached process (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/process_macos.cc ('k') | runtime/bin/process_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 patch class _WindowsCodePageDecoder { 5 patch class _WindowsCodePageDecoder {
6 /* patch */ static String _decodeBytes(List<int> bytes) 6 /* patch */ static String _decodeBytes(List<int> bytes)
7 native "SystemEncodingToString"; 7 native "SystemEncodingToString";
8 } 8 }
9 9
10 10
11 patch class _WindowsCodePageEncoder { 11 patch class _WindowsCodePageEncoder {
12 /* patch */ static List<int> _encodeString(String string) 12 /* patch */ static List<int> _encodeString(String string)
13 native "StringToSystemEncoding"; 13 native "StringToSystemEncoding";
14 } 14 }
15 15
16 16
17 patch class Process { 17 patch class Process {
18 /* patch */ static Future<Process> start( 18 /* patch */ static Future<Process> start(
19 String executable, 19 String executable,
20 List<String> arguments, 20 List<String> arguments,
21 {String workingDirectory, 21 {String workingDirectory,
22 Map<String, String> environment, 22 Map<String, String> environment,
23 bool includeParentEnvironment: true, 23 bool includeParentEnvironment: true,
24 bool runInShell: false}) { 24 bool runInShell: false,
25 bool detach: false}) {
25 _ProcessImpl process = new _ProcessImpl(executable, 26 _ProcessImpl process = new _ProcessImpl(executable,
26 arguments, 27 arguments,
27 workingDirectory, 28 workingDirectory,
28 environment, 29 environment,
29 includeParentEnvironment, 30 includeParentEnvironment,
30 runInShell); 31 runInShell,
32 detach);
31 return process._start(); 33 return process._start();
32 } 34 }
33 35
34 /* patch */ static Future<ProcessResult> run( 36 /* patch */ static Future<ProcessResult> run(
35 String executable, 37 String executable,
36 List<String> arguments, 38 List<String> arguments,
37 {String workingDirectory, 39 {String workingDirectory,
38 Map<String, String> environment, 40 Map<String, String> environment,
39 bool includeParentEnvironment: true, 41 bool includeParentEnvironment: true,
40 bool runInShell: false, 42 bool runInShell: false,
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject 168 class _ProcessImpl extends _ProcessImplNativeWrapper with _ServiceObject
167 implements Process { 169 implements Process {
168 // Use default Map so we keep order. 170 // Use default Map so we keep order.
169 static Map<int, _ProcessImpl> _processes = new Map<int, _ProcessImpl>(); 171 static Map<int, _ProcessImpl> _processes = new Map<int, _ProcessImpl>();
170 172
171 _ProcessImpl(String path, 173 _ProcessImpl(String path,
172 List<String> arguments, 174 List<String> arguments,
173 String this._workingDirectory, 175 String this._workingDirectory,
174 Map<String, String> environment, 176 Map<String, String> environment,
175 bool includeParentEnvironment, 177 bool includeParentEnvironment,
176 bool runInShell) : super() { 178 bool runInShell,
179 bool detach) : super() {
177 _processes[_serviceId] = this; 180 _processes[_serviceId] = this;
178 if (runInShell) { 181 if (runInShell) {
179 arguments = _getShellArguments(path, arguments); 182 arguments = _getShellArguments(path, arguments);
180 path = _getShellCommand(); 183 path = _getShellCommand();
181 } 184 }
182 185
183 if (path is !String) { 186 if (path is !String) {
184 throw new ArgumentError("Path is not a String: $path"); 187 throw new ArgumentError("Path is not a String: $path");
185 } 188 }
186 _path = path; 189 _path = path;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 Platform.environment.forEach((key, value) { 226 Platform.environment.forEach((key, value) {
224 assert(key is String); 227 assert(key is String);
225 assert(value is String); 228 assert(value is String);
226 // Do not override keys already set as part of environment. 229 // Do not override keys already set as part of environment.
227 if (!environment.containsKey(key)) { 230 if (!environment.containsKey(key)) {
228 _environment.add('$key=$value'); 231 _environment.add('$key=$value');
229 } 232 }
230 }); 233 });
231 } 234 }
232 235
233 // stdin going to process. 236 if (detach is !bool) {
234 _stdin = new _StdSink(new _Socket._writePipe()); 237 throw new ArgumentError("Detach is not a boolean: $detach");
235 _stdin._sink._owner = this; 238 }
236 // stdout coming from process. 239 _detach = detach;
237 _stdout = new _StdStream(new _Socket._readPipe()); 240
238 _stdout._stream._owner = this; 241
239 // stderr coming from process. 242 if (!detach) {
240 _stderr = new _StdStream(new _Socket._readPipe()); 243 // stdin going to process.
241 _stderr._stream._owner = this; 244 _stdin = new _StdSink(new _Socket._writePipe());
242 _exitHandler = new _Socket._readPipe(); 245 _stdin._sink._owner = this;
246 // stdout coming from process.
247 _stdout = new _StdStream(new _Socket._readPipe());
248 _stdout._stream._owner = this;
249 // stderr coming from process.
250 _stderr = new _StdStream(new _Socket._readPipe());
251 _stderr._stream._owner = this;
252 _exitHandler = new _Socket._readPipe();
253 }
243 _ended = false; 254 _ended = false;
244 _started = false; 255 _started = false;
245 } 256 }
246 257
247 String get _serviceTypePath => 'io/processes'; 258 String get _serviceTypePath => 'io/processes';
248 String get _serviceTypeName => 'Process'; 259 String get _serviceTypeName => 'Process';
249 260
250 Map _toJSON(bool ref) { 261 Map _toJSON(bool ref) {
251 var r = { 262 var r = {
252 'id': _servicePath, 263 'id': _servicePath,
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 367
357 int _intFromBytes(List<int> bytes, int offset) { 368 int _intFromBytes(List<int> bytes, int offset) {
358 return (bytes[offset] + 369 return (bytes[offset] +
359 (bytes[offset + 1] << 8) + 370 (bytes[offset + 1] << 8) +
360 (bytes[offset + 2] << 16) + 371 (bytes[offset + 2] << 16) +
361 (bytes[offset + 3] << 24)); 372 (bytes[offset + 3] << 24));
362 } 373 }
363 374
364 Future<Process> _start() { 375 Future<Process> _start() {
365 var completer = new Completer(); 376 var completer = new Completer();
377 if (!_detach) {
378 _exitCode = new Completer<int>();
379 }
366 // TODO(ager): Make the actual process starting really async instead of 380 // TODO(ager): Make the actual process starting really async instead of
367 // simulating it with a timer. 381 // simulating it with a timer.
368 Timer.run(() { 382 Timer.run(() {
369 var status = new _ProcessStartStatus(); 383 var status = new _ProcessStartStatus();
370 bool success = _startNative(_path, 384 bool success =
371 _arguments, 385 _startNative(_path,
372 _workingDirectory, 386 _arguments,
373 _environment, 387 _workingDirectory,
374 _stdin._sink._nativeSocket, 388 _environment,
375 _stdout._stream._nativeSocket, 389 _detach,
376 _stderr._stream._nativeSocket, 390 _detach ? null : _stdin._sink._nativeSocket,
377 _exitHandler._nativeSocket, 391 _detach ? null : _stdout._stream._nativeSocket,
378 status); 392 _detach ? null : _stderr._stream._nativeSocket,
393 _detach ? null : _exitHandler._nativeSocket,
394 status);
379 if (!success) { 395 if (!success) {
380 completer.completeError( 396 completer.completeError(
381 new ProcessException(_path, 397 new ProcessException(_path,
382 _arguments, 398 _arguments,
383 status._errorMessage, 399 status._errorMessage,
384 status._errorCode)); 400 status._errorCode));
385 return; 401 return;
386 } 402 }
387 403
388 _started = true; 404 _started = true;
389 405
390 // Setup an exit handler to handle internal cleanup and possible 406 // Setup an exit handler to handle internal cleanup and possible
391 // callback when a process terminates. 407 // callback when a process terminates.
392 int exitDataRead = 0; 408 if (!_detach) {
393 final int EXIT_DATA_SIZE = 8; 409 int exitDataRead = 0;
394 List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE); 410 final int EXIT_DATA_SIZE = 8;
395 _exitHandler.listen((data) { 411 List<int> exitDataBuffer = new List<int>(EXIT_DATA_SIZE);
412 _exitHandler.listen((data) {
396 413
397 int exitCode(List<int> ints) { 414 int exitCode(List<int> ints) {
398 var code = _intFromBytes(ints, 0); 415 var code = _intFromBytes(ints, 0);
399 var negative = _intFromBytes(ints, 4); 416 var negative = _intFromBytes(ints, 4);
400 assert(negative == 0 || negative == 1); 417 assert(negative == 0 || negative == 1);
401 return (negative == 0) ? code : -code; 418 return (negative == 0) ? code : -code;
402 } 419 }
403 420
404 void handleExit() { 421 void handleExit() {
405 _ended = true; 422 _ended = true;
406 _exitCode.complete(exitCode(exitDataBuffer)); 423 _exitCode.complete(exitCode(exitDataBuffer));
407 // Kill stdin, helping hand if the user forgot to do it. 424 // Kill stdin, helping hand if the user forgot to do it.
408 _stdin._sink.destroy(); 425 _stdin._sink.destroy();
409 _processes.remove(_serviceId); 426 _processes.remove(_serviceId);
410 } 427 }
411 428
412 exitDataBuffer.setRange(exitDataRead, exitDataRead + data.length, data); 429 exitDataBuffer.setRange(
413 exitDataRead += data.length; 430 exitDataRead, exitDataRead + data.length, data);
414 if (exitDataRead == EXIT_DATA_SIZE) { 431 exitDataRead += data.length;
415 handleExit(); 432 if (exitDataRead == EXIT_DATA_SIZE) {
416 } 433 handleExit();
417 }); 434 }
435 });
436 }
418 437
419 completer.complete(this); 438 completer.complete(this);
420 }); 439 });
421 return completer.future; 440 return completer.future;
422 } 441 }
423 442
424 ProcessResult _runAndWait(Encoding stdoutEncoding, 443 ProcessResult _runAndWait(Encoding stdoutEncoding,
425 Encoding stderrEncoding) { 444 Encoding stderrEncoding) {
426 var status = new _ProcessStartStatus(); 445 var status = new _ProcessStartStatus();
446 _exitCode = new Completer<int>();
427 bool success = _startNative(_path, 447 bool success = _startNative(_path,
428 _arguments, 448 _arguments,
429 _workingDirectory, 449 _workingDirectory,
430 _environment, 450 _environment,
451 false,
431 _stdin._sink._nativeSocket, 452 _stdin._sink._nativeSocket,
432 _stdout._stream._nativeSocket, 453 _stdout._stream._nativeSocket,
433 _stderr._stream._nativeSocket, 454 _stderr._stream._nativeSocket,
434 _exitHandler._nativeSocket, 455 _exitHandler._nativeSocket,
435 status); 456 status);
436 if (!success) { 457 if (!success) {
437 throw new ProcessException(_path, 458 throw new ProcessException(_path,
438 _arguments, 459 _arguments,
439 status._errorMessage, 460 status._errorMessage,
440 status._errorCode); 461 status._errorCode);
(...skipping 16 matching lines...) Expand all
457 result[0], 478 result[0],
458 result[1], 479 result[1],
459 getOutput(result[2], stdoutEncoding), 480 getOutput(result[2], stdoutEncoding),
460 getOutput(result[3], stderrEncoding)); 481 getOutput(result[3], stderrEncoding));
461 } 482 }
462 483
463 bool _startNative(String path, 484 bool _startNative(String path,
464 List<String> arguments, 485 List<String> arguments,
465 String workingDirectory, 486 String workingDirectory,
466 List<String> environment, 487 List<String> environment,
488 bool detach,
467 _NativeSocket stdin, 489 _NativeSocket stdin,
468 _NativeSocket stdout, 490 _NativeSocket stdout,
469 _NativeSocket stderr, 491 _NativeSocket stderr,
470 _NativeSocket exitHandler, 492 _NativeSocket exitHandler,
471 _ProcessStartStatus status) native "Process_Start"; 493 _ProcessStartStatus status) native "Process_Start";
472 494
473 _wait(_NativeSocket stdin, 495 _wait(_NativeSocket stdin,
474 _NativeSocket stdout, 496 _NativeSocket stdout,
475 _NativeSocket stderr, 497 _NativeSocket stderr,
476 _NativeSocket exitHandler) native "Process_Wait"; 498 _NativeSocket exitHandler) native "Process_Wait";
477 499
478 Stream<List<int>> get stdout { 500 Stream<List<int>> get stdout {
479 return _stdout; 501 return _stdout;
480 } 502 }
481 503
482 Stream<List<int>> get stderr { 504 Stream<List<int>> get stderr {
483 return _stderr; 505 return _stderr;
484 } 506 }
485 507
486 IOSink get stdin { 508 IOSink get stdin {
487 return _stdin; 509 return _stdin;
488 } 510 }
489 511
490 Future<int> get exitCode => _exitCode.future; 512 Future<int> get exitCode => _exitCode != null ? _exitCode.future : null;
491 513
492 bool kill([ProcessSignal signal = ProcessSignal.SIGTERM]) { 514 bool kill([ProcessSignal signal = ProcessSignal.SIGTERM]) {
493 if (signal is! ProcessSignal) { 515 if (signal is! ProcessSignal) {
494 throw new ArgumentError( 516 throw new ArgumentError(
495 "Argument 'signal' must be a ProcessSignal"); 517 "Argument 'signal' must be a ProcessSignal");
496 } 518 }
497 assert(_started); 519 assert(_started);
498 if (_ended) return false; 520 if (_ended) return false;
499 return _kill(this, signal._signalNumber); 521 return _kill(this, signal._signalNumber);
500 } 522 }
501 523
502 bool _kill(Process p, int signal) native "Process_Kill"; 524 bool _kill(Process p, int signal) native "Process_Kill";
503 525
504 int get pid => _ProcessUtils._pid(this); 526 int get pid => _ProcessUtils._pid(this);
505 527
506 String _path; 528 String _path;
507 List<String> _arguments; 529 List<String> _arguments;
508 String _workingDirectory; 530 String _workingDirectory;
509 List<String> _environment; 531 List<String> _environment;
532 bool _detach;
510 // Private methods of Socket are used by _in, _out, and _err. 533 // Private methods of Socket are used by _in, _out, and _err.
511 _StdSink _stdin; 534 _StdSink _stdin;
512 _StdStream _stdout; 535 _StdStream _stdout;
513 _StdStream _stderr; 536 _StdStream _stderr;
514 Socket _exitHandler; 537 Socket _exitHandler;
515 bool _ended; 538 bool _ended;
516 bool _started; 539 bool _started;
517 final Completer<int> _exitCode = new Completer<int>(); 540 Completer<int> _exitCode;
518 } 541 }
519 542
520 543
521 // _NonInteractiveProcess is a wrapper around an interactive process 544 // _NonInteractiveProcess is a wrapper around an interactive process
522 // that buffers output so it can be delivered when the process exits. 545 // that buffers output so it can be delivered when the process exits.
523 // _NonInteractiveProcess is used to implement the Process.run 546 // _NonInteractiveProcess is used to implement the Process.run
524 // method. 547 // method.
525 Future<ProcessResult> _runNonInteractiveProcess(String path, 548 Future<ProcessResult> _runNonInteractiveProcess(String path,
526 List<String> arguments, 549 List<String> arguments,
527 String workingDirectory, 550 String workingDirectory,
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 Map<String, String> environment, 600 Map<String, String> environment,
578 bool includeParentEnvironment, 601 bool includeParentEnvironment,
579 bool runInShell, 602 bool runInShell,
580 Encoding stdoutEncoding, 603 Encoding stdoutEncoding,
581 Encoding stderrEncoding) { 604 Encoding stderrEncoding) {
582 var process = new _ProcessImpl(executable, 605 var process = new _ProcessImpl(executable,
583 arguments, 606 arguments,
584 workingDirectory, 607 workingDirectory,
585 environment, 608 environment,
586 includeParentEnvironment, 609 includeParentEnvironment,
587 runInShell); 610 runInShell,
611 false);
588 return process._runAndWait(stdoutEncoding, stderrEncoding); 612 return process._runAndWait(stdoutEncoding, stderrEncoding);
589 } 613 }
590 614
591 615
592 class _ProcessResult implements ProcessResult { 616 class _ProcessResult implements ProcessResult {
593 const _ProcessResult(int this.pid, 617 const _ProcessResult(int this.pid,
594 int this.exitCode, 618 int this.exitCode,
595 this.stdout, 619 this.stdout,
596 this.stderr); 620 this.stderr);
597 621
598 final int pid; 622 final int pid;
599 final int exitCode; 623 final int exitCode;
600 final stdout; 624 final stdout;
601 final stderr; 625 final stderr;
602 } 626 }
OLDNEW
« no previous file with comments | « runtime/bin/process_macos.cc ('k') | runtime/bin/process_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698