diff --git a/ipc/glue/RPCChannel.h b/ipc/glue/RPCChannel.h index 3953a4072c5d..852ff2c605ee 100644 --- a/ipc/glue/RPCChannel.h +++ b/ipc/glue/RPCChannel.h @@ -94,6 +94,16 @@ public: NS_RUNTIMEABORT("default impl shouldn't be invoked"); } + virtual void OnEnteredCall() + { + NS_RUNTIMEABORT("default impl shouldn't be invoked"); + } + + virtual void OnExitedCall() + { + NS_RUNTIMEABORT("default impl shouldn't be invoked"); + } + virtual RacyRPCPolicy MediateRPCRace(const Message& parent, const Message& child) { @@ -199,12 +209,32 @@ protected: void ExitedCxxStack(); + void EnteredCall() + { + Listener()->OnEnteredCall(); + } + + void ExitedCall() + { + Listener()->OnExitedCall(); + } + enum Direction { IN_MESSAGE, OUT_MESSAGE }; struct RPCFrame { RPCFrame(Direction direction, const Message* msg) : mDirection(direction), mMsg(msg) { } + bool IsRPCIncall() const + { + return mMsg->is_rpc() && IN_MESSAGE == mDirection; + } + + bool IsRPCOutcall() const + { + return mMsg->is_rpc() && OUT_MESSAGE == mDirection; + } + void Describe(int32* id, const char** dir, const char** sems, const char** name) const { @@ -230,11 +260,16 @@ protected: mThat.EnteredCxxStack(); mThat.mCxxStackFrames.push_back(RPCFrame(direction, msg)); - mThat.mSawRPCOutMsg |= (direction == OUT_MESSAGE) && - (msg->is_rpc()); + const RPCFrame& frame = mThat.mCxxStackFrames.back(); + + if (frame.IsRPCIncall()) + mThat.EnteredCall(); + + mThat.mSawRPCOutMsg |= frame.IsRPCOutcall(); } ~CxxStackFrame() { + bool exitingCall = mThat.mCxxStackFrames.back().IsRPCIncall(); mThat.mCxxStackFrames.pop_back(); bool exitingStack = mThat.mCxxStackFrames.empty(); @@ -244,6 +279,9 @@ protected: return; mThat.AssertWorkerThread(); + if (exitingCall) + mThat.ExitedCall(); + if (exitingStack) mThat.ExitedCxxStack(); } diff --git a/ipc/ipdl/ipdl/lower.py b/ipc/ipdl/ipdl/lower.py index f704a51ffbaa..edf312553d47 100644 --- a/ipc/ipdl/ipdl/lower.py +++ b/ipc/ipdl/ipdl/lower.py @@ -1408,6 +1408,14 @@ class Protocol(ipdl.ast.Protocol): assert self.decl.type.isToplevel() return ExprVar('ExitedCxxStack') + def enteredCallVar(self): + assert self.decl.type.isToplevel() + return ExprVar('EnteredCall') + + def exitedCallVar(self): + assert self.decl.type.isToplevel() + return ExprVar('ExitedCall') + def onCxxStackVar(self): assert self.decl.type.isToplevel() return ExprVar('IsOnCxxStack') @@ -2709,13 +2717,19 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): ret=Type.BOOL, virtual=1)) shouldcontinue.addstmt(StmtReturn(ExprLiteral.TRUE)) - # void EnteredCxxStack(); default to no-op + # void Entered*()/Exited*(); default to no-op entered = MethodDefn( MethodDecl(p.enteredCxxStackVar().name, virtual=1)) exited = MethodDefn( MethodDecl(p.exitedCxxStackVar().name, virtual=1)) + enteredcall = MethodDefn( + MethodDecl(p.enteredCallVar().name, virtual=1)) + exitedcall = MethodDefn( + MethodDecl(p.exitedCallVar().name, virtual=1)) - self.cls.addstmts([ shouldcontinue, entered, exited, + self.cls.addstmts([ shouldcontinue, + entered, exited, + enteredcall, exitedcall, Whitespace.NL ]) self.cls.addstmts(( @@ -2950,13 +2964,23 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): onexited = MethodDefn(MethodDecl('OnExitedCxxStack')) onexited.addstmt(StmtReturn(ExprCall(p.exitedCxxStackVar()))) + # OnEnteredCxxStack() + onenteredcall = MethodDefn(MethodDecl('OnEnteredCall')) + onenteredcall.addstmt(StmtReturn(ExprCall(p.enteredCallVar()))) + + # OnExitedCxxStack() + onexitedcall = MethodDefn(MethodDecl('OnExitedCall')) + onexitedcall.addstmt(StmtReturn(ExprCall(p.exitedCallVar()))) + # bool IsOnCxxStack() onstack = MethodDefn( MethodDecl(p.onCxxStackVar().name, ret=Type.BOOL, const=1)) onstack.addstmt(StmtReturn(ExprCall( ExprSelect(p.channelVar(), '.', p.onCxxStackVar().name)))) - self.cls.addstmts([ onentered, onexited, onstack, Whitespace.NL ]) + self.cls.addstmts([ onentered, onexited, + onenteredcall, onexitedcall, + onstack, Whitespace.NL ]) # OnChannelClose() onclose = MethodDefn(MethodDecl('OnChannelClose')) diff --git a/ipc/ipdl/test/cxx/TestStackHooks.cpp b/ipc/ipdl/test/cxx/TestStackHooks.cpp index c7bd55319dce..daf727117435 100644 --- a/ipc/ipdl/test/cxx/TestStackHooks.cpp +++ b/ipc/ipdl/test/cxx/TestStackHooks.cpp @@ -10,7 +10,8 @@ namespace _ipdltest { //----------------------------------------------------------------------------- // parent -TestStackHooksParent::TestStackHooksParent() : mOnStack(false) +TestStackHooksParent::TestStackHooksParent() : + mOnStack(false), mIncallDepth(0) { MOZ_COUNT_CTOR(TestStackHooksParent); } @@ -40,6 +41,9 @@ TestStackHooksParent::AnswerStackFrame() if (!mOnStack) fail("not on C++ stack?!"); + if (1 != mIncallDepth) + fail("missed EnteredCall or ExitedCall hook"); + return true; } @@ -49,7 +53,8 @@ TestStackHooksParent::AnswerStackFrame() TestStackHooksChild::TestStackHooksChild() : mOnStack(false), mEntered(0), - mExited(0) + mExited(0), + mIncallDepth(0) { MOZ_COUNT_CTOR(TestStackHooksChild); } @@ -71,6 +76,9 @@ TestStackHooksChild::RecvStart() if (!mOnStack) fail("missed stack notification"); + if (0 != mIncallDepth) + fail("EnteredCall/ExitedCall malfunction"); + // kick off tests from a runnable so that we can start with // RPCChannel code on the C++ stack MessageLoop::current()->PostTask(FROM_HERE, @@ -85,12 +93,15 @@ TestStackHooksChild::AnswerStackFrame() if (!mOnStack) fail("missed stack notification"); + if (1 != mIncallDepth) + fail("missed EnteredCall or ExitedCall hook"); + // FIXME use IPDL state instead - if (4 == mEntered) { + if (4 == mEntered) { // test 4 if (!SendAsync()) fail("sending Async()"); } - else if (5 == mEntered) { + else if (5 == mEntered) { // test 5 if (!SendSync()) fail("sending Sync()"); } @@ -112,11 +123,15 @@ TestStackHooksChild::RunTests() fail("missed stack notification"); if (mOnStack) fail("spurious stack notification"); + if (0 != mIncallDepth) + fail("EnteredCall/ExitedCall malfunction"); if (!SendAsync()) fail("sending Async()"); if (mOnStack) fail("spurious stack notification"); + if (0 != mIncallDepth) + fail("EnteredCall/ExitedCall malfunction"); if (2 != mEntered) fail("missed stack notification"); @@ -124,6 +139,8 @@ TestStackHooksChild::RunTests() fail("sending Sync()"); if (mOnStack) fail("spurious stack notification"); + if (0 != mIncallDepth) + fail("EnteredCall/ExitedCall malfunction"); if (3 != mEntered) fail("missed stack notification"); @@ -131,6 +148,8 @@ TestStackHooksChild::RunTests() fail("calling RPC()"); if (mOnStack) fail("spurious stack notification"); + if (0 != mIncallDepth) + fail("EnteredCall/ExitedCall malfunction"); if (4 != mEntered) fail("missed stack notification"); @@ -138,6 +157,8 @@ TestStackHooksChild::RunTests() fail("calling StackFrame()"); if (mOnStack) fail("spurious stack notification"); + if (0 != mIncallDepth) + fail("EnteredCall/ExitedCall malfunction"); if (5 != mEntered) fail("missed stack notification"); diff --git a/ipc/ipdl/test/cxx/TestStackHooks.h b/ipc/ipdl/test/cxx/TestStackHooks.h index 2f542bc6eb9e..68af8c90aadf 100644 --- a/ipc/ipdl/test/cxx/TestStackHooks.h +++ b/ipc/ipdl/test/cxx/TestStackHooks.h @@ -62,8 +62,18 @@ protected: mOnStack = false; } + NS_OVERRIDE + virtual void EnteredCall() { + ++mIncallDepth; + } + NS_OVERRIDE + virtual void ExitedCall() { + --mIncallDepth; + } + private: bool mOnStack; + int mIncallDepth; }; @@ -109,10 +119,20 @@ protected: mOnStack = false; } + NS_OVERRIDE + virtual void EnteredCall() { + ++mIncallDepth; + } + NS_OVERRIDE + virtual void ExitedCall() { + --mIncallDepth; + } + private: bool mOnStack; int mEntered; int mExited; + int mIncallDepth; };