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