Bug 1603420 - PBackground for the Parent-Socket process bridge r=baku,jld

Differential Revision: https://phabricator.services.mozilla.com/D56955

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Kershaw Chang 2020-03-03 16:14:19 +00:00
parent 8d900cf3ef
commit 3d82922ab3
8 changed files with 488 additions and 349 deletions

View File

@ -24,6 +24,7 @@ class ContentParent;
namespace net {
class SocketProcessImpl;
class SocketProcessChild;
} // namespace net
@ -57,6 +58,7 @@ class BackgroundChild final {
friend class mozilla::dom::ContentChild;
friend class mozilla::dom::ContentParent;
friend class mozilla::net::SocketProcessImpl;
friend class mozilla::net::SocketProcessChild;
typedef mozilla::ipc::Transport Transport;
@ -75,6 +77,10 @@ class BackgroundChild final {
static PBackgroundChild* GetOrCreateSocketActorForCurrentThread(
nsIEventTarget* aMainEventTarget = nullptr);
// See above.
static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread(
nsIEventTarget* aMainEventTarget = nullptr);
private:
// Only called by ContentChild or ContentParent.
static void Startup();

View File

@ -27,6 +27,7 @@
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/ipc/ProtocolTypes.h"
#include "mozilla/net/SocketProcessChild.h"
#include "mozilla/net/SocketProcessBridgeChild.h"
#include "nsCOMPtr.h"
#include "nsIEventTarget.h"
@ -221,12 +222,17 @@ class ParentImpl final : public BackgroundParentImpl {
}
// For other-process actors.
// NOTE: ParentImpl could be used in 3 cases below.
// 1. Between parent process and content process.
// 2. Between socket process and content process.
// 3. Between parent process and socket process.
// |mContent| should be not null for case 1. For case 2 and 3, it's null.
explicit ParentImpl(ContentParent* aContent)
: mContent(aContent),
mLiveActorArray(nullptr),
mIsOtherProcessActor(true),
mActorDestroyed(false) {
MOZ_ASSERT((XRE_IsParentProcess() && aContent) || XRE_IsSocketProcess());
MOZ_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess());
AssertIsOnMainThread();
}
@ -266,17 +272,10 @@ class ChildImpl final : public BackgroundChildImpl {
typedef mozilla::ipc::Transport Transport;
class ShutdownObserver;
public:
class SendInitBackgroundRunnable;
// A thread-local index that is not valid.
static const unsigned int kBadThreadLocalIndex =
static_cast<unsigned int>(-1);
// This is only modified on the main thread. It is the thread-local index that
// we use to store the BackgroundChild for each thread.
static unsigned int sThreadLocalIndex;
static unsigned int sThreadLocalIndexForSocketProcess;
struct ThreadLocalInfo {
ThreadLocalInfo()
#ifdef DEBUG
@ -293,12 +292,156 @@ class ChildImpl final : public BackgroundChildImpl {
#endif
};
// On the main thread, we store TLS in this global instead of in
// sThreadLocalIndex. That way, cooperative main threads all share the same
// thread info.
static ThreadLocalInfo* sMainThreadInfo;
private:
// A thread-local index that is not valid.
static constexpr unsigned int kBadThreadLocalIndex =
static_cast<unsigned int>(-1);
static ThreadLocalInfo* sMainThreadInfoForSocketProcess;
// ThreadInfoWrapper encapsulates ThreadLocalInfo and ThreadLocalIndex and
// also provides some common functions for creating PBackground IPC actor.
class ThreadInfoWrapper final {
friend class ChildImpl;
public:
using ActorCreateFunc = void (*)(ThreadLocalInfo*, unsigned int,
nsIEventTarget*, ChildImpl**);
constexpr explicit ThreadInfoWrapper(ActorCreateFunc aFunc)
: mThreadLocalIndex(kBadThreadLocalIndex),
mMainThreadInfo(nullptr),
mCreateActorFunc(aFunc) {}
void Startup() {
MOZ_ASSERT(mThreadLocalIndex == kBadThreadLocalIndex,
"ThreadInfoWrapper::Startup() called more than once!");
PRStatus status =
PR_NewThreadPrivateIndex(&mThreadLocalIndex, ThreadLocalDestructor);
MOZ_RELEASE_ASSERT(status == PR_SUCCESS,
"PR_NewThreadPrivateIndex failed!");
MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex);
}
void Shutdown() {
if (sShutdownHasStarted) {
MOZ_ASSERT_IF(mThreadLocalIndex != kBadThreadLocalIndex,
!PR_GetThreadPrivate(mThreadLocalIndex));
return;
}
if (mThreadLocalIndex == kBadThreadLocalIndex) {
return;
}
ThreadLocalInfo* threadLocalInfo;
#ifdef DEBUG
threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
MOZ_ASSERT(!threadLocalInfo);
#endif
threadLocalInfo = mMainThreadInfo;
if (threadLocalInfo) {
#ifdef DEBUG
MOZ_ASSERT(!threadLocalInfo->mClosed);
threadLocalInfo->mClosed = true;
#endif
ThreadLocalDestructor(threadLocalInfo);
mMainThreadInfo = nullptr;
}
}
void CloseForCurrentThread() {
MOZ_ASSERT(!NS_IsMainThread());
if (mThreadLocalIndex == kBadThreadLocalIndex) {
return;
}
auto threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
if (!threadLocalInfo) {
return;
}
#ifdef DEBUG
MOZ_ASSERT(!threadLocalInfo->mClosed);
threadLocalInfo->mClosed = true;
#endif
// Clearing the thread local will synchronously close the actor.
DebugOnly<PRStatus> status =
PR_SetThreadPrivate(mThreadLocalIndex, nullptr);
MOZ_ASSERT(status == PR_SUCCESS);
}
PBackgroundChild* GetOrCreateForCurrentThread(
nsIEventTarget* aMainEventTarget) {
MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget);
MOZ_ASSERT(mThreadLocalIndex != kBadThreadLocalIndex,
"BackgroundChild::Startup() was never called!");
if (NS_IsMainThread() && ChildImpl::sShutdownHasStarted) {
return nullptr;
}
auto threadLocalInfo = NS_IsMainThread()
? mMainThreadInfo
: static_cast<ThreadLocalInfo*>(
PR_GetThreadPrivate(mThreadLocalIndex));
if (!threadLocalInfo) {
auto newInfo = MakeUnique<ThreadLocalInfo>();
if (NS_IsMainThread()) {
mMainThreadInfo = newInfo.get();
} else {
if (PR_SetThreadPrivate(mThreadLocalIndex, newInfo.get()) !=
PR_SUCCESS) {
CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
return nullptr;
}
}
threadLocalInfo = newInfo.release();
}
PBackgroundChild* bgChild =
GetFromThreadInfo(aMainEventTarget, threadLocalInfo);
if (bgChild) {
return bgChild;
}
RefPtr<ChildImpl> actor;
mCreateActorFunc(threadLocalInfo, mThreadLocalIndex, aMainEventTarget,
getter_AddRefs(actor));
return actor;
}
private:
// This is only modified on the main thread. It is the thread-local index
// that we use to store the BackgroundChild for each thread.
unsigned int mThreadLocalIndex;
// On the main thread, we store TLS in this global instead of in
// mThreadLocalIndex. That way, cooperative main threads all share the same
// thread info.
ThreadLocalInfo* mMainThreadInfo;
ActorCreateFunc mCreateActorFunc;
};
// For PBackground between parent and content process.
static ThreadInfoWrapper sParentAndContentProcessThreadInfo;
// For PBackground between socket and content process.
static ThreadInfoWrapper sSocketAndContentProcessThreadInfo;
// For PBackground between socket and parent process.
static ThreadInfoWrapper sSocketAndParentProcessThreadInfo;
// This is only modified on the main thread. It prevents us from trying to
// create the background thread after application shutdown has started.
@ -316,8 +459,6 @@ class ChildImpl final : public BackgroundChildImpl {
public:
static void Shutdown();
static void ShutdownWithThreadLocalIndex(unsigned int aThreadLocalIndex);
void AssertIsOnOwningThread() {
THREADSAFETY_ASSERT(mOwningEventTarget);
@ -380,9 +521,10 @@ class ChildImpl final : public BackgroundChildImpl {
nsIEventTarget* aMainEventTarget);
// Forwarded from BackgroundChild.
static void CloseForCurrentThread();
static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread(
nsIEventTarget* aMainEventTarget);
static void CloseThreadWithIndex(unsigned int aThreadLocalIndex);
static void CloseForCurrentThread();
// Forwarded from BackgroundChildImpl.
static BackgroundChildImpl::ThreadLocal* GetThreadLocalForCurrentThread();
@ -553,11 +695,13 @@ class ChildImpl::SendInitBackgroundRunnable final : public CancelableRunnable {
mozilla::Mutex mMutex;
bool mSentInitBackground;
std::function<void(Endpoint<PBackgroundParent>&& aParent)> mSendInitfunc;
unsigned int mThreadLocalIndex;
public:
static already_AddRefed<SendInitBackgroundRunnable> Create(
Endpoint<PBackgroundParent>&& aParent,
std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc);
std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
unsigned int aThreadLocalIndex);
void ClearEventTarget() {
mWorkerRef = nullptr;
@ -569,13 +713,15 @@ class ChildImpl::SendInitBackgroundRunnable final : public CancelableRunnable {
private:
explicit SendInitBackgroundRunnable(
Endpoint<PBackgroundParent>&& aParent,
std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc)
std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
unsigned int aThreadLocalIndex)
: CancelableRunnable("Background::ChildImpl::SendInitBackgroundRunnable"),
mOwningEventTarget(GetCurrentThreadSerialEventTarget()),
mParent(std::move(aParent)),
mMutex("SendInitBackgroundRunnable::mMutex"),
mSentInitBackground(false),
mSendInitfunc(std::move(aFunc)) {}
mSendInitfunc(std::move(aFunc)),
mThreadLocalIndex(aThreadLocalIndex) {}
~SendInitBackgroundRunnable() = default;
@ -662,6 +808,14 @@ PBackgroundChild* BackgroundChild::GetOrCreateSocketActorForCurrentThread(
return ChildImpl::GetOrCreateSocketActorForCurrentThread(aMainEventTarget);
}
// static
PBackgroundChild*
BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread(
nsIEventTarget* aMainEventTarget) {
return ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
aMainEventTarget);
}
// static
void BackgroundChild::CloseForCurrentThread() {
ChildImpl::CloseForCurrentThread();
@ -701,9 +855,238 @@ bool ParentImpl::sShutdownHasStarted = false;
// ChildImpl Static Members
// -----------------------------------------------------------------------------
unsigned int ChildImpl::sThreadLocalIndex = kBadThreadLocalIndex;
unsigned int ChildImpl::sThreadLocalIndexForSocketProcess =
kBadThreadLocalIndex;
static void ParentContentActorCreateFunc(
ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
ChildImpl** aOutput) {
if (XRE_IsParentProcess()) {
RefPtr<ChildImpl> strongActor =
ParentImpl::CreateActorForSameProcess(aMainEventTarget);
if (NS_WARN_IF(!strongActor)) {
return;
}
aThreadLocalInfo->mActor = strongActor;
strongActor.forget(aOutput);
return;
}
RefPtr<ContentChild> content = ContentChild::GetSingleton();
MOZ_ASSERT(content);
if (content->IsShuttingDown()) {
// The transport for ContentChild is shut down and can't be used to open
// PBackground.
return;
}
Endpoint<PBackgroundParent> parent;
Endpoint<PBackgroundChild> child;
nsresult rv;
rv = PBackground::CreateEndpoints(content->OtherPid(),
base::GetCurrentProcId(), &parent, &child);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create top level actor!");
return;
}
RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
if (!NS_IsMainThread()) {
runnable = ChildImpl::SendInitBackgroundRunnable::Create(
std::move(parent),
[](Endpoint<PBackgroundParent>&& aParent) {
RefPtr<ContentChild> content = ContentChild::GetSingleton();
MOZ_ASSERT(content);
if (!content->SendInitBackground(std::move(aParent))) {
NS_WARNING("Failed to create top level actor!");
}
},
aThreadLocalIndex);
if (!runnable) {
return;
}
}
RefPtr<ChildImpl> strongActor = new ChildImpl();
if (!child.Bind(strongActor)) {
CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
return;
}
strongActor->SetActorAlive();
if (NS_IsMainThread()) {
if (!content->SendInitBackground(std::move(parent))) {
NS_WARNING("Failed to create top level actor!");
return;
}
} else {
if (aMainEventTarget) {
MOZ_ALWAYS_SUCCEEDS(
aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
} else {
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
}
aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
}
aThreadLocalInfo->mActor = strongActor;
strongActor.forget(aOutput);
}
ChildImpl::ThreadInfoWrapper ChildImpl::sParentAndContentProcessThreadInfo(
ParentContentActorCreateFunc);
static void SocketContentActorCreateFunc(
ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
ChildImpl** aOutput) {
RefPtr<SocketProcessBridgeChild> bridgeChild =
SocketProcessBridgeChild::GetSingleton();
if (!bridgeChild || bridgeChild->IsShuttingDown()) {
// The transport for SocketProcessBridgeChild is shut down
// and can't be used to open PBackground.
return;
}
Endpoint<PBackgroundParent> parent;
Endpoint<PBackgroundChild> child;
nsresult rv;
rv = PBackground::CreateEndpoints(bridgeChild->SocketProcessPid(),
base::GetCurrentProcId(), &parent, &child);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create top level actor!");
return;
}
RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
if (!NS_IsMainThread()) {
runnable = ChildImpl::SendInitBackgroundRunnable::Create(
std::move(parent),
[](Endpoint<PBackgroundParent>&& aParent) {
RefPtr<SocketProcessBridgeChild> bridgeChild =
SocketProcessBridgeChild::GetSingleton();
if (!bridgeChild->SendInitBackground(std::move(aParent))) {
NS_WARNING("Failed to create top level actor!");
}
},
aThreadLocalIndex);
if (!runnable) {
return;
}
}
RefPtr<ChildImpl> strongActor = new ChildImpl();
if (!child.Bind(strongActor)) {
CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
return;
}
strongActor->SetActorAlive();
if (NS_IsMainThread()) {
if (!bridgeChild->SendInitBackground(std::move(parent))) {
NS_WARNING("Failed to create top level actor!");
// Need to close the IPC channel before ChildImpl getting deleted.
strongActor->Close();
strongActor->AssertActorDestroyed();
return;
}
} else {
if (aMainEventTarget) {
MOZ_ALWAYS_SUCCEEDS(
aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
} else {
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
}
aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
}
aThreadLocalInfo->mActor = strongActor;
strongActor.forget(aOutput);
}
ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndContentProcessThreadInfo(
SocketContentActorCreateFunc);
static void SocketParentActorCreateFunc(
ChildImpl::ThreadLocalInfo* aThreadLocalInfo,
unsigned int aThreadLocalIndex, nsIEventTarget* aMainEventTarget,
ChildImpl** aOutput) {
SocketProcessChild* socketChild = SocketProcessChild::GetSingleton();
if (!socketChild || socketChild->IsShuttingDown()) {
return;
}
Endpoint<PBackgroundParent> parent;
Endpoint<PBackgroundChild> child;
nsresult rv;
rv = PBackground::CreateEndpoints(socketChild->OtherPid(),
base::GetCurrentProcId(), &parent, &child);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create top level actor!");
return;
}
RefPtr<ChildImpl::SendInitBackgroundRunnable> runnable;
if (!NS_IsMainThread()) {
runnable = ChildImpl::SendInitBackgroundRunnable::Create(
std::move(parent),
[](Endpoint<PBackgroundParent>&& aParent) {
SocketProcessChild* socketChild = SocketProcessChild::GetSingleton();
MOZ_ASSERT(socketChild);
if (!socketChild->SendInitBackground(std::move(aParent))) {
MOZ_CRASH("Failed to create top level actor!");
}
},
aThreadLocalIndex);
if (!runnable) {
return;
}
}
RefPtr<ChildImpl> strongActor = new ChildImpl();
if (!child.Bind(strongActor)) {
CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
return;
}
strongActor->SetActorAlive();
if (NS_IsMainThread()) {
if (!socketChild->SendInitBackground(std::move(parent))) {
NS_WARNING("Failed to create top level actor!");
return;
}
} else {
if (aMainEventTarget) {
MOZ_ALWAYS_SUCCEEDS(
aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
} else {
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
}
aThreadLocalInfo->mSendInitBackgroundRunnable = runnable;
}
aThreadLocalInfo->mActor = strongActor;
strongActor.forget(aOutput);
}
ChildImpl::ThreadInfoWrapper ChildImpl::sSocketAndParentProcessThreadInfo(
SocketParentActorCreateFunc);
bool ChildImpl::sShutdownHasStarted = false;
@ -1040,7 +1423,6 @@ void ParentImpl::Destroy() {
void ParentImpl::MainThreadActorDestroy() {
AssertIsInMainOrSocketProcess();
AssertIsOnMainThread();
MOZ_ASSERT_IF(mIsOtherProcessActor && XRE_IsParentProcess(), mContent);
MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
mContent = nullptr;
@ -1093,11 +1475,7 @@ ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
// Do this first before calling (and spinning the event loop in)
// ShutdownBackgroundThread().
// Since we didn't call BackgroundChild::Startup() in socket process,
// we can't call ChildImpl::Shutdown() here.
if (!XRE_IsSocketProcess()) {
ChildImpl::Shutdown();
}
ChildImpl::Shutdown();
ShutdownBackgroundThread();
@ -1281,21 +1659,9 @@ void ChildImpl::Startup() {
// This happens on the main thread but before XPCOM has started so we can't
// assert that we're being called on the main thread here.
MOZ_ASSERT(sThreadLocalIndex == kBadThreadLocalIndex,
"BackgroundChild::Startup() called more than once!");
MOZ_ASSERT(sThreadLocalIndexForSocketProcess == kBadThreadLocalIndex,
"BackgroundChild::Startup() called more than once!");
PRStatus status =
PR_NewThreadPrivateIndex(&sThreadLocalIndex, ThreadLocalDestructor);
MOZ_RELEASE_ASSERT(status == PR_SUCCESS, "PR_NewThreadPrivateIndex failed!");
status = PR_NewThreadPrivateIndex(&sThreadLocalIndexForSocketProcess,
ThreadLocalDestructor);
MOZ_RELEASE_ASSERT(status == PR_SUCCESS, "PR_NewThreadPrivateIndex failed!");
MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
MOZ_ASSERT(sThreadLocalIndexForSocketProcess != kBadThreadLocalIndex);
sParentAndContentProcessThreadInfo.Startup();
sSocketAndContentProcessThreadInfo.Startup();
sSocketAndParentProcessThreadInfo.Startup();
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
MOZ_RELEASE_ASSERT(observerService);
@ -1307,67 +1673,27 @@ void ChildImpl::Startup() {
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}
void ChildImpl::ShutdownWithThreadLocalIndex(unsigned int aThreadLocalIndex) {
MOZ_ASSERT(aThreadLocalIndex != kBadThreadLocalIndex);
ThreadLocalInfo* threadLocalInfo;
#ifdef DEBUG
threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(aThreadLocalIndex));
MOZ_ASSERT(!threadLocalInfo);
#endif
threadLocalInfo = aThreadLocalIndex == sThreadLocalIndex
? sMainThreadInfo
: sMainThreadInfoForSocketProcess;
if (threadLocalInfo) {
#ifdef DEBUG
MOZ_ASSERT(!threadLocalInfo->mClosed);
threadLocalInfo->mClosed = true;
#endif
ThreadLocalDestructor(threadLocalInfo);
if (aThreadLocalIndex == sThreadLocalIndex) {
sMainThreadInfo = nullptr;
} else {
sMainThreadInfoForSocketProcess = nullptr;
}
}
}
// static
void ChildImpl::Shutdown() {
AssertIsOnMainThread();
if (sShutdownHasStarted) {
MOZ_ASSERT_IF(sThreadLocalIndex != kBadThreadLocalIndex,
!PR_GetThreadPrivate(sThreadLocalIndex));
MOZ_ASSERT_IF(sThreadLocalIndexForSocketProcess != kBadThreadLocalIndex,
!PR_GetThreadPrivate(sThreadLocalIndexForSocketProcess));
return;
}
sParentAndContentProcessThreadInfo.Shutdown();
sSocketAndContentProcessThreadInfo.Shutdown();
sSocketAndParentProcessThreadInfo.Shutdown();
sShutdownHasStarted = true;
ShutdownWithThreadLocalIndex(sThreadLocalIndex);
if (sThreadLocalIndexForSocketProcess != kBadThreadLocalIndex) {
ShutdownWithThreadLocalIndex(sThreadLocalIndexForSocketProcess);
}
}
ChildImpl::ThreadLocalInfo* ChildImpl::sMainThreadInfo = nullptr;
ChildImpl::ThreadLocalInfo* ChildImpl::sMainThreadInfoForSocketProcess =
nullptr;
// static
PBackgroundChild* ChildImpl::GetForCurrentThread() {
MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
kBadThreadLocalIndex);
auto threadLocalInfo = NS_IsMainThread()
? sMainThreadInfo
: static_cast<ThreadLocalInfo*>(
PR_GetThreadPrivate(sThreadLocalIndex));
auto threadLocalInfo =
NS_IsMainThread()
? sParentAndContentProcessThreadInfo.mMainThreadInfo
: static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
sParentAndContentProcessThreadInfo.mThreadLocalIndex));
if (!threadLocalInfo) {
return nullptr;
@ -1414,247 +1740,22 @@ PBackgroundChild* ChildImpl::GetFromThreadInfo(
/* static */
PBackgroundChild* ChildImpl::GetOrCreateForCurrentThread(
nsIEventTarget* aMainEventTarget) {
MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget);
MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
"BackgroundChild::Startup() was never called!");
if (NS_IsMainThread() && sShutdownHasStarted) {
return nullptr;
}
auto threadLocalInfo = NS_IsMainThread()
? sMainThreadInfo
: static_cast<ThreadLocalInfo*>(
PR_GetThreadPrivate(sThreadLocalIndex));
if (!threadLocalInfo) {
auto newInfo = MakeUnique<ThreadLocalInfo>();
if (NS_IsMainThread()) {
sMainThreadInfo = newInfo.get();
} else {
if (PR_SetThreadPrivate(sThreadLocalIndex, newInfo.get()) != PR_SUCCESS) {
CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
return nullptr;
}
}
threadLocalInfo = newInfo.release();
}
PBackgroundChild* bgChild =
GetFromThreadInfo(aMainEventTarget, threadLocalInfo);
if (bgChild) {
return bgChild;
}
if (XRE_IsParentProcess()) {
RefPtr<ChildImpl> strongActor =
ParentImpl::CreateActorForSameProcess(aMainEventTarget);
if (NS_WARN_IF(!strongActor)) {
return nullptr;
}
RefPtr<ChildImpl>& actor = threadLocalInfo->mActor;
strongActor.swap(actor);
return actor;
}
RefPtr<ContentChild> content = ContentChild::GetSingleton();
MOZ_ASSERT(content);
if (content->IsShuttingDown()) {
// The transport for ContentChild is shut down and can't be used to open
// PBackground.
return nullptr;
}
Endpoint<PBackgroundParent> parent;
Endpoint<PBackgroundChild> child;
nsresult rv;
rv = PBackground::CreateEndpoints(content->OtherPid(),
base::GetCurrentProcId(), &parent, &child);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create top level actor!");
return nullptr;
}
RefPtr<SendInitBackgroundRunnable> runnable;
if (!NS_IsMainThread()) {
runnable = SendInitBackgroundRunnable::Create(
std::move(parent), [](Endpoint<PBackgroundParent>&& aParent) {
RefPtr<ContentChild> content = ContentChild::GetSingleton();
MOZ_ASSERT(content);
if (!content->SendInitBackground(std::move(aParent))) {
NS_WARNING("Failed to create top level actor!");
}
});
if (!runnable) {
return nullptr;
}
}
RefPtr<ChildImpl> strongActor = new ChildImpl();
if (!child.Bind(strongActor)) {
CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
return nullptr;
}
strongActor->SetActorAlive();
if (NS_IsMainThread()) {
if (!content->SendInitBackground(std::move(parent))) {
NS_WARNING("Failed to create top level actor!");
return nullptr;
}
} else {
if (aMainEventTarget) {
MOZ_ALWAYS_SUCCEEDS(
aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
} else {
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
}
threadLocalInfo->mSendInitBackgroundRunnable = runnable;
}
RefPtr<ChildImpl>& actor = threadLocalInfo->mActor;
strongActor.swap(actor);
return actor;
return sParentAndContentProcessThreadInfo.GetOrCreateForCurrentThread(
aMainEventTarget);
}
/* static */
PBackgroundChild* ChildImpl::GetOrCreateSocketActorForCurrentThread(
nsIEventTarget* aMainEventTarget) {
MOZ_ASSERT_IF(NS_IsMainThread(), !aMainEventTarget);
MOZ_ASSERT(sThreadLocalIndexForSocketProcess != kBadThreadLocalIndex,
"BackgroundChild::Startup() was never called!");
if (NS_IsMainThread() && sShutdownHasStarted) {
return nullptr;
}
auto threadLocalInfo =
NS_IsMainThread() ? sMainThreadInfoForSocketProcess
: static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
sThreadLocalIndexForSocketProcess));
if (!threadLocalInfo) {
auto newInfo = MakeUnique<ThreadLocalInfo>();
if (NS_IsMainThread()) {
sMainThreadInfoForSocketProcess = newInfo.get();
} else {
if (PR_SetThreadPrivate(sThreadLocalIndexForSocketProcess,
newInfo.get()) != PR_SUCCESS) {
CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
return nullptr;
}
}
threadLocalInfo = newInfo.release();
}
PBackgroundChild* bgChild =
GetFromThreadInfo(aMainEventTarget, threadLocalInfo);
if (bgChild) {
return bgChild;
}
RefPtr<SocketProcessBridgeChild> bridgeChild =
SocketProcessBridgeChild::GetSingleton();
if (!bridgeChild || bridgeChild->IsShuttingDown()) {
// The transport for SocketProcessBridgeChild is shut down
// and can't be used to open PBackground.
return nullptr;
}
Endpoint<PBackgroundParent> parent;
Endpoint<PBackgroundChild> child;
nsresult rv;
rv = PBackground::CreateEndpoints(bridgeChild->SocketProcessPid(),
base::GetCurrentProcId(), &parent, &child);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create top level actor!");
return nullptr;
}
RefPtr<SendInitBackgroundRunnable> runnable;
if (!NS_IsMainThread()) {
runnable = SendInitBackgroundRunnable::Create(
std::move(parent), [](Endpoint<PBackgroundParent>&& aParent) {
RefPtr<SocketProcessBridgeChild> bridgeChild =
SocketProcessBridgeChild::GetSingleton();
if (!bridgeChild->SendInitBackground(std::move(aParent))) {
NS_WARNING("Failed to create top level actor!");
}
});
if (!runnable) {
return nullptr;
}
}
RefPtr<ChildImpl> strongActor = new ChildImpl();
if (!child.Bind(strongActor)) {
CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
return nullptr;
}
strongActor->SetActorAlive();
if (NS_IsMainThread()) {
if (!bridgeChild->SendInitBackground(std::move(parent))) {
NS_WARNING("Failed to create top level actor!");
// Need to close the IPC channel before ChildImpl getting deleted.
strongActor->Close();
strongActor->AssertActorDestroyed();
return nullptr;
}
} else {
if (aMainEventTarget) {
MOZ_ALWAYS_SUCCEEDS(
aMainEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
} else {
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
}
threadLocalInfo->mSendInitBackgroundRunnable = runnable;
}
RefPtr<ChildImpl>& actor = threadLocalInfo->mActor;
strongActor.swap(actor);
return actor;
return sSocketAndContentProcessThreadInfo.GetOrCreateForCurrentThread(
aMainEventTarget);
}
// static
void ChildImpl::CloseThreadWithIndex(unsigned int aThreadLocalIndex) {
auto threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(aThreadLocalIndex));
if (!threadLocalInfo) {
return;
}
#ifdef DEBUG
MOZ_ASSERT(!threadLocalInfo->mClosed);
threadLocalInfo->mClosed = true;
#endif
// Clearing the thread local will synchronously close the actor.
DebugOnly<PRStatus> status = PR_SetThreadPrivate(aThreadLocalIndex, nullptr);
MOZ_ASSERT(status == PR_SUCCESS);
/* static */
PBackgroundChild* ChildImpl::GetOrCreateForSocketParentBridgeForCurrentThread(
nsIEventTarget* aMainEventTarget) {
return sSocketAndParentProcessThreadInfo.GetOrCreateForCurrentThread(
aMainEventTarget);
}
// static
@ -1663,23 +1764,22 @@ void ChildImpl::CloseForCurrentThread() {
"PBackground for the main thread should be shut down via "
"ChildImpl::Shutdown().");
if (sThreadLocalIndex != kBadThreadLocalIndex) {
CloseThreadWithIndex(sThreadLocalIndex);
}
if (sThreadLocalIndexForSocketProcess != kBadThreadLocalIndex) {
CloseThreadWithIndex(sThreadLocalIndexForSocketProcess);
}
sParentAndContentProcessThreadInfo.CloseForCurrentThread();
sSocketAndContentProcessThreadInfo.CloseForCurrentThread();
sSocketAndParentProcessThreadInfo.CloseForCurrentThread();
}
// static
BackgroundChildImpl::ThreadLocal* ChildImpl::GetThreadLocalForCurrentThread() {
MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
MOZ_ASSERT(sParentAndContentProcessThreadInfo.mThreadLocalIndex !=
kBadThreadLocalIndex,
"BackgroundChild::Startup() was never called!");
auto threadLocalInfo = NS_IsMainThread()
? sMainThreadInfo
: static_cast<ThreadLocalInfo*>(
PR_GetThreadPrivate(sThreadLocalIndex));
auto threadLocalInfo =
NS_IsMainThread()
? sParentAndContentProcessThreadInfo.mMainThreadInfo
: static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(
sParentAndContentProcessThreadInfo.mThreadLocalIndex));
if (!threadLocalInfo) {
return nullptr;
@ -1741,11 +1841,12 @@ ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
already_AddRefed<ChildImpl::SendInitBackgroundRunnable>
ChildImpl::SendInitBackgroundRunnable::Create(
Endpoint<PBackgroundParent>&& aParent,
std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc) {
std::function<void(Endpoint<PBackgroundParent>&& aParent)>&& aFunc,
unsigned int aThreadLocalIndex) {
MOZ_ASSERT(!NS_IsMainThread());
RefPtr<SendInitBackgroundRunnable> runnable =
new SendInitBackgroundRunnable(std::move(aParent), std::move(aFunc));
RefPtr<SendInitBackgroundRunnable> runnable = new SendInitBackgroundRunnable(
std::move(aParent), std::move(aFunc), aThreadLocalIndex);
WorkerPrivate* workerPrivate = mozilla::dom::GetCurrentThreadWorkerPrivate();
if (!workerPrivate) {
@ -1795,7 +1896,7 @@ ChildImpl::SendInitBackgroundRunnable::Run() {
ClearEventTarget();
auto threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(mThreadLocalIndex));
if (!threadLocalInfo) {
return NS_OK;

View File

@ -19,6 +19,7 @@ namespace mozilla {
namespace net {
class SocketProcessBridgeParent;
class SocketProcessParent;
} // namespace net
@ -46,6 +47,7 @@ class BackgroundParent final {
typedef mozilla::dom::ContentParent ContentParent;
typedef mozilla::ipc::Transport Transport;
friend class mozilla::net::SocketProcessBridgeParent;
friend class mozilla::net::SocketProcessParent;
public:
// This function allows the caller to determine if the given parent actor
@ -82,7 +84,8 @@ class BackgroundParent final {
static bool Alloc(ContentParent* aContent,
Endpoint<PBackgroundParent>&& aEndpoint);
// Only called by SocketProcessBridgeParent for cross-process actors.
// Called by SocketProcessBridgeParent and SocketProcessParent for
// cross-process actors.
static bool Alloc(Endpoint<PBackgroundParent>&& aEndpoint);
};

View File

@ -13,6 +13,7 @@ include protocol PFileDescriptorSet;
include protocol PChildToParentStream;
include protocol PParentToChildStream;
include protocol PInputChannelThrottleQueue;
include protocol PBackground;
include MemoryReportTypes;
include NeckoChannelParams;
@ -67,6 +68,7 @@ parent:
PRTime aTimestamp,
uint64_t aExtraSizeData,
nsCString aExtraStringData);
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
child:
async PreferenceUpdate(Pref pref);

View File

@ -13,6 +13,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/dom/MemoryReportRequest.h"
#include "mozilla/ipc/CrashReporterClient.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/FileDescriptorSetChild.h"
#include "mozilla/ipc/IPCStreamAlloc.h"
#include "mozilla/ipc/ProcessChild.h"
@ -40,9 +41,9 @@ namespace net {
using namespace ipc;
static SocketProcessChild* sSocketProcessChild;
SocketProcessChild* sSocketProcessChild;
SocketProcessChild::SocketProcessChild() {
SocketProcessChild::SocketProcessChild() : mShuttingDown(false) {
LOG(("CONSTRUCT SocketProcessChild::SocketProcessChild\n"));
nsDebugImpl::SetMultiprocessMode("Socket");
@ -93,6 +94,7 @@ bool SocketProcessChild::Init(base::ProcessId aParentPid,
return false;
}
BackgroundChild::Startup();
SetThisProcessName("Socket Process");
#if defined(XP_MACOSX)
// Close all current connections to the WindowServer. This ensures that the
@ -106,6 +108,8 @@ bool SocketProcessChild::Init(base::ProcessId aParentPid,
void SocketProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
LOG(("SocketProcessChild::ActorDestroy\n"));
mShuttingDown = true;
if (AbnormalShutdown == aWhy) {
NS_WARNING("Shutting down Socket process early due to a crash!");
ProcessChild::QuickExit();

View File

@ -25,8 +25,9 @@ class SocketProcessChild final
: public PSocketProcessChild,
public mozilla::ipc::ChildToParentStreamActorManager {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SocketProcessChild)
SocketProcessChild();
~SocketProcessChild();
static SocketProcessChild* GetSingleton();
@ -78,6 +79,12 @@ class SocketProcessChild final
AllocPInputChannelThrottleQueueChild(const uint32_t& aMeanBytesPerSecond,
const uint32_t& aMaxBytesPerSecond);
bool IsShuttingDown() { return mShuttingDown; }
protected:
friend class SocketProcessImpl;
~SocketProcessChild();
private:
// Mapping of content process id and the SocketProcessBridgeParent.
// This table keeps SocketProcessBridgeParent alive in socket process.
@ -87,6 +94,8 @@ class SocketProcessChild final
#ifdef MOZ_GECKO_PROFILER
RefPtr<ChildProfilerController> mProfilerController;
#endif
bool mShuttingDown;
};
} // namespace net

View File

@ -226,6 +226,16 @@ mozilla::ipc::IPCResult SocketProcessParent::RecvObserveHttpActivity(
return IPC_OK();
}
mozilla::ipc::IPCResult SocketProcessParent::RecvInitBackground(
Endpoint<PBackgroundParent>&& aEndpoint) {
LOG(("SocketProcessParent::RecvInitBackground\n"));
if (!ipc::BackgroundParent::Alloc(nullptr, std::move(aEndpoint))) {
return IPC_FAIL(this, "BackgroundParent::Alloc failed");
}
return IPC_OK();
}
// To ensure that IPDL is finished before SocketParent gets deleted.
class DeferredDeleteSocketProcessParent : public Runnable {
public:

View File

@ -7,6 +7,7 @@
#define mozilla_net_SocketProcessParent_h
#include "mozilla/UniquePtr.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/CrashReporterHelper.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/net/PSocketProcessParent.h"
@ -93,6 +94,9 @@ class SocketProcessParent final
const uint32_t& aActivitySubtype, const PRTime& aTimestamp,
const uint64_t& aExtraSizeData, const nsCString& aExtraStringData);
mozilla::ipc::IPCResult RecvInitBackground(
Endpoint<PBackgroundParent>&& aEndpoint);
private:
SocketProcessHost* mHost;
UniquePtr<dom::MemoryReportRequestHost> mMemoryReportRequest;