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/IOThreadChild.h"
25 #include "mozilla/GeckoArgs.h"
30 ProcessChild
* ProcessChild::gProcessChild
;
31 StaticMutex
ProcessChild::gIPCShutdownStateLock
;
32 nsCString
ProcessChild::gIPCShutdownStateAnnotation
;
34 static Atomic
<bool> sExpectingShutdown(false);
36 ProcessChild::ProcessChild(ProcessId aParentPid
, const nsID
& aMessageChannelId
)
37 : ChildProcess(new IOThreadChild(aParentPid
)),
38 mUILoop(MessageLoop::current()),
39 mParentPid(aParentPid
),
40 mMessageChannelId(aMessageChannelId
) {
41 MOZ_ASSERT(mUILoop
, "UILoop should be created by now");
42 MOZ_ASSERT(!gProcessChild
, "should only be one ProcessChild");
43 CrashReporter::RegisterAnnotationNSCString(
44 CrashReporter::Annotation::IPCShutdownState
,
45 &gIPCShutdownStateAnnotation
);
50 void ProcessChild::AddPlatformBuildID(std::vector
<std::string
>& aExtraArgs
) {
51 nsCString
parentBuildID(mozilla::PlatformBuildID());
52 geckoargs::sParentBuildID
.Put(parentBuildID
.get(), aExtraArgs
);
56 bool ProcessChild::InitPrefs(int aArgc
, char* aArgv
[]) {
57 Maybe
<uint64_t> prefsHandle
= Some(0);
58 Maybe
<uint64_t> prefMapHandle
= Some(0);
59 Maybe
<uint64_t> prefsLen
= geckoargs::sPrefsLen
.Get(aArgc
, aArgv
);
60 Maybe
<uint64_t> prefMapSize
= geckoargs::sPrefMapSize
.Get(aArgc
, aArgv
);
62 if (prefsLen
.isNothing() || prefMapSize
.isNothing()) {
67 prefsHandle
= geckoargs::sPrefsHandle
.Get(aArgc
, aArgv
);
68 prefMapHandle
= geckoargs::sPrefMapHandle
.Get(aArgc
, aArgv
);
70 if (prefsHandle
.isNothing() || prefMapHandle
.isNothing()) {
75 SharedPreferenceDeserializer deserializer
;
76 return deserializer
.DeserializeFromSharedMemory(*prefsHandle
, *prefMapHandle
,
77 *prefsLen
, *prefMapSize
);
81 // Allow tests to cause a synthetic delay/"hang" during child process
82 // shutdown by setting environment variables.
84 static void ReallySleep(int aSeconds
) {
85 struct ::timespec snooze
= {aSeconds
, 0};
86 HANDLE_EINTR(nanosleep(&snooze
, &snooze
));
89 static void ReallySleep(int aSeconds
) { ::Sleep(aSeconds
* 1000); }
91 static void SleepIfEnv(const char* aName
) {
92 if (auto* value
= PR_GetEnv(aName
)) {
93 ReallySleep(atoi(value
));
97 static void SleepIfEnv(const char* aName
) {}
100 ProcessChild::~ProcessChild() {
101 #ifdef NS_FREE_PERMANENT_DATA
102 // In this case, we won't early-exit and we'll wait indefinitely for
103 // child processes to terminate. This sleep is late enough that, in
104 // content processes, it won't block parent process shutdown, so
105 // we'll get into late IPC shutdown with processes still running.
106 SleepIfEnv("MOZ_TEST_CHILD_EXIT_HANG");
108 gIPCShutdownStateAnnotation
= ""_ns
;
109 gProcessChild
= nullptr;
113 void ProcessChild::NotifiedImpendingShutdown() {
114 sExpectingShutdown
= true;
115 ProcessChild::AppendToIPCShutdownStateAnnotation(
116 "NotifiedImpendingShutdown"_ns
);
120 bool ProcessChild::ExpectingShutdown() { return sExpectingShutdown
; }
123 void ProcessChild::QuickExit() {
124 #ifndef NS_FREE_PERMANENT_DATA
125 // In this case, we're going to terminate the child process before
126 // we get to ~ProcessChild above (and terminate the parent process
127 // before the shutdown hook in ProcessWatcher). Instead, blocking
128 // earlier will let us exercise ProcessWatcher's kill timer.
129 SleepIfEnv("MOZ_TEST_CHILD_EXIT_HANG");
131 AppShutdown::DoImmediateExit();
134 UntypedEndpoint
ProcessChild::TakeInitialEndpoint() {
135 return UntypedEndpoint
{PrivateIPDLInterface
{},
136 child_thread()->TakeInitialPort(), mMessageChannelId
,
137 base::GetCurrentProcId(), mParentPid
};
141 } // namespace mozilla