| OLD | NEW |
| 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 #if !defined(DART_IO_DISABLED) | 5 #if !defined(DART_IO_DISABLED) |
| 6 | 6 |
| 7 #include "platform/globals.h" | 7 #include "platform/globals.h" |
| 8 #if defined(HOST_OS_MACOS) | 8 #if defined(HOST_OS_MACOS) |
| 9 | 9 |
| 10 #include "bin/process.h" | 10 #include "bin/process.h" |
| 11 | 11 |
| 12 #if !HOST_OS_IOS | 12 #if !HOST_OS_IOS |
| 13 #include <crt_externs.h> // NOLINT | 13 #include <crt_externs.h> // NOLINT |
| 14 #endif | 14 #endif |
| 15 #include <errno.h> // NOLINT | 15 #include <errno.h> // NOLINT |
| 16 #include <fcntl.h> // NOLINT | 16 #include <fcntl.h> // NOLINT |
| 17 #include <mach/mach.h> // NOLINT | 17 #include <mach/mach.h> // NOLINT |
| 18 #include <poll.h> // NOLINT | 18 #include <poll.h> // NOLINT |
| 19 #include <signal.h> // NOLINT | 19 #include <signal.h> // NOLINT |
| 20 #include <stdio.h> // NOLINT | 20 #include <stdio.h> // NOLINT |
| 21 #include <stdlib.h> // NOLINT | 21 #include <stdlib.h> // NOLINT |
| 22 #include <string.h> // NOLINT | 22 #include <string.h> // NOLINT |
| 23 #include <unistd.h> // NOLINT | 23 #include <unistd.h> // NOLINT |
| 24 | 24 |
| 25 #include "bin/dartutils.h" | 25 #include "bin/dartutils.h" |
| 26 #include "bin/fdutils.h" | 26 #include "bin/fdutils.h" |
| 27 #include "bin/lockers.h" | 27 #include "bin/lockers.h" |
| 28 #include "bin/log.h" | 28 #include "bin/log.h" |
| 29 #include "bin/thread.h" | 29 #include "bin/thread.h" |
| 30 | 30 |
| 31 #include "platform/signal_blocker.h" | 31 #include "platform/signal_blocker.h" |
| 32 #include "platform/utils.h" | 32 #include "platform/utils.h" |
| 33 | 33 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 57 void set_next(ProcessInfo* info) { next_ = info; } | 57 void set_next(ProcessInfo* info) { next_ = info; } |
| 58 | 58 |
| 59 private: | 59 private: |
| 60 pid_t pid_; | 60 pid_t pid_; |
| 61 intptr_t fd_; | 61 intptr_t fd_; |
| 62 ProcessInfo* next_; | 62 ProcessInfo* next_; |
| 63 | 63 |
| 64 DISALLOW_COPY_AND_ASSIGN(ProcessInfo); | 64 DISALLOW_COPY_AND_ASSIGN(ProcessInfo); |
| 65 }; | 65 }; |
| 66 | 66 |
| 67 | |
| 68 // Singly-linked list of ProcessInfo objects for all active processes | 67 // Singly-linked list of ProcessInfo objects for all active processes |
| 69 // started from Dart. | 68 // started from Dart. |
| 70 class ProcessInfoList { | 69 class ProcessInfoList { |
| 71 public: | 70 public: |
| 72 static void AddProcess(pid_t pid, intptr_t fd) { | 71 static void AddProcess(pid_t pid, intptr_t fd) { |
| 73 MutexLocker locker(mutex_); | 72 MutexLocker locker(mutex_); |
| 74 ProcessInfo* info = new ProcessInfo(pid, fd); | 73 ProcessInfo* info = new ProcessInfo(pid, fd); |
| 75 info->set_next(active_processes_); | 74 info->set_next(active_processes_); |
| 76 active_processes_ = info; | 75 active_processes_ = info; |
| 77 } | 76 } |
| 78 | 77 |
| 79 | |
| 80 static intptr_t LookupProcessExitFd(pid_t pid) { | 78 static intptr_t LookupProcessExitFd(pid_t pid) { |
| 81 MutexLocker locker(mutex_); | 79 MutexLocker locker(mutex_); |
| 82 ProcessInfo* current = active_processes_; | 80 ProcessInfo* current = active_processes_; |
| 83 while (current != NULL) { | 81 while (current != NULL) { |
| 84 if (current->pid() == pid) { | 82 if (current->pid() == pid) { |
| 85 return current->fd(); | 83 return current->fd(); |
| 86 } | 84 } |
| 87 current = current->next(); | 85 current = current->next(); |
| 88 } | 86 } |
| 89 return 0; | 87 return 0; |
| 90 } | 88 } |
| 91 | 89 |
| 92 | |
| 93 static void RemoveProcess(pid_t pid) { | 90 static void RemoveProcess(pid_t pid) { |
| 94 MutexLocker locker(mutex_); | 91 MutexLocker locker(mutex_); |
| 95 ProcessInfo* prev = NULL; | 92 ProcessInfo* prev = NULL; |
| 96 ProcessInfo* current = active_processes_; | 93 ProcessInfo* current = active_processes_; |
| 97 while (current != NULL) { | 94 while (current != NULL) { |
| 98 if (current->pid() == pid) { | 95 if (current->pid() == pid) { |
| 99 if (prev == NULL) { | 96 if (prev == NULL) { |
| 100 active_processes_ = current->next(); | 97 active_processes_ = current->next(); |
| 101 } else { | 98 } else { |
| 102 prev->set_next(current->next()); | 99 prev->set_next(current->next()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 114 // started from Dart code. | 111 // started from Dart code. |
| 115 static ProcessInfo* active_processes_; | 112 static ProcessInfo* active_processes_; |
| 116 // Mutex protecting all accesses to the linked list of active | 113 // Mutex protecting all accesses to the linked list of active |
| 117 // processes. | 114 // processes. |
| 118 static Mutex* mutex_; | 115 static Mutex* mutex_; |
| 119 | 116 |
| 120 DISALLOW_ALLOCATION(); | 117 DISALLOW_ALLOCATION(); |
| 121 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessInfoList); | 118 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessInfoList); |
| 122 }; | 119 }; |
| 123 | 120 |
| 124 | |
| 125 ProcessInfo* ProcessInfoList::active_processes_ = NULL; | 121 ProcessInfo* ProcessInfoList::active_processes_ = NULL; |
| 126 Mutex* ProcessInfoList::mutex_ = new Mutex(); | 122 Mutex* ProcessInfoList::mutex_ = new Mutex(); |
| 127 | 123 |
| 128 | |
| 129 // The exit code handler sets up a separate thread which waits for child | 124 // The exit code handler sets up a separate thread which waits for child |
| 130 // processes to terminate. That separate thread can then get the exit code from | 125 // processes to terminate. That separate thread can then get the exit code from |
| 131 // processes that have exited and communicate it to Dart through the | 126 // processes that have exited and communicate it to Dart through the |
| 132 // event loop. | 127 // event loop. |
| 133 class ExitCodeHandler { | 128 class ExitCodeHandler { |
| 134 public: | 129 public: |
| 135 // Notify the ExitCodeHandler that another process exists. | 130 // Notify the ExitCodeHandler that another process exists. |
| 136 static void ProcessStarted() { | 131 static void ProcessStarted() { |
| 137 // Multiple isolates could be starting processes at the same | 132 // Multiple isolates could be starting processes at the same |
| 138 // time. Make sure that only one ExitCodeHandler thread exists. | 133 // time. Make sure that only one ExitCodeHandler thread exists. |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 | 227 |
| 233 static bool terminate_done_; | 228 static bool terminate_done_; |
| 234 static int process_count_; | 229 static int process_count_; |
| 235 static bool running_; | 230 static bool running_; |
| 236 static Monitor* monitor_; | 231 static Monitor* monitor_; |
| 237 | 232 |
| 238 DISALLOW_ALLOCATION(); | 233 DISALLOW_ALLOCATION(); |
| 239 DISALLOW_IMPLICIT_CONSTRUCTORS(ExitCodeHandler); | 234 DISALLOW_IMPLICIT_CONSTRUCTORS(ExitCodeHandler); |
| 240 }; | 235 }; |
| 241 | 236 |
| 242 | |
| 243 bool ExitCodeHandler::running_ = false; | 237 bool ExitCodeHandler::running_ = false; |
| 244 int ExitCodeHandler::process_count_ = 0; | 238 int ExitCodeHandler::process_count_ = 0; |
| 245 bool ExitCodeHandler::terminate_done_ = false; | 239 bool ExitCodeHandler::terminate_done_ = false; |
| 246 Monitor* ExitCodeHandler::monitor_ = new Monitor(); | 240 Monitor* ExitCodeHandler::monitor_ = new Monitor(); |
| 247 | 241 |
| 248 | |
| 249 class ProcessStarter { | 242 class ProcessStarter { |
| 250 public: | 243 public: |
| 251 ProcessStarter(const char* path, | 244 ProcessStarter(const char* path, |
| 252 char* arguments[], | 245 char* arguments[], |
| 253 intptr_t arguments_length, | 246 intptr_t arguments_length, |
| 254 const char* working_directory, | 247 const char* working_directory, |
| 255 char* environment[], | 248 char* environment[], |
| 256 intptr_t environment_length, | 249 intptr_t environment_length, |
| 257 ProcessStartMode mode, | 250 ProcessStartMode mode, |
| 258 intptr_t* in, | 251 intptr_t* in, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 if (environment != NULL) { | 284 if (environment != NULL) { |
| 292 program_environment_ = reinterpret_cast<char**>(Dart_ScopeAllocate( | 285 program_environment_ = reinterpret_cast<char**>(Dart_ScopeAllocate( |
| 293 (environment_length + 1) * sizeof(*program_environment_))); | 286 (environment_length + 1) * sizeof(*program_environment_))); |
| 294 for (int i = 0; i < environment_length; i++) { | 287 for (int i = 0; i < environment_length; i++) { |
| 295 program_environment_[i] = environment[i]; | 288 program_environment_[i] = environment[i]; |
| 296 } | 289 } |
| 297 program_environment_[environment_length] = NULL; | 290 program_environment_[environment_length] = NULL; |
| 298 } | 291 } |
| 299 } | 292 } |
| 300 | 293 |
| 301 | |
| 302 int Start() { | 294 int Start() { |
| 303 // Create pipes required. | 295 // Create pipes required. |
| 304 int err = CreatePipes(); | 296 int err = CreatePipes(); |
| 305 if (err != 0) { | 297 if (err != 0) { |
| 306 return err; | 298 return err; |
| 307 } | 299 } |
| 308 | 300 |
| 309 // Fork to create the new process. | 301 // Fork to create the new process. |
| 310 pid_t pid = TEMP_FAILURE_RETRY(fork()); | 302 pid_t pid = TEMP_FAILURE_RETRY(fork()); |
| 311 if (pid < 0) { | 303 if (pid < 0) { |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 if (result < 0) { | 416 if (result < 0) { |
| 425 return CleanupAndReturnError(); | 417 return CleanupAndReturnError(); |
| 426 } | 418 } |
| 427 FDUtils::SetCloseOnExec(write_out_[0]); | 419 FDUtils::SetCloseOnExec(write_out_[0]); |
| 428 FDUtils::SetCloseOnExec(write_out_[1]); | 420 FDUtils::SetCloseOnExec(write_out_[1]); |
| 429 } | 421 } |
| 430 | 422 |
| 431 return 0; | 423 return 0; |
| 432 } | 424 } |
| 433 | 425 |
| 434 | |
| 435 void NewProcess() { | 426 void NewProcess() { |
| 436 // Wait for parent process before setting up the child process. | 427 // Wait for parent process before setting up the child process. |
| 437 char msg; | 428 char msg; |
| 438 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); | 429 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); |
| 439 if (bytes_read != sizeof(msg)) { | 430 if (bytes_read != sizeof(msg)) { |
| 440 perror("Failed receiving notification message"); | 431 perror("Failed receiving notification message"); |
| 441 exit(1); | 432 exit(1); |
| 442 } | 433 } |
| 443 if (mode_ == kNormal) { | 434 if (mode_ == kNormal) { |
| 444 ExecProcess(); | 435 ExecProcess(); |
| 445 } else { | 436 } else { |
| 446 ExecDetachedProcess(); | 437 ExecDetachedProcess(); |
| 447 } | 438 } |
| 448 } | 439 } |
| 449 | 440 |
| 450 | |
| 451 void ExecProcess() { | 441 void ExecProcess() { |
| 452 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { | 442 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { |
| 453 ReportChildError(); | 443 ReportChildError(); |
| 454 } | 444 } |
| 455 | 445 |
| 456 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { | 446 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { |
| 457 ReportChildError(); | 447 ReportChildError(); |
| 458 } | 448 } |
| 459 | 449 |
| 460 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { | 450 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 474 *environ = program_environment_; | 464 *environ = program_environment_; |
| 475 } | 465 } |
| 476 #endif | 466 #endif |
| 477 | 467 |
| 478 VOID_TEMP_FAILURE_RETRY( | 468 VOID_TEMP_FAILURE_RETRY( |
| 479 execvp(path_, const_cast<char* const*>(program_arguments_))); | 469 execvp(path_, const_cast<char* const*>(program_arguments_))); |
| 480 | 470 |
| 481 ReportChildError(); | 471 ReportChildError(); |
| 482 } | 472 } |
| 483 | 473 |
| 484 | |
| 485 void ExecDetachedProcess() { | 474 void ExecDetachedProcess() { |
| 486 if (mode_ == kDetached) { | 475 if (mode_ == kDetached) { |
| 487 ASSERT(write_out_[0] == -1); | 476 ASSERT(write_out_[0] == -1); |
| 488 ASSERT(write_out_[1] == -1); | 477 ASSERT(write_out_[1] == -1); |
| 489 ASSERT(read_err_[0] == -1); | 478 ASSERT(read_err_[0] == -1); |
| 490 ASSERT(read_err_[1] == -1); | 479 ASSERT(read_err_[1] == -1); |
| 491 // For a detached process the pipe to connect stdout is only used for | 480 // For a detached process the pipe to connect stdout is only used for |
| 492 // signaling when to do the first fork. | 481 // signaling when to do the first fork. |
| 493 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); | 482 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); |
| 494 read_in_[0] = -1; | 483 read_in_[0] = -1; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 // Exit the intermeiate process. | 521 // Exit the intermeiate process. |
| 533 exit(0); | 522 exit(0); |
| 534 } | 523 } |
| 535 } | 524 } |
| 536 } else { | 525 } else { |
| 537 // Exit the intermeiate process. | 526 // Exit the intermeiate process. |
| 538 exit(0); | 527 exit(0); |
| 539 } | 528 } |
| 540 } | 529 } |
| 541 | 530 |
| 542 | |
| 543 int RegisterProcess(pid_t pid) { | 531 int RegisterProcess(pid_t pid) { |
| 544 int result; | 532 int result; |
| 545 int event_fds[2]; | 533 int event_fds[2]; |
| 546 result = TEMP_FAILURE_RETRY(pipe(event_fds)); | 534 result = TEMP_FAILURE_RETRY(pipe(event_fds)); |
| 547 if (result < 0) { | 535 if (result < 0) { |
| 548 return CleanupAndReturnError(); | 536 return CleanupAndReturnError(); |
| 549 } | 537 } |
| 550 FDUtils::SetCloseOnExec(event_fds[0]); | 538 FDUtils::SetCloseOnExec(event_fds[0]); |
| 551 FDUtils::SetCloseOnExec(event_fds[1]); | 539 FDUtils::SetCloseOnExec(event_fds[1]); |
| 552 | 540 |
| 553 ProcessInfoList::AddProcess(pid, event_fds[1]); | 541 ProcessInfoList::AddProcess(pid, event_fds[1]); |
| 554 *exit_event_ = event_fds[0]; | 542 *exit_event_ = event_fds[0]; |
| 555 FDUtils::SetNonBlocking(event_fds[0]); | 543 FDUtils::SetNonBlocking(event_fds[0]); |
| 556 return 0; | 544 return 0; |
| 557 } | 545 } |
| 558 | 546 |
| 559 | |
| 560 int ReadExecResult() { | 547 int ReadExecResult() { |
| 561 int child_errno; | 548 int child_errno; |
| 562 int bytes_read = -1; | 549 int bytes_read = -1; |
| 563 // Read exec result from child. If no data is returned the exec was | 550 // Read exec result from child. If no data is returned the exec was |
| 564 // successful and the exec call closed the pipe. Otherwise the errno | 551 // successful and the exec call closed the pipe. Otherwise the errno |
| 565 // is written to the pipe. | 552 // is written to the pipe. |
| 566 bytes_read = FDUtils::ReadFromBlocking(exec_control_[0], &child_errno, | 553 bytes_read = FDUtils::ReadFromBlocking(exec_control_[0], &child_errno, |
| 567 sizeof(child_errno)); | 554 sizeof(child_errno)); |
| 568 if (bytes_read == sizeof(child_errno)) { | 555 if (bytes_read == sizeof(child_errno)) { |
| 569 ReadChildError(); | 556 ReadChildError(); |
| 570 return child_errno; | 557 return child_errno; |
| 571 } else if (bytes_read == -1) { | 558 } else if (bytes_read == -1) { |
| 572 return errno; | 559 return errno; |
| 573 } | 560 } |
| 574 return 0; | 561 return 0; |
| 575 } | 562 } |
| 576 | 563 |
| 577 | |
| 578 int ReadDetachedExecResult(pid_t* pid) { | 564 int ReadDetachedExecResult(pid_t* pid) { |
| 579 int child_errno; | 565 int child_errno; |
| 580 int bytes_read = -1; | 566 int bytes_read = -1; |
| 581 // Read exec result from child. If only pid data is returned the exec was | 567 // Read exec result from child. If only pid data is returned the exec was |
| 582 // successful and the exec call closed the pipe. Otherwise the errno | 568 // successful and the exec call closed the pipe. Otherwise the errno |
| 583 // is written to the pipe as well. | 569 // is written to the pipe as well. |
| 584 int result[2]; | 570 int result[2]; |
| 585 bytes_read = | 571 bytes_read = |
| 586 FDUtils::ReadFromBlocking(exec_control_[0], result, sizeof(result)); | 572 FDUtils::ReadFromBlocking(exec_control_[0], result, sizeof(result)); |
| 587 if (bytes_read == sizeof(int)) { | 573 if (bytes_read == sizeof(int)) { |
| 588 *pid = result[0]; | 574 *pid = result[0]; |
| 589 } else if (bytes_read == 2 * sizeof(int)) { | 575 } else if (bytes_read == 2 * sizeof(int)) { |
| 590 *pid = result[0]; | 576 *pid = result[0]; |
| 591 child_errno = result[1]; | 577 child_errno = result[1]; |
| 592 ReadChildError(); | 578 ReadChildError(); |
| 593 return child_errno; | 579 return child_errno; |
| 594 } else if (bytes_read == -1) { | 580 } else if (bytes_read == -1) { |
| 595 return errno; | 581 return errno; |
| 596 } | 582 } |
| 597 return 0; | 583 return 0; |
| 598 } | 584 } |
| 599 | 585 |
| 600 | |
| 601 void SetupDetached() { | 586 void SetupDetached() { |
| 602 ASSERT(mode_ == kDetached); | 587 ASSERT(mode_ == kDetached); |
| 603 | 588 |
| 604 // Close all open file descriptors except for exec_control_[1]. | 589 // Close all open file descriptors except for exec_control_[1]. |
| 605 int max_fds = sysconf(_SC_OPEN_MAX); | 590 int max_fds = sysconf(_SC_OPEN_MAX); |
| 606 if (max_fds == -1) { | 591 if (max_fds == -1) { |
| 607 max_fds = _POSIX_OPEN_MAX; | 592 max_fds = _POSIX_OPEN_MAX; |
| 608 } | 593 } |
| 609 for (int fd = 0; fd < max_fds; fd++) { | 594 for (int fd = 0; fd < max_fds; fd++) { |
| 610 if (fd != exec_control_[1]) { | 595 if (fd != exec_control_[1]) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 ReportChildError(); | 638 ReportChildError(); |
| 654 } | 639 } |
| 655 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); | 640 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); |
| 656 | 641 |
| 657 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { | 642 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { |
| 658 ReportChildError(); | 643 ReportChildError(); |
| 659 } | 644 } |
| 660 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); | 645 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); |
| 661 } | 646 } |
| 662 | 647 |
| 663 | |
| 664 int CleanupAndReturnError() { | 648 int CleanupAndReturnError() { |
| 665 int actual_errno = errno; | 649 int actual_errno = errno; |
| 666 // If CleanupAndReturnError is called without an actual errno make | 650 // If CleanupAndReturnError is called without an actual errno make |
| 667 // sure to return an error anyway. | 651 // sure to return an error anyway. |
| 668 if (actual_errno == 0) { | 652 if (actual_errno == 0) { |
| 669 actual_errno = EPERM; | 653 actual_errno = EPERM; |
| 670 } | 654 } |
| 671 SetChildOsErrorMessage(); | 655 SetChildOsErrorMessage(); |
| 672 CloseAllPipes(); | 656 CloseAllPipes(); |
| 673 return actual_errno; | 657 return actual_errno; |
| 674 } | 658 } |
| 675 | 659 |
| 676 | |
| 677 void SetChildOsErrorMessage() { | 660 void SetChildOsErrorMessage() { |
| 678 const int kBufferSize = 1024; | 661 const int kBufferSize = 1024; |
| 679 char* error_message = DartUtils::ScopedCString(kBufferSize); | 662 char* error_message = DartUtils::ScopedCString(kBufferSize); |
| 680 Utils::StrError(errno, error_message, kBufferSize); | 663 Utils::StrError(errno, error_message, kBufferSize); |
| 681 *os_error_message_ = error_message; | 664 *os_error_message_ = error_message; |
| 682 } | 665 } |
| 683 | 666 |
| 684 | |
| 685 void ReportChildError() { | 667 void ReportChildError() { |
| 686 // In the case of failure in the child process write the errno and | 668 // In the case of failure in the child process write the errno and |
| 687 // the OS error message to the exec control pipe and exit. | 669 // the OS error message to the exec control pipe and exit. |
| 688 int child_errno = errno; | 670 int child_errno = errno; |
| 689 const int kBufferSize = 1024; | 671 const int kBufferSize = 1024; |
| 690 char os_error_message[kBufferSize]; | 672 char os_error_message[kBufferSize]; |
| 691 Utils::StrError(errno, os_error_message, kBufferSize); | 673 Utils::StrError(errno, os_error_message, kBufferSize); |
| 692 int bytes_written = FDUtils::WriteToBlocking(exec_control_[1], &child_errno, | 674 int bytes_written = FDUtils::WriteToBlocking(exec_control_[1], &child_errno, |
| 693 sizeof(child_errno)); | 675 sizeof(child_errno)); |
| 694 if (bytes_written == sizeof(child_errno)) { | 676 if (bytes_written == sizeof(child_errno)) { |
| 695 FDUtils::WriteToBlocking(exec_control_[1], os_error_message, | 677 FDUtils::WriteToBlocking(exec_control_[1], os_error_message, |
| 696 strlen(os_error_message) + 1); | 678 strlen(os_error_message) + 1); |
| 697 } | 679 } |
| 698 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); | 680 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); |
| 699 exit(1); | 681 exit(1); |
| 700 } | 682 } |
| 701 | 683 |
| 702 | |
| 703 void ReportPid(int pid) { | 684 void ReportPid(int pid) { |
| 704 // In the case of starting a detached process the actual pid of that process | 685 // In the case of starting a detached process the actual pid of that process |
| 705 // is communicated using the exec control pipe. | 686 // is communicated using the exec control pipe. |
| 706 int bytes_written = | 687 int bytes_written = |
| 707 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid)); | 688 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid)); |
| 708 ASSERT(bytes_written == sizeof(int)); | 689 ASSERT(bytes_written == sizeof(int)); |
| 709 USE(bytes_written); | 690 USE(bytes_written); |
| 710 } | 691 } |
| 711 | 692 |
| 712 | |
| 713 void ReadChildError() { | 693 void ReadChildError() { |
| 714 const int kMaxMessageSize = 256; | 694 const int kMaxMessageSize = 256; |
| 715 char* message = DartUtils::ScopedCString(kMaxMessageSize); | 695 char* message = DartUtils::ScopedCString(kMaxMessageSize); |
| 716 if (message != NULL) { | 696 if (message != NULL) { |
| 717 FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize); | 697 FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize); |
| 718 message[kMaxMessageSize - 1] = '\0'; | 698 message[kMaxMessageSize - 1] = '\0'; |
| 719 *os_error_message_ = message; | 699 *os_error_message_ = message; |
| 720 } else { | 700 } else { |
| 721 // Could not get error message. It will be NULL. | 701 // Could not get error message. It will be NULL. |
| 722 ASSERT(*os_error_message_ == NULL); | 702 ASSERT(*os_error_message_ == NULL); |
| 723 } | 703 } |
| 724 } | 704 } |
| 725 | 705 |
| 726 | |
| 727 void ClosePipe(int* fds) { | 706 void ClosePipe(int* fds) { |
| 728 for (int i = 0; i < 2; i++) { | 707 for (int i = 0; i < 2; i++) { |
| 729 if (fds[i] != -1) { | 708 if (fds[i] != -1) { |
| 730 VOID_TEMP_FAILURE_RETRY(close(fds[i])); | 709 VOID_TEMP_FAILURE_RETRY(close(fds[i])); |
| 731 fds[i] = -1; | 710 fds[i] = -1; |
| 732 } | 711 } |
| 733 } | 712 } |
| 734 } | 713 } |
| 735 | 714 |
| 736 | |
| 737 void CloseAllPipes() { | 715 void CloseAllPipes() { |
| 738 ClosePipe(exec_control_); | 716 ClosePipe(exec_control_); |
| 739 ClosePipe(read_in_); | 717 ClosePipe(read_in_); |
| 740 ClosePipe(read_err_); | 718 ClosePipe(read_err_); |
| 741 ClosePipe(write_out_); | 719 ClosePipe(write_out_); |
| 742 } | 720 } |
| 743 | 721 |
| 744 | |
| 745 int read_in_[2]; // Pipe for stdout to child process. | 722 int read_in_[2]; // Pipe for stdout to child process. |
| 746 int read_err_[2]; // Pipe for stderr to child process. | 723 int read_err_[2]; // Pipe for stderr to child process. |
| 747 int write_out_[2]; // Pipe for stdin to child process. | 724 int write_out_[2]; // Pipe for stdin to child process. |
| 748 int exec_control_[2]; // Pipe to get the result from exec. | 725 int exec_control_[2]; // Pipe to get the result from exec. |
| 749 | 726 |
| 750 char** program_arguments_; | 727 char** program_arguments_; |
| 751 char** program_environment_; | 728 char** program_environment_; |
| 752 | 729 |
| 753 const char* path_; | 730 const char* path_; |
| 754 const char* working_directory_; | 731 const char* working_directory_; |
| 755 ProcessStartMode mode_; | 732 ProcessStartMode mode_; |
| 756 intptr_t* in_; | 733 intptr_t* in_; |
| 757 intptr_t* out_; | 734 intptr_t* out_; |
| 758 intptr_t* err_; | 735 intptr_t* err_; |
| 759 intptr_t* id_; | 736 intptr_t* id_; |
| 760 intptr_t* exit_event_; | 737 intptr_t* exit_event_; |
| 761 char** os_error_message_; | 738 char** os_error_message_; |
| 762 | 739 |
| 763 DISALLOW_ALLOCATION(); | 740 DISALLOW_ALLOCATION(); |
| 764 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter); | 741 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter); |
| 765 }; | 742 }; |
| 766 | 743 |
| 767 | |
| 768 int Process::Start(const char* path, | 744 int Process::Start(const char* path, |
| 769 char* arguments[], | 745 char* arguments[], |
| 770 intptr_t arguments_length, | 746 intptr_t arguments_length, |
| 771 const char* working_directory, | 747 const char* working_directory, |
| 772 char* environment[], | 748 char* environment[], |
| 773 intptr_t environment_length, | 749 intptr_t environment_length, |
| 774 ProcessStartMode mode, | 750 ProcessStartMode mode, |
| 775 intptr_t* in, | 751 intptr_t* in, |
| 776 intptr_t* out, | 752 intptr_t* out, |
| 777 intptr_t* err, | 753 intptr_t* err, |
| 778 intptr_t* id, | 754 intptr_t* id, |
| 779 intptr_t* exit_event, | 755 intptr_t* exit_event, |
| 780 char** os_error_message) { | 756 char** os_error_message) { |
| 781 ProcessStarter starter(path, arguments, arguments_length, working_directory, | 757 ProcessStarter starter(path, arguments, arguments_length, working_directory, |
| 782 environment, environment_length, mode, in, out, err, | 758 environment, environment_length, mode, in, out, err, |
| 783 id, exit_event, os_error_message); | 759 id, exit_event, os_error_message); |
| 784 return starter.Start(); | 760 return starter.Start(); |
| 785 } | 761 } |
| 786 | 762 |
| 787 | |
| 788 static bool CloseProcessBuffers(struct pollfd fds[3]) { | 763 static bool CloseProcessBuffers(struct pollfd fds[3]) { |
| 789 int e = errno; | 764 int e = errno; |
| 790 VOID_TEMP_FAILURE_RETRY(close(fds[0].fd)); | 765 VOID_TEMP_FAILURE_RETRY(close(fds[0].fd)); |
| 791 VOID_TEMP_FAILURE_RETRY(close(fds[1].fd)); | 766 VOID_TEMP_FAILURE_RETRY(close(fds[1].fd)); |
| 792 VOID_TEMP_FAILURE_RETRY(close(fds[2].fd)); | 767 VOID_TEMP_FAILURE_RETRY(close(fds[2].fd)); |
| 793 errno = e; | 768 errno = e; |
| 794 return false; | 769 return false; |
| 795 } | 770 } |
| 796 | 771 |
| 797 | |
| 798 bool Process::Wait(intptr_t pid, | 772 bool Process::Wait(intptr_t pid, |
| 799 intptr_t in, | 773 intptr_t in, |
| 800 intptr_t out, | 774 intptr_t out, |
| 801 intptr_t err, | 775 intptr_t err, |
| 802 intptr_t exit_event, | 776 intptr_t exit_event, |
| 803 ProcessResult* result) { | 777 ProcessResult* result) { |
| 804 // Close input to the process right away. | 778 // Close input to the process right away. |
| 805 VOID_TEMP_FAILURE_RETRY(close(in)); | 779 VOID_TEMP_FAILURE_RETRY(close(in)); |
| 806 | 780 |
| 807 // There is no return from this function using Dart_PropagateError | 781 // There is no return from this function using Dart_PropagateError |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 881 intptr_t exit_code = exit_code_data.ints[0]; | 855 intptr_t exit_code = exit_code_data.ints[0]; |
| 882 intptr_t negative = exit_code_data.ints[1]; | 856 intptr_t negative = exit_code_data.ints[1]; |
| 883 if (negative != 0) { | 857 if (negative != 0) { |
| 884 exit_code = -exit_code; | 858 exit_code = -exit_code; |
| 885 } | 859 } |
| 886 result->set_exit_code(exit_code); | 860 result->set_exit_code(exit_code); |
| 887 | 861 |
| 888 return true; | 862 return true; |
| 889 } | 863 } |
| 890 | 864 |
| 891 | |
| 892 static int SignalMap(intptr_t id) { | 865 static int SignalMap(intptr_t id) { |
| 893 switch (static_cast<ProcessSignals>(id)) { | 866 switch (static_cast<ProcessSignals>(id)) { |
| 894 case kSighup: | 867 case kSighup: |
| 895 return SIGHUP; | 868 return SIGHUP; |
| 896 case kSigint: | 869 case kSigint: |
| 897 return SIGINT; | 870 return SIGINT; |
| 898 case kSigquit: | 871 case kSigquit: |
| 899 return SIGQUIT; | 872 return SIGQUIT; |
| 900 case kSigill: | 873 case kSigill: |
| 901 return SIGILL; | 874 return SIGILL; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 946 case kSigwinch: | 919 case kSigwinch: |
| 947 return SIGWINCH; | 920 return SIGWINCH; |
| 948 case kSigpoll: | 921 case kSigpoll: |
| 949 return -1; | 922 return -1; |
| 950 case kSigsys: | 923 case kSigsys: |
| 951 return SIGSYS; | 924 return SIGSYS; |
| 952 } | 925 } |
| 953 return -1; | 926 return -1; |
| 954 } | 927 } |
| 955 | 928 |
| 956 | |
| 957 bool Process::Kill(intptr_t id, int signal) { | 929 bool Process::Kill(intptr_t id, int signal) { |
| 958 return (TEMP_FAILURE_RETRY(kill(id, SignalMap(signal))) != -1); | 930 return (TEMP_FAILURE_RETRY(kill(id, SignalMap(signal))) != -1); |
| 959 } | 931 } |
| 960 | 932 |
| 961 | |
| 962 void Process::TerminateExitCodeHandler() { | 933 void Process::TerminateExitCodeHandler() { |
| 963 ExitCodeHandler::TerminateExitCodeThread(); | 934 ExitCodeHandler::TerminateExitCodeThread(); |
| 964 } | 935 } |
| 965 | 936 |
| 966 | |
| 967 intptr_t Process::CurrentProcessId() { | 937 intptr_t Process::CurrentProcessId() { |
| 968 return static_cast<intptr_t>(getpid()); | 938 return static_cast<intptr_t>(getpid()); |
| 969 } | 939 } |
| 970 | 940 |
| 971 | |
| 972 int64_t Process::CurrentRSS() { | 941 int64_t Process::CurrentRSS() { |
| 973 struct mach_task_basic_info info; | 942 struct mach_task_basic_info info; |
| 974 mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; | 943 mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; |
| 975 kern_return_t result = | 944 kern_return_t result = |
| 976 task_info(mach_task_self(), MACH_TASK_BASIC_INFO, | 945 task_info(mach_task_self(), MACH_TASK_BASIC_INFO, |
| 977 reinterpret_cast<task_info_t>(&info), &infoCount); | 946 reinterpret_cast<task_info_t>(&info), &infoCount); |
| 978 if (result != KERN_SUCCESS) { | 947 if (result != KERN_SUCCESS) { |
| 979 return -1; | 948 return -1; |
| 980 } | 949 } |
| 981 return info.resident_size; | 950 return info.resident_size; |
| 982 } | 951 } |
| 983 | 952 |
| 984 | |
| 985 int64_t Process::MaxRSS() { | 953 int64_t Process::MaxRSS() { |
| 986 struct rusage usage; | 954 struct rusage usage; |
| 987 usage.ru_maxrss = 0; | 955 usage.ru_maxrss = 0; |
| 988 int r = getrusage(RUSAGE_SELF, &usage); | 956 int r = getrusage(RUSAGE_SELF, &usage); |
| 989 if (r < 0) { | 957 if (r < 0) { |
| 990 return -1; | 958 return -1; |
| 991 } | 959 } |
| 992 return usage.ru_maxrss; | 960 return usage.ru_maxrss; |
| 993 } | 961 } |
| 994 | 962 |
| 995 | |
| 996 static Mutex* signal_mutex = new Mutex(); | 963 static Mutex* signal_mutex = new Mutex(); |
| 997 static SignalInfo* signal_handlers = NULL; | 964 static SignalInfo* signal_handlers = NULL; |
| 998 static const int kSignalsCount = 7; | 965 static const int kSignalsCount = 7; |
| 999 static const int kSignals[kSignalsCount] = { | 966 static const int kSignals[kSignalsCount] = { |
| 1000 SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGWINCH, | 967 SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGWINCH, |
| 1001 SIGQUIT // Allow VMService to listen on SIGQUIT. | 968 SIGQUIT // Allow VMService to listen on SIGQUIT. |
| 1002 }; | 969 }; |
| 1003 | 970 |
| 1004 | |
| 1005 SignalInfo::~SignalInfo() { | 971 SignalInfo::~SignalInfo() { |
| 1006 VOID_TEMP_FAILURE_RETRY(close(fd_)); | 972 VOID_TEMP_FAILURE_RETRY(close(fd_)); |
| 1007 } | 973 } |
| 1008 | 974 |
| 1009 | |
| 1010 static void SignalHandler(int signal) { | 975 static void SignalHandler(int signal) { |
| 1011 MutexLocker lock(signal_mutex); | 976 MutexLocker lock(signal_mutex); |
| 1012 const SignalInfo* handler = signal_handlers; | 977 const SignalInfo* handler = signal_handlers; |
| 1013 while (handler != NULL) { | 978 while (handler != NULL) { |
| 1014 if (handler->signal() == signal) { | 979 if (handler->signal() == signal) { |
| 1015 int value = 0; | 980 int value = 0; |
| 1016 VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1)); | 981 VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1)); |
| 1017 } | 982 } |
| 1018 handler = handler->next(); | 983 handler = handler->next(); |
| 1019 } | 984 } |
| 1020 } | 985 } |
| 1021 | 986 |
| 1022 | |
| 1023 intptr_t Process::SetSignalHandler(intptr_t signal) { | 987 intptr_t Process::SetSignalHandler(intptr_t signal) { |
| 1024 signal = SignalMap(signal); | 988 signal = SignalMap(signal); |
| 1025 if (signal == -1) { | 989 if (signal == -1) { |
| 1026 return -1; | 990 return -1; |
| 1027 } | 991 } |
| 1028 bool found = false; | 992 bool found = false; |
| 1029 for (int i = 0; i < kSignalsCount; i++) { | 993 for (int i = 0; i < kSignalsCount; i++) { |
| 1030 if (kSignals[i] == signal) { | 994 if (kSignals[i] == signal) { |
| 1031 found = true; | 995 found = true; |
| 1032 break; | 996 break; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1068 if (status < 0) { | 1032 if (status < 0) { |
| 1069 VOID_TEMP_FAILURE_RETRY(close(fds[0])); | 1033 VOID_TEMP_FAILURE_RETRY(close(fds[0])); |
| 1070 VOID_TEMP_FAILURE_RETRY(close(fds[1])); | 1034 VOID_TEMP_FAILURE_RETRY(close(fds[1])); |
| 1071 return -1; | 1035 return -1; |
| 1072 } | 1036 } |
| 1073 } | 1037 } |
| 1074 signal_handlers = new SignalInfo(fds[1], signal, signal_handlers); | 1038 signal_handlers = new SignalInfo(fds[1], signal, signal_handlers); |
| 1075 return fds[0]; | 1039 return fds[0]; |
| 1076 } | 1040 } |
| 1077 | 1041 |
| 1078 | |
| 1079 void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) { | 1042 void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) { |
| 1080 // Either the port is illegal or there is no current isolate, but not both. | 1043 // Either the port is illegal or there is no current isolate, but not both. |
| 1081 ASSERT((port != ILLEGAL_PORT) || (Dart_CurrentIsolate() == NULL)); | 1044 ASSERT((port != ILLEGAL_PORT) || (Dart_CurrentIsolate() == NULL)); |
| 1082 ASSERT((port == ILLEGAL_PORT) || (Dart_CurrentIsolate() != NULL)); | 1045 ASSERT((port == ILLEGAL_PORT) || (Dart_CurrentIsolate() != NULL)); |
| 1083 signal = SignalMap(signal); | 1046 signal = SignalMap(signal); |
| 1084 if (signal == -1) { | 1047 if (signal == -1) { |
| 1085 return; | 1048 return; |
| 1086 } | 1049 } |
| 1087 ThreadSignalBlocker blocker(kSignalsCount, kSignals); | 1050 ThreadSignalBlocker blocker(kSignalsCount, kSignals); |
| 1088 MutexLocker lock(signal_mutex); | 1051 MutexLocker lock(signal_mutex); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1114 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); | 1077 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); |
| 1115 } | 1078 } |
| 1116 } | 1079 } |
| 1117 | 1080 |
| 1118 } // namespace bin | 1081 } // namespace bin |
| 1119 } // namespace dart | 1082 } // namespace dart |
| 1120 | 1083 |
| 1121 #endif // defined(HOST_OS_MACOS) | 1084 #endif // defined(HOST_OS_MACOS) |
| 1122 | 1085 |
| 1123 #endif // !defined(DART_IO_DISABLED) | 1086 #endif // !defined(DART_IO_DISABLED) |
| OLD | NEW |