summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-10 23:04:55 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-10 23:04:55 +0000
commit361e25c6d29fdae737b5ddf846606093b5502187 (patch)
tree3114ddee1266088582391d5be9d0ab7aecbd5b8d /base
parentc6b652b9298b037d8a18dd241061122200019dba (diff)
downloadchromium_src-361e25c6d29fdae737b5ddf846606093b5502187.zip
chromium_src-361e25c6d29fdae737b5ddf846606093b5502187.tar.gz
chromium_src-361e25c6d29fdae737b5ddf846606093b5502187.tar.bz2
Linux: refactor zygote support
http://code.google.com/p/chromium/wiki/LinuxZygote * Move Chrome specific bits out of base * Move away from the idea of reserved file descriptors (which don't really work with zygotes) * Load resources before forking renderers (means that we don't need communication between the zygote process and the renderers) * Make sure that gdb works against the browser again * Make sure that we have different ASLR between the renderers and the browser. http://codereview.chromium.org/119335 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18109 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/base.gyp9
-rw-r--r--base/command_line.cc6
-rw-r--r--base/command_line.h3
-rw-r--r--base/file_util_posix.cc16
-rw-r--r--base/global_descriptors_posix.cc46
-rw-r--r--base/global_descriptors_posix.h66
-rw-r--r--base/logging.cc18
-rw-r--r--base/process_util.h8
-rw-r--r--base/process_util_linux.cc17
-rw-r--r--base/reserved_file_descriptors.h36
-rw-r--r--base/unix_domain_socket_posix.cc98
-rw-r--r--base/unix_domain_socket_posix.h22
-rw-r--r--base/zygote_manager.cc832
-rw-r--r--base/zygote_manager.h143
14 files changed, 246 insertions, 1074 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 5d09098..96deb53 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -133,6 +133,8 @@
'fix_wp64.h',
'float_util.h',
'foundation_utils_mac.h',
+ 'global_descriptors_posix.h',
+ 'global_descriptors_posix.cc',
'hash_tables.h',
'histogram.cc',
'histogram.h',
@@ -324,6 +326,7 @@
'tracked_objects.cc',
'tracked_objects.h',
'tuple.h',
+ 'unix_domain_socket_posix.cc',
'values.cc',
'values.h',
'version.cc',
@@ -418,9 +421,6 @@
# so use idle_timer_none.cc instead.
'idle_timer.cc',
],
- 'sources': [
- 'zygote_manager.cc',
- ],
'dependencies': [
'../build/util/build_util.gyp:lastchange',
'../build/linux/system.gyp:gtk',
@@ -685,9 +685,6 @@
],
'conditions': [
['OS == "linux"', {
- 'sources': [
- 'zygote_manager_unittest.cc',
- ],
'sources!': [
'file_version_info_unittest.cc',
# Linux has an implementation of idle_timer, but it's unclear
diff --git a/base/command_line.cc b/base/command_line.cc
index 735620d..582c8b8 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -168,6 +168,12 @@ bool CommandLine::IsSwitch(const StringType& parameter_string,
}
// static
+void CommandLine::Reset() {
+ delete current_process_commandline_;
+ current_process_commandline_ = NULL;
+}
+
+// static
void CommandLine::Init(int argc, const char* const* argv) {
#if defined(OS_WIN)
current_process_commandline_ = new CommandLine;
diff --git a/base/command_line.h b/base/command_line.h
index c895b81..d128d49 100644
--- a/base/command_line.h
+++ b/base/command_line.h
@@ -45,6 +45,9 @@ class CommandLine {
// TODO(port): should be a FilePath.
explicit CommandLine(const std::wstring& program);
+ // Uninit and free the current process's command line.
+ static void Reset();
+
// Initialize the current process CommandLine singleton. On Windows,
// ignores its arguments (we instead parse GetCommandLineW()
// directly) because we don't trust the CRT's parsing of the command
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index 92b9d00..aca0ff9 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -27,7 +27,6 @@
#include "base/logging.h"
#include "base/string_util.h"
#include "base/time.h"
-#include "base/zygote_manager.h"
namespace file_util {
@@ -646,19 +645,8 @@ MemoryMappedFile::MemoryMappedFile()
}
bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) {
- file_ = -1;
-#if defined(OS_LINUX)
- base::ZygoteManager* zm = base::ZygoteManager::Get();
- if (zm) {
- file_ = zm->OpenFile(file_name.value().c_str());
- if (file_ == -1) {
- LOG(INFO) << "Zygote manager can't open " << file_name.value()
- << ", retrying locally. (OK at start of ui_tests.)";
- }
- }
-#endif // defined(OS_LINUX)
- if (file_ == -1)
- file_ = open(file_name.value().c_str(), O_RDONLY);
+ file_ = open(file_name.value().c_str(), O_RDONLY);
+
if (file_ == -1) {
LOG(ERROR) << "Couldn't open " << file_name.value();
return false;
diff --git a/base/global_descriptors_posix.cc b/base/global_descriptors_posix.cc
new file mode 100644
index 0000000..869d196
--- /dev/null
+++ b/base/global_descriptors_posix.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/global_descriptors_posix.h"
+
+#include <vector>
+#include <utility>
+
+#include "base/logging.h"
+
+namespace base {
+
+int GlobalDescriptors::MaybeGet(Key key) const {
+ for (Mapping::const_iterator
+ i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+ if (i->first == key)
+ return i->second;
+ }
+
+ // In order to make unittests pass, we define a default mapping from keys to
+ // descriptors by adding a fixed offset:
+ return kBaseDescriptor + key;
+}
+
+int GlobalDescriptors::Get(Key key) const {
+ const int ret = MaybeGet(key);
+
+ if (ret == -1)
+ LOG(FATAL) << "Unknown global descriptor: " << key;
+ return ret;
+}
+
+void GlobalDescriptors::Set(Key key, int fd) {
+ for (Mapping::iterator
+ i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+ if (i->first == key) {
+ i->second = fd;
+ return;
+ }
+ }
+
+ descriptors_.push_back(std::make_pair(key, fd));
+}
+
+} // namespace base
diff --git a/base/global_descriptors_posix.h b/base/global_descriptors_posix.h
new file mode 100644
index 0000000..f606a82
--- /dev/null
+++ b/base/global_descriptors_posix.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_GLOBAL_DESCRIPTORS_POSIX_H_
+#define BASE_GLOBAL_DESCRIPTORS_POSIX_H_
+
+#include "build/build_config.h"
+
+#include <vector>
+#include <utility>
+
+#include <stdint.h>
+
+#include "base/singleton.h"
+
+namespace base {
+
+// It's common practice to install file descriptors into well known slot
+// numbers before execing a child; stdin, stdout and stderr are ubiqutous
+// examples.
+//
+// However, when using a zygote model, this becomes troublesome. Since the
+// descriptors which need to be in these slots generally aren't known, any code
+// could open a resource and take one of the reserved descriptors. Simply
+// overwriting the slot isn't a viable solution.
+//
+// We could try to fill the reserved slots as soon as possible, but this is a
+// fragile solution since global constructors etc are able to open files.
+//
+// Instead, we retreat from the idea of installing descriptors in specific
+// slots and add a layer of indirection in the form of this singleton object.
+// It maps from an abstract key to a descriptor. If independent modules each
+// need to define keys, then values should be chosen randomly so as not to
+// collide.
+class GlobalDescriptors {
+ public:
+ typedef uint32_t Key;
+ // Often we want a canonical descriptor for a given Key. In this case, we add
+ // the following constant to the key value:
+ static const int kBaseDescriptor = 3; // 0, 1, 2 are already taken.
+
+ // Get a descriptor given a key. It is a fatal error if the key is not known.
+ int Get(Key key) const;
+ // Get a descriptor give a key. Returns -1 on error.
+ int MaybeGet(Key key) const;
+
+ typedef std::vector<std::pair<Key, int> > Mapping;
+
+ // Set the descriptor for the given key.
+ void Set(Key key, int fd);
+
+ void Reset(const Mapping& mapping) {
+ descriptors_ = mapping;
+ }
+
+ private:
+ GlobalDescriptors() { }
+ friend struct DefaultSingletonTraits<GlobalDescriptors>;
+
+ Mapping descriptors_;
+};
+
+} // namespace base
+
+#endif // BASE_GLOBAL_DESCRIPTORS_POSIX_H_
diff --git a/base/logging.cc b/base/logging.cc
index 77e9583..b5af671 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -19,12 +19,9 @@ typedef HANDLE MutexHandle;
#endif
#if defined(OS_POSIX)
-#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <unistd.h>
#define MAX_PATH PATH_MAX
typedef FILE* FileHandle;
@@ -40,7 +37,6 @@ typedef pthread_mutex_t* MutexHandle;
#include "base/command_line.h"
#include "base/debug_util.h"
#include "base/lock_impl.h"
-#include "base/reserved_file_descriptors.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
@@ -208,20 +204,6 @@ bool InitializeLogFileHandle() {
}
}
SetFilePointer(log_file, 0, 0, FILE_END);
-#elif defined(OS_LINUX)
- // Reserve global fd slots.
- int reserved_fds[kReservedFds];
- for (int i=0; i < kReservedFds; i++)
- reserved_fds[i] = open("/dev/null", O_RDONLY, 0);
-
- log_file = fopen(log_file_name->c_str(), "a");
-
- // Release the reserved fds.
- for (int i=0; i < kReservedFds; i++)
- close(reserved_fds[i]);
-
- if (log_file == NULL)
- return false;
#elif defined(OS_POSIX)
log_file = fopen(log_file_name->c_str(), "a");
if (log_file == NULL)
diff --git a/base/process_util.h b/base/process_util.h
index 4fe081f..41d0470 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -141,14 +141,6 @@ typedef std::vector<std::pair<int, int> > file_handle_mapping_vector;
bool LaunchApp(const std::vector<std::string>& argv,
const file_handle_mapping_vector& fds_to_remap,
bool wait, ProcessHandle* process_handle);
-
-#if defined(OS_LINUX)
-// Like LaunchApp, but if zygote manager is enabled,
-// forks the zygote instead of forking and exec'ing.
-bool ForkApp(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap,
- ProcessHandle* process_handle);
-#endif
#endif
// Executes the application specified by cl. This function delegates to one
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index ba2d8cd..7560257 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -17,7 +17,6 @@
#include "base/logging.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
-#include "base/zygote_manager.h"
namespace {
@@ -86,22 +85,6 @@ FilePath GetProcessExecutablePath(ProcessHandle process) {
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) {
- ZygoteManager* zm = ZygoteManager::Get();
- if (!zm)
- return LaunchApp(argv, fds_to_remap, false, process_handle);
-
- pid_t pid = zm->LongFork(argv, fds_to_remap);
- if (pid < 0)
- return false;
-
- if (process_handle)
- *process_handle = pid;
- return 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/base/reserved_file_descriptors.h b/base/reserved_file_descriptors.h
deleted file mode 100644
index 5236a08..0000000
--- a/base/reserved_file_descriptors.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_RESERVED_FILE_DESCRIPTORS_H_
-#define BASE_RESERVED_FILE_DESCRIPTORS_H_
-
-#if defined(OS_POSIX)
-
-// Chrome uses predefined file descriptors to communicate with child processes.
-// Normally this is a private contract between code that does fork/exec and the
-// code it invokes, but in zygote mode, things get a little more interesting.
-// It's a huge layering violation for this to be in base, but
-// logging and ZygoteManager need kReservedFileDescriptors, so there.
-
-enum GlobalReservedFds {
- // Classic unix file descriptors.
- // Let's leave them alone even if we don't use them.
- kStdinFd = 0,
- kStdoutFd = 1,
- kStderrFd = 2,
-
- // See chrome/common/ipc_channel_posix.cc
- kClientChannelFd = 3,
-
- // See chrome/app/breakpad_linux.cc and
- // chrome/browser/renderer_host/browser_render_process_host.cc
- kMagicCrashSignalFd = 4,
-
- // One plus highest fd mentioned in this enum.
- kReservedFds = 5
-};
-
-#endif
-
-#endif
diff --git a/base/unix_domain_socket_posix.cc b/base/unix_domain_socket_posix.cc
new file mode 100644
index 0000000..af7c0c3
--- /dev/null
+++ b/base/unix_domain_socket_posix.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/unix_domain_socket_posix.h"
+
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+
+namespace base {
+
+bool SendMsg(int fd, const void* buf, size_t length, std::vector<int>& fds) {
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+ struct iovec iov = {const_cast<void*>(buf), length};
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ char* control_buffer = NULL;
+ if (fds.size()) {
+ const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size());
+ control_buffer = new char[control_len];
+ if (!control_buffer)
+ return false;
+
+ struct cmsghdr *cmsg;
+
+ msg.msg_control = control_buffer;
+ msg.msg_controllen = control_len;
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
+ memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size());
+ msg.msg_controllen = cmsg->cmsg_len;
+ }
+
+ const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, 0));
+ const bool ret = static_cast<ssize_t>(length) == r;
+ delete[] control_buffer;
+ return ret;
+}
+
+ssize_t RecvMsg(int fd, void* buf, size_t length, std::vector<int>* fds) {
+ static const unsigned kMaxDescriptors = 16;
+
+ fds->clear();
+
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+ struct iovec iov = {buf, length};
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ char control_buffer[CMSG_SPACE(sizeof(int) * kMaxDescriptors)];
+ msg.msg_control = control_buffer;
+ msg.msg_controllen = sizeof(control_buffer);
+
+ const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, 0));
+ if (r == -1)
+ return -1;
+
+ int* wire_fds;
+ unsigned wire_fds_len = 0;
+
+ if (msg.msg_controllen > 0) {
+ struct cmsghdr* cmsg;
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
+ DCHECK(payload_len % sizeof(int) == 0);
+ wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ wire_fds_len = payload_len / sizeof(int);
+ break;
+ }
+ }
+ }
+
+ if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) {
+ for (unsigned i = 0; i < wire_fds_len; ++i)
+ close(wire_fds[i]);
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ fds->resize(wire_fds_len);
+ memcpy(&(*fds)[0], wire_fds, sizeof(int) * wire_fds_len);
+
+ return r;
+}
+
+} // namespace base
diff --git a/base/unix_domain_socket_posix.h b/base/unix_domain_socket_posix.h
new file mode 100644
index 0000000..46c473a
--- /dev/null
+++ b/base/unix_domain_socket_posix.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_UNIX_DOMAIN_SOCKET_POSIX_H_
+#define BASE_UNIX_DOMAIN_SOCKET_POSIX_H_
+
+#include <vector>
+
+namespace base {
+
+// Use sendmsg to write the given msg and include a vector
+// of file descriptors. Returns true iff successful.
+bool SendMsg(int fd, const void* msg, size_t length,
+ std::vector<int>& fds);
+// Use recvmsg to read a message and an array of file descriptors. Returns
+// -1 on failure. Note: will read, at most, 16 descriptors.
+ssize_t RecvMsg(int fd, void* msg, size_t length, std::vector<int>* fds);
+
+} // namespace base
+
+#endif // BASE_UNIX_DOMAIN_SOCKET_POSIX_H_
diff --git a/base/zygote_manager.cc b/base/zygote_manager.cc
deleted file mode 100644
index 7b2c026..0000000
--- a/base/zygote_manager.cc
+++ /dev/null
@@ -1,832 +0,0 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/zygote_manager.h"
-
-#if defined(OS_LINUX)
-
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <stdlib.h>
-#include <sys/file.h> // for flock()
-#include <sys/stat.h>
-#include <sys/uio.h> // for struct iovec
-#include <sys/wait.h>
-#include <unistd.h> // for ssize_t
-
-#include <string>
-
-#include "base/eintr_wrapper.h"
-#include "base/file_descriptor_shuffle.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/process_util.h"
-#include "base/reserved_file_descriptors.h"
-#include "base/singleton.h"
-
-using file_util::Delete;
-
-// See comment below, where sigaction is called.
-static void SIGCHLDHandler(int signal) {
-}
-
-namespace base {
-
-const char ZygoteManager::kZMagic[] = "zygo";
-
-ZygoteManager::~ZygoteManager() {
- if (server_fd_ != -1) {
- close(server_fd_);
- server_fd_ = -1;
- }
- if (client_fd_ != -1) {
- close(client_fd_);
- client_fd_ = -1;
- }
- if (lockfd_ != -1) {
- close(lockfd_);
- lockfd_ = -1;
- }
- if (canary_fd_ != -1) {
- // Wake up the poll() in ReadAndHandleMessage()
- 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
-ZygoteManager* ZygoteManager::Get() {
- static bool checked = false;
- static bool enabled = false;
- if (!checked) {
- enabled = (getenv("ENABLE_ZYGOTE_MANAGER") != NULL);
- checked = true;
- }
- if (!enabled)
- return NULL;
- return Singleton<ZygoteManager>::get();
-}
-
-// Runs in zygote manager process
-int ZygoteManager::UnpickleHeader(const Pickle& reply, void** iter) {
- std::string magic;
- if (!reply.ReadString(iter, &magic) || magic != std::string(kZMagic)) {
- LOG(ERROR) << "reply didn't start with " << kZMagic;
- return ZMBAD;
- }
- pid_t clientpid = (pid_t) -1;
- if (!reply.ReadInt(iter, &clientpid)) {
- LOG(ERROR) << "Can't read client pid";
- return ZMBAD;
- }
- if (clientpid != getpid()) {
- LOG(ERROR) << "got client pid " << clientpid << ", expected " << getpid();
- DCHECK(clientpid == getpid());
- return ZMBAD;
- }
- int kind;
- if (!reply.ReadInt(iter, &kind)) {
- LOG(ERROR) << "can't read kind";
- return ZMBAD;
- }
- return kind;
-}
-
-// Runs in client process (only used in unit test)
-bool ZygoteManager::Ping(base::TimeDelta* delta) {
- if (client_fd_ == -1)
- return false;
-
- Pickle pickle;
- pickle.WriteString(kZMagic);
- pickle.WriteInt(getpid());
- pickle.WriteInt(ZMPING);
-
- int bytes_sent;
- int bytes_read = -1;
-
- TimeTicks time_sent = TimeTicks::HighResNow();
-
- // Lock fork server, send the pickle, wait for the reply, unlock
- if (flock(lockfd_, LOCK_EX))
- LOG(ERROR) << "flock failed, errno " << errno;
- bytes_sent = HANDLE_EINTR(write(client_fd_,
- const_cast<void *>(pickle.data()), pickle.size()));
- if (bytes_sent > 0) {
- bytes_read = HANDLE_EINTR(read(client_fd_, msg_buf_, kMAX_MSG_LEN));
- }
- if (flock(lockfd_, LOCK_UN))
- LOG(ERROR) << "flock failed, errno " << errno;
-
- TimeTicks time_received = TimeTicks::HighResNow();
-
- if (bytes_sent < 1) {
- LOG(ERROR) << "Can't send to zm, errno " << errno;
- return false;
- }
- if (bytes_read < 1) {
- LOG(ERROR) << "Can't get from zm, errno " << errno;
- return false;
- }
-
- // Unpickle the reply
- Pickle reply(msg_buf_, bytes_read);
- void* iter = NULL;
- int kind = UnpickleHeader(reply, &iter);
- if (kind != ZMPINGED) {
- LOG(ERROR) << "reply wrong kind " << kind;
- return false;
- }
- *delta = TimeTicks::HighResNow() - time_sent;
- LOG(INFO) << "Round trip time in microseconds: " << delta->InMicroseconds();
- return true;
-}
-
-// Runs in zygote manager process
-void ZygoteManager::PingHandler(const Pickle& request, void* iter,
- Pickle* reply, std::vector<std::string>** newargv) {
- reply->WriteInt(ZMPINGED);
-}
-
-// Runs in browser process, called only by base::ForkApp()
-pid_t ZygoteManager::LongFork(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap) {
- if (client_fd_ == -1)
- return -1;
-
- Pickle pickle;
-
- // Encode the arguments and the desired remote fd numbers in the pickle,
- // and the fds in a separate buffer
- pickle.WriteString(kZMagic);
- pickle.WriteInt(getpid());
- pickle.WriteInt(ZMFORK);
- pickle.WriteInt(argv.size());
- std::vector<std::string>::const_iterator argi;
- for (argi = argv.begin(); argi != argv.end(); ++argi)
- pickle.WriteString(*argi);
- pickle.WriteInt(fds_to_remap.size());
-
- // Wrap the pickle and the fds together in a msghdr
- ::msghdr msg;
- memset(&msg, 0, sizeof(msg));
- struct iovec iov;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cmsg_buf_;
- msg.msg_controllen = CMSG_LEN(sizeof(int) * fds_to_remap.size());
- struct cmsghdr* cmsg;
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = msg.msg_controllen;
- int* wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
- for (size_t i = 0; i < fds_to_remap.size(); i++) {
- pickle.WriteInt(fds_to_remap[i].second);
- wire_fds[i] = fds_to_remap[i].first;
- }
- iov.iov_base = const_cast<void *>(pickle.data());
- iov.iov_len = pickle.size();
-
- int bytes_sent;
- int bytes_read = -1;
-
- // Lock fork server, send the pickle, wait for the reply, unlock
- if (flock(lockfd_, LOCK_EX))
- LOG(ERROR) << "flock failed, errno " << errno;
- bytes_sent = HANDLE_EINTR(sendmsg(client_fd_, &msg, MSG_WAITALL));
- if (bytes_sent > 0) {
- bytes_read = HANDLE_EINTR(read(client_fd_, msg_buf_, kMAX_MSG_LEN));
- }
- if (flock(lockfd_, LOCK_UN))
- LOG(ERROR) << "flock failed, errno " << errno;
-
- if (bytes_sent < 1) {
- LOG(ERROR) << "Can't send to zm, errno " << errno << ", fd " << client_fd_;
- return (pid_t) -1;
- }
- if (bytes_read < 1) {
- LOG(ERROR) << "Can't get from zm, errno " << errno;
- return (pid_t) -1;
- }
-
- // Unpickle the reply
- Pickle reply(msg_buf_, bytes_read);
- void* iter = NULL;
- int kind = UnpickleHeader(reply, &iter);
- if (kind != ZMFORKED) {
- LOG(ERROR) << "reply wrong kind " << kind;
- return (pid_t) -1;
- }
- pid_t newpid = (pid_t) -1;
- int pid_errno;
- if (!reply.ReadInt(&iter, &newpid) || !reply.ReadInt(&iter, &pid_errno)) {
- LOG(ERROR) << "fork failed, can't read pid/errno";
- return (pid_t) -1;
- }
- if ((newpid == (pid_t) -1) || pid_errno != 0) {
- LOG(ERROR) << "fork failed, pid " << newpid << ", errno " << pid_errno;
- return (pid_t) -1;
- }
- return newpid;
-}
-
-// Runs in zygote manager process
-bool ZygoteManager::LongForkHandler(const Pickle& request, void* iter,
- Pickle* reply, std::vector<std::string>** newargv,
- const int wire_fds[], int num_wire_fds) {
- file_handle_mapping_vector fds_to_remap;
- pid_t childpid;
-
- reply->WriteInt(ZMFORKED);
-
- // Unpickle commandline for new child
- std::vector<std::string>* argv = new std::vector<std::string>;
- int argc;
- request.ReadInt(&iter, &argc);
- for (int i = 0; i < argc; i++) {
- std::string arg;
- if (!request.ReadString(&iter, &arg)) {
- LOG(ERROR) << "can't read arg?";
- goto error_reply;
- }
- argv->push_back(arg);
- }
- // Unpickle file descriptor map for new child
- int numfds;
- request.ReadInt(&iter, &numfds);
- DCHECK(numfds == num_wire_fds);
- if (numfds != num_wire_fds) {
- LOG(ERROR) << "numfds " << numfds << " != num_wire_fds " << num_wire_fds;
- goto error_reply;
- }
- for (int i = 0; i < numfds; i++) {
- int fd;
- if (!request.ReadInt(&iter, &fd)) {
- LOG(ERROR) << "can't read fd?";
- goto error_reply;
- }
- fds_to_remap.push_back(std::pair<int, int>(wire_fds[i], fd));
- }
-
- // Mitosis!
- childpid = fork();
-
- if (childpid != 0) {
- // parent
- // first off, close our copy of the child's file descriptors
- for (file_handle_mapping_vector::const_iterator
- it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
- close(it->first);
- }
-
- // Finish formatting the reply
- reply->WriteInt(childpid);
- if (childpid == (pid_t) -1) {
- reply->WriteInt(errno);
- return false;
- } else {
- reply->WriteInt(0);
- }
- } else {
- // child
- // Apply file descriptor map
- InjectiveMultimap fd_shuffle;
- for (file_handle_mapping_vector::const_iterator
- it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
- fd_shuffle.push_back(InjectionArc(it->first, it->second, false));
- }
-
- // Avoid closing descriptor children will need to contact fork server.
- fd_shuffle.push_back(InjectionArc(client_fd_, client_fd_, false));
- // Avoid closing log descriptor we're using
- int logfd = logging::GetLoggingFileDescriptor();
- if (logfd != -1)
- fd_shuffle.push_back(InjectionArc(logfd, logfd, false));
- // And of course avoid closing the cached fds.
- std::map<std::string, int>::iterator i;
- for (i = cached_fds_.begin(); i != cached_fds_.end(); ++i) {
- fd_shuffle.push_back(InjectionArc(i->second, i->second, false));
- }
-
- // If there is any clash in the mapping, this function will DCHECK.
- if (!ShuffleFileDescriptors(fd_shuffle))
- exit(127);
-
- // Open this after shuffle to avoid using reserved slots.
- lockfd_ = open(lockfile_.c_str(), O_RDWR, 0);
- if (lockfd_ == -1) {
- // TODO(dkegel): real error handling
- exit(126);
- }
- // Mark it as not to be closed.
- fd_shuffle.push_back(InjectionArc(lockfd_, lockfd_, false));
-
- // Also closes reserved fds.
- CloseSuperfluousFds(fd_shuffle);
-
- *newargv = argv;
- // Because *newargv is set, we will return to main instead of looping
- }
- return true;
-
- error_reply:
- reply->WriteInt(-1);
- reply->WriteInt(-1);
- for (int i=0; i<num_wire_fds; i++)
- close(wire_fds[i]);
- return false;
-}
-
-// Runs in browser process, called by ProcessWatcher::EnsureProcessTerminated().
-void ZygoteManager::EnsureProcessTerminated(pid_t childpid) {
- if (client_fd_ == -1)
- return;
-
- Pickle pickle;
-
- pickle.WriteString(kZMagic);
- pickle.WriteInt(getpid());
- pickle.WriteInt(ZMREAP);
- pickle.WriteInt(childpid);
-
- int bytes_sent = HANDLE_EINTR(
- write(client_fd_, const_cast<void*>(pickle.data()), pickle.size()));
-
- if (bytes_sent < 1) {
- LOG(ERROR) << "Can't send to zm, errno " << errno << ", fd " << client_fd_;
- }
-}
-
-// Runs in zygote manager process
-void ZygoteManager::EnsureProcessTerminatedHandler(const Pickle& request,
- void* iter) {
- pid_t childpid;
- request.ReadInt(&iter, &childpid);
- NOTIMPLEMENTED();
- // TODO(dkegel): put childpid on a watch list, and terminate it
- // after a while as chrome/common/process_watcher does.
-}
-
-static bool ValidateFilename(const std::string& filename) {
- // We only have to open one kind of file, but we don't know
- // the directory it's in, so be as restrictive as we can within
- // those bounds.
-
- static const char* allowed_prefix = "/";
- if (filename.compare(0, strlen(allowed_prefix), allowed_prefix) != 0) {
- LOG(ERROR) << "filename did not start with " << allowed_prefix;
- return false;
- }
- static const char* allowed_suffix = ".pak";
- if ((filename.length() <= strlen(allowed_suffix)) ||
- (filename.compare(filename.length() - strlen(allowed_suffix),
- strlen(allowed_suffix), allowed_suffix) != 0)) {
- LOG(ERROR) << "filename did not end in " << allowed_suffix;
- return false;
- }
- if (filename.find("../") != std::string::npos) {
- LOG(ERROR) << "filename contained relative component";
- return false;
- }
- static const char* forbidden_prefixes[] = {
- "/var/", "/tmp/", "/etc/", "/dev/", "/proc/", 0 };
- for (const char** p = forbidden_prefixes;
- *p; p++) {
- if (filename.compare(0, strlen(*p), *p) == 0) {
- LOG(ERROR) << "filename began with " << *p;
- return false;
- }
- }
- return true;
-}
-
-// Runs in browser process
-int ZygoteManager::OpenFile(const std::string& filename) {
- // For security reasons, we only support .pak files,
- // and only in certain locations.
- if (!ValidateFilename(filename)) {
- LOG(INFO) << "ZygoteManager: filename " << filename << " disallowed.";
- return -1;
- }
-
- std::map<std::string, int>::iterator mapiter = cached_fds_.find(filename);
- if (mapiter != cached_fds_.end())
- return mapiter->second;
-
- if (client_fd_ == -1)
- return -1;
-
- Pickle pickle;
-
- pickle.WriteString(kZMagic);
- pickle.WriteInt(getpid());
- pickle.WriteInt(ZMOPEN);
- pickle.WriteString(filename);
-
- // Get ready to receive fds
- ::msghdr msg = {0};
- struct iovec iov = {msg_buf_, kMAX_MSG_LEN};
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cmsg_buf_;
- msg.msg_controllen = kMAX_CMSG_LEN;
-
- ssize_t bytes_sent;
- ssize_t bytes_read = 0;
-
- if (flock(lockfd_, LOCK_EX))
- LOG(ERROR) << "flock failed, errno " << errno;
- bytes_sent = HANDLE_EINTR(
- write(client_fd_, const_cast<void *>(pickle.data()), pickle.size()));
- if (bytes_sent > 0) {
- bytes_read = HANDLE_EINTR(recvmsg(client_fd_, &msg, MSG_WAITALL));
- }
- if (flock(lockfd_, LOCK_UN))
- LOG(ERROR) << "flock failed, errno " << errno;
-
- if (bytes_sent < 1) {
- LOG(ERROR) << "Can't send to zm, errno " << errno << ", fd " << client_fd_;
- return -1;
- }
- if (bytes_read < 1) {
- LOG(ERROR) << "Can't get from zm, errno " << errno;
- return -1;
- }
-
- // Locate the sole block of sent file descriptors within the list of
- // control messages
- const int* wire_fds = NULL;
- unsigned num_wire_fds = 0;
- if (msg.msg_controllen > 0) {
- struct cmsghdr* cmsg;
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_RIGHTS) {
- const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
- assert(payload_len % sizeof(int) == 0);
- wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
- num_wire_fds = payload_len / sizeof(int);
- break;
- }
- }
- }
- DCHECK(!(msg.msg_flags & MSG_CTRUNC));
-
- // Unpickle the reply
- Pickle reply(msg_buf_, bytes_read);
- void* iter = NULL;
- int kind = UnpickleHeader(reply, &iter);
- if (kind != ZMOPENED) {
- LOG(ERROR) << "reply wrong kind " << kind;
- goto error_close;
- }
- int newfd_errno;
- if (!reply.ReadInt(&iter, &newfd_errno)) {
- LOG(ERROR) << "open failed, can't read errno";
- goto error_close;
- }
- if (newfd_errno != 0) {
- LOG(ERROR) << "open failed, errno " << newfd_errno;
- goto error_close;
- }
- if (num_wire_fds != 1) {
- LOG(ERROR) << "open failed, reply wrong number fds " << num_wire_fds;
- goto error_close;
- }
- if (wire_fds[0] == -1) {
- LOG(ERROR) << "open failed, fd -1";
- NOTREACHED();
- return -1;
- }
- return wire_fds[0];
-
- error_close:
- for (unsigned i=0; i<num_wire_fds; i++)
- close(wire_fds[i]);
- return -1;
-}
-
-// Runs in zygote manager process
-bool ZygoteManager::OpenFileHandler(const Pickle& request, void* iter,
- Pickle* reply, ::msghdr* msg) {
- reply->WriteInt(ZMOPENED);
-
- std::string filename;
- if (!request.ReadString(&iter, &filename)) {
- LOG(ERROR) << "no filename?";
- return false;
- }
- if (!ValidateFilename(filename)) {
- // Fake a unix error code
- reply->WriteInt(EPERM);
- return false;
- }
-
- std::map<std::string, int>::iterator i;
- int newfd;
- std::map<std::string, int>::iterator mapiter = cached_fds_.find(filename);
- if (mapiter == cached_fds_.end()) {
- // Verify that file is a plain file
- struct stat statbuf;
- if (lstat(filename.c_str(), &statbuf) != 0) {
- LOG(ERROR) << "can't stat " << filename << ", errno " << errno;
- return false;
- }
- if (!S_ISREG(statbuf.st_mode)) {
- LOG(ERROR) << "not regular file " << filename;
- // Fake a unix error code
- reply->WriteInt(EISDIR);
- return false;
- }
- newfd = open(filename.c_str(), O_RDONLY, 0);
- if (newfd != -1) {
- cached_fds_[filename] = newfd;
- } else {
- LOG(ERROR) << "can't open " << filename << ", errno " << errno;
- }
- } else {
- newfd = mapiter->second;
- }
- if (newfd == -1) {
- reply->WriteInt(errno);
- } else {
- reply->WriteInt(0);
- msg->msg_control = cmsg_buf_;
- msg->msg_controllen = CMSG_LEN(sizeof(int));
- struct cmsghdr* cmsg;
- cmsg = CMSG_FIRSTHDR(msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = msg->msg_controllen;
- int* wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
- wire_fds[0] = newfd;
- }
-
- return true;
-}
-
-// Runs in zygote manager process
-bool ZygoteManager::ReadAndHandleMessage(std::vector<std::string>** newargv) {
- // Wait for activity either on canary fd or main fd.
- struct pollfd watcher[2];
- memset(watcher, 0, sizeof(watcher));
- watcher[0].fd = canary_fd_;
- watcher[0].events = POLLIN|POLLHUP;
- watcher[1].fd = server_fd_;
- watcher[1].events = POLLIN;
- // Wait at most one minute. This lets us detect case where
- // canary socket is closed abruptly because the main client aborted.
- // Also lets us reap dead children once a minute even if we don't get SIGCHLD.
- // We'd like to wait less time, but that's hard on battery life.
- // Note: handle EINTR manually here, not with wrapper, as we need
- // to return when we're interrupted so caller can reap promptly.
- int nactive = poll(watcher, 2, 60*1000);
-
- if (nactive == -1) {
- if (errno == EINTR) {
- // Probably SIGCHLD. Return to main loop so it can reap.
- return true;
- }
- LOG(ERROR) << "poll failed, errno " << errno << ", aborting";
- return false;
- }
-
- // If it was the canary, exit
- if (watcher[0].revents != 0) {
- LOG(INFO) << "notified of peer destruction, exiting";
- return false;
- }
- if ((watcher[1].revents & POLLIN) != POLLIN) {
- // spurious wakeup?
- return true;
- }
-
- ssize_t bytes_read = 0;
- struct msghdr msg = {0};
- struct iovec iov = {msg_buf_, kMAX_MSG_LEN};
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cmsg_buf_;
- msg.msg_controllen = kMAX_CMSG_LEN;
- bytes_read = HANDLE_EINTR(recvmsg(server_fd_, &msg, MSG_WAITALL));
- if (bytes_read == 0) {
- LOG(ERROR) << "got EOF, aborting";
- return false;
- }
- if (bytes_read == -1) {
- LOG(ERROR) << "got errno " << errno << ", aborting";
- return false;
- }
-
- // Locate the sole block of sent file descriptors within the list of
- // control messages
- const int* wire_fds = NULL;
- unsigned num_wire_fds = 0;
- if (msg.msg_controllen > 0) {
- struct cmsghdr* cmsg;
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_RIGHTS) {
- const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
- assert(payload_len % sizeof(int) == 0);
- wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
- num_wire_fds = payload_len / sizeof(int);
- break;
- }
- }
- }
- DCHECK(!(msg.msg_flags & MSG_CTRUNC));
-
- // Unpickle/parse message
- Pickle pickle(msg_buf_, bytes_read);
- void* iter = NULL;
- std::string magic;
- if (!pickle.ReadString(&iter, &magic) || magic != std::string(kZMagic)) {
- LOG(ERROR) << "msg didn't start with " << kZMagic << ", got " << magic;
- for (unsigned i=0; i<num_wire_fds; i++)
- close(wire_fds[i]);
- return true;
- }
- pid_t clientpid = (pid_t) -1;
- pickle.ReadInt(&iter, &clientpid);
- int kind;
- pickle.ReadInt(&iter, &kind);
-
- Pickle reply;
- reply.WriteString(kZMagic);
- reply.WriteInt(clientpid);
-
- struct msghdr replymsg = {0};
- memset(&replymsg, 0, sizeof(replymsg));
-
- switch (kind) {
- case ZMPING:
- DCHECK_EQ(0U, num_wire_fds);
- PingHandler(pickle, iter, &reply, newargv);
- break;
- case ZMFORK:
- // TODO(dkegel): real error handling
- (void) LongForkHandler(pickle, iter, &reply, newargv, wire_fds,
- num_wire_fds);
- if (*newargv != NULL) {
- // Child. Just return to caller, who will return from SetLongFork.
- return true;
- }
- break;
- case ZMREAP:
- DCHECK_EQ(0U, num_wire_fds);
- EnsureProcessTerminatedHandler(pickle, iter);
- // no reply to this message
- return true;
- case ZMOPEN:
- DCHECK_EQ(0U, num_wire_fds);
- // TODO(dkegel): real error handling
- (void) OpenFileHandler(pickle, iter, &reply, &replymsg);
- break;
- default:
- // TODO(dkegel): real error handling
- LOG(ERROR) << "Unknown message kind " << kind;
- DCHECK_EQ(0U, num_wire_fds);
- break;
- }
-
- struct iovec riov = {const_cast<void *>(reply.data()), reply.size()};
- replymsg.msg_iov = &riov;
- replymsg.msg_iovlen = 1;
-
- int bytes_sent;
- bytes_sent = HANDLE_EINTR(sendmsg(server_fd_, &replymsg, MSG_WAITALL));
- if (bytes_sent != static_cast<int>(riov.iov_len)) {
- // TODO(dkegel): real error handling
- LOG(ERROR) << "Can't send reply.";
- return false;
- }
- return true;
-}
-
-// Called only by ChromeMain(), forks the zygote manager process.
-std::vector<std::string>* ZygoteManager::Start() {
- DCHECK(lockfd_ == -1);
- DCHECK(canary_fd_ == -1);
- 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.
- int reserved_fds[kReservedFds];
- for (int i=0; i < kReservedFds; i++)
- reserved_fds[i] = open("/dev/null", O_RDONLY, 0);
-
- // Create the main communications pipe.
- int err = HANDLE_EINTR(socketpair(AF_UNIX, SOCK_DGRAM, 0, pipe_fds));
- if (err != 0) {
- // TODO(dkegel): real error handling
- exit(99);
- }
- server_fd_ = pipe_fds[1];
- client_fd_ = pipe_fds[0];
-
- // Create the pipe used only to relay destruction event server.
- // Must be SOCK_STREAM so close() is sensed by poll().
- err = HANDLE_EINTR(socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds));
- if (err != 0) {
- // TODO(dkegel): real error handling
- exit(99);
- }
-
- // Create lock file.
- // TODO(dkegel): get rid of this
- char lockfile[256];
- strcpy(lockfile, "/tmp/zygote_manager_lock.XXXXXX");
- lockfd_ = mkstemp(lockfile);
- if (lockfd_ == -1) {
- // TODO(dkegel): real error handling
- exit(99);
- }
- lockfile_.assign(lockfile);
-
- // Fork a fork server.
- pid_t childpid = fork();
-
- if (!childpid) {
- for (int i=0; i < kReservedFds; i++)
- close(reserved_fds[i]);
-
- // Original child. Continues on with the main program
- // and becomes the first client.
- close(server_fd_);
- server_fd_ = -1;
-
- close(pipe_fds[1]);
- canary_fd_ = pipe_fds[0];
-
- // Return now to indicate this is the original process.
- return NULL;
- } else {
- close(lockfd_);
-
- close(pipe_fds[0]);
- canary_fd_ = pipe_fds[1];
-
- // We need to accept SIGCHLD, even though our handler is a no-op because
- // otherwise we cannot wait on children. (According to POSIX 2001.)
- // (And otherwise poll() might not wake up on SIGCHLD.)
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- action.sa_handler = SIGCHLDHandler;
- CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
-
- // Original process. Acts as the server.
- while (true) {
- std::vector<std::string>* newargv = NULL;
- if (!ReadAndHandleMessage(&newargv))
- break;
- if (newargv) {
- // Return new commandline to show caller this is a new child process.
- return newargv;
- }
- // Server process continues around loop.
-
- // Reap children.
- while (true) {
- int status = -1;
- pid_t reaped = waitpid(-1, &status, WNOHANG);
- if (reaped != -1 && reaped != 0) {
- LOG(INFO) << "Reaped pid " << reaped;
- continue;
- }
- break;
- }
- }
- // Server cleanup after EOF or error reading from the socket.
- Delete(FilePath(lockfile_), false);
- // TODO(dkegel): real error handling
- LOG(INFO) << "exiting. " << cached_fds_.size() << " cached fds.";
- std::map<std::string, int>::iterator i;
- for (i = cached_fds_.begin(); i != cached_fds_.end(); ++i) {
- LOG(INFO) << "Closing fd " << i->second << " filename " << i->first;
- close(i->second);
- }
- exit(0);
- }
-}
-}
-#endif // defined(OS_LINUX)
diff --git a/base/zygote_manager.h b/base/zygote_manager.h
deleted file mode 100644
index 5b94533..0000000
--- a/base/zygote_manager.h
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_ZYGOTE_MANAGER_H_
-#define BASE_ZYGOTE_MANAGER_H_
-
-#include "build/build_config.h"
-
-#if defined(OS_LINUX)
-
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/pickle.h"
-#include "base/time.h"
-#include "base/process_util.h" // for file_handle_mapping_vector
-
-namespace base {
-
-class ZygoteManager {
- public:
- // 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();
-
- // Measure round trip time. Return true on success.
- // Only used during testing.
- bool Ping(base::TimeDelta* delta);
-
- // Start the zygote manager.
- // Called only once, but returns many times.
- // Returns once in original process and once in each spawned child.
- // In original process, returns NULL.
- // In child processes, returns the argv to use for the child.
- // In Chromium, called from ChromeMain().
- std::vector<std::string>* Start();
-
- // Like longjmp() and base::LaunchApp().
- // Ask the fork server to spawn a new process with
- // the given commandline and the given file descriptors.
- // Returns process id of copy, or -1 on failure.
- // In Chromium, called from base::ForkApp(), which is
- // called from BrowserRenderProcessHost::Init().
- pid_t LongFork(const std::vector<std::string>& argv,
- const file_handle_mapping_vector& fds_to_remap);
-
- // Tell ZygoteManager that we expect the given process to
- // exit on its own soon. If it doesn't die within a few
- // seconds, kill it. Does not block (unless pipe to server full).
- // In Chromium, called from ProcessWatcher::EnsureProcessTerminated().
- void EnsureProcessTerminated(pid_t childpid);
-
- // Open a file, or retrieve a previously cached file descriptor
- // for this file. The files are opened for readonly access.
- // Caution: do not seek file descriptors returned
- // by this API, as all children share the same file objects, so
- // a seek on one is a seek on all.
- // Works even if the file is unlinked after the first call
- // (e.g. when an app is updated by the linux system autoupdater).
- // Returns file descriptor, or -1 for error.
- // In Chromium, called from MemoryMappedFile::MapFileToMemory().
- // Only allows openeing files named .pak in reasonable looking locations.
- int OpenFile(const std::string& filename);
-
- private:
- int UnpickleHeader(const Pickle& reply, void** iter);
-
- // Returns false on EOF
- // Sets *newargv to a new commandline if the remote side requested a fork.
- bool ReadAndHandleMessage(std::vector<std::string>** newargv);
-
- void PingHandler(const Pickle& request, void* iter, Pickle* reply,
- std::vector<std::string>** newargv);
-
- bool LongForkHandler(const Pickle& request, void* iter, Pickle* reply,
- std::vector<std::string>** newargv,
- const int wire_fds[], int num_wire_fds);
-
- void EnsureProcessTerminatedHandler(const Pickle& request, void* iter);
-
- bool OpenFileHandler(const Pickle& request, void* iter, Pickle* reply,
- ::msghdr* msg);
-
- // The fd used by the server to receive requests
- int server_fd_;
-
- // The fd used by the clients to send requests
- int client_fd_;
-
- // fd used only to notify server of destruction.
- int canary_fd_;
-
- // Temporary file used only for locking.
- // Each client must do its own open for locking to work;
- // inherited file descriptors can't lock each other out.
- // FIXME: locking is lame.
- std::string lockfile_;
- int lockfd_;
-
- enum message_kind_t { ZMPING, ZMPINGED,
- ZMFORK, ZMFORKED,
- ZMREAP,
- ZMOPEN, ZMOPENED,
- ZMBAD };
-
- // See common/reserved_file_descriptors.h for who uses the reserved
- // file descriptors. kReservedFds is one plus the highest fd mentioned there.
- // TODO(dkegel): move kReservedFds to reserved_file_descriptors.h
- static const int kReservedFds = 5;
-
- static const int kMAX_MSG_LEN = 2000;
- static const int kMAX_CMSG_LEN = 100;
-
- static const char kZMagic[];
-
- char msg_buf_[kMAX_MSG_LEN];
- char cmsg_buf_[kMAX_CMSG_LEN];
-
- // Where we remember file descriptors for already-opened files.
- // Both client and server maintain this table.
- // Client should check the table before requesting the
- // server to open a file, as it might have been already
- // opened before this client was forked.
- std::map<std::string, int> cached_fds_;
-};
-
-} // namespace base
-
-#endif // defined(OS_LINUX)
-
-#endif // BASE_ZYGOTE_MANAGER_H_