| 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_ANDROID) | 8 #if defined(HOST_OS_ANDROID) |
| 9 | 9 |
| 10 #include "bin/process.h" | 10 #include "bin/process.h" |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after 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 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 | 230 |
| 236 static bool terminate_done_; | 231 static bool terminate_done_; |
| 237 static int process_count_; | 232 static int process_count_; |
| 238 static bool running_; | 233 static bool running_; |
| 239 static Monitor* monitor_; | 234 static Monitor* monitor_; |
| 240 | 235 |
| 241 DISALLOW_ALLOCATION(); | 236 DISALLOW_ALLOCATION(); |
| 242 DISALLOW_IMPLICIT_CONSTRUCTORS(ExitCodeHandler); | 237 DISALLOW_IMPLICIT_CONSTRUCTORS(ExitCodeHandler); |
| 243 }; | 238 }; |
| 244 | 239 |
| 245 | |
| 246 bool ExitCodeHandler::running_ = false; | 240 bool ExitCodeHandler::running_ = false; |
| 247 int ExitCodeHandler::process_count_ = 0; | 241 int ExitCodeHandler::process_count_ = 0; |
| 248 bool ExitCodeHandler::terminate_done_ = false; | 242 bool ExitCodeHandler::terminate_done_ = false; |
| 249 Monitor* ExitCodeHandler::monitor_ = new Monitor(); | 243 Monitor* ExitCodeHandler::monitor_ = new Monitor(); |
| 250 | 244 |
| 251 | |
| 252 class ProcessStarter { | 245 class ProcessStarter { |
| 253 public: | 246 public: |
| 254 ProcessStarter(const char* path, | 247 ProcessStarter(const char* path, |
| 255 char* arguments[], | 248 char* arguments[], |
| 256 intptr_t arguments_length, | 249 intptr_t arguments_length, |
| 257 const char* working_directory, | 250 const char* working_directory, |
| 258 char* environment[], | 251 char* environment[], |
| 259 intptr_t environment_length, | 252 intptr_t environment_length, |
| 260 ProcessStartMode mode, | 253 ProcessStartMode mode, |
| 261 intptr_t* in, | 254 intptr_t* in, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 if (environment != NULL) { | 287 if (environment != NULL) { |
| 295 program_environment_ = reinterpret_cast<char**>(Dart_ScopeAllocate( | 288 program_environment_ = reinterpret_cast<char**>(Dart_ScopeAllocate( |
| 296 (environment_length + 1) * sizeof(*program_environment_))); | 289 (environment_length + 1) * sizeof(*program_environment_))); |
| 297 for (int i = 0; i < environment_length; i++) { | 290 for (int i = 0; i < environment_length; i++) { |
| 298 program_environment_[i] = environment[i]; | 291 program_environment_[i] = environment[i]; |
| 299 } | 292 } |
| 300 program_environment_[environment_length] = NULL; | 293 program_environment_[environment_length] = NULL; |
| 301 } | 294 } |
| 302 } | 295 } |
| 303 | 296 |
| 304 | |
| 305 int Start() { | 297 int Start() { |
| 306 // Create pipes required. | 298 // Create pipes required. |
| 307 int err = CreatePipes(); | 299 int err = CreatePipes(); |
| 308 if (err != 0) { | 300 if (err != 0) { |
| 309 return err; | 301 return err; |
| 310 } | 302 } |
| 311 | 303 |
| 312 // Fork to create the new process. | 304 // Fork to create the new process. |
| 313 pid_t pid = TEMP_FAILURE_RETRY(fork()); | 305 pid_t pid = TEMP_FAILURE_RETRY(fork()); |
| 314 if (pid < 0) { | 306 if (pid < 0) { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 | 411 |
| 420 result = TEMP_FAILURE_RETRY(pipe2(write_out_, O_CLOEXEC)); | 412 result = TEMP_FAILURE_RETRY(pipe2(write_out_, O_CLOEXEC)); |
| 421 if (result < 0) { | 413 if (result < 0) { |
| 422 return CleanupAndReturnError(); | 414 return CleanupAndReturnError(); |
| 423 } | 415 } |
| 424 } | 416 } |
| 425 | 417 |
| 426 return 0; | 418 return 0; |
| 427 } | 419 } |
| 428 | 420 |
| 429 | |
| 430 void NewProcess() { | 421 void NewProcess() { |
| 431 // Wait for parent process before setting up the child process. | 422 // Wait for parent process before setting up the child process. |
| 432 char msg; | 423 char msg; |
| 433 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); | 424 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); |
| 434 if (bytes_read != sizeof(msg)) { | 425 if (bytes_read != sizeof(msg)) { |
| 435 perror("Failed receiving notification message"); | 426 perror("Failed receiving notification message"); |
| 436 exit(1); | 427 exit(1); |
| 437 } | 428 } |
| 438 if (mode_ == kNormal) { | 429 if (mode_ == kNormal) { |
| 439 ExecProcess(); | 430 ExecProcess(); |
| 440 } else { | 431 } else { |
| 441 ExecDetachedProcess(); | 432 ExecDetachedProcess(); |
| 442 } | 433 } |
| 443 } | 434 } |
| 444 | 435 |
| 445 | |
| 446 void ExecProcess() { | 436 void ExecProcess() { |
| 447 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { | 437 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { |
| 448 ReportChildError(); | 438 ReportChildError(); |
| 449 } | 439 } |
| 450 | 440 |
| 451 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { | 441 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { |
| 452 ReportChildError(); | 442 ReportChildError(); |
| 453 } | 443 } |
| 454 | 444 |
| 455 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { | 445 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { |
| 456 ReportChildError(); | 446 ReportChildError(); |
| 457 } | 447 } |
| 458 | 448 |
| 459 if (working_directory_ != NULL && | 449 if (working_directory_ != NULL && |
| 460 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { | 450 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { |
| 461 ReportChildError(); | 451 ReportChildError(); |
| 462 } | 452 } |
| 463 | 453 |
| 464 if (program_environment_ != NULL) { | 454 if (program_environment_ != NULL) { |
| 465 environ = program_environment_; | 455 environ = program_environment_; |
| 466 } | 456 } |
| 467 | 457 |
| 468 VOID_TEMP_FAILURE_RETRY( | 458 VOID_TEMP_FAILURE_RETRY( |
| 469 execvp(path_, const_cast<char* const*>(program_arguments_))); | 459 execvp(path_, const_cast<char* const*>(program_arguments_))); |
| 470 | 460 |
| 471 ReportChildError(); | 461 ReportChildError(); |
| 472 } | 462 } |
| 473 | 463 |
| 474 | |
| 475 void ExecDetachedProcess() { | 464 void ExecDetachedProcess() { |
| 476 if (mode_ == kDetached) { | 465 if (mode_ == kDetached) { |
| 477 ASSERT(write_out_[0] == -1); | 466 ASSERT(write_out_[0] == -1); |
| 478 ASSERT(write_out_[1] == -1); | 467 ASSERT(write_out_[1] == -1); |
| 479 ASSERT(read_err_[0] == -1); | 468 ASSERT(read_err_[0] == -1); |
| 480 ASSERT(read_err_[1] == -1); | 469 ASSERT(read_err_[1] == -1); |
| 481 // For a detached process the pipe to connect stdout is only used for | 470 // For a detached process the pipe to connect stdout is only used for |
| 482 // signaling when to do the first fork. | 471 // signaling when to do the first fork. |
| 483 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); | 472 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); |
| 484 read_in_[0] = -1; | 473 read_in_[0] = -1; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 // Exit the intermediate process. | 511 // Exit the intermediate process. |
| 523 exit(0); | 512 exit(0); |
| 524 } | 513 } |
| 525 } | 514 } |
| 526 } else { | 515 } else { |
| 527 // Exit the intermediate process. | 516 // Exit the intermediate process. |
| 528 exit(0); | 517 exit(0); |
| 529 } | 518 } |
| 530 } | 519 } |
| 531 | 520 |
| 532 | |
| 533 int RegisterProcess(pid_t pid) { | 521 int RegisterProcess(pid_t pid) { |
| 534 int result; | 522 int result; |
| 535 int event_fds[2]; | 523 int event_fds[2]; |
| 536 result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC)); | 524 result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC)); |
| 537 if (result < 0) { | 525 if (result < 0) { |
| 538 return CleanupAndReturnError(); | 526 return CleanupAndReturnError(); |
| 539 } | 527 } |
| 540 | 528 |
| 541 ProcessInfoList::AddProcess(pid, event_fds[1]); | 529 ProcessInfoList::AddProcess(pid, event_fds[1]); |
| 542 *exit_event_ = event_fds[0]; | 530 *exit_event_ = event_fds[0]; |
| 543 FDUtils::SetNonBlocking(event_fds[0]); | 531 FDUtils::SetNonBlocking(event_fds[0]); |
| 544 return 0; | 532 return 0; |
| 545 } | 533 } |
| 546 | 534 |
| 547 | |
| 548 int ReadExecResult() { | 535 int ReadExecResult() { |
| 549 int child_errno; | 536 int child_errno; |
| 550 int bytes_read = -1; | 537 int bytes_read = -1; |
| 551 // Read exec result from child. If no data is returned the exec was | 538 // Read exec result from child. If no data is returned the exec was |
| 552 // successful and the exec call closed the pipe. Otherwise the errno | 539 // successful and the exec call closed the pipe. Otherwise the errno |
| 553 // is written to the pipe. | 540 // is written to the pipe. |
| 554 bytes_read = FDUtils::ReadFromBlocking(exec_control_[0], &child_errno, | 541 bytes_read = FDUtils::ReadFromBlocking(exec_control_[0], &child_errno, |
| 555 sizeof(child_errno)); | 542 sizeof(child_errno)); |
| 556 if (bytes_read == sizeof(child_errno)) { | 543 if (bytes_read == sizeof(child_errno)) { |
| 557 ReadChildError(); | 544 ReadChildError(); |
| 558 return child_errno; | 545 return child_errno; |
| 559 } else if (bytes_read == -1) { | 546 } else if (bytes_read == -1) { |
| 560 return errno; | 547 return errno; |
| 561 } | 548 } |
| 562 return 0; | 549 return 0; |
| 563 } | 550 } |
| 564 | 551 |
| 565 | |
| 566 int ReadDetachedExecResult(pid_t* pid) { | 552 int ReadDetachedExecResult(pid_t* pid) { |
| 567 int child_errno; | 553 int child_errno; |
| 568 int bytes_read = -1; | 554 int bytes_read = -1; |
| 569 // Read exec result from child. If only pid data is returned the exec was | 555 // Read exec result from child. If only pid data is returned the exec was |
| 570 // successful and the exec call closed the pipe. Otherwise the errno | 556 // successful and the exec call closed the pipe. Otherwise the errno |
| 571 // is written to the pipe as well. | 557 // is written to the pipe as well. |
| 572 int result[2]; | 558 int result[2]; |
| 573 bytes_read = | 559 bytes_read = |
| 574 FDUtils::ReadFromBlocking(exec_control_[0], result, sizeof(result)); | 560 FDUtils::ReadFromBlocking(exec_control_[0], result, sizeof(result)); |
| 575 if (bytes_read == sizeof(int)) { | 561 if (bytes_read == sizeof(int)) { |
| 576 *pid = result[0]; | 562 *pid = result[0]; |
| 577 } else if (bytes_read == 2 * sizeof(int)) { | 563 } else if (bytes_read == 2 * sizeof(int)) { |
| 578 *pid = result[0]; | 564 *pid = result[0]; |
| 579 child_errno = result[1]; | 565 child_errno = result[1]; |
| 580 ReadChildError(); | 566 ReadChildError(); |
| 581 return child_errno; | 567 return child_errno; |
| 582 } else if (bytes_read == -1) { | 568 } else if (bytes_read == -1) { |
| 583 return errno; | 569 return errno; |
| 584 } | 570 } |
| 585 return 0; | 571 return 0; |
| 586 } | 572 } |
| 587 | 573 |
| 588 | |
| 589 void SetupDetached() { | 574 void SetupDetached() { |
| 590 ASSERT(mode_ == kDetached); | 575 ASSERT(mode_ == kDetached); |
| 591 | 576 |
| 592 // Close all open file descriptors except for exec_control_[1]. | 577 // Close all open file descriptors except for exec_control_[1]. |
| 593 int max_fds = sysconf(_SC_OPEN_MAX); | 578 int max_fds = sysconf(_SC_OPEN_MAX); |
| 594 if (max_fds == -1) { | 579 if (max_fds == -1) { |
| 595 max_fds = _POSIX_OPEN_MAX; | 580 max_fds = _POSIX_OPEN_MAX; |
| 596 } | 581 } |
| 597 for (int fd = 0; fd < max_fds; fd++) { | 582 for (int fd = 0; fd < max_fds; fd++) { |
| 598 if (fd != exec_control_[1]) { | 583 if (fd != exec_control_[1]) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 ReportChildError(); | 626 ReportChildError(); |
| 642 } | 627 } |
| 643 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); | 628 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); |
| 644 | 629 |
| 645 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { | 630 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { |
| 646 ReportChildError(); | 631 ReportChildError(); |
| 647 } | 632 } |
| 648 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); | 633 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); |
| 649 } | 634 } |
| 650 | 635 |
| 651 | |
| 652 int CleanupAndReturnError() { | 636 int CleanupAndReturnError() { |
| 653 int actual_errno = errno; | 637 int actual_errno = errno; |
| 654 // If CleanupAndReturnError is called without an actual errno make | 638 // If CleanupAndReturnError is called without an actual errno make |
| 655 // sure to return an error anyway. | 639 // sure to return an error anyway. |
| 656 if (actual_errno == 0) { | 640 if (actual_errno == 0) { |
| 657 actual_errno = EPERM; | 641 actual_errno = EPERM; |
| 658 } | 642 } |
| 659 SetChildOsErrorMessage(); | 643 SetChildOsErrorMessage(); |
| 660 CloseAllPipes(); | 644 CloseAllPipes(); |
| 661 return actual_errno; | 645 return actual_errno; |
| 662 } | 646 } |
| 663 | 647 |
| 664 | |
| 665 void SetChildOsErrorMessage() { | 648 void SetChildOsErrorMessage() { |
| 666 const int kBufferSize = 1024; | 649 const int kBufferSize = 1024; |
| 667 char* error_message = DartUtils::ScopedCString(kBufferSize); | 650 char* error_message = DartUtils::ScopedCString(kBufferSize); |
| 668 Utils::StrError(errno, error_message, kBufferSize); | 651 Utils::StrError(errno, error_message, kBufferSize); |
| 669 *os_error_message_ = error_message; | 652 *os_error_message_ = error_message; |
| 670 } | 653 } |
| 671 | 654 |
| 672 | |
| 673 void ReportChildError() { | 655 void ReportChildError() { |
| 674 // In the case of failure in the child process write the errno and | 656 // In the case of failure in the child process write the errno and |
| 675 // the OS error message to the exec control pipe and exit. | 657 // the OS error message to the exec control pipe and exit. |
| 676 int child_errno = errno; | 658 int child_errno = errno; |
| 677 const int kBufferSize = 1024; | 659 const int kBufferSize = 1024; |
| 678 char os_error_message[kBufferSize]; | 660 char os_error_message[kBufferSize]; |
| 679 Utils::StrError(errno, os_error_message, kBufferSize); | 661 Utils::StrError(errno, os_error_message, kBufferSize); |
| 680 int bytes_written = FDUtils::WriteToBlocking(exec_control_[1], &child_errno, | 662 int bytes_written = FDUtils::WriteToBlocking(exec_control_[1], &child_errno, |
| 681 sizeof(child_errno)); | 663 sizeof(child_errno)); |
| 682 if (bytes_written == sizeof(child_errno)) { | 664 if (bytes_written == sizeof(child_errno)) { |
| 683 FDUtils::WriteToBlocking(exec_control_[1], os_error_message, | 665 FDUtils::WriteToBlocking(exec_control_[1], os_error_message, |
| 684 strlen(os_error_message) + 1); | 666 strlen(os_error_message) + 1); |
| 685 } | 667 } |
| 686 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); | 668 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); |
| 687 | 669 |
| 688 // We avoid running through registered atexit() handlers because that is | 670 // We avoid running through registered atexit() handlers because that is |
| 689 // unnecessary work. | 671 // unnecessary work. |
| 690 _exit(1); | 672 _exit(1); |
| 691 } | 673 } |
| 692 | 674 |
| 693 | |
| 694 void ReportPid(int pid) { | 675 void ReportPid(int pid) { |
| 695 // In the case of starting a detached process the actual pid of that process | 676 // In the case of starting a detached process the actual pid of that process |
| 696 // is communicated using the exec control pipe. | 677 // is communicated using the exec control pipe. |
| 697 int bytes_written = | 678 int bytes_written = |
| 698 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid)); | 679 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid)); |
| 699 ASSERT(bytes_written == sizeof(int)); | 680 ASSERT(bytes_written == sizeof(int)); |
| 700 USE(bytes_written); | 681 USE(bytes_written); |
| 701 } | 682 } |
| 702 | 683 |
| 703 | |
| 704 void ReadChildError() { | 684 void ReadChildError() { |
| 705 const int kMaxMessageSize = 256; | 685 const int kMaxMessageSize = 256; |
| 706 char* message = DartUtils::ScopedCString(kMaxMessageSize); | 686 char* message = DartUtils::ScopedCString(kMaxMessageSize); |
| 707 if (message != NULL) { | 687 if (message != NULL) { |
| 708 FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize); | 688 FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize); |
| 709 message[kMaxMessageSize - 1] = '\0'; | 689 message[kMaxMessageSize - 1] = '\0'; |
| 710 *os_error_message_ = message; | 690 *os_error_message_ = message; |
| 711 } else { | 691 } else { |
| 712 // Could not get error message. It will be NULL. | 692 // Could not get error message. It will be NULL. |
| 713 ASSERT(*os_error_message_ == NULL); | 693 ASSERT(*os_error_message_ == NULL); |
| 714 } | 694 } |
| 715 } | 695 } |
| 716 | 696 |
| 717 | |
| 718 void ClosePipe(int* fds) { | 697 void ClosePipe(int* fds) { |
| 719 for (int i = 0; i < 2; i++) { | 698 for (int i = 0; i < 2; i++) { |
| 720 if (fds[i] != -1) { | 699 if (fds[i] != -1) { |
| 721 VOID_TEMP_FAILURE_RETRY(close(fds[i])); | 700 VOID_TEMP_FAILURE_RETRY(close(fds[i])); |
| 722 fds[i] = -1; | 701 fds[i] = -1; |
| 723 } | 702 } |
| 724 } | 703 } |
| 725 } | 704 } |
| 726 | 705 |
| 727 | |
| 728 void CloseAllPipes() { | 706 void CloseAllPipes() { |
| 729 ClosePipe(exec_control_); | 707 ClosePipe(exec_control_); |
| 730 ClosePipe(read_in_); | 708 ClosePipe(read_in_); |
| 731 ClosePipe(read_err_); | 709 ClosePipe(read_err_); |
| 732 ClosePipe(write_out_); | 710 ClosePipe(write_out_); |
| 733 } | 711 } |
| 734 | 712 |
| 735 | |
| 736 int read_in_[2]; // Pipe for stdout to child process. | 713 int read_in_[2]; // Pipe for stdout to child process. |
| 737 int read_err_[2]; // Pipe for stderr to child process. | 714 int read_err_[2]; // Pipe for stderr to child process. |
| 738 int write_out_[2]; // Pipe for stdin to child process. | 715 int write_out_[2]; // Pipe for stdin to child process. |
| 739 int exec_control_[2]; // Pipe to get the result from exec. | 716 int exec_control_[2]; // Pipe to get the result from exec. |
| 740 | 717 |
| 741 char** program_arguments_; | 718 char** program_arguments_; |
| 742 char** program_environment_; | 719 char** program_environment_; |
| 743 | 720 |
| 744 const char* path_; | 721 const char* path_; |
| 745 const char* working_directory_; | 722 const char* working_directory_; |
| 746 ProcessStartMode mode_; | 723 ProcessStartMode mode_; |
| 747 intptr_t* in_; | 724 intptr_t* in_; |
| 748 intptr_t* out_; | 725 intptr_t* out_; |
| 749 intptr_t* err_; | 726 intptr_t* err_; |
| 750 intptr_t* id_; | 727 intptr_t* id_; |
| 751 intptr_t* exit_event_; | 728 intptr_t* exit_event_; |
| 752 char** os_error_message_; | 729 char** os_error_message_; |
| 753 | 730 |
| 754 DISALLOW_ALLOCATION(); | 731 DISALLOW_ALLOCATION(); |
| 755 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter); | 732 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter); |
| 756 }; | 733 }; |
| 757 | 734 |
| 758 | |
| 759 int Process::Start(const char* path, | 735 int Process::Start(const char* path, |
| 760 char* arguments[], | 736 char* arguments[], |
| 761 intptr_t arguments_length, | 737 intptr_t arguments_length, |
| 762 const char* working_directory, | 738 const char* working_directory, |
| 763 char* environment[], | 739 char* environment[], |
| 764 intptr_t environment_length, | 740 intptr_t environment_length, |
| 765 ProcessStartMode mode, | 741 ProcessStartMode mode, |
| 766 intptr_t* in, | 742 intptr_t* in, |
| 767 intptr_t* out, | 743 intptr_t* out, |
| 768 intptr_t* err, | 744 intptr_t* err, |
| 769 intptr_t* id, | 745 intptr_t* id, |
| 770 intptr_t* exit_event, | 746 intptr_t* exit_event, |
| 771 char** os_error_message) { | 747 char** os_error_message) { |
| 772 ProcessStarter starter(path, arguments, arguments_length, working_directory, | 748 ProcessStarter starter(path, arguments, arguments_length, working_directory, |
| 773 environment, environment_length, mode, in, out, err, | 749 environment, environment_length, mode, in, out, err, |
| 774 id, exit_event, os_error_message); | 750 id, exit_event, os_error_message); |
| 775 return starter.Start(); | 751 return starter.Start(); |
| 776 } | 752 } |
| 777 | 753 |
| 778 | |
| 779 static bool CloseProcessBuffers(struct pollfd fds[3]) { | 754 static bool CloseProcessBuffers(struct pollfd fds[3]) { |
| 780 int e = errno; | 755 int e = errno; |
| 781 VOID_TEMP_FAILURE_RETRY(close(fds[0].fd)); | 756 VOID_TEMP_FAILURE_RETRY(close(fds[0].fd)); |
| 782 VOID_TEMP_FAILURE_RETRY(close(fds[1].fd)); | 757 VOID_TEMP_FAILURE_RETRY(close(fds[1].fd)); |
| 783 VOID_TEMP_FAILURE_RETRY(close(fds[2].fd)); | 758 VOID_TEMP_FAILURE_RETRY(close(fds[2].fd)); |
| 784 errno = e; | 759 errno = e; |
| 785 return false; | 760 return false; |
| 786 } | 761 } |
| 787 | 762 |
| 788 | |
| 789 bool Process::Wait(intptr_t pid, | 763 bool Process::Wait(intptr_t pid, |
| 790 intptr_t in, | 764 intptr_t in, |
| 791 intptr_t out, | 765 intptr_t out, |
| 792 intptr_t err, | 766 intptr_t err, |
| 793 intptr_t exit_event, | 767 intptr_t exit_event, |
| 794 ProcessResult* result) { | 768 ProcessResult* result) { |
| 795 // Close input to the process right away. | 769 // Close input to the process right away. |
| 796 VOID_TEMP_FAILURE_RETRY(close(in)); | 770 VOID_TEMP_FAILURE_RETRY(close(in)); |
| 797 | 771 |
| 798 // There is no return from this function using Dart_PropagateError | 772 // There is no return from this function using Dart_PropagateError |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 intptr_t exit_code = exit_code_data.ints[0]; | 840 intptr_t exit_code = exit_code_data.ints[0]; |
| 867 intptr_t negative = exit_code_data.ints[1]; | 841 intptr_t negative = exit_code_data.ints[1]; |
| 868 if (negative != 0) { | 842 if (negative != 0) { |
| 869 exit_code = -exit_code; | 843 exit_code = -exit_code; |
| 870 } | 844 } |
| 871 result->set_exit_code(exit_code); | 845 result->set_exit_code(exit_code); |
| 872 | 846 |
| 873 return true; | 847 return true; |
| 874 } | 848 } |
| 875 | 849 |
| 876 | |
| 877 bool Process::Kill(intptr_t id, int signal) { | 850 bool Process::Kill(intptr_t id, int signal) { |
| 878 return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1); | 851 return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1); |
| 879 } | 852 } |
| 880 | 853 |
| 881 | |
| 882 void Process::TerminateExitCodeHandler() { | 854 void Process::TerminateExitCodeHandler() { |
| 883 ExitCodeHandler::TerminateExitCodeThread(); | 855 ExitCodeHandler::TerminateExitCodeThread(); |
| 884 } | 856 } |
| 885 | 857 |
| 886 | |
| 887 intptr_t Process::CurrentProcessId() { | 858 intptr_t Process::CurrentProcessId() { |
| 888 return static_cast<intptr_t>(getpid()); | 859 return static_cast<intptr_t>(getpid()); |
| 889 } | 860 } |
| 890 | 861 |
| 891 | |
| 892 int64_t Process::CurrentRSS() { | 862 int64_t Process::CurrentRSS() { |
| 893 // The second value in /proc/self/statm is the current RSS in pages. | 863 // The second value in /proc/self/statm is the current RSS in pages. |
| 894 File* statm = File::Open("/proc/self/statm", File::kRead); | 864 File* statm = File::Open("/proc/self/statm", File::kRead); |
| 895 if (statm == NULL) { | 865 if (statm == NULL) { |
| 896 return -1; | 866 return -1; |
| 897 } | 867 } |
| 898 RefCntReleaseScope<File> releaser(statm); | 868 RefCntReleaseScope<File> releaser(statm); |
| 899 const intptr_t statm_length = 1 * KB; | 869 const intptr_t statm_length = 1 * KB; |
| 900 void* buffer = reinterpret_cast<void*>(Dart_ScopeAllocate(statm_length)); | 870 void* buffer = reinterpret_cast<void*>(Dart_ScopeAllocate(statm_length)); |
| 901 const intptr_t statm_read = statm->Read(buffer, statm_length); | 871 const intptr_t statm_read = statm->Read(buffer, statm_length); |
| 902 if (statm_read <= 0) { | 872 if (statm_read <= 0) { |
| 903 return -1; | 873 return -1; |
| 904 } | 874 } |
| 905 int64_t current_rss_pages = 0; | 875 int64_t current_rss_pages = 0; |
| 906 int matches = sscanf(reinterpret_cast<char*>(buffer), "%*s%" Pd64 "", | 876 int matches = sscanf(reinterpret_cast<char*>(buffer), "%*s%" Pd64 "", |
| 907 ¤t_rss_pages); | 877 ¤t_rss_pages); |
| 908 if (matches != 1) { | 878 if (matches != 1) { |
| 909 return -1; | 879 return -1; |
| 910 } | 880 } |
| 911 return current_rss_pages * getpagesize(); | 881 return current_rss_pages * getpagesize(); |
| 912 } | 882 } |
| 913 | 883 |
| 914 | |
| 915 int64_t Process::MaxRSS() { | 884 int64_t Process::MaxRSS() { |
| 916 struct rusage usage; | 885 struct rusage usage; |
| 917 usage.ru_maxrss = 0; | 886 usage.ru_maxrss = 0; |
| 918 int r = getrusage(RUSAGE_SELF, &usage); | 887 int r = getrusage(RUSAGE_SELF, &usage); |
| 919 if (r < 0) { | 888 if (r < 0) { |
| 920 return -1; | 889 return -1; |
| 921 } | 890 } |
| 922 return usage.ru_maxrss * KB; | 891 return usage.ru_maxrss * KB; |
| 923 } | 892 } |
| 924 | 893 |
| 925 | |
| 926 static Mutex* signal_mutex = new Mutex(); | 894 static Mutex* signal_mutex = new Mutex(); |
| 927 static SignalInfo* signal_handlers = NULL; | 895 static SignalInfo* signal_handlers = NULL; |
| 928 static const int kSignalsCount = 7; | 896 static const int kSignalsCount = 7; |
| 929 static const int kSignals[kSignalsCount] = { | 897 static const int kSignals[kSignalsCount] = { |
| 930 SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGWINCH, | 898 SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGWINCH, |
| 931 SIGQUIT // Allow VMService to listen on SIGQUIT. | 899 SIGQUIT // Allow VMService to listen on SIGQUIT. |
| 932 }; | 900 }; |
| 933 | 901 |
| 934 | |
| 935 SignalInfo::~SignalInfo() { | 902 SignalInfo::~SignalInfo() { |
| 936 VOID_TEMP_FAILURE_RETRY(close(fd_)); | 903 VOID_TEMP_FAILURE_RETRY(close(fd_)); |
| 937 } | 904 } |
| 938 | 905 |
| 939 | |
| 940 static void SignalHandler(int signal) { | 906 static void SignalHandler(int signal) { |
| 941 MutexLocker lock(signal_mutex); | 907 MutexLocker lock(signal_mutex); |
| 942 const SignalInfo* handler = signal_handlers; | 908 const SignalInfo* handler = signal_handlers; |
| 943 while (handler != NULL) { | 909 while (handler != NULL) { |
| 944 if (handler->signal() == signal) { | 910 if (handler->signal() == signal) { |
| 945 int value = 0; | 911 int value = 0; |
| 946 VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1)); | 912 VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1)); |
| 947 } | 913 } |
| 948 handler = handler->next(); | 914 handler = handler->next(); |
| 949 } | 915 } |
| 950 } | 916 } |
| 951 | 917 |
| 952 | |
| 953 intptr_t Process::SetSignalHandler(intptr_t signal) { | 918 intptr_t Process::SetSignalHandler(intptr_t signal) { |
| 954 bool found = false; | 919 bool found = false; |
| 955 for (int i = 0; i < kSignalsCount; i++) { | 920 for (int i = 0; i < kSignalsCount; i++) { |
| 956 if (kSignals[i] == signal) { | 921 if (kSignals[i] == signal) { |
| 957 found = true; | 922 found = true; |
| 958 break; | 923 break; |
| 959 } | 924 } |
| 960 } | 925 } |
| 961 if (!found) { | 926 if (!found) { |
| 962 return -1; | 927 return -1; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 993 if (status < 0) { | 958 if (status < 0) { |
| 994 VOID_TEMP_FAILURE_RETRY(close(fds[0])); | 959 VOID_TEMP_FAILURE_RETRY(close(fds[0])); |
| 995 VOID_TEMP_FAILURE_RETRY(close(fds[1])); | 960 VOID_TEMP_FAILURE_RETRY(close(fds[1])); |
| 996 return -1; | 961 return -1; |
| 997 } | 962 } |
| 998 } | 963 } |
| 999 signal_handlers = new SignalInfo(fds[1], signal, signal_handlers); | 964 signal_handlers = new SignalInfo(fds[1], signal, signal_handlers); |
| 1000 return fds[0]; | 965 return fds[0]; |
| 1001 } | 966 } |
| 1002 | 967 |
| 1003 | |
| 1004 void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) { | 968 void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) { |
| 1005 // Either the port is illegal or there is no current isolate, but not both. | 969 // Either the port is illegal or there is no current isolate, but not both. |
| 1006 ASSERT((port != ILLEGAL_PORT) || (Dart_CurrentIsolate() == NULL)); | 970 ASSERT((port != ILLEGAL_PORT) || (Dart_CurrentIsolate() == NULL)); |
| 1007 ASSERT((port == ILLEGAL_PORT) || (Dart_CurrentIsolate() != NULL)); | 971 ASSERT((port == ILLEGAL_PORT) || (Dart_CurrentIsolate() != NULL)); |
| 1008 ThreadSignalBlocker blocker(kSignalsCount, kSignals); | 972 ThreadSignalBlocker blocker(kSignalsCount, kSignals); |
| 1009 MutexLocker lock(signal_mutex); | 973 MutexLocker lock(signal_mutex); |
| 1010 SignalInfo* handler = signal_handlers; | 974 SignalInfo* handler = signal_handlers; |
| 1011 bool unlisten = true; | 975 bool unlisten = true; |
| 1012 while (handler != NULL) { | 976 while (handler != NULL) { |
| 1013 bool remove = false; | 977 bool remove = false; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1035 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); | 999 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); |
| 1036 } | 1000 } |
| 1037 } | 1001 } |
| 1038 | 1002 |
| 1039 } // namespace bin | 1003 } // namespace bin |
| 1040 } // namespace dart | 1004 } // namespace dart |
| 1041 | 1005 |
| 1042 #endif // defined(HOST_OS_ANDROID) | 1006 #endif // defined(HOST_OS_ANDROID) |
| 1043 | 1007 |
| 1044 #endif // !defined(DART_IO_DISABLED) | 1008 #endif // !defined(DART_IO_DISABLED) |
| OLD | NEW |