/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdefined(XP_LINUX) && defined(MOZ_SANDBOX) # include "mozilla/SandboxLaunch.h" #endif
#include <algorithm>
namespace mozilla { namespace ipc {
LazyLogModule gForkServiceLog("ForkService");
ForkServer::ForkServer(int* aArgc, char*** aArgv) : mArgc(aArgc), mArgv(aArgv) { // Eventually (bug 1752638) we'll want a real SIGCHLD handler, but // for now, cause child processes to be automatically collected.
signal(SIGCHLD, SIG_IGN);
/** * Preload any resources that the forked child processes might need, * and which might change incompatibly or become unavailable by the * time they're started. For example: the omnijar files, or certain * shared libraries.
*/ staticvoid ForkServerPreload(int& aArgc, char** aArgv) {
Omnijar::ChildProcessInit(aArgc, aArgv);
}
/** * Start providing the service at the IPC channel.
*/ bool ForkServer::HandleMessages() { while (true) {
UniquePtr<IPC::Message> msg; if (!mTcver->Recv(msg)) { break;
}
if (OnMessageReceived(std::move(msg))) { // New process - child returnfalse;
}
} // Stop the server returntrue;
}
/** * Parse a Message to obtain a `LaunchOptions` and the attached fd * that the child will use to receive its `SubprocessExecInfo`.
*/ staticbool ParseForkNewSubprocess(IPC::Message& aMsg,
UniqueFileHandle* aExecFd,
base::LaunchOptions* aOptions) { if (aMsg.type() != Msg_ForkNewSubprocess__ID) {
MOZ_LOG(gForkServiceLog, LogLevel::Verbose,
("unknown message type %d (!= %d)\n", aMsg.type(),
Msg_ForkNewSubprocess__ID)); returnfalse;
}
IPC::MessageReader reader(aMsg);
// FIXME(jld): This should all be fallible, but that will have to // wait until bug 1752638 before it makes sense. #ifdefined(XP_LINUX) && defined(MOZ_SANDBOX)
ReadParamInfallible(&reader, &aOptions->fork_flags, "Error deserializing 'int'");
ReadParamInfallible(&reader, &aOptions->sandbox_chroot_server, "Error deserializing 'UniqueFileHandle'"); #endif
ReadParamInfallible(&reader, aExecFd, "Error deserializing 'UniqueFileHandle'");
reader.EndRead();
returntrue;
}
/** * Parse a `Message`, in the forked child process, to get the argument * and environment strings.
*/ staticbool ParseSubprocessExecInfo(IPC::Message& aMsg,
geckoargs::ChildProcessArgs* aArgs,
base::environment_map* aEnv) { if (aMsg.type() != Msg_SubprocessExecInfo__ID) {
MOZ_LOG(gForkServiceLog, LogLevel::Verbose,
("unknown message type %d (!= %d)\n", aMsg.type(),
Msg_SubprocessExecInfo__ID)); returnfalse;
}
// Run in the forked child process. Receives a message on `aExecFd` containing // the new process configuration, and updates the environment, command line, and // passed file handles to reflect the new process. staticvoid ForkedChildProcessInit(int aExecFd, int* aArgc, char*** aArgv) { // The fork server handle SIGCHLD to read status of content // processes to handle Zombies. But, it is not necessary for // content processes.
signal(SIGCHLD, SIG_DFL);
// Content process
MiniTransceiver execTcver(aExecFd);
UniquePtr<IPC::Message> execMsg; if (!execTcver.Recv(execMsg)) { // Crashing here isn't great, because the crash reporter isn't // set up, but we don't have a lot of options currently. Also, // receive probably won't fail unless the parent also crashes.
printf_stderr("ForkServer: SubprocessExecInfo receive error\n");
MOZ_CRASH();
}
// Change argc & argv of main() with the arguments passing // through IPC. char** argv = newchar*[args.mArgs.size() + 1]; char** p = argv; for (auto& elt : args.mArgs) {
*p++ = strdup(elt.c_str());
}
*p = nullptr;
*aArgv = argv;
*aArgc = args.mArgs.size();
mozilla::SetProcessTitle(args.mArgs);
}
/** * Extract parameters from the |Message| to create a * |base::AppProcessBuilder| as |mAppProcBuilder|. * * It will return in both the fork server process and the new content * process. |mAppProcBuilder| is null for the fork server.
*/ bool ForkServer::OnMessageReceived(UniquePtr<IPC::Message> message) {
UniqueFileHandle execFd;
base::LaunchOptions options; if (!ParseForkNewSubprocess(*message, &execFd, &options)) { returnfalse;
}
#ifdefined(MOZ_MEMORY) && defined(DEBUG)
jemalloc_stats_t stats;
jemalloc_stats(&stats);
MOZ_ASSERT(stats.narenas == 1, "ForkServer before fork()/clone() should have a single arena."); #endif
// Avoid any contents of buffered stdout/stderr being sent by forked // children.
fflush(stdout);
fflush(stderr);
pid_t pid = launcher.Fork(); if (pid < 0) {
MOZ_CRASH("failed to fork");
}
// NOTE: After this point, if pid == 0, we're in the newly forked child // process.
if (pid == 0) { // Re-configure to a child process, and return to our caller.
ForkedChildProcessInit(execFd.get(), mArgc, mArgv); returntrue;
}
// Fork server process
IPC::Message reply(MSG_ROUTING_CONTROL, Reply_ForkNewSubprocess__ID);
IPC::MessageWriter writer(reply);
WriteIPDLParam(&writer, nullptr, pid);
mTcver->SendInfallible(reply, "failed to send a reply message");
returnfalse;
}
/** * Setup and run a fork server at the main thread. * * This function returns for two reasons: * - the fork server is stopped normally, or * - a new process is forked from the fork server and this function * returned in the child, the new process. * * For the later case, aArgc and aArgv are modified to pass the * arguments from the chrome process.
*/ bool ForkServer::RunForkServer(int* aArgc, char*** aArgv) {
MOZ_ASSERT(XRE_IsForkServerProcess(), "fork server process only");
#ifdef DEBUG if (getenv("MOZ_FORKSERVER_WAIT_GDB")) {
printf( "Waiting for 30 seconds." " Attach the fork server with gdb %s %d\n",
(*aArgv)[0], base::GetCurrentProcId());
sleep(30);
} bool sleep_newproc = !!getenv("MOZ_FORKSERVER_WAIT_GDB_NEWPROC"); #endif
SetProcessTitleInit(*aArgv);
// Do this before NS_LogInit() to avoid log files taking lower // FDs.
ForkServer forkserver(aArgc, aArgv);
NS_LogInit();
mozilla::LogModule::Init(0, nullptr);
ForkServerPreload(*aArgc, *aArgv);
MOZ_LOG(gForkServiceLog, LogLevel::Verbose, ("Start a fork server"));
{
DebugOnly<base::ProcessHandle> forkserver_pid = base::GetCurrentProcId(); if (forkserver.HandleMessages()) { // In the fork server process // The server has stopped.
MOZ_LOG(gForkServiceLog, LogLevel::Verbose,
("Terminate the fork server"));
Omnijar::CleanUp();
NS_LogTerm(); returntrue;
} // Now, we are running in a content process just forked from // the fork server process.
MOZ_ASSERT(base::GetCurrentProcId() != forkserver_pid);
MOZ_LOG(gForkServiceLog, LogLevel::Verbose, ("Fork a new content process"));
} #ifdef DEBUG if (sleep_newproc) {
printf( "Waiting for 30 seconds." " Attach the new process with gdb %s %d\n",
(*aArgv)[0], base::GetCurrentProcId());
sleep(30);
} #endif
NS_LogTerm();
nsTraceRefcnt::CloseLogFilesAfterFork();
// Update our GeckoProcessType and GeckoChildID, removing the arguments. if (*aArgc < 2) {
MOZ_CRASH("forked process missing process type and childid arguments");
}
SetGeckoProcessType((*aArgv)[--*aArgc]);
SetGeckoChildID((*aArgv)[--*aArgc]);
MOZ_ASSERT(!XRE_IsForkServerProcess(), "fork server created another fork server?");
// This is now a child process, and it may even be a Content process. // It is required that the PRNG at least is re-initialized so the same state // is not shared accross all child processes, and in case of a Content process // it is also required that the small allocation are not being randomized ; // failing to do so will lead to performance regressions, e.g. as in // bug 1912262. #ifdefined(MOZ_MEMORY)
jemalloc_reset_small_alloc_randomization( /* aRandomizeSmall */ !XRE_IsContentProcess()); #endif
// Open log files again with right names and the new PID.
nsTraceRefcnt::ReopenLogFilesAfterFork(XRE_GetProcessTypeString());
returnfalse;
}
} // namespace ipc
} // namespace mozilla
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.