зеркало из https://github.com/mozilla/pjs.git
Bug 533055: Part 3: Track |Message|s being processed on the C++ stack and offer a DumpRPCStack() method to print them. r=bent
This commit is contained in:
Родитель
83622b0ddc
Коммит
e15df582cd
|
@ -96,8 +96,7 @@ RPCChannel::RPCChannel(RPCListener* aListener)
|
|||
mOutOfTurnReplies(),
|
||||
mDeferred(),
|
||||
mRemoteStackDepthGuess(0),
|
||||
mBlockedOnParent(false),
|
||||
mCxxStackFrames(0)
|
||||
mBlockedOnParent(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(RPCChannel);
|
||||
|
||||
|
@ -109,7 +108,7 @@ RPCChannel::RPCChannel(RPCListener* aListener)
|
|||
RPCChannel::~RPCChannel()
|
||||
{
|
||||
MOZ_COUNT_DTOR(RPCChannel);
|
||||
RPC_ASSERT(0 == mCxxStackFrames, "mismatched CxxStackFrame ctor/dtors");
|
||||
RPC_ASSERT(mCxxStackFrames.empty(), "mismatched CxxStackFrame ctor/dtors");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -142,14 +141,16 @@ RPCChannel::EventOccurred()
|
|||
bool
|
||||
RPCChannel::Send(Message* msg)
|
||||
{
|
||||
CxxStackFrame f(*this);
|
||||
Message copy = *msg;
|
||||
CxxStackFrame f(*this, OUT_MESSAGE, ©);
|
||||
return AsyncChannel::Send(msg);
|
||||
}
|
||||
|
||||
bool
|
||||
RPCChannel::Send(Message* msg, Message* reply)
|
||||
{
|
||||
CxxStackFrame f(*this);
|
||||
Message copy = *msg;
|
||||
CxxStackFrame f(*this, OUT_MESSAGE, ©);
|
||||
return SyncChannel::Send(msg, reply);
|
||||
}
|
||||
|
||||
|
@ -162,7 +163,8 @@ RPCChannel::Call(Message* msg, Message* reply)
|
|||
"violation of sync handler invariant");
|
||||
RPC_ASSERT(msg->is_rpc(), "can only Call() RPC messages here");
|
||||
|
||||
CxxStackFrame f(*this);
|
||||
Message copy = *msg;
|
||||
CxxStackFrame f(*this, OUT_MESSAGE, ©);
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
|
@ -227,7 +229,10 @@ RPCChannel::Call(Message* msg, Message* reply)
|
|||
|
||||
if (!recvd.is_sync() && !recvd.is_rpc()) {
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
|
||||
CxxStackFrame f(*this, IN_MESSAGE, &recvd);
|
||||
AsyncChannel::OnDispatchMessage(recvd);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -235,7 +240,10 @@ RPCChannel::Call(Message* msg, Message* reply)
|
|||
RPC_ASSERT(mPending.empty(),
|
||||
"other side should have been blocked");
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
|
||||
CxxStackFrame f(*this, IN_MESSAGE, &recvd);
|
||||
SyncChannel::OnDispatchMessage(recvd);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -296,6 +304,7 @@ RPCChannel::Call(Message* msg, Message* reply)
|
|||
{
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
// someone called in to us from the other side. handle the call
|
||||
CxxStackFrame f(*this, IN_MESSAGE, &recvd);
|
||||
Incall(recvd, stackDepth);
|
||||
// FIXME/cjones: error handling
|
||||
}
|
||||
|
@ -332,6 +341,8 @@ RPCChannel::MaybeProcessDeferredIncall()
|
|||
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
fprintf(stderr, " (processing deferred in-call)\n");
|
||||
|
||||
CxxStackFrame f(*this, IN_MESSAGE, &call);
|
||||
Incall(call, stackDepth);
|
||||
}
|
||||
|
||||
|
@ -383,7 +394,7 @@ RPCChannel::OnMaybeDequeueOne()
|
|||
mPending.pop();
|
||||
}
|
||||
|
||||
CxxStackFrame f(*this);
|
||||
CxxStackFrame f(*this, IN_MESSAGE, &recvd);
|
||||
|
||||
if (recvd.is_rpc())
|
||||
return Incall(recvd, 0);
|
||||
|
@ -554,6 +565,8 @@ RPCChannel::BlockOnParent()
|
|||
mPending.pop();
|
||||
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
|
||||
CxxStackFrame f(*this, IN_MESSAGE, &recvd);
|
||||
if (recvd.is_rpc()) {
|
||||
// stack depth must be 0 here
|
||||
Incall(recvd, 0);
|
||||
|
@ -594,8 +607,7 @@ RPCChannel::DebugAbort(const char* file, int line, const char* cond,
|
|||
why,
|
||||
type, reply ? "reply" : "");
|
||||
// technically we need the mutex for this, but we're dying anyway
|
||||
fprintf(stderr, " local RPC stack size: %lu\n",
|
||||
mStack.size());
|
||||
DumpRPCStack(stderr, " ");
|
||||
fprintf(stderr, " remote RPC stack guess: %lu\n",
|
||||
mRemoteStackDepthGuess);
|
||||
fprintf(stderr, " deferred stack size: %lu\n",
|
||||
|
@ -615,6 +627,28 @@ RPCChannel::DebugAbort(const char* file, int line, const char* cond,
|
|||
NS_RUNTIMEABORT(why);
|
||||
}
|
||||
|
||||
void
|
||||
RPCChannel::DumpRPCStack(FILE* outfile, const char* const pfx)
|
||||
{
|
||||
NS_WARN_IF_FALSE(MessageLoop::current() != mWorkerLoop,
|
||||
"The worker thread had better be paused in a debugger!");
|
||||
|
||||
if (!outfile)
|
||||
outfile = stdout;
|
||||
|
||||
fprintf(outfile, "%sRPCChannel 'backtrace':\n", pfx);
|
||||
|
||||
// print a python-style backtrace, first frame to last
|
||||
for (PRUint32 i = 0; i < mCxxStackFrames.size(); ++i) {
|
||||
int32 id;
|
||||
const char* dir, *sems, *name;
|
||||
mCxxStackFrames[i].Describe(&id, &dir, &sems, &name);
|
||||
|
||||
fprintf(outfile, "%s[(%u) %s %s %s(actor=%d) ]\n", pfx,
|
||||
i, dir, sems, name, id);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The methods below run in the context of the IO thread, and can proxy
|
||||
// back to the methods above
|
||||
|
|
|
@ -39,9 +39,12 @@
|
|||
#ifndef ipc_glue_RPCChannel_h
|
||||
#define ipc_glue_RPCChannel_h 1
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// FIXME/cjones probably shouldn't depend on STL
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
|
@ -140,7 +143,7 @@ public:
|
|||
|
||||
// Return true iff this has code on the C++ stack.
|
||||
bool IsOnCxxStack() const {
|
||||
return 0 < mCxxStackFrames;
|
||||
return !mCxxStackFrames.empty();
|
||||
}
|
||||
|
||||
NS_OVERRIDE
|
||||
|
@ -183,7 +186,7 @@ protected:
|
|||
|
||||
NS_OVERRIDE
|
||||
virtual bool ShouldDeferNotifyMaybeError() {
|
||||
return 0 < mCxxStackFrames;
|
||||
return IsOnCxxStack();
|
||||
}
|
||||
|
||||
bool EventOccurred();
|
||||
|
@ -212,20 +215,42 @@ protected:
|
|||
Listener()->OnExitedCxxStack();
|
||||
}
|
||||
|
||||
enum Direction { IN_MESSAGE, OUT_MESSAGE };
|
||||
struct RPCFrame {
|
||||
RPCFrame(Direction direction, const Message* msg) :
|
||||
mDirection(direction), mMsg(msg)
|
||||
{ }
|
||||
|
||||
void Describe(int32* id, const char** dir, const char** sems,
|
||||
const char** name)
|
||||
const
|
||||
{
|
||||
*id = mMsg->routing_id();
|
||||
*dir = (IN_MESSAGE == mDirection) ? "in" : "out";
|
||||
*sems = mMsg->is_rpc() ? "rpc" : mMsg->is_sync() ? "sync" : "async";
|
||||
*name = mMsg->name();
|
||||
}
|
||||
|
||||
Direction mDirection;
|
||||
const Message* mMsg;
|
||||
};
|
||||
|
||||
class NS_STACK_CLASS CxxStackFrame
|
||||
{
|
||||
public:
|
||||
CxxStackFrame(RPCChannel& that) : mThat(that) {
|
||||
NS_ABORT_IF_FALSE(0 <= mThat.mCxxStackFrames,
|
||||
"mismatched CxxStackFrame ctor/dtor");
|
||||
|
||||
CxxStackFrame(RPCChannel& that, Direction direction,
|
||||
const Message* msg) : mThat(that) {
|
||||
mThat.AssertWorkerThread();
|
||||
|
||||
if (0 == mThat.mCxxStackFrames++)
|
||||
if (mThat.mCxxStackFrames.empty())
|
||||
mThat.EnteredCxxStack();
|
||||
mThat.mCxxStackFrames.push_back(RPCFrame(direction, msg));
|
||||
}
|
||||
|
||||
~CxxStackFrame() {
|
||||
bool exitingStack = (0 == --mThat.mCxxStackFrames);
|
||||
mThat.mCxxStackFrames.pop_back();
|
||||
bool exitingStack = mThat.mCxxStackFrames.empty();
|
||||
|
||||
// mListener could have gone away if Close() was called while
|
||||
// RPCChannel code was still on the stack
|
||||
|
@ -255,6 +280,10 @@ protected:
|
|||
const char* why,
|
||||
const char* type="rpc", bool reply=false);
|
||||
|
||||
// This method is only safe to call on the worker thread, or in a
|
||||
// debugger with all threads paused. |outfile| defaults to stdout.
|
||||
void DumpRPCStack(FILE* outfile=NULL, const char* const pfx="");
|
||||
|
||||
//
|
||||
// Queue of all incoming messages, except for replies to sync
|
||||
// messages, which are delivered directly to the SyncChannel
|
||||
|
@ -350,15 +379,15 @@ protected:
|
|||
// True iff the parent has put us in a |BlockChild()| state.
|
||||
bool mBlockedOnParent;
|
||||
|
||||
// Approximation of number of Sync/RPCChannel-code frames on the
|
||||
// C++ stack. It can only be interpreted as the implication
|
||||
// Approximation of Sync/RPCChannel-code frames on the C++ stack.
|
||||
// It can only be interpreted as the implication
|
||||
//
|
||||
// mCxxStackDepth > 0 => RPCChannel code on C++ stack
|
||||
// !mCxxStackFrames.empty() => 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;
|
||||
std::vector<RPCFrame> mCxxStackFrames;
|
||||
|
||||
private:
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче