diff options
-rw-r--r-- | base/file_util_posix.cc | 2 | ||||
-rw-r--r-- | base/logging.cc | 6 | ||||
-rw-r--r-- | base/process_util.h | 9 | ||||
-rw-r--r-- | base/process_util_linux.cc | 46 | ||||
-rw-r--r-- | base/process_util_unittest.cc | 7 | ||||
-rw-r--r-- | base/zygote_manager.cc | 30 | ||||
-rw-r--r-- | base/zygote_manager.h | 4 | ||||
-rw-r--r-- | chrome/test/chrome_process_util.cc | 22 |
8 files changed, 107 insertions, 19 deletions
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc index b9aa206..7f40c17 100644 --- a/base/file_util_posix.cc +++ b/base/file_util_posix.cc @@ -633,7 +633,7 @@ bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) { file_ = zm->OpenFile(file_name.value().c_str()); if (file_ == -1) { LOG(INFO) << "Zygote manager can't open " << file_name.value() - << ", retrying locally"; + << ", retrying locally. (OK at start of ui_tests.)"; } } #endif // defined(OS_LINUX) diff --git a/base/logging.cc b/base/logging.cc index b6aa730..77e9583 100644 --- a/base/logging.cc +++ b/base/logging.cc @@ -208,7 +208,7 @@ bool InitializeLogFileHandle() { } } SetFilePointer(log_file, 0, 0, FILE_END); -#elif defined(OS_POSIX) +#elif defined(OS_LINUX) // Reserve global fd slots. int reserved_fds[kReservedFds]; for (int i=0; i < kReservedFds; i++) @@ -222,6 +222,10 @@ bool InitializeLogFileHandle() { if (log_file == NULL) return false; +#elif defined(OS_POSIX) + log_file = fopen(log_file_name->c_str(), "a"); + if (log_file == NULL) + return false; #endif } diff --git a/base/process_util.h b/base/process_util.h index b558541..4fe081f 100644 --- a/base/process_util.h +++ b/base/process_util.h @@ -23,6 +23,7 @@ #include <vector> #include "base/command_line.h" +#include "base/file_path.h" #include "base/process.h" #if defined(OS_WIN) @@ -87,6 +88,14 @@ void CloseProcessHandle(ProcessHandle process); // Win XP SP1 as well. ProcessId GetProcId(ProcessHandle process); +#if defined(OS_LINUX) +// Returns the ID for the parent of the given process. +ProcessId GetParentProcessId(ProcessHandle process); + +// Returns the path to the executable of the given process. +FilePath GetProcessExecutablePath(ProcessHandle process); +#endif + #if defined(OS_POSIX) // Sets all file descriptors to close on exec except for stdin, stdout // and stderr. diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc index 78725cc..ba2d8cd 100644 --- a/base/process_util_linux.cc +++ b/base/process_util_linux.cc @@ -7,10 +7,10 @@ #include <ctype.h> #include <dirent.h> #include <fcntl.h> -#include <unistd.h> #include <string> #include <sys/types.h> #include <sys/wait.h> +#include <unistd.h> #include "base/eintr_wrapper.h" #include "base/file_util.h" @@ -42,6 +42,50 @@ void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) { namespace base { +ProcessId GetParentProcessId(ProcessHandle process) { + FilePath stat_file("/proc"); + stat_file = stat_file.Append(IntToString(process)); + stat_file = stat_file.Append("status"); + std::string status; + if (!file_util::ReadFileToString(stat_file, &status)) + return -1; + + StringTokenizer tokenizer(status, ":\n"); + ParsingState state = KEY_NAME; + std::string last_key_name; + while (tokenizer.GetNext()) { + switch (state) { + case KEY_NAME: + last_key_name = tokenizer.token(); + state = KEY_VALUE; + break; + case KEY_VALUE: + DCHECK(!last_key_name.empty()); + if (last_key_name == "PPid") { + pid_t ppid = StringToInt(tokenizer.token()); + return ppid; + } + state = KEY_NAME; + break; + } + } + NOTREACHED(); + return -1; +} + +FilePath GetProcessExecutablePath(ProcessHandle process) { + FilePath stat_file("/proc"); + stat_file = stat_file.Append(IntToString(process)); + stat_file = stat_file.Append("exe"); + char exename[2048]; + ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename)); + if (len < 1) { + // No such process. Happens frequently in e.g. TerminateAllChromeProcesses + return FilePath(); + } + return FilePath(std::string(exename, len)); +} + bool ForkApp(const std::vector<std::string>& argv, const file_handle_mapping_vector& fds_to_remap, ProcessHandle* process_handle) { diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc index 1e5c272..7b30be6 100644 --- a/base/process_util_unittest.cc +++ b/base/process_util_unittest.cc @@ -270,6 +270,13 @@ TEST_F(ProcessUtilTest, GetAppOutput) { EXPECT_STREQ("foobar42", output.c_str()); } +#if defined(OS_LINUX) +TEST_F(ProcessUtilTest, GetParentProcessId) { + base::ProcessId ppid = GetParentProcessId(GetCurrentProcId()); + EXPECT_EQ(ppid, getppid()); +} +#endif + #endif // defined(OS_POSIX) } // namespace base diff --git a/base/zygote_manager.cc b/base/zygote_manager.cc index 2310c2d..7f0043a 100644 --- a/base/zygote_manager.cc +++ b/base/zygote_manager.cc @@ -54,6 +54,12 @@ ZygoteManager::~ZygoteManager() { close(canary_fd_); canary_fd_ = -1; } +#ifndef OFFICIAL_BUILD + // Closing the canary kills the server, + // so after this it's ok for e.g. unit tests + // to start a new zygote server. + (void) unsetenv("ZYGOTE_MANAGER_STARTED"); +#endif } // Runs in client process @@ -61,13 +67,7 @@ ZygoteManager* ZygoteManager::Get() { static bool checked = false; static bool enabled = false; if (!checked) { - enabled = (getenv("ENABLE_ZYGOTE_MANAGER") != NULL); - // sanity check - make sure all the places that relaunch chrome - // have been zygotified. - if (enabled) - DCHECK(getenv("ZYGOTE_MANAGER_STARTED") == NULL) - << "fork/exec used instead of LongFork"; - (void) setenv("ZYGOTE_MANAGER_STARTED", "1", 1); + enabled = (getenv("DISABLE_ZYGOTE_MANAGER") == NULL); checked = true; } if (!enabled) @@ -594,7 +594,6 @@ bool ZygoteManager::ReadAndHandleMessage(std::vector<std::string>** newargv) { if (nactive == -1) { if (errno == EINTR) { - LOG(INFO) << "poll interrupted"; // Probably SIGCHLD. Return to main loop so it can reap. return true; } @@ -723,6 +722,12 @@ std::vector<std::string>* ZygoteManager::Start() { DCHECK(server_fd_ == -1); DCHECK(client_fd_ == -1); +#ifndef OFFICIAL_BUILD + // Disallow nested ZygoteManager servers + CHECK(getenv("ZYGOTE_MANAGER_STARTED") == NULL) << "already started?!"; + (void) setenv("ZYGOTE_MANAGER_STARTED", "1", 1); +#endif + int pipe_fds[2]; // Avoid using the reserved fd slots. @@ -761,11 +766,11 @@ std::vector<std::string>* ZygoteManager::Start() { // Fork a fork server. pid_t childpid = fork(); - if (childpid) { + if (!childpid) { for (int i=0; i < kReservedFds; i++) close(reserved_fds[i]); - // Original parent. Continues on with the main program + // Original child. Continues on with the main program // and becomes the first client. close(server_fd_); server_fd_ = -1; @@ -789,7 +794,7 @@ std::vector<std::string>* ZygoteManager::Start() { action.sa_handler = SIGCHLDHandler; CHECK(sigaction(SIGCHLD, &action, NULL) == 0); - // Original child. Acts as the server. + // Original process. Acts as the server. while (true) { std::vector<std::string>* newargv = NULL; if (!ReadAndHandleMessage(&newargv)) @@ -812,7 +817,6 @@ std::vector<std::string>* ZygoteManager::Start() { } } // Server cleanup after EOF or error reading from the socket. - // Chrome doesn't seem to get here in practice. Delete(FilePath(lockfile_), false); // TODO(dkegel): real error handling LOG(INFO) << "exiting. " << cached_fds_.size() << " cached fds."; @@ -821,7 +825,7 @@ std::vector<std::string>* ZygoteManager::Start() { LOG(INFO) << "Closing fd " << i->second << " filename " << i->first; close(i->second); } - exit(-1); + exit(0); } } } diff --git a/base/zygote_manager.h b/base/zygote_manager.h index 7936167..5b94533 100644 --- a/base/zygote_manager.h +++ b/base/zygote_manager.h @@ -29,8 +29,8 @@ class ZygoteManager { // The normal way to get a ZygoteManager is via this singleton factory. static ZygoteManager* Get(); - ZygoteManager() : server_fd_(-1), client_fd_(-1), canary_fd_(-1), - lockfd_(-1) { + ZygoteManager() : + server_fd_(-1), client_fd_(-1), canary_fd_(-1), lockfd_(-1) { } ~ZygoteManager(); diff --git a/chrome/test/chrome_process_util.cc b/chrome/test/chrome_process_util.cc index 461194f..296b291 100644 --- a/chrome/test/chrome_process_util.cc +++ b/chrome/test/chrome_process_util.cc @@ -77,13 +77,33 @@ ChromeProcessList GetRunningChromeProcesses(const FilePath& data_dir) { if (browser_pid < 0) return result; - ChromeProcessFilter filter(browser_pid); + // Normally, the browser is the parent process for all the renderers + base::ProcessId parent_pid = browser_pid; + +#if defined(OS_LINUX) + // But if the browser's parent is the same executable as the browser, + // then it's the zygote manager, and it's the parent for all the renderers. + base::ProcessId manager_pid = base::GetParentProcessId(browser_pid); + FilePath selfPath = base::GetProcessExecutablePath(browser_pid); + FilePath managerPath = base::GetProcessExecutablePath(manager_pid); + if (!selfPath.empty() && !managerPath.empty() && selfPath == managerPath) { + LOG(INFO) << "Zygote manager in use."; + parent_pid = manager_pid; + } +#endif + + ChromeProcessFilter filter(parent_pid); base::NamedProcessIterator it(chrome::kBrowserProcessExecutableName, &filter); const ProcessEntry* process_entry; while ((process_entry = it.NextProcessEntry())) { #if defined(OS_WIN) result.push_back(process_entry->th32ProcessID); +#elif defined(OS_LINUX) + // Don't count the zygote manager, that screws up unit tests, + // and it will exit cleanly on its own when first client exits. + if (process_entry->pid != manager_pid) + result.push_back(process_entry->pid); #elif defined(OS_POSIX) result.push_back(process_entry->pid); #endif |