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 |