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

Side by Side Diff: runtime/bin/process_android.cc

Issue 890633002: Add an option for starting a detached process with stdio connected (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased Created 5 years, 10 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.cc ('k') | runtime/bin/process_linux.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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 #include "platform/globals.h" 5 #include "platform/globals.h"
6 #if defined(TARGET_OS_ANDROID) 6 #if defined(TARGET_OS_ANDROID)
7 7
8 #include "bin/process.h" 8 #include "bin/process.h"
9 9
10 #include <errno.h> // NOLINT 10 #include <errno.h> // NOLINT
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 231
232 232
233 class ProcessStarter { 233 class ProcessStarter {
234 public: 234 public:
235 ProcessStarter(const char* path, 235 ProcessStarter(const char* path,
236 char* arguments[], 236 char* arguments[],
237 intptr_t arguments_length, 237 intptr_t arguments_length,
238 const char* working_directory, 238 const char* working_directory,
239 char* environment[], 239 char* environment[],
240 intptr_t environment_length, 240 intptr_t environment_length,
241 bool detach, 241 ProcessStartMode mode,
242 intptr_t* in, 242 intptr_t* in,
243 intptr_t* out, 243 intptr_t* out,
244 intptr_t* err, 244 intptr_t* err,
245 intptr_t* id, 245 intptr_t* id,
246 intptr_t* exit_event, 246 intptr_t* exit_event,
247 char** os_error_message) 247 char** os_error_message)
248 : path_(path), 248 : path_(path),
249 working_directory_(working_directory), 249 working_directory_(working_directory),
250 detach_(detach), 250 mode_(mode),
251 in_(in), 251 in_(in),
252 out_(out), 252 out_(out),
253 err_(err), 253 err_(err),
254 id_(id), 254 id_(id),
255 exit_event_(exit_event), 255 exit_event_(exit_event),
256 os_error_message_(os_error_message) { 256 os_error_message_(os_error_message) {
257 read_in_[0] = -1; 257 read_in_[0] = -1;
258 read_in_[1] = -1; 258 read_in_[1] = -1;
259 read_err_[0] = -1; 259 read_err_[0] = -1;
260 read_err_[1] = -1; 260 read_err_[1] = -1;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 // This runs in the new process. 301 // This runs in the new process.
302 NewProcess(); 302 NewProcess();
303 } 303 }
304 304
305 // This runs in the original process. 305 // This runs in the original process.
306 306
307 // Be sure to listen for exit-codes, now we have a child-process. 307 // Be sure to listen for exit-codes, now we have a child-process.
308 ExitCodeHandler::ProcessStarted(); 308 ExitCodeHandler::ProcessStarted();
309 309
310 // Register the child process if not detached. 310 // Register the child process if not detached.
311 if (!detach_) { 311 if (mode_ == kNormal) {
312 err = RegisterProcess(pid); 312 err = RegisterProcess(pid);
313 if (err != 0) return err; 313 if (err != 0) return err;
314 } 314 }
315 315
316 // Notify child process to start. This is done to delay the call to exec 316 // Notify child process to start. This is done to delay the call to exec
317 // until the process is registered above, and we are ready to receive the 317 // until the process is registered above, and we are ready to receive the
318 // exit code. 318 // exit code.
319 char msg = '1'; 319 char msg = '1';
320 int bytes_written = 320 int bytes_written =
321 FDUtils::WriteToBlocking(read_in_[1], &msg, sizeof(msg)); 321 FDUtils::WriteToBlocking(read_in_[1], &msg, sizeof(msg));
322 if (bytes_written != sizeof(msg)) { 322 if (bytes_written != sizeof(msg)) {
323 return CleanupAndReturnError(); 323 return CleanupAndReturnError();
324 } 324 }
325 325
326 // Read the result of executing the child process. 326 // Read the result of executing the child process.
327 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); 327 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1]));
328 exec_control_[1] = -1; 328 exec_control_[1] = -1;
329 if (!detach_) { 329 if (mode_ == kNormal) {
330 err = ReadExecResult(); 330 err = ReadExecResult();
331 } else { 331 } else {
332 err = ReadDetachedExecResult(&pid); 332 err = ReadDetachedExecResult(&pid);
333 } 333 }
334 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0])); 334 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0]));
335 exec_control_[0] = -1; 335 exec_control_[0] = -1;
336 336
337 // Return error code if any failures. 337 // Return error code if any failures.
338 if (err != 0) { 338 if (err != 0) {
339 if (!detach_) { 339 if (mode_ == kNormal) {
340 // Since exec() failed, we're not interested in the exit code. 340 // Since exec() failed, we're not interested in the exit code.
341 // We close the reading side of the exit code pipe here. 341 // We close the reading side of the exit code pipe here.
342 // GetProcessExitCodes will get a broken pipe error when it 342 // GetProcessExitCodes will get a broken pipe error when it
343 // tries to write to the writing side of the pipe and it will 343 // tries to write to the writing side of the pipe and it will
344 // ignore the error. 344 // ignore the error.
345 VOID_TEMP_FAILURE_RETRY(close(*exit_event_)); 345 VOID_TEMP_FAILURE_RETRY(close(*exit_event_));
346 *exit_event_ = -1; 346 *exit_event_ = -1;
347 } 347 }
348 CloseAllPipes(); 348 CloseAllPipes();
349 return err; 349 return err;
350 } 350 }
351 351
352 if (!detach_) { 352 if (mode_ != kDetached) {
353 // Connect stdio, stdout and stderr. 353 // Connect stdio, stdout and stderr.
354 FDUtils::SetNonBlocking(read_in_[0]); 354 FDUtils::SetNonBlocking(read_in_[0]);
355 *in_ = read_in_[0]; 355 *in_ = read_in_[0];
356 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); 356 VOID_TEMP_FAILURE_RETRY(close(read_in_[1]));
357 FDUtils::SetNonBlocking(write_out_[1]); 357 FDUtils::SetNonBlocking(write_out_[1]);
358 *out_ = write_out_[1]; 358 *out_ = write_out_[1];
359 VOID_TEMP_FAILURE_RETRY(close(write_out_[0])); 359 VOID_TEMP_FAILURE_RETRY(close(write_out_[0]));
360 FDUtils::SetNonBlocking(read_err_[0]); 360 FDUtils::SetNonBlocking(read_err_[0]);
361 *err_ = read_err_[0]; 361 *err_ = read_err_[0];
362 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); 362 VOID_TEMP_FAILURE_RETRY(close(read_err_[1]));
(...skipping 25 matching lines...) Expand all
388 388
389 // For a detached process the pipe to connect stdout is still used for 389 // For a detached process the pipe to connect stdout is still used for
390 // signaling when to do the first fork. 390 // signaling when to do the first fork.
391 result = TEMP_FAILURE_RETRY(pipe(read_in_)); 391 result = TEMP_FAILURE_RETRY(pipe(read_in_));
392 if (result < 0) { 392 if (result < 0) {
393 return CleanupAndReturnError(); 393 return CleanupAndReturnError();
394 } 394 }
395 FDUtils::SetCloseOnExec(read_in_[0]); 395 FDUtils::SetCloseOnExec(read_in_[0]);
396 396
397 // For detached processes the pipe to connect stderr and stdin are not used. 397 // For detached processes the pipe to connect stderr and stdin are not used.
398 if (!detach_) { 398 if (mode_ != kDetached) {
399 result = TEMP_FAILURE_RETRY(pipe(read_err_)); 399 result = TEMP_FAILURE_RETRY(pipe(read_err_));
400 if (result < 0) { 400 if (result < 0) {
401 return CleanupAndReturnError(); 401 return CleanupAndReturnError();
402 } 402 }
403 FDUtils::SetCloseOnExec(read_err_[0]); 403 FDUtils::SetCloseOnExec(read_err_[0]);
404 404
405 result = TEMP_FAILURE_RETRY(pipe(write_out_)); 405 result = TEMP_FAILURE_RETRY(pipe(write_out_));
406 if (result < 0) { 406 if (result < 0) {
407 return CleanupAndReturnError(); 407 return CleanupAndReturnError();
408 } 408 }
409 FDUtils::SetCloseOnExec(write_out_[1]); 409 FDUtils::SetCloseOnExec(write_out_[1]);
410 } 410 }
411 411
412 return 0; 412 return 0;
413 } 413 }
414 414
415 415
416 void NewProcess() { 416 void NewProcess() {
417 // Wait for parent process before setting up the child process. 417 // Wait for parent process before setting up the child process.
418 char msg; 418 char msg;
419 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); 419 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg));
420 if (bytes_read != sizeof(msg)) { 420 if (bytes_read != sizeof(msg)) {
421 perror("Failed receiving notification message"); 421 perror("Failed receiving notification message");
422 exit(1); 422 exit(1);
423 } 423 }
424 if (detach_) { 424 if (mode_ == kNormal) {
425 ExecProcess();
426 } else {
425 ExecDetachedProcess(); 427 ExecDetachedProcess();
426 } else {
427 ExecProcess();
428 } 428 }
429 } 429 }
430 430
431 431
432 void ExecProcess() { 432 void ExecProcess() {
433 VOID_TEMP_FAILURE_RETRY(close(write_out_[1])); 433 VOID_TEMP_FAILURE_RETRY(close(write_out_[1]));
434 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); 434 VOID_TEMP_FAILURE_RETRY(close(read_in_[0]));
435 VOID_TEMP_FAILURE_RETRY(close(read_err_[0])); 435 VOID_TEMP_FAILURE_RETRY(close(read_err_[0]));
436 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0])); 436 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0]));
437 437
(...skipping 22 matching lines...) Expand all
460 } 460 }
461 461
462 VOID_TEMP_FAILURE_RETRY( 462 VOID_TEMP_FAILURE_RETRY(
463 execvp(path_, const_cast<char* const*>(program_arguments_))); 463 execvp(path_, const_cast<char* const*>(program_arguments_)));
464 464
465 ReportChildError(); 465 ReportChildError();
466 } 466 }
467 467
468 468
469 void ExecDetachedProcess() { 469 void ExecDetachedProcess() {
470 ASSERT(write_out_[0] == -1); 470 if (mode_ == kDetached) {
471 ASSERT(write_out_[1] == -1); 471 ASSERT(write_out_[0] == -1);
472 ASSERT(read_err_[0] == -1); 472 ASSERT(write_out_[1] == -1);
473 ASSERT(read_err_[1] == -1); 473 ASSERT(read_err_[0] == -1);
474 // For a detached process the pipe to connect stdout is only used for 474 ASSERT(read_err_[1] == -1);
475 // signaling when to do the first fork. 475 // For a detached process the pipe to connect stdout is only used for
476 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); 476 // signaling when to do the first fork.
477 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); 477 VOID_TEMP_FAILURE_RETRY(close(read_in_[0]));
478 read_in_[0] = -1;
479 VOID_TEMP_FAILURE_RETRY(close(read_in_[1]));
480 read_in_[1] = -1;
481 } else {
482 // Don't close any fds if keeping stdio open to the detached process.
483 ASSERT(mode_ == kDetachedWithStdio);
484 }
478 // Fork once more to start a new session. 485 // Fork once more to start a new session.
479 pid_t pid = TEMP_FAILURE_RETRY(fork()); 486 pid_t pid = TEMP_FAILURE_RETRY(fork());
480 if (pid < 0) { 487 if (pid < 0) {
481 ReportChildError(); 488 ReportChildError();
482 } else if (pid == 0) { 489 } else if (pid == 0) {
483 // Start a new session. 490 // Start a new session.
484 if (TEMP_FAILURE_RETRY(setsid()) == -1) { 491 if (TEMP_FAILURE_RETRY(setsid()) == -1) {
485 ReportChildError(); 492 ReportChildError();
486 } else { 493 } else {
487 // Do a final fork to not be the session leader. 494 // Do a final fork to not be the session leader.
488 pid = TEMP_FAILURE_RETRY(fork()); 495 pid = TEMP_FAILURE_RETRY(fork());
489 if (pid < 0) { 496 if (pid < 0) {
490 ReportChildError(); 497 ReportChildError();
491 } else if (pid == 0) { 498 } else if (pid == 0) {
492 // Close all open file descriptors except for exec_control_[1]. 499 if (mode_ == kDetached) {
493 int max_fds = sysconf(_SC_OPEN_MAX); 500 SetupDetached();
494 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX; 501 } else {
495 for (int fd = 0; fd < max_fds; fd++) { 502 SetupDetachedWithStdio();
496 if (fd != exec_control_[1]) {
497 VOID_TEMP_FAILURE_RETRY(close(fd));
498 }
499 } 503 }
500 504
501 // Re-open stdin, stdout and stderr and connect them to /dev/null. 505 if (working_directory_ != NULL &&
502 // The loop above should already have closed all of them, so 506 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) {
503 // creating new file descriptors should start at STDIN_FILENO.
504 int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
505 if (fd != STDIN_FILENO) {
506 ReportChildError();
507 }
508 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) !=
509 STDOUT_FILENO) {
510 ReportChildError();
511 }
512 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) !=
513 STDERR_FILENO) {
514 ReportChildError(); 507 ReportChildError();
515 } 508 }
516 509
517 // Report the final PID and do the exec. 510 // Report the final PID and do the exec.
518 ReportPid(getpid()); // getpid cannot fail. 511 ReportPid(getpid()); // getpid cannot fail.
519 VOID_TEMP_FAILURE_RETRY( 512 VOID_TEMP_FAILURE_RETRY(
520 execvp(path_, const_cast<char* const*>(program_arguments_))); 513 execvp(path_, const_cast<char* const*>(program_arguments_)));
521 ReportChildError(); 514 ReportChildError();
522 } else { 515 } else {
523 // Exit the intermeiate process. 516 // Exit the intermeiate process.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 child_errno = result[1]; 577 child_errno = result[1];
585 ReadChildError(); 578 ReadChildError();
586 return child_errno; 579 return child_errno;
587 } else if (bytes_read == -1) { 580 } else if (bytes_read == -1) {
588 return errno; 581 return errno;
589 } 582 }
590 return 0; 583 return 0;
591 } 584 }
592 585
593 586
587 void SetupDetached() {
588 ASSERT(mode_ == kDetached);
589
590 // Close all open file descriptors except for exec_control_[1].
591 int max_fds = sysconf(_SC_OPEN_MAX);
592 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX;
593 for (int fd = 0; fd < max_fds; fd++) {
594 if (fd != exec_control_[1]) {
595 VOID_TEMP_FAILURE_RETRY(close(fd));
596 }
597 }
598
599 // Re-open stdin, stdout and stderr and connect them to /dev/null.
600 // The loop above should already have closed all of them, so
601 // creating new file descriptors should start at STDIN_FILENO.
602 int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
603 if (fd != STDIN_FILENO) {
604 ReportChildError();
605 }
606 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) !=
607 STDOUT_FILENO) {
608 ReportChildError();
609 }
610 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) !=
611 STDERR_FILENO) {
612 ReportChildError();
613 }
614 }
615
616 void SetupDetachedWithStdio() {
617 // Close all open file descriptors except for
618 // exec_control_[1], write_out_[0], read_in_[1] and
619 // read_err_[1].
620 int max_fds = sysconf(_SC_OPEN_MAX);
621 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX;
622 for (int fd = 0; fd < max_fds; fd++) {
623 if (fd != exec_control_[1] &&
624 fd != write_out_[0] &&
625 fd != read_in_[1] &&
626 fd != read_err_[1]) {
627 VOID_TEMP_FAILURE_RETRY(close(fd));
628 }
629 }
630
631 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) {
632 ReportChildError();
633 }
634 VOID_TEMP_FAILURE_RETRY(close(write_out_[0]));
635
636 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) {
637 ReportChildError();
638 }
639 VOID_TEMP_FAILURE_RETRY(close(read_in_[1]));
640
641 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) {
642 ReportChildError();
643 }
644 VOID_TEMP_FAILURE_RETRY(close(read_err_[1]));
645 }
646
647
594 int CleanupAndReturnError() { 648 int CleanupAndReturnError() {
595 int actual_errno = errno; 649 int actual_errno = errno;
596 // If CleanupAndReturnError is called without an actual errno make 650 // If CleanupAndReturnError is called without an actual errno make
597 // sure to return an error anyway. 651 // sure to return an error anyway.
598 if (actual_errno == 0) actual_errno = EPERM; 652 if (actual_errno == 0) actual_errno = EPERM;
599 SetChildOsErrorMessage(); 653 SetChildOsErrorMessage();
600 CloseAllPipes(); 654 CloseAllPipes();
601 return actual_errno; 655 return actual_errno;
602 } 656 }
603 657
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
674 int read_in_[2]; // Pipe for stdout to child process. 728 int read_in_[2]; // Pipe for stdout to child process.
675 int read_err_[2]; // Pipe for stderr to child process. 729 int read_err_[2]; // Pipe for stderr to child process.
676 int write_out_[2]; // Pipe for stdin to child process. 730 int write_out_[2]; // Pipe for stdin to child process.
677 int exec_control_[2]; // Pipe to get the result from exec. 731 int exec_control_[2]; // Pipe to get the result from exec.
678 732
679 char** program_arguments_; 733 char** program_arguments_;
680 char** program_environment_; 734 char** program_environment_;
681 735
682 const char* path_; 736 const char* path_;
683 const char* working_directory_; 737 const char* working_directory_;
684 bool detach_; 738 ProcessStartMode mode_;
685 intptr_t* in_; 739 intptr_t* in_;
686 intptr_t* out_; 740 intptr_t* out_;
687 intptr_t* err_; 741 intptr_t* err_;
688 intptr_t* id_; 742 intptr_t* id_;
689 intptr_t* exit_event_; 743 intptr_t* exit_event_;
690 char** os_error_message_; 744 char** os_error_message_;
691 }; 745 };
692 746
693 747
694 int Process::Start(const char* path, 748 int Process::Start(const char* path,
695 char* arguments[], 749 char* arguments[],
696 intptr_t arguments_length, 750 intptr_t arguments_length,
697 const char* working_directory, 751 const char* working_directory,
698 char* environment[], 752 char* environment[],
699 intptr_t environment_length, 753 intptr_t environment_length,
700 bool detach, 754 ProcessStartMode mode,
701 intptr_t* in, 755 intptr_t* in,
702 intptr_t* out, 756 intptr_t* out,
703 intptr_t* err, 757 intptr_t* err,
704 intptr_t* id, 758 intptr_t* id,
705 intptr_t* exit_event, 759 intptr_t* exit_event,
706 char** os_error_message) { 760 char** os_error_message) {
707 ProcessStarter starter(path, 761 ProcessStarter starter(path,
708 arguments, 762 arguments,
709 arguments_length, 763 arguments_length,
710 working_directory, 764 working_directory,
711 environment, 765 environment,
712 environment_length, 766 environment_length,
713 detach, 767 mode,
714 in, 768 in,
715 out, 769 out,
716 err, 770 err,
717 id, 771 id,
718 exit_event, 772 exit_event,
719 os_error_message); 773 os_error_message);
720 return starter.Start(); 774 return starter.Start();
721 } 775 }
722 776
723 777
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
959 bzero(&act, sizeof(act)); 1013 bzero(&act, sizeof(act));
960 act.sa_handler = SIG_DFL; 1014 act.sa_handler = SIG_DFL;
961 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); 1015 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL));
962 } 1016 }
963 } 1017 }
964 1018
965 } // namespace bin 1019 } // namespace bin
966 } // namespace dart 1020 } // namespace dart
967 1021
968 #endif // defined(TARGET_OS_ANDROID) 1022 #endif // defined(TARGET_OS_ANDROID)
OLDNEW
« no previous file with comments | « runtime/bin/process.cc ('k') | runtime/bin/process_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698