forked from mirrors/gecko-dev
Bug 1470591 - Part 6: Create a fork server process. r=gsvelto
This patch make changes of Gecko infrastrutures to run a fork server process. - ForkServerLauncher is a component, which creates a fork server process at XPCOM startup. - nsBrowserApp.cpp and related files have been chagned to start a fork server in a process. - Logging and nsTraceRefcnt were changed to make it work with the fork server. Depends on D46883 Differential Revision: https://phabricator.services.mozilla.com/D46884 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
c50a650261
commit
7cfdf6a788
16 changed files with 276 additions and 11 deletions
|
|
@ -219,6 +219,10 @@ static int do_main(int argc, char* argv[], char* envp[]) {
|
|||
}
|
||||
|
||||
static nsresult InitXPCOMGlue(LibLoadingStrategy aLibLoadingStrategy) {
|
||||
if (gBootstrap) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
UniqueFreePtr<char> exePath = BinaryPath::Get();
|
||||
if (!exePath) {
|
||||
Output("Couldn't find the application directory.\n");
|
||||
|
|
@ -243,6 +247,33 @@ uint32_t gBlocklistInitFlags = eDllBlocklistInitFlagDefault;
|
|||
#endif
|
||||
|
||||
int main(int argc, char* argv[], char* envp[]) {
|
||||
#if defined(MOZ_ENABLE_FORKSERVER)
|
||||
if (strcmp(argv[argc - 1], "forkserver") == 0) {
|
||||
nsresult rv = InitXPCOMGlue(LibLoadingStrategy::NoReadAhead);
|
||||
if (NS_FAILED(rv)) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
// Run a fork server in this process, single thread. When it
|
||||
// returns, it means the fork server have been stopped or a new
|
||||
// content process is created.
|
||||
//
|
||||
// For the later case, XRE_ForkServer() will return false, running
|
||||
// in a content process just forked from the fork server process.
|
||||
// argc & argv will be updated with the values passing from the
|
||||
// chrome process. With the new values, this function
|
||||
// continues the reset of the code acting as a content process.
|
||||
if(gBootstrap->XRE_ForkServer(&argc, &argv)) {
|
||||
// Return from the fork server in the fork server process.
|
||||
// Stop the fork server.
|
||||
gBootstrap->NS_LogTerm();
|
||||
return 0;
|
||||
}
|
||||
// In a content process forked from the fork server.
|
||||
// Start acting as a content process.
|
||||
}
|
||||
#endif
|
||||
|
||||
mozilla::TimeStamp start = mozilla::TimeStamp::Now();
|
||||
|
||||
AUTO_BASE_PROFILER_INIT;
|
||||
|
|
|
|||
|
|
@ -13,18 +13,67 @@
|
|||
|
||||
using namespace mozilla;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef HAS_DLL_BLOCKLIST
|
||||
DllBlocklist_Initialize(eDllBlocklistInitFlagIsChildProcess);
|
||||
static bool
|
||||
UseForkServer(int argc, char* argv[]) {
|
||||
#if defined(MOZ_ENABLE_FORKSERVER)
|
||||
return strcmp(argv[argc - 1], "forkserver") == 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
RunForkServer(Bootstrap::UniquePtr&& bootstrap, int argc, char* argv[]) {
|
||||
#if defined(MOZ_ENABLE_FORKSERVER)
|
||||
int ret = 0;
|
||||
|
||||
bootstrap->NS_LogInit();
|
||||
|
||||
// Run a fork server in this process, single thread. When it
|
||||
// returns, it means the fork server have been stopped or a new
|
||||
// content process is created.
|
||||
//
|
||||
// For the later case, XRE_ForkServer() will return false, running
|
||||
// in a content process just forked from the fork server process.
|
||||
// argc & argv will be updated with the values passing from the
|
||||
// chrome process. With the new values, this function
|
||||
// continues the reset of the code acting as a content process.
|
||||
if(bootstrap->XRE_ForkServer(&argc, &argv)) {
|
||||
// Return from the fork server in the fork server process.
|
||||
// Stop the fork server.
|
||||
} else {
|
||||
// In a content process forked from the fork server.
|
||||
// Start acting as a content process.
|
||||
ret = content_process_main(bootstrap.get(), argc, argv);
|
||||
}
|
||||
|
||||
bootstrap->NS_LogTerm();
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
Bootstrap::UniquePtr bootstrap = GetBootstrap();
|
||||
if (!bootstrap) {
|
||||
return 2;
|
||||
}
|
||||
int ret = content_process_main(bootstrap.get(), argc, argv);
|
||||
#if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
|
||||
DllBlocklist_Shutdown();
|
||||
|
||||
int ret;
|
||||
if (UseForkServer(argc, argv)) {
|
||||
ret = RunForkServer(std::move(bootstrap), argc, argv);
|
||||
} else {
|
||||
#ifdef HAS_DLL_BLOCKLIST
|
||||
DllBlocklist_Initialize(eDllBlocklistInitFlagIsChildProcess);
|
||||
#endif
|
||||
|
||||
ret = content_process_main(bootstrap.get(), argc, argv);
|
||||
|
||||
#if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
|
||||
DllBlocklist_Shutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,14 +162,32 @@ handle_sigchld(int s) {
|
|||
waitpid(-1, nullptr, WNOHANG);
|
||||
}
|
||||
|
||||
void
|
||||
InitForkServerProcess() {
|
||||
static void
|
||||
InstallChildSignalHandler() {
|
||||
// Since content processes are not children of the chrome process
|
||||
// any more, the fork server process has to handle SIGCHLD, or
|
||||
// content process would remain zombie after dead.
|
||||
signal(SIGCHLD, handle_sigchld);
|
||||
}
|
||||
|
||||
static void
|
||||
ReserveFileDescriptors() {
|
||||
// Reserve the lower positions of the file descriptors to make sure
|
||||
// debug files and other files don't take these positions. So we
|
||||
// can keep their file descriptors during CloseSuperfluousFds() with
|
||||
// out any confliction with mapping passing from the parent process.
|
||||
int fd = open("/dev/null", O_RDONLY);
|
||||
for (int i = 1; i < 10; i++) {
|
||||
dup(fd);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InitForkServerProcess() {
|
||||
InstallChildSignalHandler();
|
||||
ReserveFileDescriptors();
|
||||
}
|
||||
|
||||
static bool
|
||||
LaunchAppWithForkServer(const std::vector<std::string>& argv,
|
||||
const LaunchOptions& options,
|
||||
|
|
|
|||
|
|
@ -300,6 +300,9 @@ ForkServer::RunForkServer(int* aArgc, char*** aArgv) {
|
|||
forkserver.mAppProcBuilder->InitAppProcess(aArgc, aArgv);
|
||||
forkserver.mAppProcBuilder.reset();
|
||||
|
||||
// Open log files again with the right names with the new PID.
|
||||
nsTraceRefcnt::ResetLogFiles();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,5 +112,45 @@ ForkServiceChild::OnMessageReceived(IPC::Message&& message) {
|
|||
message.EndRead(iter__, message.type());
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(ForkServerLauncher, nsIObserver)
|
||||
|
||||
bool ForkServerLauncher::mHaveStartedClient = false;
|
||||
StaticRefPtr<ForkServerLauncher> ForkServerLauncher::mSingleton;
|
||||
|
||||
ForkServerLauncher::ForkServerLauncher() {
|
||||
}
|
||||
|
||||
ForkServerLauncher::~ForkServerLauncher() {
|
||||
}
|
||||
|
||||
already_AddRefed<ForkServerLauncher>
|
||||
ForkServerLauncher::Create() {
|
||||
if (mSingleton == nullptr) {
|
||||
mSingleton = new ForkServerLauncher();
|
||||
}
|
||||
RefPtr<ForkServerLauncher> launcher = mSingleton;
|
||||
return launcher.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ForkServerLauncher::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData) {
|
||||
if (!mHaveStartedClient && strcmp(aTopic, NS_XPCOM_STARTUP_CATEGORY) == 0) {
|
||||
mHaveStartedClient = true;
|
||||
ForkServiceChild::StartForkServer();
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
|
||||
MOZ_ASSERT(obsSvc != nullptr);
|
||||
obsSvc->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
}
|
||||
|
||||
if (mHaveStartedClient && strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
|
||||
mHaveStartedClient = false;
|
||||
ForkServiceChild::StopForkServer();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,24 @@ private:
|
|||
GeckoChildProcessHost* mProcess;
|
||||
};
|
||||
|
||||
/**
|
||||
* Start a fork server at |xpcom-startup| from the chrome process.
|
||||
*/
|
||||
class ForkServerLauncher : public nsIObserver {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
ForkServerLauncher();
|
||||
static already_AddRefed<ForkServerLauncher> Create();
|
||||
|
||||
private:
|
||||
virtual ~ForkServerLauncher();
|
||||
|
||||
static bool mHaveStartedClient;
|
||||
static StaticRefPtr<ForkServerLauncher> mSingleton;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
22
ipc/glue/components.conf
Normal file
22
ipc/glue/components.conf
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
Headers = [
|
||||
'mozilla/ipc/ForkServer.h',
|
||||
]
|
||||
|
||||
Classes = [
|
||||
{
|
||||
'cid': '{cdb4757f-f51b-40c0-8b38-66d12c3bff7b}',
|
||||
'contract_ids': ['@mozilla.org/fork-server-launcher;1'],
|
||||
'singleton': True,
|
||||
'type': 'mozilla::ipc::ForkServerLauncher',
|
||||
'headers': ['mozilla/ipc/ForkServiceChild.h'],
|
||||
'constructor': 'mozilla::ipc::ForkServerLauncher::Create',
|
||||
'processes': ProcessSelector.MAIN_PROCESS_ONLY,
|
||||
'categories': {'xpcom-startup': 'Fork Server Launcher'},
|
||||
},
|
||||
]
|
||||
|
|
@ -231,6 +231,9 @@ if CONFIG['MOZ_ENABLE_FORKSERVER']:
|
|||
'ForkServiceChild.cpp',
|
||||
'MiniTransceiver.cpp',
|
||||
]
|
||||
XPCOM_MANIFESTS += [
|
||||
'components.conf',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/ipc',
|
||||
|
|
|
|||
|
|
@ -634,6 +634,19 @@ llvm_objdump = check_prog('LLVM_OBJDUMP', llvm_objdump, what='llvm-objdump',
|
|||
|
||||
add_old_configure_assignment('LLVM_OBJDUMP', llvm_objdump)
|
||||
|
||||
# Fork server
|
||||
option('--enable-forkserver', env='MOZ_ENABLE_FORKSERVER', help='Enable fork server')
|
||||
|
||||
@depends('--enable-forkserver', target)
|
||||
def forkserver_flag(value, target):
|
||||
if target.os == 'Android' or \
|
||||
(target.os == 'GNU' and target.kernel == 'Linux'):
|
||||
return bool(value)
|
||||
pass
|
||||
|
||||
set_config('MOZ_ENABLE_FORKSERVER', forkserver_flag)
|
||||
set_define('MOZ_ENABLE_FORKSERVER', forkserver_flag, forkserver_flag)
|
||||
|
||||
|
||||
# Please do not add configure checks from here on.
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,12 @@ class BootstrapImpl final : public Bootstrap {
|
|||
return ::XRE_RunIPDLTest(argc, argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_ENABLE_FORKSERVER
|
||||
virtual int XRE_ForkServer(int* argc, char*** argv) override {
|
||||
return ::XRE_ForkServer(argc, argv);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
extern "C" NS_EXPORT void NS_FROZENCALL
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@ class Bootstrap {
|
|||
#ifdef MOZ_IPDL_TESTS
|
||||
virtual int XRE_RunIPDLTest(int argc, char** argv) = 0;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_ENABLE_FORKSERVER
|
||||
virtual int XRE_ForkServer(int* argc, char*** argv) = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum class LibLoadingStrategy {
|
||||
|
|
|
|||
|
|
@ -133,6 +133,10 @@ using mozilla::_ipdltest::IPDLUnitTestProcessChild;
|
|||
# include "mozilla/sandboxing/sandboxLogging.h"
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_ENABLE_FORKSERVER)
|
||||
# include "mozilla/ipc/ForkServer.h"
|
||||
#endif
|
||||
|
||||
#include "VRProcessChild.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
|
@ -264,7 +268,8 @@ void XRE_SetAndroidChildFds(JNIEnv* env, const XRE_AndroidChildFds& fds) {
|
|||
|
||||
void XRE_SetProcessType(const char* aProcessTypeString) {
|
||||
static bool called = false;
|
||||
if (called) {
|
||||
if (called &&
|
||||
sChildProcessType != GeckoProcessType_ForkServer) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
called = true;
|
||||
|
|
@ -730,6 +735,12 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
|
|||
process = new RemoteSandboxBrokerProcessChild(parentPID);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_ENABLE_FORKSERVER)
|
||||
case GeckoProcessType_ForkServer:
|
||||
MOZ_CRASH("Fork server should not go here");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
MOZ_CRASH("Unknown main thread class");
|
||||
}
|
||||
|
|
@ -1025,3 +1036,9 @@ void XRE_InstallX11ErrorHandler() {
|
|||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_ENABLE_FORKSERVER
|
||||
int XRE_ForkServer(int* aArgc, char*** aArgv) {
|
||||
return mozilla::ipc::ForkServer::RunForkServer(aArgc, aArgv) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -377,8 +377,7 @@ class LogModuleManager {
|
|||
|
||||
void Print(const char* aName, LogLevel aLevel, const char* aFmt,
|
||||
va_list aArgs) MOZ_FORMAT_PRINTF(4, 0) {
|
||||
// We don't do nuwa-style forking anymore, so our pid can't change.
|
||||
static long pid = static_cast<long>(base::GetCurrentProcId());
|
||||
long pid = static_cast<long>(base::GetCurrentProcId());
|
||||
const size_t kBuffSize = 1024;
|
||||
char buff[kBuffSize];
|
||||
|
||||
|
|
|
|||
|
|
@ -523,6 +523,9 @@ static bool InitLog(const EnvCharType* aEnvVar, const char* aMsg,
|
|||
#endif
|
||||
if (stream) {
|
||||
MozillaRegisterDebugFD(fileno(stream));
|
||||
#ifdef MOZ_ENABLE_FORKSERVER
|
||||
base::RegisterForkServerNoCloseFD(fileno(stream));
|
||||
#endif
|
||||
*aResult = stream;
|
||||
fprintf(stderr,
|
||||
"### " ENVVAR_PRINTF " defined -- logging %s to " ENVVAR_PRINTF
|
||||
|
|
@ -1157,3 +1160,32 @@ void nsTraceRefcnt::SetActivityIsLegal(bool aLegal) {
|
|||
|
||||
PR_SetThreadPrivate(gActivityTLS, reinterpret_cast<void*>(!aLegal));
|
||||
}
|
||||
|
||||
#ifdef MOZ_ENABLE_FORKSERVER
|
||||
void nsTraceRefcnt::ResetLogFiles() {
|
||||
#ifdef XP_WIN
|
||||
# define ENVVAR(x) u"" x
|
||||
#else
|
||||
# define ENVVAR(x) x
|
||||
#endif
|
||||
if (gBloatLog) {
|
||||
maybeUnregisterAndCloseFile(gBloatLog);
|
||||
bool defined = InitLog(ENVVAR("XPCOM_MEM_BLOAT_LOG"), "bloat/leaks", &gBloatLog);
|
||||
if (!defined) {
|
||||
InitLog(ENVVAR("XPCOM_MEM_LEAK_LOG"), "leaks", &gBloatLog);
|
||||
}
|
||||
}
|
||||
if (gRefcntsLog) {
|
||||
maybeUnregisterAndCloseFile(gRefcntsLog);
|
||||
InitLog(ENVVAR("XPCOM_MEM_REFCNT_LOG"), "refcounts", &gRefcntsLog);
|
||||
}
|
||||
if (gAllocLog) {
|
||||
maybeUnregisterAndCloseFile(gAllocLog);
|
||||
InitLog(ENVVAR("XPCOM_MEM_ALLOC_LOG"), "new/delete", &gAllocLog);
|
||||
}
|
||||
if(gCOMPtrLog) {
|
||||
maybeUnregisterAndCloseFile(gCOMPtrLog);
|
||||
InitLog(ENVVAR("XPCOM_MEM_COMPTR_LOG"), "nsCOMPtr", &gCOMPtrLog);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ class nsTraceRefcnt {
|
|||
* activity that occurs because of static constructors or destructors.
|
||||
*/
|
||||
static void SetActivityIsLegal(bool aLegal);
|
||||
|
||||
#ifdef MOZ_ENABLE_FORKSERVER
|
||||
static void ResetLogFiles();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // nsTraceRefcnt_h
|
||||
|
|
|
|||
|
|
@ -509,4 +509,10 @@ XRE_API(void, XRE_LibFuzzerSetDriver, (LibFuzzerDriver))
|
|||
|
||||
#endif // LIBFUZZER
|
||||
|
||||
#ifdef MOZ_ENABLE_FORKSERVER
|
||||
|
||||
XRE_API(int, XRE_ForkServer, (int* aArgc, char*** aArgv))
|
||||
|
||||
#endif // MOZ_ENABLE_FORKSERVER
|
||||
|
||||
#endif // _nsXULAppAPI_h__
|
||||
|
|
|
|||
Loading…
Reference in a new issue