1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ipc/ProcessChild.h"
13 # include <stdlib.h> // for _exit()
14 # include <synchapi.h>
16 # include <unistd.h> // for _exit()
18 # include "base/eintr_wrapper.h"
22 #include "nsAppRunner.h"
23 #include "mozilla/AppShutdown.h"
24 #include "mozilla/ipc/CrashReporterClient.h"
25 #include "mozilla/ipc/IOThreadChild.h"
26 #include "mozilla/GeckoArgs.h"
31 ProcessChild
* ProcessChild::gProcessChild
;
33 static Atomic
<bool> sExpectingShutdown(false);
35 ProcessChild::ProcessChild(ProcessId aParentPid
, const nsID
& aMessageChannelId
)
36 : ChildProcess(new IOThreadChild(aParentPid
)),
37 mUILoop(MessageLoop::current()),
38 mParentPid(aParentPid
),
39 mMessageChannelId(aMessageChannelId
) {
40 MOZ_ASSERT(mUILoop
, "UILoop should be created by now");
41 MOZ_ASSERT(!gProcessChild
, "should only be one ProcessChild");
46 void ProcessChild::AddPlatformBuildID(std::vector
<std::string
>& aExtraArgs
) {
47 nsCString
parentBuildID(mozilla::PlatformBuildID());
48 geckoargs::sParentBuildID
.Put(parentBuildID
.get(), aExtraArgs
);
52 bool ProcessChild::InitPrefs(int aArgc
, char* aArgv
[]) {
53 Maybe
<uint64_t> prefsHandle
= Some(0);
54 Maybe
<uint64_t> prefMapHandle
= Some(0);
55 Maybe
<uint64_t> prefsLen
= geckoargs::sPrefsLen
.Get(aArgc
, aArgv
);
56 Maybe
<uint64_t> prefMapSize
= geckoargs::sPrefMapSize
.Get(aArgc
, aArgv
);
58 if (prefsLen
.isNothing() || prefMapSize
.isNothing()) {
63 prefsHandle
= geckoargs::sPrefsHandle
.Get(aArgc
, aArgv
);
64 prefMapHandle
= geckoargs::sPrefMapHandle
.Get(aArgc
, aArgv
);
66 if (prefsHandle
.isNothing() || prefMapHandle
.isNothing()) {
71 SharedPreferenceDeserializer deserializer
;
72 return deserializer
.DeserializeFromSharedMemory(*prefsHandle
, *prefMapHandle
,
73 *prefsLen
, *prefMapSize
);
77 // Allow tests to cause a synthetic delay/"hang" during child process
78 // shutdown by setting environment variables.
80 static void ReallySleep(int aSeconds
) {
81 struct ::timespec snooze
= {aSeconds
, 0};
82 HANDLE_EINTR(nanosleep(&snooze
, &snooze
));
85 static void ReallySleep(int aSeconds
) { ::Sleep(aSeconds
* 1000); }
87 static void SleepIfEnv(const char* aName
) {
88 if (auto* value
= PR_GetEnv(aName
)) {
89 ReallySleep(atoi(value
));
93 static void SleepIfEnv(const char* aName
) {}
96 ProcessChild::~ProcessChild() {
97 #ifdef NS_FREE_PERMANENT_DATA
98 // In this case, we won't early-exit and we'll wait indefinitely for
99 // child processes to terminate. This sleep is late enough that, in
100 // content processes, it won't block parent process shutdown, so
101 // we'll get into late IPC shutdown with processes still running.
102 SleepIfEnv("MOZ_TEST_CHILD_EXIT_HANG");
104 gProcessChild
= nullptr;
108 void ProcessChild::NotifiedImpendingShutdown() {
109 sExpectingShutdown
= true;
110 CrashReporter::AppendToCrashReportAnnotation(
111 CrashReporter::Annotation::IPCShutdownState
,
112 "NotifiedImpendingShutdown"_ns
);
116 bool ProcessChild::ExpectingShutdown() { return sExpectingShutdown
; }
119 void ProcessChild::QuickExit() {
120 #ifndef NS_FREE_PERMANENT_DATA
121 // In this case, we're going to terminate the child process before
122 // we get to ~ProcessChild above (and terminate the parent process
123 // before the shutdown hook in ProcessWatcher). Instead, blocking
124 // earlier will let us exercise ProcessWatcher's kill timer.
125 SleepIfEnv("MOZ_TEST_CHILD_EXIT_HANG");
127 AppShutdown::DoImmediateExit();
130 UntypedEndpoint
ProcessChild::TakeInitialEndpoint() {
131 return UntypedEndpoint
{PrivateIPDLInterface
{},
132 child_thread()->TakeInitialPort(), mMessageChannelId
,
133 base::GetCurrentProcId(), mParentPid
};
137 } // namespace mozilla