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/IOThread.h"
25 #include "mozilla/ipc/ProcessUtils.h"
26 #include "mozilla/GeckoArgs.h"
31 ProcessChild
* ProcessChild::gProcessChild
;
32 StaticMutex
ProcessChild::gIPCShutdownStateLock
;
33 MOZ_CONSTINIT nsCString
ProcessChild::gIPCShutdownStateAnnotation
;
35 static Atomic
<bool> sExpectingShutdown(false);
37 ProcessChild::ProcessChild(IPC::Channel::ChannelHandle aClientChannel
,
38 ProcessId aParentPid
, const nsID
& aMessageChannelId
)
39 : mUILoop(MessageLoop::current()),
40 mParentPid(aParentPid
),
41 mMessageChannelId(aMessageChannelId
),
43 MakeUnique
<IOThreadChild
>(std::move(aClientChannel
), aParentPid
)) {
44 MOZ_ASSERT(mUILoop
, "UILoop should be created by now");
45 MOZ_ASSERT(!gProcessChild
, "should only be one ProcessChild");
46 CrashReporter::RegisterAnnotationNSCString(
47 CrashReporter::Annotation::IPCShutdownState
,
48 &gIPCShutdownStateAnnotation
);
53 void ProcessChild::AddPlatformBuildID(geckoargs::ChildProcessArgs
& aExtraArgs
) {
54 nsCString
parentBuildID(mozilla::PlatformBuildID());
55 geckoargs::sParentBuildID
.Put(parentBuildID
.get(), aExtraArgs
);
59 bool ProcessChild::InitPrefs(int aArgc
, char* aArgv
[]) {
60 Maybe
<SharedMemoryHandle
> prefsHandle
=
61 geckoargs::sPrefsHandle
.Get(aArgc
, aArgv
);
62 Maybe
<SharedMemoryHandle
> prefMapHandle
=
63 geckoargs::sPrefMapHandle
.Get(aArgc
, aArgv
);
64 Maybe
<uint64_t> prefsLen
= geckoargs::sPrefsLen
.Get(aArgc
, aArgv
);
65 Maybe
<uint64_t> prefMapSize
= geckoargs::sPrefMapSize
.Get(aArgc
, aArgv
);
67 if (prefsLen
.isNothing() || prefMapSize
.isNothing() ||
68 prefsHandle
.isNothing() || prefMapHandle
.isNothing()) {
72 SharedPreferenceDeserializer deserializer
;
73 return deserializer
.DeserializeFromSharedMemory(std::move(*prefsHandle
),
74 std::move(*prefMapHandle
),
75 *prefsLen
, *prefMapSize
);
79 // Allow tests to cause a synthetic delay/"hang" during child process
80 // shutdown by setting environment variables.
82 static void ReallySleep(int aSeconds
) {
83 struct ::timespec snooze
= {aSeconds
, 0};
84 HANDLE_EINTR(nanosleep(&snooze
, &snooze
));
87 static void ReallySleep(int aSeconds
) { ::Sleep(aSeconds
* 1000); }
89 static void SleepIfEnv(const char* aName
) {
90 if (auto* value
= PR_GetEnv(aName
)) {
91 ReallySleep(atoi(value
));
95 static void SleepIfEnv(const char* aName
) {}
98 ProcessChild::~ProcessChild() {
99 #ifdef NS_FREE_PERMANENT_DATA
100 // In this case, we won't early-exit and we'll wait indefinitely for
101 // child processes to terminate. This sleep is late enough that, in
102 // content processes, it won't block parent process shutdown, so
103 // we'll get into late IPC shutdown with processes still running.
104 SleepIfEnv("MOZ_TEST_CHILD_EXIT_HANG");
106 gIPCShutdownStateAnnotation
= ""_ns
;
107 gProcessChild
= nullptr;
111 void ProcessChild::NotifiedImpendingShutdown() {
112 sExpectingShutdown
= true;
113 ProcessChild::AppendToIPCShutdownStateAnnotation(
114 "NotifiedImpendingShutdown"_ns
);
118 bool ProcessChild::ExpectingShutdown() { return sExpectingShutdown
; }
121 void ProcessChild::QuickExit() {
122 #ifndef NS_FREE_PERMANENT_DATA
123 // In this case, we're going to terminate the child process before
124 // we get to ~ProcessChild above (and terminate the parent process
125 // before the shutdown hook in ProcessWatcher). Instead, blocking
126 // earlier will let us exercise ProcessWatcher's kill timer.
127 SleepIfEnv("MOZ_TEST_CHILD_EXIT_HANG");
129 AppShutdown::DoImmediateExit();
132 UntypedEndpoint
ProcessChild::TakeInitialEndpoint() {
133 return UntypedEndpoint
{PrivateIPDLInterface
{},
134 mChildThread
->TakeInitialPort(), mMessageChannelId
,
135 EndpointProcInfo::Current(),
136 EndpointProcInfo
{.mPid
= mParentPid
, .mChildID
= 0}};
140 } // namespace mozilla