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 |