summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/file_util_posix.cc2
-rw-r--r--base/logging.cc6
-rw-r--r--base/process_util.h9
-rw-r--r--base/process_util_linux.cc46
-rw-r--r--base/process_util_unittest.cc7
-rw-r--r--base/zygote_manager.cc30
-rw-r--r--base/zygote_manager.h4
-rw-r--r--chrome/test/chrome_process_util.cc22
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