diff options
-rw-r--r-- | base/process_util.h | 17 | ||||
-rw-r--r-- | base/process_util_posix.cc | 39 | ||||
-rw-r--r-- | chrome/test/test_launcher/out_of_proc_test_runner.cc | 18 |
3 files changed, 71 insertions, 3 deletions
diff --git a/base/process_util.h b/base/process_util.h index e64d0a7..c513f3d 100644 --- a/base/process_util.h +++ b/base/process_util.h @@ -226,6 +226,14 @@ bool LaunchApp(const std::vector<std::string>& argv, const file_handle_mapping_vector& fds_to_remap, bool wait, ProcessHandle* process_handle); +// Similar to the above two methods, but starts the child process in a process +// group of its own, instead of allowing it to inherit the parent's process +// group. The pgid of the child process will be the same as its pid. +bool LaunchAppInNewProcessGroup(const std::vector<std::string>& argv, + const environment_vector& environ, + const file_handle_mapping_vector& fds_to_remap, + bool wait, ProcessHandle* process_handle); + // AlterEnvironment returns a modified environment vector, constructed from the // given environment and the list of changes given in |changes|. Each key in // the environment is matched against the first element of the pairs. In the @@ -276,7 +284,7 @@ int GetProcessCount(const std::wstring& executable_name, // Attempts to kill all the processes on the current machine that were launched // from the given executable name, ending them with the given exit code. If // filter is non-null, then only processes selected by the filter are killed. -// Returns false if all processes were able to be killed off, false if at least +// Returns true if all processes were able to be killed off, false if at least // one couldn't be killed. bool KillProcesses(const std::wstring& executable_name, int exit_code, const ProcessFilter* filter); @@ -286,6 +294,13 @@ bool KillProcesses(const std::wstring& executable_name, int exit_code, // for the process to be actually terminated before returning. // Returns true if this is successful, false otherwise. bool KillProcess(ProcessHandle process, int exit_code, bool wait); + +#if defined(OS_POSIX) +// Attempts to kill the process group identified by |process_group_id|. Returns +// true on success. +bool KillProcessGroup(ProcessHandle process_group_id); +#endif + #if defined(OS_WIN) bool KillProcessById(ProcessId process_id, int exit_code, bool wait); #endif diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc index d6171b1..31a8e9d 100644 --- a/base/process_util_posix.cc +++ b/base/process_util_posix.cc @@ -195,6 +195,13 @@ bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) { return result; } +bool KillProcessGroup(ProcessHandle process_group_id) { + bool result = kill(-1 * process_group_id, SIGKILL) == 0; + if (!result) + PLOG(ERROR) << "Unable to terminate process group " << process_group_id; + return result; +} + // A class to handle auto-closing of DIR*'s. class ScopedDIRClose { public: @@ -420,12 +427,13 @@ char** AlterEnvironment(const environment_vector& changes, return ret; } -bool LaunchApp( +bool LaunchAppImpl( const std::vector<std::string>& argv, const environment_vector& env_changes, const file_handle_mapping_vector& fds_to_remap, bool wait, - ProcessHandle* process_handle) { + ProcessHandle* process_handle, + bool start_new_process_group) { pid_t pid; InjectiveMultimap fd_shuffle1, fd_shuffle2; fd_shuffle1.reserve(fds_to_remap.size()); @@ -439,6 +447,13 @@ bool LaunchApp( if (pid == 0) { // Child process + + if (start_new_process_group) { + // Instead of inheriting the process group ID of the parent, the child + // starts off a new process group with pgid equal to its process ID. + if (setpgid(0, 0) < 0) + return false; + } #if defined(OS_MACOSX) RestoreDefaultExceptionHandler(); #endif @@ -498,6 +513,26 @@ bool LaunchApp( return true; } +bool LaunchApp( + const std::vector<std::string>& argv, + const environment_vector& env_changes, + const file_handle_mapping_vector& fds_to_remap, + bool wait, + ProcessHandle* process_handle) { + return LaunchAppImpl(argv, env_changes, fds_to_remap, + wait, process_handle, false); +} + +bool LaunchAppInNewProcessGroup( + const std::vector<std::string>& argv, + const environment_vector& env_changes, + const file_handle_mapping_vector& fds_to_remap, + bool wait, + ProcessHandle* process_handle) { + return LaunchAppImpl(argv, env_changes, fds_to_remap, wait, + process_handle, true); +} + bool LaunchApp(const std::vector<std::string>& argv, const file_handle_mapping_vector& fds_to_remap, bool wait, ProcessHandle* process_handle) { diff --git a/chrome/test/test_launcher/out_of_proc_test_runner.cc b/chrome/test/test_launcher/out_of_proc_test_runner.cc index 47be495..282ae4a 100644 --- a/chrome/test/test_launcher/out_of_proc_test_runner.cc +++ b/chrome/test/test_launcher/out_of_proc_test_runner.cc @@ -89,7 +89,18 @@ class OutOfProcTestRunner : public tests::TestRunner { new_cmd_line.AppendSwitch(base::TestSuite::kStrictFailureHandling); base::ProcessHandle process_handle; +#if defined(OS_POSIX) + // On POSIX, we launch the test in a new process group with pgid equal to + // its pid. Any child processes that the test may create will inherit the + // same pgid. This way, if the test is abruptly terminated, we can clean up + // any orphaned child processes it may have left behind. + base::environment_vector no_env; + base::file_handle_mapping_vector no_files; + if (!base::LaunchAppInNewProcessGroup(new_cmd_line.argv(), no_env, no_files, + false, &process_handle)) +#else if (!base::LaunchApp(new_cmd_line, false, false, &process_handle)) +#endif return false; int test_terminate_timeout_ms = kDefaultTestTimeoutMs; @@ -111,6 +122,13 @@ class OutOfProcTestRunner : public tests::TestRunner { // Ensure that the process terminates. base::KillProcess(process_handle, -1, true); + +#if defined(OS_POSIX) + // On POSIX, we need to clean up any child processes that the test might + // have created. On windows, child processes are automatically cleaned up + // using JobObjects. + base::KillProcessGroup(process_handle); +#endif } return exit_code == 0; |