Bug 977762 - 'Provide a mechanism to get the PContentParent associated with a PBackgroundParent'. r=mrbkap.

This commit is contained in:
Ben Turner 2014-02-27 11:59:12 -08:00
parent 85bbd9301e
commit f90d07c4fd
2 changed files with 132 additions and 23 deletions

View File

@ -35,6 +35,12 @@
#include "nsXPCOMPrivate.h"
#include "prthread.h"
#ifdef RELEASE_BUILD
#define THREADSAFETY_ASSERT MOZ_ASSERT
#else
#define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
#endif
#define CRASH_IN_CHILD_PROCESS(_msg) \
do { \
if (IsMainProcess()) { \
@ -86,7 +92,7 @@ AssertIsInChildProcess()
void
AssertIsOnMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
THREADSAFETY_ASSERT(NS_IsMainThread());
}
// -----------------------------------------------------------------------------
@ -174,10 +180,18 @@ private:
// deleting it on the wrong thread. Only non-null for other-process actors.
Transport* mTransport;
// Set when the actor is opened successfully and used to handle shutdown
// hangs. Only touched on the background thread.
nsTArray<ParentImpl*>* mLiveActorArray;
// Used to assert things in DEBUG builds.
DebugOnly<bool> mIsOtherProcessActorDEBUG;
// Set at construction to indicate whether this parent actor corresponds to a
// child actor in another process or to a child actor from a different thread
// in the same process.
const bool mIsOtherProcessActor;
// Set after ActorDestroy has been called. Only touched on the background
// thread.
bool mActorDestroyed;
public:
static bool
@ -192,7 +206,7 @@ public:
static void
AssertIsOnBackgroundThread()
{
MOZ_ASSERT(IsOnBackgroundThread());
THREADSAFETY_ASSERT(IsOnBackgroundThread());
}
NS_INLINE_DECL_REFCOUNTING(ParentImpl)
@ -201,6 +215,14 @@ public:
Destroy();
private:
// Forwarded from BackgroundParent.
static bool
IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
// Forwarded from BackgroundParent.
static already_AddRefed<ContentParent>
GetContentParent(PBackgroundParent* aBackgroundActor);
// Forwarded from BackgroundParent.
static PBackgroundParent*
Alloc(ContentParent* aContent,
@ -218,8 +240,8 @@ private:
// For same-process actors.
ParentImpl()
: mTransport(nullptr), mLiveActorArray(nullptr),
mIsOtherProcessActorDEBUG(false)
: mTransport(nullptr), mLiveActorArray(nullptr), mIsOtherProcessActor(false),
mActorDestroyed(false)
{
AssertIsInMainProcess();
AssertIsOnMainThread();
@ -230,7 +252,7 @@ private:
// For other-process actors.
ParentImpl(ContentParent* aContent, Transport* aTransport)
: mContent(aContent), mTransport(aTransport), mLiveActorArray(nullptr),
mIsOtherProcessActorDEBUG(true)
mIsOtherProcessActor(true), mActorDestroyed(false)
{
AssertIsInMainProcess();
AssertIsOnMainThread();
@ -257,7 +279,7 @@ private:
MOZ_ASSERT(aLiveActorArray);
MOZ_ASSERT(!aLiveActorArray->Contains(this));
MOZ_ASSERT(!mLiveActorArray);
MOZ_ASSERT(mIsOtherProcessActorDEBUG);
MOZ_ASSERT(mIsOtherProcessActor);
mLiveActorArray = aLiveActorArray;
mLiveActorArray->AppendElement(this);
@ -318,7 +340,11 @@ class ChildImpl MOZ_FINAL : public BackgroundChildImpl
// create the background thread after application shutdown has started.
static bool sShutdownHasStarted;
#ifdef RELEASE_BUILD
DebugOnly<nsIThread*> mBoundThread;
#else
nsIThread* mBoundThread;
#endif
public:
static bool
@ -330,15 +356,18 @@ public:
void
AssertIsOnBoundThread()
{
MOZ_ASSERT(mBoundThread);
THREADSAFETY_ASSERT(mBoundThread);
#ifdef RELEASE_BUILD
DebugOnly<bool> current;
MOZ_ASSERT(NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(&current)));
MOZ_ASSERT(current);
#else
bool current;
#endif
THREADSAFETY_ASSERT(
NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(&current)));
THREADSAFETY_ASSERT(current);
}
ChildImpl()
: mBoundThread(nullptr)
{
@ -387,11 +416,13 @@ private:
void
SetBoundThread()
{
#ifdef DEBUG
MOZ_ASSERT(!mBoundThread);
THREADSAFETY_ASSERT(!mBoundThread);
#if defined(DEBUG) || !defined(RELEASE_BUILD)
mBoundThread = NS_GetCurrentThread();
MOZ_ASSERT(mBoundThread);
#endif
THREADSAFETY_ASSERT(mBoundThread);
}
// Only called by IPDL.
@ -740,6 +771,20 @@ AssertIsOnBackgroundThread()
// BackgroundParent Public Methods
// -----------------------------------------------------------------------------
// static
bool
BackgroundParent::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
{
return ParentImpl::IsOtherProcessActor(aBackgroundActor);
}
// static
already_AddRefed<ContentParent>
BackgroundParent::GetContentParent(PBackgroundParent* aBackgroundActor)
{
return ParentImpl::GetContentParent(aBackgroundActor);
}
// static
PBackgroundParent*
BackgroundParent::Alloc(ContentParent* aContent,
@ -826,6 +871,46 @@ bool ChildImpl::sShutdownHasStarted = false;
// ParentImpl Implementation
// -----------------------------------------------------------------------------
// static
bool
ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aBackgroundActor);
return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
}
// static
already_AddRefed<ContentParent>
ParentImpl::GetContentParent(PBackgroundParent* aBackgroundActor)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aBackgroundActor);
auto actor = static_cast<ParentImpl*>(aBackgroundActor);
if (actor->mActorDestroyed) {
MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
return nullptr;
}
if (actor->mContent) {
// We need to hand out a reference to our ContentParent but we also need to
// keep the one we have. We can't call AddRef here because ContentParent is
// not threadsafe so instead we dispatch a runnable to the main thread to do
// it for us. This is safe since we are guaranteed that our AddRef runnable
// will run before the reference we hand out can be released, and the
// ContentParent can't die as long as the existing reference is maintained.
nsCOMPtr<nsIRunnable> runnable =
NS_NewNonOwningRunnableMethod(actor->mContent, &ContentParent::AddRef);
MOZ_ASSERT(runnable);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
}
return actor->mContent.get();
}
// static
PBackgroundParent*
ParentImpl::Alloc(ContentParent* aContent,
@ -1095,10 +1180,10 @@ ParentImpl::MainThreadActorDestroy()
{
AssertIsInMainProcess();
AssertIsOnMainThread();
MOZ_ASSERT_IF(mIsOtherProcessActorDEBUG, mContent);
MOZ_ASSERT_IF(!mIsOtherProcessActorDEBUG, !mContent);
MOZ_ASSERT_IF(mIsOtherProcessActorDEBUG, mTransport);
MOZ_ASSERT_IF(!mIsOtherProcessActorDEBUG, !mTransport);
MOZ_ASSERT_IF(mIsOtherProcessActor, mContent);
MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
MOZ_ASSERT_IF(mIsOtherProcessActor, mTransport);
MOZ_ASSERT_IF(!mIsOtherProcessActor, !mTransport);
if (mTransport) {
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
@ -1167,10 +1252,13 @@ ParentImpl::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT_IF(mIsOtherProcessActorDEBUG, mLiveActorArray);
MOZ_ASSERT(!mActorDestroyed);
MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
BackgroundParentImpl::ActorDestroy(aWhy);
mActorDestroyed = true;
if (mLiveActorArray) {
MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
mLiveActorArray = nullptr;

View File

@ -9,6 +9,8 @@
#include "mozilla/Attributes.h"
#include "mozilla/ipc/Transport.h"
template <class> class already_AddRefed;
namespace mozilla {
namespace dom {
@ -20,8 +22,8 @@ namespace ipc {
class PBackgroundParent;
// This class is not designed for public consumption. It must only be used by
// ContentParent.
// This class is not designed for public consumption beyond the few static
// member functions.
class BackgroundParent MOZ_FINAL
{
friend class mozilla::dom::ContentParent;
@ -30,6 +32,25 @@ class BackgroundParent MOZ_FINAL
typedef mozilla::dom::ContentParent ContentParent;
typedef mozilla::ipc::Transport Transport;
public:
// This function allows the caller to determine if the given parent actor
// corresponds to a child actor from another process or a child actor from a
// different thread in the same process.
// This function may only be called on the background thread.
static bool
IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
// This function returns the ContentParent associated with the parent actor if
// the parent actor corresponds to a child actor from another process. If the
// parent actor corresponds to a child actor from a different thread in the
// same process then this function returns null.
// This function may only be called on the background thread. However,
// ContentParent is not threadsafe and the returned pointer may not be used on
// any thread other than the main thread. Callers must take care to use (and
// release) the returned pointer appropriately.
static already_AddRefed<ContentParent>
GetContentParent(PBackgroundParent* aBackgroundActor);
private:
// Only called by ContentParent for cross-process actors.
static PBackgroundParent*