diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-10 23:04:55 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-10 23:04:55 +0000 |
commit | 361e25c6d29fdae737b5ddf846606093b5502187 (patch) | |
tree | 3114ddee1266088582391d5be9d0ab7aecbd5b8d /chrome/browser/zygote_main_linux.cc | |
parent | c6b652b9298b037d8a18dd241061122200019dba (diff) | |
download | chromium_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 'chrome/browser/zygote_main_linux.cc')
-rw-r--r-- | chrome/browser/zygote_main_linux.cc | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/chrome/browser/zygote_main_linux.cc b/chrome/browser/zygote_main_linux.cc new file mode 100644 index 0000000..d450c39 --- /dev/null +++ b/chrome/browser/zygote_main_linux.cc @@ -0,0 +1,168 @@ +// 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 <unistd.h> +#include <sys/epoll.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/signal.h> + +#include "base/command_line.h" +#include "base/eintr_wrapper.h" +#include "base/global_descriptors_posix.h" +#include "base/pickle.h" +#include "base/unix_domain_socket_posix.h" + +#include "chrome/browser/zygote_host_linux.h" +#include "chrome/common/chrome_descriptors.h" +#include "chrome/common/main_function_params.h" +#include "chrome/common/process_watcher.h" + +// http://code.google.com/p/chromium/wiki/LinuxZygote + +// This is the object which implements the zygote. The ZygoteMain function, +// which is called from ChromeMain, at the the bottom and simple constructs one +// of these objects and runs it. +class Zygote { + public: + bool ProcessRequests() { + // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the + // browser on it. + + // We need to accept SIGCHLD, even though our handler is a no-op because + // otherwise we cannot wait on children. (According to POSIX 2001.) + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = SIGCHLDHandler; + CHECK(sigaction(SIGCHLD, &action, NULL) == 0); + + for (;;) { + if (HandleRequestFromBrowser(3)) + return true; + } + } + + private: + // See comment below, where sigaction is called. + static void SIGCHLDHandler(int signal) { } + + // --------------------------------------------------------------------------- + // Requests from the browser... + + // Read and process a request from the browser. Returns true if we are in a + // new process and thus need to unwind back into ChromeMain. + bool HandleRequestFromBrowser(int fd) { + std::vector<int> fds; + static const unsigned kMaxMessageLength = 2048; + char buf[kMaxMessageLength]; + const ssize_t len = base::RecvMsg(fd, buf, sizeof(buf), &fds); + if (len == -1) { + LOG(WARNING) << "Error reading message from browser: " << errno; + return false; + } + + if (len == 0) { + // EOF from the browser. We should die. + _exit(0); + return false; + } + + Pickle pickle(buf, len); + void* iter = NULL; + + int kind; + if (!pickle.ReadInt(&iter, &kind)) + goto error; + + if (kind == ZygoteHost::kCmdFork) { + return HandleForkRequest(fd, pickle, iter, fds); + } else if (kind == ZygoteHost::kCmdReap) { + if (fds.size()) + goto error; + return HandleReapRequest(fd, pickle, iter); + } + + error: + LOG(WARNING) << "Error parsing message from browser"; + for (std::vector<int>::const_iterator + i = fds.begin(); i != fds.end(); ++i) + close(*i); + return false; + } + + bool HandleReapRequest(int fd, Pickle& pickle, void* iter) { + pid_t child; + + if (!pickle.ReadInt(&iter, &child)) { + LOG(WARNING) << "Error parsing reap request from browser"; + return false; + } + + ProcessWatcher::EnsureProcessTerminated(child); + + return false; + } + + // Handle a 'fork' request from the browser: this means that the browser + // wishes to start a new renderer. + bool HandleForkRequest(int fd, Pickle& pickle, void* iter, + std::vector<int>& fds) { + std::vector<std::string> args; + int argc, numfds; + base::GlobalDescriptors::Mapping mapping; + pid_t child; + + if (!pickle.ReadInt(&iter, &argc)) + goto error; + + for (int i = 0; i < argc; ++i) { + std::string arg; + if (!pickle.ReadString(&iter, &arg)) + goto error; + args.push_back(arg); + } + + if (!pickle.ReadInt(&iter, &numfds)) + goto error; + if (numfds != static_cast<int>(fds.size())) + goto error; + + for (int i = 0; i < numfds; ++i) { + base::GlobalDescriptors::Key key; + if (!pickle.ReadUInt32(&iter, &key)) + goto error; + mapping.push_back(std::make_pair(key, fds[i])); + } + + child = fork(); + + if (!child) { + close(3); // our socket from the browser is in fd 3 + Singleton<base::GlobalDescriptors>()->Reset(mapping); + CommandLine::Reset(); + CommandLine::Init(args); + return true; + } + + for (std::vector<int>::const_iterator + i = fds.begin(); i != fds.end(); ++i) + close(*i); + + HANDLE_EINTR(write(fd, &child, sizeof(child))); + return false; + + error: + LOG(WARNING) << "Error parsing fork request from browser"; + for (std::vector<int>::const_iterator + i = fds.begin(); i != fds.end(); ++i) + close(*i); + return false; + } + // --------------------------------------------------------------------------- +}; + +bool ZygoteMain(const MainFunctionParams& params) { + Zygote zygote; + return zygote.ProcessRequests(); +} |