| Index: chrome/browser/zygote_main_linux.cc
|
| diff --git a/chrome/browser/zygote_main_linux.cc b/chrome/browser/zygote_main_linux.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9de389d3dcd003f870f96385a0420b3ee681872a
|
| --- /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);
|
| + 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();
|
| +}
|
|
|