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 |