| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <dirent.h> | 5 #include <dirent.h> |
| 6 #include <errno.h> | 6 #include <errno.h> |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <signal.h> | 8 #include <signal.h> |
| 9 #include <stdlib.h> | 9 #include <stdlib.h> |
| 10 #include <sys/resource.h> | 10 #include <sys/resource.h> |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 | 124 |
| 125 return status; | 125 return status; |
| 126 } | 126 } |
| 127 | 127 |
| 128 // Android has built-in crash handling. | 128 // Android has built-in crash handling. |
| 129 #if !defined(OS_ANDROID) | 129 #if !defined(OS_ANDROID) |
| 130 void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) { | 130 void StackDumpSignalHandler(int signal, siginfo_t* info, ucontext_t* context) { |
| 131 if (debug::BeingDebugged()) | 131 if (debug::BeingDebugged()) |
| 132 debug::BreakDebugger(); | 132 debug::BreakDebugger(); |
| 133 | 133 |
| 134 LOG(ERROR) << "Received signal " << signal; | 134 DLOG(ERROR) << "Received signal " << signal; |
| 135 debug::StackTrace().PrintBacktrace(); | 135 debug::StackTrace().PrintBacktrace(); |
| 136 | 136 |
| 137 // TODO(shess): Port to Linux. | 137 // TODO(shess): Port to Linux. |
| 138 #if defined(OS_MACOSX) | 138 #if defined(OS_MACOSX) |
| 139 // TODO(shess): Port to 64-bit. | 139 // TODO(shess): Port to 64-bit. |
| 140 #if ARCH_CPU_32_BITS | 140 #if ARCH_CPU_32_BITS |
| 141 char buf[1024]; | 141 char buf[1024]; |
| 142 size_t len; | 142 size_t len; |
| 143 | 143 |
| 144 // NOTE: Even |snprintf()| is not on the approved list for signal | 144 // NOTE: Even |snprintf()| is not on the approved list for signal |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 | 289 |
| 290 if (!result) | 290 if (!result) |
| 291 DPLOG(ERROR) << "Unable to terminate process " << process_id; | 291 DPLOG(ERROR) << "Unable to terminate process " << process_id; |
| 292 | 292 |
| 293 return result; | 293 return result; |
| 294 } | 294 } |
| 295 | 295 |
| 296 bool KillProcessGroup(ProcessHandle process_group_id) { | 296 bool KillProcessGroup(ProcessHandle process_group_id) { |
| 297 bool result = kill(-1 * process_group_id, SIGKILL) == 0; | 297 bool result = kill(-1 * process_group_id, SIGKILL) == 0; |
| 298 if (!result) | 298 if (!result) |
| 299 PLOG(ERROR) << "Unable to terminate process group " << process_group_id; | 299 DPLOG(ERROR) << "Unable to terminate process group " << process_group_id; |
| 300 return result; | 300 return result; |
| 301 } | 301 } |
| 302 | 302 |
| 303 // A class to handle auto-closing of DIR*'s. | 303 // A class to handle auto-closing of DIR*'s. |
| 304 class ScopedDIRClose { | 304 class ScopedDIRClose { |
| 305 public: | 305 public: |
| 306 inline void operator()(DIR* x) const { | 306 inline void operator()(DIR* x) const { |
| 307 if (x) { | 307 if (x) { |
| 308 closedir(x); | 308 closedir(x); |
| 309 } | 309 } |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 #if defined(OS_MACOSX) | 558 #if defined(OS_MACOSX) |
| 559 int synchronization_pipe_fds[2]; | 559 int synchronization_pipe_fds[2]; |
| 560 file_util::ScopedFD synchronization_read_fd; | 560 file_util::ScopedFD synchronization_read_fd; |
| 561 file_util::ScopedFD synchronization_write_fd; | 561 file_util::ScopedFD synchronization_write_fd; |
| 562 | 562 |
| 563 if (options.synchronize) { | 563 if (options.synchronize) { |
| 564 // wait means "don't return from LaunchProcess until the child exits", and | 564 // wait means "don't return from LaunchProcess until the child exits", and |
| 565 // synchronize means "return from LaunchProcess but don't let the child | 565 // synchronize means "return from LaunchProcess but don't let the child |
| 566 // run until LaunchSynchronize is called". These two options are highly | 566 // run until LaunchSynchronize is called". These two options are highly |
| 567 // incompatible. | 567 // incompatible. |
| 568 CHECK(!options.wait); | 568 DCHECK(!options.wait); |
| 569 | 569 |
| 570 // Create the pipe used for synchronization. | 570 // Create the pipe used for synchronization. |
| 571 if (HANDLE_EINTR(pipe(synchronization_pipe_fds)) != 0) { | 571 if (HANDLE_EINTR(pipe(synchronization_pipe_fds)) != 0) { |
| 572 PLOG(ERROR) << "pipe"; | 572 DPLOG(ERROR) << "pipe"; |
| 573 return false; | 573 return false; |
| 574 } | 574 } |
| 575 | 575 |
| 576 // The parent process will only use synchronization_write_fd as the write | 576 // The parent process will only use synchronization_write_fd as the write |
| 577 // side of the pipe. It can close the read side as soon as the child | 577 // side of the pipe. It can close the read side as soon as the child |
| 578 // process has forked off. The child process will only use | 578 // process has forked off. The child process will only use |
| 579 // synchronization_read_fd as the read side of the pipe. In that process, | 579 // synchronization_read_fd as the read side of the pipe. In that process, |
| 580 // the write side can be closed as soon as it has forked. | 580 // the write side can be closed as soon as it has forked. |
| 581 synchronization_read_fd.reset(&synchronization_pipe_fds[0]); | 581 synchronization_read_fd.reset(&synchronization_pipe_fds[0]); |
| 582 synchronization_write_fd.reset(&synchronization_pipe_fds[1]); | 582 synchronization_write_fd.reset(&synchronization_pipe_fds[1]); |
| 583 } | 583 } |
| 584 #endif // OS_MACOSX | 584 #endif // OS_MACOSX |
| 585 | 585 |
| 586 pid_t pid; | 586 pid_t pid; |
| 587 #if defined(OS_LINUX) | 587 #if defined(OS_LINUX) |
| 588 if (options.clone_flags) { | 588 if (options.clone_flags) { |
| 589 pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0); | 589 pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0); |
| 590 } else | 590 } else |
| 591 #endif | 591 #endif |
| 592 { | 592 { |
| 593 pid = fork(); | 593 pid = fork(); |
| 594 } | 594 } |
| 595 | 595 |
| 596 if (pid < 0) { | 596 if (pid < 0) { |
| 597 PLOG(ERROR) << "fork"; | 597 DPLOG(ERROR) << "fork"; |
| 598 return false; | 598 return false; |
| 599 } else if (pid == 0) { | 599 } else if (pid == 0) { |
| 600 // Child process | 600 // Child process |
| 601 | 601 |
| 602 // DANGER: fork() rule: in the child, if you don't end up doing exec*(), | 602 // DANGER: fork() rule: in the child, if you don't end up doing exec*(), |
| 603 // you call _exit() instead of exit(). This is because _exit() does not | 603 // you call _exit() instead of exit(). This is because _exit() does not |
| 604 // call any previously-registered (in the parent) exit handlers, which | 604 // call any previously-registered (in the parent) exit handlers, which |
| 605 // might do things like block waiting for threads that don't even exist | 605 // might do things like block waiting for threads that don't even exist |
| 606 // in the child. | 606 // in the child. |
| 607 | 607 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 742 } | 742 } |
| 743 | 743 |
| 744 #if defined(OS_MACOSX) | 744 #if defined(OS_MACOSX) |
| 745 void LaunchSynchronize(LaunchSynchronizationHandle handle) { | 745 void LaunchSynchronize(LaunchSynchronizationHandle handle) { |
| 746 int synchronization_fd = *handle; | 746 int synchronization_fd = *handle; |
| 747 file_util::ScopedFD synchronization_fd_closer(&synchronization_fd); | 747 file_util::ScopedFD synchronization_fd_closer(&synchronization_fd); |
| 748 delete handle; | 748 delete handle; |
| 749 | 749 |
| 750 // Write a '\0' character to the pipe. | 750 // Write a '\0' character to the pipe. |
| 751 if (HANDLE_EINTR(write(synchronization_fd, "", 1)) != 1) { | 751 if (HANDLE_EINTR(write(synchronization_fd, "", 1)) != 1) { |
| 752 PLOG(ERROR) << "write"; | 752 DPLOG(ERROR) << "write"; |
| 753 } | 753 } |
| 754 } | 754 } |
| 755 #endif // defined(OS_MACOSX) | 755 #endif // defined(OS_MACOSX) |
| 756 | 756 |
| 757 ProcessMetrics::~ProcessMetrics() { } | 757 ProcessMetrics::~ProcessMetrics() { } |
| 758 | 758 |
| 759 bool EnableInProcessStackDumping() { | 759 bool EnableInProcessStackDumping() { |
| 760 // When running in an application, our code typically expects SIGPIPE | 760 // When running in an application, our code typically expects SIGPIPE |
| 761 // to be ignored. Therefore, when testing that same code, it should run | 761 // to be ignored. Therefore, when testing that same code, it should run |
| 762 // with SIGPIPE ignored as well. | 762 // with SIGPIPE ignored as well. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 782 | 782 |
| 783 void RaiseProcessToHighPriority() { | 783 void RaiseProcessToHighPriority() { |
| 784 // On POSIX, we don't actually do anything here. We could try to nice() or | 784 // On POSIX, we don't actually do anything here. We could try to nice() or |
| 785 // setpriority() or sched_getscheduler, but these all require extra rights. | 785 // setpriority() or sched_getscheduler, but these all require extra rights. |
| 786 } | 786 } |
| 787 | 787 |
| 788 TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { | 788 TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { |
| 789 int status = 0; | 789 int status = 0; |
| 790 const pid_t result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); | 790 const pid_t result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); |
| 791 if (result == -1) { | 791 if (result == -1) { |
| 792 PLOG(ERROR) << "waitpid(" << handle << ")"; | 792 DPLOG(ERROR) << "waitpid(" << handle << ")"; |
| 793 if (exit_code) | 793 if (exit_code) |
| 794 *exit_code = 0; | 794 *exit_code = 0; |
| 795 return TERMINATION_STATUS_NORMAL_TERMINATION; | 795 return TERMINATION_STATUS_NORMAL_TERMINATION; |
| 796 } else if (result == 0) { | 796 } else if (result == 0) { |
| 797 // the child hasn't exited yet. | 797 // the child hasn't exited yet. |
| 798 if (exit_code) | 798 if (exit_code) |
| 799 *exit_code = 0; | 799 *exit_code = 0; |
| 800 return TERMINATION_STATUS_STILL_RUNNING; | 800 return TERMINATION_STATUS_STILL_RUNNING; |
| 801 } | 801 } |
| 802 | 802 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 867 // Using kqueue on Mac so that we can wait on non-child processes. | 867 // Using kqueue on Mac so that we can wait on non-child processes. |
| 868 // We can't use kqueues on child processes because we need to reap | 868 // We can't use kqueues on child processes because we need to reap |
| 869 // our own children using wait. | 869 // our own children using wait. |
| 870 static bool WaitForSingleNonChildProcess(ProcessHandle handle, | 870 static bool WaitForSingleNonChildProcess(ProcessHandle handle, |
| 871 int64 wait_milliseconds) { | 871 int64 wait_milliseconds) { |
| 872 DCHECK_GT(handle, 0); | 872 DCHECK_GT(handle, 0); |
| 873 DCHECK(wait_milliseconds == base::kNoTimeout || wait_milliseconds > 0); | 873 DCHECK(wait_milliseconds == base::kNoTimeout || wait_milliseconds > 0); |
| 874 | 874 |
| 875 int kq = kqueue(); | 875 int kq = kqueue(); |
| 876 if (kq == -1) { | 876 if (kq == -1) { |
| 877 PLOG(ERROR) << "kqueue"; | 877 DPLOG(ERROR) << "kqueue"; |
| 878 return false; | 878 return false; |
| 879 } | 879 } |
| 880 file_util::ScopedFD kq_closer(&kq); | 880 file_util::ScopedFD kq_closer(&kq); |
| 881 | 881 |
| 882 struct kevent change = {0}; | 882 struct kevent change = {0}; |
| 883 EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); | 883 EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); |
| 884 int result = HANDLE_EINTR(kevent(kq, &change, 1, NULL, 0, NULL)); | 884 int result = HANDLE_EINTR(kevent(kq, &change, 1, NULL, 0, NULL)); |
| 885 if (result == -1) { | 885 if (result == -1) { |
| 886 if (errno == ESRCH) { | 886 if (errno == ESRCH) { |
| 887 // If the process wasn't found, it must be dead. | 887 // If the process wasn't found, it must be dead. |
| 888 return true; | 888 return true; |
| 889 } | 889 } |
| 890 | 890 |
| 891 PLOG(ERROR) << "kevent (setup " << handle << ")"; | 891 DPLOG(ERROR) << "kevent (setup " << handle << ")"; |
| 892 return false; | 892 return false; |
| 893 } | 893 } |
| 894 | 894 |
| 895 // Keep track of the elapsed time to be able to restart kevent if it's | 895 // Keep track of the elapsed time to be able to restart kevent if it's |
| 896 // interrupted. | 896 // interrupted. |
| 897 bool wait_forever = wait_milliseconds == base::kNoTimeout; | 897 bool wait_forever = wait_milliseconds == base::kNoTimeout; |
| 898 base::TimeDelta remaining_delta; | 898 base::TimeDelta remaining_delta; |
| 899 base::Time deadline; | 899 base::Time deadline; |
| 900 if (!wait_forever) { | 900 if (!wait_forever) { |
| 901 remaining_delta = base::TimeDelta::FromMilliseconds(wait_milliseconds); | 901 remaining_delta = base::TimeDelta::FromMilliseconds(wait_milliseconds); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 921 if (!wait_forever) { | 921 if (!wait_forever) { |
| 922 remaining_delta = deadline - base::Time::Now(); | 922 remaining_delta = deadline - base::Time::Now(); |
| 923 } | 923 } |
| 924 result = 0; | 924 result = 0; |
| 925 } else { | 925 } else { |
| 926 break; | 926 break; |
| 927 } | 927 } |
| 928 } | 928 } |
| 929 | 929 |
| 930 if (result < 0) { | 930 if (result < 0) { |
| 931 PLOG(ERROR) << "kevent (wait " << handle << ")"; | 931 DPLOG(ERROR) << "kevent (wait " << handle << ")"; |
| 932 return false; | 932 return false; |
| 933 } else if (result > 1) { | 933 } else if (result > 1) { |
| 934 LOG(ERROR) << "kevent (wait " << handle << "): unexpected result " | 934 DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result " |
| 935 << result; | 935 << result; |
| 936 return false; | 936 return false; |
| 937 } else if (result == 0) { | 937 } else if (result == 0) { |
| 938 // Timed out. | 938 // Timed out. |
| 939 return false; | 939 return false; |
| 940 } | 940 } |
| 941 | 941 |
| 942 DCHECK_EQ(result, 1); | 942 DCHECK_EQ(result, 1); |
| 943 | 943 |
| 944 if (event.filter != EVFILT_PROC || | 944 if (event.filter != EVFILT_PROC || |
| 945 (event.fflags & NOTE_EXIT) == 0 || | 945 (event.fflags & NOTE_EXIT) == 0 || |
| 946 event.ident != static_cast<uintptr_t>(handle)) { | 946 event.ident != static_cast<uintptr_t>(handle)) { |
| 947 LOG(ERROR) << "kevent (wait " << handle | 947 DLOG(ERROR) << "kevent (wait " << handle |
| 948 << "): unexpected event: filter=" << event.filter | 948 << "): unexpected event: filter=" << event.filter |
| 949 << ", fflags=" << event.fflags | 949 << ", fflags=" << event.fflags |
| 950 << ", ident=" << event.ident; | 950 << ", ident=" << event.ident; |
| 951 return false; | 951 return false; |
| 952 } | 952 } |
| 953 | 953 |
| 954 return true; | 954 return true; |
| 955 } | 955 } |
| 956 #endif // OS_MACOSX | 956 #endif // OS_MACOSX |
| 957 | 957 |
| 958 bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) { | 958 bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) { |
| 959 ProcessHandle parent_pid = GetParentProcessId(handle); | 959 ProcessHandle parent_pid = GetParentProcessId(handle); |
| 960 ProcessHandle our_pid = Process::Current().handle(); | 960 ProcessHandle our_pid = Process::Current().handle(); |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1186 const ProcessFilter* filter) { | 1186 const ProcessFilter* filter) { |
| 1187 bool exited_cleanly = | 1187 bool exited_cleanly = |
| 1188 WaitForProcessesToExit(executable_name, wait_milliseconds, | 1188 WaitForProcessesToExit(executable_name, wait_milliseconds, |
| 1189 filter); | 1189 filter); |
| 1190 if (!exited_cleanly) | 1190 if (!exited_cleanly) |
| 1191 KillProcesses(executable_name, exit_code, filter); | 1191 KillProcesses(executable_name, exit_code, filter); |
| 1192 return exited_cleanly; | 1192 return exited_cleanly; |
| 1193 } | 1193 } |
| 1194 | 1194 |
| 1195 } // namespace base | 1195 } // namespace base |
| OLD | NEW |