Bug 545455, part 1: Track when RPCChannel code is first pushed on the C++ stack and last popped. r=bent

--HG--
extra : rebase_source : 1bf50aac0f5da1c4322347b42b24e72215543915
This commit is contained in:
Chris Jones 2010-02-16 12:44:21 -06:00
Родитель bae495bb08
Коммит 40a5e9f8b9
4 изменённых файлов: 93 добавлений и 5 удалений

Просмотреть файл

@ -112,7 +112,7 @@ public:
void Close(); void Close();
// Asynchronously send a message to the other side of the channel // Asynchronously send a message to the other side of the channel
bool Send(Message* msg); virtual bool Send(Message* msg);
// //
// These methods are called on the "IO" thread // These methods are called on the "IO" thread

Просмотреть файл

@ -98,7 +98,8 @@ RPCChannel::RPCChannel(RPCListener* aListener,
mDeferred(), mDeferred(),
mRemoteStackDepthGuess(0), mRemoteStackDepthGuess(0),
mRacePolicy(aPolicy), mRacePolicy(aPolicy),
mBlockedOnParent(false) mBlockedOnParent(false),
mCxxStackFrames(0)
{ {
MOZ_COUNT_CTOR(RPCChannel); MOZ_COUNT_CTOR(RPCChannel);
} }
@ -106,7 +107,7 @@ RPCChannel::RPCChannel(RPCListener* aListener,
RPCChannel::~RPCChannel() RPCChannel::~RPCChannel()
{ {
MOZ_COUNT_DTOR(RPCChannel); MOZ_COUNT_DTOR(RPCChannel);
// FIXME/cjones: impl RPC_ASSERT(0 == mCxxStackFrames, "mismatched CxxStackFrame ctor/dtors");
} }
#ifdef OS_WIN #ifdef OS_WIN
@ -128,6 +129,20 @@ RPCChannel::EventOccurred()
!= mOutOfTurnReplies.end())); != mOutOfTurnReplies.end()));
} }
bool
RPCChannel::Send(Message* msg)
{
CxxStackFrame f(*this);
return AsyncChannel::Send(msg);
}
bool
RPCChannel::Send(Message* msg, Message* reply)
{
CxxStackFrame f(*this);
return SyncChannel::Send(msg, reply);
}
bool bool
RPCChannel::Call(Message* msg, Message* reply) RPCChannel::Call(Message* msg, Message* reply)
{ {
@ -137,6 +152,8 @@ RPCChannel::Call(Message* msg, Message* reply)
"violation of sync handler invariant"); "violation of sync handler invariant");
RPC_ASSERT(msg->is_rpc(), "can only Call() RPC messages here"); RPC_ASSERT(msg->is_rpc(), "can only Call() RPC messages here");
CxxStackFrame f(*this);
MutexAutoLock lock(mMutex); MutexAutoLock lock(mMutex);
if (!Connected()) { if (!Connected()) {
@ -341,6 +358,8 @@ RPCChannel::OnMaybeDequeueOne()
mPending.pop(); mPending.pop();
} }
CxxStackFrame f(*this);
if (recvd.is_rpc()) if (recvd.is_rpc())
return Incall(recvd, 0); return Incall(recvd, 0);
else if (recvd.is_sync()) else if (recvd.is_sync())

Просмотреть файл

@ -51,6 +51,8 @@ namespace ipc {
class RPCChannel : public SyncChannel class RPCChannel : public SyncChannel
{ {
friend class CxxStackFrame;
public: public:
class /*NS_INTERFACE_CLASS*/ RPCListener : class /*NS_INTERFACE_CLASS*/ RPCListener :
public SyncChannel::SyncListener public SyncChannel::SyncListener
@ -82,6 +84,13 @@ public:
// Make an RPC to the other side of the channel // Make an RPC to the other side of the channel
bool Call(Message* msg, Message* reply); bool Call(Message* msg, Message* reply);
// RPCChannel overrides these so that the async and sync messages
// can be counted against mStackFrames
NS_OVERRIDE
virtual bool Send(Message* msg);
NS_OVERRIDE
virtual bool Send(Message* msg, Message* reply);
// Asynchronously, send the child a message that puts it in such a // Asynchronously, send the child a message that puts it in such a
// state that it can't send messages to the parent unless the // state that it can't send messages to the parent unless the
// parent sends a message to it first. The child stays in this // parent sends a message to it first. The child stays in this
@ -151,6 +160,55 @@ protected:
void BlockOnParent(); void BlockOnParent();
void UnblockFromParent(); void UnblockFromParent();
// This helper class managed RPCChannel.mCxxStackDepth on behalf
// of RPCChannel. When the stack depth is incremented from zero
// to non-zero, it invokes an RPCChannel callback, and similarly
// for when the depth goes from non-zero to zero;
void EnteredCxxStack()
{
// FIXME/bug 545455: call mListener hook
printf("[%s] +++ CXX STACK\n", mChild ? "child" : "parent");
}
void ExitedCxxStack()
{
// FIXME/bug 545455: call mListener hook
printf("[%s] --- CXX STACK\n", mChild ? "child" : "parent");
}
class NS_STACK_CLASS CxxStackFrame
{
public:
CxxStackFrame(RPCChannel& that) : mThat(that) {
NS_ABORT_IF_FALSE(0 <= mThat.mCxxStackFrames,
"mismatched CxxStackFrame ctor/dtor");
mThat.AssertWorkerThread();
if (0 == mThat.mCxxStackFrames++)
mThat.EnteredCxxStack();
}
~CxxStackFrame() {
bool exitingStack = (0 == --mThat.mCxxStackFrames);
// mListener could have gone away if Close() was called while
// RPCChannel code was still on the stack
if (!mThat.mListener)
return;
mThat.AssertWorkerThread();
if (exitingStack)
mThat.ExitedCxxStack();
}
private:
RPCChannel& mThat;
// disable harmful methods
CxxStackFrame();
CxxStackFrame(const CxxStackFrame&);
CxxStackFrame& operator=(const CxxStackFrame&);
};
// Called from both threads // Called from both threads
size_t StackDepth() { size_t StackDepth() {
mMutex.AssertCurrentThreadOwns(); mMutex.AssertCurrentThreadOwns();
@ -256,6 +314,16 @@ protected:
// True iff the parent has put us in a |BlockChild()| state. // True iff the parent has put us in a |BlockChild()| state.
bool mBlockedOnParent; bool mBlockedOnParent;
// Approximation of number of Sync/RPCChannel-code frames on the
// C++ stack. It can only be interpreted as the implication
//
// mCxxStackDepth > 0 => RPCChannel code on C++ stack
//
// This member is only accessed on the worker thread, and so is
// not protected by mMutex. It is managed exclusively by the
// helper |class CxxStackFrame|.
int mCxxStackFrames;
}; };

Просмотреть файл

@ -71,12 +71,13 @@ public:
SyncChannel(SyncListener* aListener); SyncChannel(SyncListener* aListener);
virtual ~SyncChannel(); virtual ~SyncChannel();
bool Send(Message* msg) { NS_OVERRIDE
virtual bool Send(Message* msg) {
return AsyncChannel::Send(msg); return AsyncChannel::Send(msg);
} }
// Synchronously send |msg| (i.e., wait for |reply|) // Synchronously send |msg| (i.e., wait for |reply|)
bool Send(Message* msg, Message* reply); virtual bool Send(Message* msg, Message* reply);
void SetReplyTimeoutMs(int32 aTimeoutMs) { void SetReplyTimeoutMs(int32 aTimeoutMs) {
AssertWorkerThread(); AssertWorkerThread();