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

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

Issue 1156313004: Clean up process spawning. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 6 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
« no previous file with comments | « no previous file | tests/standalone/io/platform_executable_test.dart » ('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_LINUX) 6 #if defined(TARGET_OS_LINUX)
7 7
8 #include "bin/process.h" 8 #include "bin/process.h"
9 9
10 #include <errno.h> // NOLINT 10 #include <errno.h> // NOLINT
11 #include <fcntl.h> // NOLINT 11 #include <fcntl.h> // NOLINT
12 #include <poll.h> // NOLINT 12 #include <poll.h> // NOLINT
13 #include <stdio.h> // NOLINT 13 #include <stdio.h> // NOLINT
14 #include <stdlib.h> // NOLINT 14 #include <stdlib.h> // NOLINT
15 #include <string.h> // NOLINT 15 #include <string.h> // NOLINT
16 #include <sys/wait.h> // NOLINT 16 #include <sys/wait.h> // NOLINT
17 #include <unistd.h> // NOLINT 17 #include <unistd.h> // NOLINT
18 18
19 #include "platform/signal_blocker.h" 19 #include "platform/signal_blocker.h"
20 #include "bin/fdutils.h" 20 #include "bin/fdutils.h"
21 #include "bin/lockers.h" 21 #include "bin/lockers.h"
22 #include "bin/log.h" 22 #include "bin/log.h"
23 #include "bin/thread.h" 23 #include "bin/thread.h"
24 24
25 25
26 extern char **environ;
27
28
29 namespace dart { 26 namespace dart {
30 namespace bin { 27 namespace bin {
31 28
32 // ProcessInfo is used to map a process id to the file descriptor for 29 // ProcessInfo is used to map a process id to the file descriptor for
33 // the pipe used to communicate the exit code of the process to Dart. 30 // the pipe used to communicate the exit code of the process to Dart.
34 // ProcessInfo objects are kept in the static singly-linked 31 // ProcessInfo objects are kept in the static singly-linked
35 // ProcessInfoList. 32 // ProcessInfoList.
36 class ProcessInfo { 33 class ProcessInfo {
37 public: 34 public:
38 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) { } 35 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) { }
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 if (!running_) { 143 if (!running_) {
147 return; 144 return;
148 } 145 }
149 146
150 // Set terminate_done_ to false, so we can use it as a guard for our 147 // Set terminate_done_ to false, so we can use it as a guard for our
151 // monitor. 148 // monitor.
152 running_ = false; 149 running_ = false;
153 150
154 // Fork to wake up waitpid. 151 // Fork to wake up waitpid.
155 if (TEMP_FAILURE_RETRY(fork()) == 0) { 152 if (TEMP_FAILURE_RETRY(fork()) == 0) {
156 exit(0); 153 _exit(0);
157 } 154 }
158 155
159 monitor_->Notify(); 156 monitor_->Notify();
160 157
161 while (!terminate_done_) { 158 while (!terminate_done_) {
162 monitor_->Wait(Monitor::kNoTimeout); 159 monitor_->Wait(Monitor::kNoTimeout);
163 } 160 }
164 } 161 }
165 162
166 private: 163 private:
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 return 0; 403 return 0;
407 } 404 }
408 405
409 406
410 void NewProcess() { 407 void NewProcess() {
411 // Wait for parent process before setting up the child process. 408 // Wait for parent process before setting up the child process.
412 char msg; 409 char msg;
413 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); 410 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg));
414 if (bytes_read != sizeof(msg)) { 411 if (bytes_read != sizeof(msg)) {
415 perror("Failed receiving notification message"); 412 perror("Failed receiving notification message");
416 exit(1); 413 _exit(1);
Søren Gjesse 2015/06/10 07:20:25 Good catch!
417 } 414 }
418 if (mode_ == kNormal) { 415 if (mode_ == kNormal) {
419 ExecProcess(); 416 ExecProcess();
420 } else { 417 } else {
421 ExecDetachedProcess(); 418 ExecDetachedProcess();
422 } 419 }
423 } 420 }
424 421
425 422
426 void ExecProcess() { 423 void ExecProcess() {
427 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { 424 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) {
428 ReportChildError(); 425 ReportChildError();
429 } 426 }
430 427
431 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { 428 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) {
432 ReportChildError(); 429 ReportChildError();
433 } 430 }
434 431
435 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { 432 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) {
436 ReportChildError(); 433 ReportChildError();
437 } 434 }
438 435
439 if (working_directory_ != NULL && 436 if (working_directory_ != NULL &&
440 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { 437 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) {
441 ReportChildError(); 438 ReportChildError();
442 } 439 }
443 440
444 if (program_environment_ != NULL) { 441 if (program_environment_ != NULL) {
445 environ = program_environment_; 442 VOID_TEMP_FAILURE_RETRY(
443 execvpe(path_, const_cast<char* const*>(program_arguments_),
444 program_environment_));
445 } else {
446 VOID_TEMP_FAILURE_RETRY(
447 execvp(path_, const_cast<char* const*>(program_arguments_)));
446 } 448 }
447 449
448 VOID_TEMP_FAILURE_RETRY(
449 execvp(path_, const_cast<char* const*>(program_arguments_)));
450 450
451 ReportChildError(); 451 ReportChildError();
452 } 452 }
453 453
454 454
455 void ExecDetachedProcess() { 455 void ExecDetachedProcess() {
456 if (mode_ == kDetached) { 456 if (mode_ == kDetached) {
457 ASSERT(write_out_[0] == -1); 457 ASSERT(write_out_[0] == -1);
458 ASSERT(write_out_[1] == -1); 458 ASSERT(write_out_[1] == -1);
459 ASSERT(read_err_[0] == -1); 459 ASSERT(read_err_[0] == -1);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { 492 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) {
493 ReportChildError(); 493 ReportChildError();
494 } 494 }
495 495
496 // Report the final PID and do the exec. 496 // Report the final PID and do the exec.
497 ReportPid(getpid()); // getpid cannot fail. 497 ReportPid(getpid()); // getpid cannot fail.
498 VOID_TEMP_FAILURE_RETRY( 498 VOID_TEMP_FAILURE_RETRY(
499 execvp(path_, const_cast<char* const*>(program_arguments_))); 499 execvp(path_, const_cast<char* const*>(program_arguments_)));
500 ReportChildError(); 500 ReportChildError();
501 } else { 501 } else {
502 // Exit the intermeiate process. 502 // Exit the intermeiate process.
Søren Gjesse 2015/06/10 07:20:25 Not you fault, but please change intermeiate -> i
Anders Johnsen 2015/06/10 08:00:45 Done.
503 exit(0); 503 _exit(0);
504 } 504 }
505 } 505 }
506 } else { 506 } else {
507 // Exit the intermeiate process. 507 // Exit the intermeiate process.
Søren Gjesse 2015/06/10 07:20:25 ditto.
Anders Johnsen 2015/06/10 08:00:45 Done.
508 exit(0); 508 _exit(0);
509 } 509 }
510 } 510 }
511 511
512 512
513 int RegisterProcess(pid_t pid) { 513 int RegisterProcess(pid_t pid) {
514 int result; 514 int result;
515 int event_fds[2]; 515 int event_fds[2];
516 result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC)); 516 result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC));
517 if (result < 0) { 517 if (result < 0) {
518 return CleanupAndReturnError(); 518 return CleanupAndReturnError();
519 } 519 }
520 520
521 ProcessInfoList::AddProcess(pid, event_fds[1]); 521 ProcessInfoList::AddProcess(pid, event_fds[1]);
522 *exit_event_ = event_fds[0]; 522 *exit_event_ = event_fds[0];
523 FDUtils::SetNonBlocking(event_fds[0]); 523 FDUtils::SetNonBlocking(event_fds[0]);
524 return 0; 524 return 0;
525 } 525 }
526 526
527 527
528 int ReadExecResult() { 528 int ReadExecResult() {
529 int child_errno; 529 int child_errno;
530 int bytes_read = -1; 530 int bytes_read = -1;
531 // Read exec result from child. If no data is returned the exec was 531 // Read exec result from child. If no data is returned the exec was
532 // successful and the exec call closed the pipe. Otherwise the errno 532 // successful and the exec call closed the pipe. Otherwise the errno
533 // is written to the pipe. 533 // is written to the pipe.
534 bytes_read = 534 bytes_read =
535 FDUtils::ReadFromBlocking( 535 FDUtils::ReadFromBlocking(
536 exec_control_[0], &child_errno, sizeof(child_errno)); 536 exec_control_[0], &child_errno, sizeof(child_errno));
537 if (bytes_read == sizeof(child_errno)) { 537 if (bytes_read == sizeof(child_errno)) {
538 ReadChildError(); 538 ReadChildError(child_errno);
539 return child_errno; 539 return child_errno;
540 } else if (bytes_read == -1) { 540 } else if (bytes_read == -1) {
541 return errno; 541 return errno;
542 } 542 }
543 return 0; 543 return 0;
544 } 544 }
545 545
546 546
547 int ReadDetachedExecResult(pid_t *pid) { 547 int ReadDetachedExecResult(pid_t *pid) {
548 int child_errno; 548 int child_errno;
549 int bytes_read = -1; 549 int bytes_read = -1;
550 // Read exec result from child. If only pid data is returned the exec was 550 // Read exec result from child. If only pid data is returned the exec was
551 // successful and the exec call closed the pipe. Otherwise the errno 551 // successful and the exec call closed the pipe. Otherwise the errno
552 // is written to the pipe as well. 552 // is written to the pipe as well.
553 int result[2]; 553 int result[2];
554 bytes_read = 554 bytes_read =
555 FDUtils::ReadFromBlocking( 555 FDUtils::ReadFromBlocking(
556 exec_control_[0], result, sizeof(result)); 556 exec_control_[0], result, sizeof(result));
557 if (bytes_read == sizeof(int)) { 557 if (bytes_read == sizeof(int)) {
558 *pid = result[0]; 558 *pid = result[0];
559 } else if (bytes_read == 2 * sizeof(int)) { 559 } else if (bytes_read == 2 * sizeof(int)) {
560 *pid = result[0]; 560 *pid = result[0];
561 child_errno = result[1]; 561 child_errno = result[1];
562 ReadChildError(); 562 ReadChildError(child_errno);
563 return child_errno; 563 return child_errno;
564 } else if (bytes_read == -1) { 564 } else if (bytes_read == -1) {
565 return errno; 565 return errno;
566 } 566 }
567 return 0; 567 return 0;
568 } 568 }
569 569
570 570
571 void SetupDetached() { 571 void SetupDetached() {
572 ASSERT(mode_ == kDetached); 572 ASSERT(mode_ == kDetached);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
641 641
642 642
643 void SetChildOsErrorMessage() { 643 void SetChildOsErrorMessage() {
644 const int kBufferSize = 1024; 644 const int kBufferSize = 1024;
645 char error_buf[kBufferSize]; 645 char error_buf[kBufferSize];
646 *os_error_message_ = strdup(strerror_r(errno, error_buf, kBufferSize)); 646 *os_error_message_ = strdup(strerror_r(errno, error_buf, kBufferSize));
647 } 647 }
648 648
649 649
650 void ReportChildError() { 650 void ReportChildError() {
651 // In the case of failure in the child process write the errno and 651 // In the case of failure in the child process write the errno to the exec
652 // the OS error message to the exec control pipe and exit. 652 // control pipe and exit.
653 int child_errno = errno; 653 int child_errno = errno;
654 const int kBufferSize = 1024; 654 FDUtils::WriteToBlocking(
655 char error_buf[kBufferSize]; 655 exec_control_[1], &child_errno, sizeof(child_errno));
656 char* os_error_message = strerror_r(errno, error_buf, kBufferSize); 656 _exit(1);
657 int bytes_written =
658 FDUtils::WriteToBlocking(
659 exec_control_[1], &child_errno, sizeof(child_errno));
660 if (bytes_written == sizeof(child_errno)) {
661 FDUtils::WriteToBlocking(
662 exec_control_[1], os_error_message, strlen(os_error_message) + 1);
663 }
664 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1]));
665 exit(1);
666 } 657 }
667 658
668 659
669 void ReportPid(int pid) { 660 void ReportPid(int pid) {
670 // In the case of starting a detached process the actual pid of that process 661 // In the case of starting a detached process the actual pid of that process
671 // is communicated using the exec control pipe. 662 // is communicated using the exec control pipe.
672 int bytes_written = 663 int bytes_written =
673 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid)); 664 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid));
674 ASSERT(bytes_written == sizeof(int)); 665 ASSERT(bytes_written == sizeof(int));
675 USE(bytes_written); 666 USE(bytes_written);
676 } 667 }
677 668
678 669
679 void ReadChildError() { 670 void ReadChildError(int child_errno) {
Søren Gjesse 2015/06/10 07:20:25 Please rename this to e.g. SetOSErrorMessage.
Anders Johnsen 2015/06/10 08:00:45 Done.
680 const int kMaxMessageSize = 256; 671 const int kMaxMessageSize = 256;
681 char* message = static_cast<char*>(malloc(kMaxMessageSize)); 672 char* message = static_cast<char*>(calloc(kMaxMessageSize, 0));
682 if (message != NULL) { 673 char* os_error_message = strerror_r(
683 FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize); 674 child_errno, message, kMaxMessageSize - 1);
684 message[kMaxMessageSize - 1] = '\0'; 675 if (message == os_error_message) {
685 *os_error_message_ = message; 676 *os_error_message_ = message;
686 } else { 677 } else {
687 // Could not get error message. It will be NULL. 678 free(message);
688 ASSERT(*os_error_message_ == NULL); 679 *os_error_message_ = strdup(os_error_message);
689 } 680 }
690 } 681 }
691 682
692 683
693 void ClosePipe(int* fds) { 684 void ClosePipe(int* fds) {
694 for (int i = 0; i < 2; i++) { 685 for (int i = 0; i < 2; i++) {
695 if (fds[i] != -1) { 686 if (fds[i] != -1) {
696 VOID_TEMP_FAILURE_RETRY(close(fds[i])); 687 VOID_TEMP_FAILURE_RETRY(close(fds[i]));
697 fds[i] = -1; 688 fds[i] = -1;
698 } 689 }
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after
993 bzero(&act, sizeof(act)); 984 bzero(&act, sizeof(act));
994 act.sa_handler = SIG_DFL; 985 act.sa_handler = SIG_DFL;
995 sigaction(signal, &act, NULL); 986 sigaction(signal, &act, NULL);
996 } 987 }
997 } 988 }
998 989
999 } // namespace bin 990 } // namespace bin
1000 } // namespace dart 991 } // namespace dart
1001 992
1002 #endif // defined(TARGET_OS_LINUX) 993 #endif // defined(TARGET_OS_LINUX)
OLDNEW
« no previous file with comments | « no previous file | tests/standalone/io/platform_executable_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698