Skip to content
This repository has been archived by the owner on Aug 4, 2022. It is now read-only.

Commit

Permalink
Bug 1317844 - Allow an event target to be specified for each IPC acto…
Browse files Browse the repository at this point in the history
…r (r=dvander)

MozReview-Commit-ID: 1xuWFTS8skZ
  • Loading branch information
bill-mccloskey committed Nov 22, 2016
1 parent 5e3aff9 commit 30396b9
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 15 deletions.
9 changes: 8 additions & 1 deletion ipc/glue/MessageChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1628,7 +1628,14 @@ MessageChannel::MessageTask::Post()
mScheduled = true;

RefPtr<MessageTask> self = this;
mChannel->mWorkerLoop->PostTask(self.forget());
nsCOMPtr<nsIEventTarget> eventTarget =
mChannel->mListener->GetMessageEventTarget(mMessage);

if (eventTarget) {
eventTarget->Dispatch(self.forget(), NS_DISPATCH_NORMAL);
} else {
mChannel->mWorkerLoop->PostTask(self.forget());
}
}

void
Expand Down
97 changes: 94 additions & 3 deletions ipc/glue/ProtocolUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,9 @@ IProtocol::Lookup(int32_t aId)
void
IProtocol::Unregister(int32_t aId)
{
if (mId == aId) {
mId = kFreedActorId;
}
Manager()->Unregister(aId);
}

Expand Down Expand Up @@ -518,12 +521,35 @@ IProtocol::DeallocShmem(Shmem& aMem)
return ok;
}

void
IProtocol::SetManager(IProtocol* aManager)
{
MOZ_RELEASE_ASSERT(!mManager || mManager == aManager);
mManager = aManager;
}

void
IProtocol::SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget)
{
// Make sure we have a manager for the internal method to access.
aActor->SetManager(this);
SetEventTargetForActorInternal(aActor, aEventTarget);
}

void
IProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
nsIEventTarget* aEventTarget)
{
Manager()->SetEventTargetForActorInternal(aActor, aEventTarget);
}

IToplevelProtocol::IToplevelProtocol(ProtocolId aProtoId, Side aSide)
: IProtocol(aSide),
mProtocolId(aProtoId),
mOtherPid(mozilla::ipc::kInvalidProcessId),
mLastRouteId(aSide == ParentSide ? 1 : 0),
mLastShmemId(aSide == ParentSide ? 1 : 0)
mLastRouteId(aSide == ParentSide ? kFreedActorId : kNullActorId),
mLastShmemId(aSide == ParentSide ? kFreedActorId : kNullActorId),
mEventTargetMutex("ProtocolEventTargetMutex")
{
}

Expand Down Expand Up @@ -598,8 +624,22 @@ IToplevelProtocol::IsOnCxxStack() const
int32_t
IToplevelProtocol::Register(IProtocol* aRouted)
{
if (aRouted->Id() != kNullActorId && aRouted->Id() != kFreedActorId) {
// If there's already an ID, just return that.
return aRouted->Id();
}
int32_t id = GetSide() == ParentSide ? ++mLastRouteId : --mLastRouteId;
mActorMap.AddWithID(aRouted, id);
aRouted->SetId(id);

// Inherit our event target from our manager.
if (IProtocol* manager = aRouted->Manager()) {
MutexAutoLock lock(mEventTargetMutex);
if (nsCOMPtr<nsIEventTarget> target = mEventTargetMap.Lookup(manager->Id())) {
mEventTargetMap.AddWithID(target, id);
}
}

return id;
}

Expand All @@ -608,6 +648,7 @@ IToplevelProtocol::RegisterID(IProtocol* aRouted,
int32_t aId)
{
mActorMap.AddWithID(aRouted, aId);
aRouted->SetId(aId);
return aId;
}

Expand All @@ -620,7 +661,10 @@ IToplevelProtocol::Lookup(int32_t aId)
void
IToplevelProtocol::Unregister(int32_t aId)
{
return mActorMap.Remove(aId);
mActorMap.Remove(aId);

MutexAutoLock lock(mEventTargetMutex);
mEventTargetMap.RemoveIfPresent(aId);
}

Shmem::SharedMemory*
Expand Down Expand Up @@ -726,5 +770,52 @@ IToplevelProtocol::ShmemDestroyed(const Message& aMsg)
return true;
}

already_AddRefed<nsIEventTarget>
IToplevelProtocol::GetMessageEventTarget(const Message& aMsg)
{
int32_t route = aMsg.routing_id();

MutexAutoLock lock(mEventTargetMutex);
nsCOMPtr<nsIEventTarget> target = mEventTargetMap.Lookup(route);

if (aMsg.is_constructor()) {
ActorHandle handle;
PickleIterator iter = PickleIterator(aMsg);
if (!IPC::ReadParam(&aMsg, &iter, &handle)) {
return nullptr;
}

// Normally a new actor inherits its event target from its manager. If the
// manager has no event target, we give the subclass a chance to make a new
// one.
if (!target) {
MutexAutoUnlock unlock(mEventTargetMutex);
target = GetConstructedEventTarget(aMsg);
}

mEventTargetMap.AddWithID(target, handle.mId);
}

return target.forget();
}

void
IToplevelProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
nsIEventTarget* aEventTarget)
{
// We should only call this function on actors that haven't been used for IPC
// code yet. Otherwise we'll be posting stuff to the wrong event target before
// we're called.
MOZ_RELEASE_ASSERT(aActor->Id() == kNullActorId || aActor->Id() == kFreedActorId);

// Register the actor early. When it's registered again, it will keep the same
// ID.
int32_t id = Register(aActor);
aActor->SetId(id);

MutexAutoLock lock(mEventTargetMutex);
mEventTargetMap.AddWithID(aEventTarget, id);
}

} // namespace ipc
} // namespace mozilla
36 changes: 34 additions & 2 deletions ipc/glue/ProtocolUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "prenv.h"

#include "IPCMessageStart.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Attributes.h"
#include "mozilla/ipc/FileDescriptor.h"
#include "mozilla/ipc/Shmem.h"
Expand Down Expand Up @@ -56,6 +57,8 @@ enum {

} // namespace

class nsIEventTarget;

namespace mozilla {
namespace dom {
class ContentParent;
Expand Down Expand Up @@ -141,6 +144,8 @@ enum RacyInterruptPolicy {
RIPParentWins
};

class IToplevelProtocol;

class IProtocol : public HasResultCodes
{
public:
Expand Down Expand Up @@ -196,11 +201,26 @@ class IProtocol : public HasResultCodes
bool AllocUnsafeShmem(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aOutMem);
bool DeallocShmem(Shmem& aMem);

// Sets an event target to which all messages for aActor will be
// dispatched. This method must be called before right before the SendPFoo
// message for aActor is sent. And SendPFoo *must* be called if
// SetEventTargetForActor is called. The receiver when calling
// SetEventTargetForActor must be the actor that will be the manager for
// aActor.
void SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget);

protected:
friend class IToplevelProtocol;

void SetId(int32_t aId) { mId = aId; }
void SetManager(IProtocol* aManager) { mManager = aManager; }
void SetManager(IProtocol* aManager);
void SetIPCChannel(MessageChannel* aChannel) { mChannel = aChannel; }

virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget);

static const int32_t kNullActorId = 0;
static const int32_t kFreedActorId = 1;

private:
int32_t mId;
Side mSide;
Expand Down Expand Up @@ -359,14 +379,26 @@ class IToplevelProtocol : public IProtocol
virtual void ProcessRemoteNativeEventsInInterruptCall() {
}

private:
virtual already_AddRefed<nsIEventTarget>
GetMessageEventTarget(const Message& aMsg);

protected:
virtual already_AddRefed<nsIEventTarget>
GetConstructedEventTarget(const Message& aMsg) { return nullptr; }

virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget);

private:
ProtocolId mProtocolId;
UniquePtr<Transport> mTrans;
base::ProcessId mOtherPid;
IDMap<IProtocol*> mActorMap;
int32_t mLastRouteId;
IDMap<Shmem::SharedMemory*> mShmemMap;
Shmem::id_t mLastShmemId;

Mutex mEventTargetMutex;
IDMap<nsCOMPtr<nsIEventTarget>> mEventTargetMap;
};

class IShmemAllocator
Expand Down
20 changes: 11 additions & 9 deletions ipc/ipdl/ipdl/lower.py
Original file line number Diff line number Diff line change
Expand Up @@ -4096,15 +4096,15 @@ def ctorPrologue(self, md, errfn=ExprLiteral.NULL, idexpr=None):
actortype = ipdl.type.ActorType(actorproto)

if idexpr is None:
idexpr = ExprCall(self.protocol.registerMethod(),
args=[ actorvar ])
registerexpr = ExprCall(self.protocol.registerMethod(),
args=[ actorvar ])
else:
idexpr = ExprCall(self.protocol.registerIDMethod(),
args=[ actorvar, idexpr ])
registerexpr = ExprCall(self.protocol.registerIDMethod(),
args=[ actorvar, idexpr ])

return [
self.failIfNullActor(actorvar, errfn, msg="Error constructing actor %s" % actortype.name() + self.side.capitalize()),
StmtExpr(ExprCall(ExprSelect(actorvar, '->', 'SetId'), args=[idexpr])),
StmtExpr(ExprCall(registerexpr)),
StmtExpr(ExprCall(ExprSelect(actorvar, '->', 'SetManager'), args=[ExprVar.THIS])),
StmtExpr(ExprCall(ExprSelect(actorvar, '->', 'SetIPCChannel'),
args=[self.protocol.callGetChannel()])),
Expand Down Expand Up @@ -4211,11 +4211,14 @@ def destroyActor(self, md, actorexpr, why=_DestroyReason.Deletion):
destroyedType = md.decl.type.constructedType()
else:
destroyedType = self.protocol.decl.type
return ([ StmtExpr(self.callActorDestroy(actorexpr, why)),
managervar = ExprVar('mgr')
return ([ StmtDecl(Decl(Type('IProtocol', ptr=1), managervar.name),
init=self.protocol.managerVar(actorexpr)),
StmtExpr(self.callActorDestroy(actorexpr, why)),
StmtExpr(self.callDeallocSubtree(md, actorexpr)),
StmtExpr(self.callRemoveActor(
actorexpr,
manager=self.protocol.managerVar(actorexpr),
manager=managervar,
ipdltype=destroyedType))
])

Expand Down Expand Up @@ -4358,8 +4361,7 @@ def failIfNullActor(self, actorExpr, retOnNull=ExprLiteral.FALSE, msg=None):

def unregisterActor(self):
return [ StmtExpr(ExprCall(self.protocol.unregisterMethod(),
args=[ _actorId() ])),
StmtExpr(ExprCall(ExprVar('SetId'), args=[_FREED_ACTOR_ID])) ]
args=[ _actorId() ])) ]

def makeMessage(self, md, errfn, fromActor=None):
msgvar = self.msgvar
Expand Down

0 comments on commit 30396b9

Please sign in to comment.