Bug 556214, part 3: IPC code wants to be using non-reentrant Monitor. r=bent

This commit is contained in:
Chris Jones 2011-04-29 14:21:57 -05:00
parent 6b36ed55c1
commit f7c811a3e7
9 changed files with 88 additions and 92 deletions

View File

@ -45,7 +45,7 @@
#include "nsTraceRefcnt.h"
#include "nsXULAppAPI.h"
using mozilla::MutexAutoLock;
using mozilla::MonitorAutoLock;
template<>
struct RunnableMethodTraits<mozilla::ipc::AsyncChannel>
@ -106,8 +106,7 @@ AsyncChannel::AsyncChannel(AsyncListener* aListener)
: mTransport(0),
mListener(aListener),
mChannelState(ChannelClosed),
mMutex("mozilla.ipc.AsyncChannel.mMutex"),
mCvar(mMutex, "mozilla.ipc.AsyncChannel.mCvar"),
mMonitor("mozilla.ipc.AsyncChannel.mMonitor"),
mIOLoop(),
mWorkerLoop(),
mChild(false),
@ -155,7 +154,7 @@ AsyncChannel::Open(Transport* aTransport, MessageLoop* aIOLoop)
NS_ASSERTION(mWorkerLoop, "need a worker loop");
if (needOpen) { // child process
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
mIOLoop->PostTask(FROM_HERE,
NewRunnableMethod(this,
@ -163,7 +162,7 @@ AsyncChannel::Open(Transport* aTransport, MessageLoop* aIOLoop)
// FIXME/cjones: handle errors
while (mChannelState != ChannelConnected) {
mCvar.Wait();
mMonitor.Wait();
}
}
@ -176,7 +175,7 @@ AsyncChannel::Close()
AssertWorkerThread();
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (ChannelError == mChannelState ||
ChannelTimeout == mChannelState) {
@ -186,7 +185,7 @@ AsyncChannel::Close()
// also be deleted and the listener will never be notified
// of the channel error.
if (mListener) {
MutexAutoUnlock unlock(mMutex);
MonitorAutoUnlock unlock(mMonitor);
NotifyMaybeChannelError();
}
return;
@ -212,24 +211,24 @@ void
AsyncChannel::SynchronouslyClose()
{
AssertWorkerThread();
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
mIOLoop->PostTask(
FROM_HERE, NewRunnableMethod(this, &AsyncChannel::OnCloseChannel));
while (ChannelClosed != mChannelState)
mCvar.Wait();
mMonitor.Wait();
}
bool
AsyncChannel::Send(Message* msg)
{
AssertWorkerThread();
mMutex.AssertNotCurrentThreadOwns();
mMonitor.AssertNotCurrentThreadOwns();
NS_ABORT_IF_FALSE(MSG_ROUTING_NONE != msg->routing_id(), "need a route");
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (!Connected()) {
ReportConnectionError("AsyncChannel");
@ -289,14 +288,14 @@ void
AsyncChannel::OnNotifyMaybeChannelError()
{
AssertWorkerThread();
mMutex.AssertNotCurrentThreadOwns();
mMonitor.AssertNotCurrentThreadOwns();
// OnChannelError holds mMutex when it posts this task and this
// OnChannelError holds mMonitor when it posts this task and this
// task cannot be allowed to run until OnChannelError has
// exited. We enforce that order by grabbing the mutex here which
// should only continue once OnChannelError has completed.
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
// nothing to do here
}
@ -314,7 +313,7 @@ AsyncChannel::OnNotifyMaybeChannelError()
void
AsyncChannel::NotifyChannelClosed()
{
mMutex.AssertNotCurrentThreadOwns();
mMonitor.AssertNotCurrentThreadOwns();
if (ChannelClosed != mChannelState)
NS_RUNTIMEABORT("channel should have been closed!");
@ -329,7 +328,7 @@ AsyncChannel::NotifyChannelClosed()
void
AsyncChannel::NotifyMaybeChannelError()
{
mMutex.AssertNotCurrentThreadOwns();
mMonitor.AssertNotCurrentThreadOwns();
// TODO sort out Close() on this side racing with Close() on the
// other side
@ -456,7 +455,7 @@ AsyncChannel::OnMessageReceived(const Message& msg)
AssertIOThread();
NS_ASSERTION(mChannelState != ChannelError, "Shouldn't get here!");
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (!MaybeInterceptSpecialIOMessage(msg))
// wake up the worker, there's work to do
@ -470,7 +469,7 @@ AsyncChannel::OnChannelOpened()
{
AssertIOThread();
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
mChannelState = ChannelOpening;
}
/*assert*/mTransport->Connect();
@ -490,9 +489,9 @@ AsyncChannel::OnChannelConnected(int32 peer_pid)
AssertIOThread();
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
mChannelState = ChannelConnected;
mCvar.Notify();
mMonitor.Notify();
}
if(mExistingListener)
@ -508,7 +507,7 @@ AsyncChannel::OnChannelError()
{
AssertIOThread();
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (ChannelClosing != mChannelState)
mChannelState = ChannelError;
@ -520,7 +519,7 @@ void
AsyncChannel::PostErrorNotifyTask()
{
AssertIOThread();
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
NS_ASSERTION(!mChannelErrorTask, "OnChannelError called twice?");
@ -537,16 +536,16 @@ AsyncChannel::OnCloseChannel()
mTransport->Close();
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
mChannelState = ChannelClosed;
mCvar.Notify();
mMonitor.Notify();
}
bool
AsyncChannel::MaybeInterceptSpecialIOMessage(const Message& msg)
{
AssertIOThread();
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
if (MSG_ROUTING_NONE == msg.routing_id()
&& GOODBYE_MESSAGE_TYPE == msg.type()) {
@ -560,7 +559,7 @@ void
AsyncChannel::ProcessGoodbyeMessage()
{
AssertIOThread();
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
// TODO sort out Close() on this side racing with Close() on the
// other side

View File

@ -44,8 +44,7 @@
#include "base/message_loop.h"
#include "chrome/common/ipc_channel.h"
#include "mozilla/CondVar.h"
#include "mozilla/Mutex.h"
#include "mozilla/Monitor.h"
//-----------------------------------------------------------------------------
@ -70,8 +69,7 @@ struct HasResultCodes
class AsyncChannel : public IPC::Channel::Listener, protected HasResultCodes
{
protected:
typedef mozilla::CondVar CondVar;
typedef mozilla::Mutex Mutex;
typedef mozilla::Monitor Monitor;
enum ChannelState {
ChannelClosed,
@ -145,7 +143,7 @@ protected:
}
bool Connected() const {
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
return ChannelConnected == mChannelState;
}
@ -187,8 +185,7 @@ protected:
Transport* mTransport;
AsyncListener* mListener;
ChannelState mChannelState;
Mutex mMutex;
CondVar mCvar;
Monitor mMonitor;
MessageLoop* mIOLoop; // thread where IO happens
MessageLoop* mWorkerLoop; // thread where work is done
bool mChild; // am I the child or parent?

View File

@ -74,7 +74,7 @@
#include "APKOpen.h"
#endif
using mozilla::ReentrantMonitorAutoEnter;
using mozilla::MonitorAutoLock;
using mozilla::ipc::GeckoChildProcessHost;
#ifdef ANDROID
@ -95,7 +95,7 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
base::WaitableEventWatcher::Delegate* aDelegate)
: ChildProcessHost(RENDER_PROCESS), // FIXME/cjones: we should own this enum
mProcessType(aProcessType),
mReentrantMonitor("mozilla.ipc.GeckChildProcessHost.mReentrantMonitor"),
mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
mLaunched(false),
mChannelInitialized(false),
mDelegate(aDelegate),
@ -289,14 +289,14 @@ GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTime
aExtraOpts, arch));
// NB: this uses a different mechanism than the chromium parent
// class.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MonitorAutoLock lock(mMonitor);
PRIntervalTime waitStart = PR_IntervalNow();
PRIntervalTime current;
// We'll receive several notifications, we need to exit when we
// have either successfully launched or have timed out.
while (!mLaunched) {
mon.Wait(timeoutTicks);
lock.Wait(timeoutTicks);
if (timeoutTicks != PR_INTERVAL_NO_TIMEOUT) {
current = PR_IntervalNow();
@ -327,9 +327,9 @@ GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts)
// This may look like the sync launch wait, but we only delay as
// long as it takes to create the channel.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MonitorAutoLock lock(mMonitor);
while (!mChannelInitialized) {
mon.Wait();
lock.Wait();
}
return true;
@ -340,9 +340,9 @@ GeckoChildProcessHost::InitializeChannel()
{
CreateChannel();
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MonitorAutoLock lock(mMonitor);
mChannelInitialized = true;
mon.Notify();
lock.Notify();
}
PRInt32 GeckoChildProcessHost::mChildCounter = 0;
@ -644,13 +644,13 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
void
GeckoChildProcessHost::OnChannelConnected(int32 peer_pid)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MonitorAutoLock lock(mMonitor);
mLaunched = true;
if (!base::OpenPrivilegedProcessHandle(peer_pid, &mChildProcessHandle))
NS_RUNTIMEABORT("can't open handle to child process");
mon.Notify();
lock.Notify();
}
// XXX/cjones: these next two methods should basically never be called.

View File

@ -43,7 +43,7 @@
#include "base/waitable_event.h"
#include "chrome/common/child_process_host.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/Monitor.h"
#include "nsXULAppAPI.h" // for GeckoProcessType
#include "nsString.h"
@ -54,7 +54,7 @@ namespace ipc {
class GeckoChildProcessHost : public ChildProcessHost
{
protected:
typedef mozilla::ReentrantMonitor ReentrantMonitor;
typedef mozilla::Monitor Monitor;
public:
typedef base::ProcessHandle ProcessHandle;
@ -106,7 +106,7 @@ public:
protected:
GeckoProcessType mProcessType;
ReentrantMonitor mReentrantMonitor;
Monitor mMonitor;
bool mLaunched;
bool mChannelInitialized;
FilePath mProcessPath;

View File

@ -49,8 +49,8 @@
DebugAbort(__FILE__, __LINE__, #_cond,## __VA_ARGS__); \
} while (0)
using mozilla::MutexAutoLock;
using mozilla::MutexAutoUnlock;
using mozilla::MonitorAutoLock;
using mozilla::MonitorAutoUnlock;
template<>
struct RunnableMethodTraits<mozilla::ipc::RPCChannel>
@ -124,7 +124,7 @@ bool
RPCChannel::EventOccurred() const
{
AssertWorkerThread();
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
RPC_ASSERT(StackDepth() > 0, "not in wait loop");
return (!Connected() ||
@ -154,7 +154,7 @@ bool
RPCChannel::Call(Message* msg, Message* reply)
{
AssertWorkerThread();
mMutex.AssertNotCurrentThreadOwns();
mMonitor.AssertNotCurrentThreadOwns();
RPC_ASSERT(!ProcessingSyncMessage(),
"violation of sync handler invariant");
RPC_ASSERT(msg->is_rpc(), "can only Call() RPC messages here");
@ -166,7 +166,7 @@ RPCChannel::Call(Message* msg, Message* reply)
Message copy = *msg;
CxxStackFrame f(*this, OUT_MESSAGE, &copy);
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (!Connected()) {
ReportConnectionError("RPCChannel");
@ -238,7 +238,7 @@ RPCChannel::Call(Message* msg, Message* reply)
}
if (!recvd.is_sync() && !recvd.is_rpc()) {
MutexAutoUnlock unlock(mMutex);
MonitorAutoUnlock unlock(mMonitor);
CxxStackFrame f(*this, IN_MESSAGE, &recvd);
AsyncChannel::OnDispatchMessage(recvd);
@ -249,7 +249,7 @@ RPCChannel::Call(Message* msg, Message* reply)
if (recvd.is_sync()) {
RPC_ASSERT(mPending.empty(),
"other side should have been blocked");
MutexAutoUnlock unlock(mMutex);
MonitorAutoUnlock unlock(mMonitor);
CxxStackFrame f(*this, IN_MESSAGE, &recvd);
SyncChannel::OnDispatchMessage(recvd);
@ -301,10 +301,10 @@ RPCChannel::Call(Message* msg, Message* reply)
// in-call. process in a new stack frame.
// "snapshot" the current stack depth while we own the Mutex
// "snapshot" the current stack depth while we own the Monitor
size_t stackDepth = StackDepth();
{
MutexAutoUnlock unlock(mMutex);
MonitorAutoUnlock unlock(mMonitor);
// someone called in to us from the other side. handle the call
CxxStackFrame f(*this, IN_MESSAGE, &recvd);
Incall(recvd, stackDepth);
@ -319,7 +319,7 @@ void
RPCChannel::MaybeUndeferIncall()
{
AssertWorkerThread();
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
if (mDeferred.empty())
return;
@ -348,7 +348,7 @@ void
RPCChannel::EnqueuePendingMessages()
{
AssertWorkerThread();
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
MaybeUndeferIncall();
@ -370,10 +370,10 @@ void
RPCChannel::FlushPendingRPCQueue()
{
AssertWorkerThread();
mMutex.AssertNotCurrentThreadOwns();
mMonitor.AssertNotCurrentThreadOwns();
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (mDeferred.empty()) {
if (mPending.empty())
@ -395,11 +395,11 @@ RPCChannel::OnMaybeDequeueOne()
// messages here
AssertWorkerThread();
mMutex.AssertNotCurrentThreadOwns();
mMonitor.AssertNotCurrentThreadOwns();
Message recvd;
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (!Connected()) {
ReportConnectionError("RPCChannel");
@ -439,7 +439,7 @@ void
RPCChannel::Incall(const Message& call, size_t stackDepth)
{
AssertWorkerThread();
mMutex.AssertNotCurrentThreadOwns();
mMonitor.AssertNotCurrentThreadOwns();
RPC_ASSERT(call.is_rpc() && !call.is_reply(), "wrong message type");
// Race detection: see the long comment near
@ -502,7 +502,7 @@ void
RPCChannel::DispatchIncall(const Message& call)
{
AssertWorkerThread();
mMutex.AssertNotCurrentThreadOwns();
mMonitor.AssertNotCurrentThreadOwns();
RPC_ASSERT(call.is_rpc() && !call.is_reply(),
"wrong message type");
@ -523,7 +523,7 @@ RPCChannel::DispatchIncall(const Message& call)
reply->set_seqno(call.seqno());
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (ChannelConnected == mChannelState)
SendThroughTransport(reply);
}
@ -578,7 +578,7 @@ RPCChannel::BlockOnParent()
if (!mChild)
NS_RUNTIMEABORT("child tried to block parent");
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (mBlockedOnParent || AwaitingSyncReply() || 0 < StackDepth())
NS_RUNTIMEABORT("attempt to block child when it's already blocked");
@ -602,7 +602,7 @@ RPCChannel::BlockOnParent()
Message recvd = mPending.front();
mPending.pop();
MutexAutoUnlock unlock(mMutex);
MonitorAutoUnlock unlock(mMonitor);
CxxStackFrame f(*this, IN_MESSAGE, &recvd);
if (recvd.is_rpc()) {
@ -628,7 +628,7 @@ RPCChannel::UnblockFromParent()
if (!mChild)
NS_RUNTIMEABORT("child tried to block parent");
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
mBlockedOnParent = false;
}
@ -637,7 +637,7 @@ RPCChannel::ExitedCxxStack()
{
Listener()->OnExitedCxxStack();
if (mSawRPCOutMsg) {
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
// see long comment in OnMaybeDequeueOne()
EnqueuePendingMessages();
mSawRPCOutMsg = false;
@ -710,7 +710,7 @@ void
RPCChannel::OnMessageReceived(const Message& msg)
{
AssertIOThread();
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (MaybeInterceptSpecialIOMessage(msg))
return;
@ -740,7 +740,7 @@ RPCChannel::OnChannelError()
{
AssertIOThread();
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (ChannelClosing != mChannelState)
mChannelState = ChannelError;

View File

@ -311,7 +311,7 @@ protected:
// Called from both threads
size_t StackDepth() const {
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
return mStack.size();
}
@ -425,7 +425,7 @@ protected:
// !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
// not protected by mMonitor. It is managed exclusively by the
// helper |class CxxStackFrame|.
std::vector<RPCFrame> mCxxStackFrames;

View File

@ -42,7 +42,7 @@
#include "nsDebug.h"
#include "nsTraceRefcnt.h"
using mozilla::MutexAutoLock;
using mozilla::MonitorAutoLock;
template<>
struct RunnableMethodTraits<mozilla::ipc::SyncChannel>
@ -88,7 +88,7 @@ bool
SyncChannel::EventOccurred()
{
AssertWorkerThread();
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
NS_ABORT_IF_FALSE(AwaitingSyncReply(), "not in wait loop");
return (!Connected() || 0 != mRecvd.type());
@ -98,7 +98,7 @@ bool
SyncChannel::Send(Message* msg, Message* reply)
{
AssertWorkerThread();
mMutex.AssertNotCurrentThreadOwns();
mMonitor.AssertNotCurrentThreadOwns();
NS_ABORT_IF_FALSE(!ProcessingSyncMessage(),
"violation of sync handler invariant");
NS_ABORT_IF_FALSE(msg->is_sync(), "can only Send() sync messages here");
@ -109,7 +109,7 @@ SyncChannel::Send(Message* msg, Message* reply)
msg->set_seqno(NextSeqno());
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (!Connected()) {
ReportConnectionError("SyncChannel");
@ -181,7 +181,7 @@ SyncChannel::OnDispatchMessage(const Message& msg)
reply->set_seqno(msg.seqno());
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (ChannelConnected == mChannelState)
SendThroughTransport(reply);
}
@ -200,7 +200,7 @@ SyncChannel::OnMessageReceived(const Message& msg)
return AsyncChannel::OnMessageReceived(msg);
}
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (MaybeInterceptSpecialIOMessage(msg))
return;
@ -223,7 +223,7 @@ SyncChannel::OnChannelError()
{
AssertIOThread();
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (ChannelClosing != mChannelState)
mChannelState = ChannelError;
@ -253,11 +253,11 @@ bool
SyncChannel::ShouldContinueFromTimeout()
{
AssertWorkerThread();
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
bool cont;
{
MutexAutoUnlock unlock(mMutex);
MonitorAutoUnlock unlock(mMonitor);
cont = static_cast<SyncListener*>(mListener)->OnReplyTimeout();
}
@ -295,7 +295,7 @@ SyncChannel::WaitForNotify()
// XXX could optimize away this syscall for "no timeout" case if desired
PRIntervalTime waitStart = PR_IntervalNow();
mCvar.Wait(timeout);
mMonitor.Wait(timeout);
// if the timeout didn't expire, we know we received an event.
// The converse is not true.
@ -305,7 +305,7 @@ SyncChannel::WaitForNotify()
void
SyncChannel::NotifyWorkerThread()
{
mCvar.Notify();
mMonitor.Notify();
}
#endif // ifndef OS_WIN

View File

@ -171,7 +171,7 @@ protected:
// On both
bool AwaitingSyncReply() const {
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
return mPendingReply != 0;
}

View File

@ -655,7 +655,7 @@ RPCChannel::SpinInternalEventLoop()
// Don't get wrapped up in here if the child connection dies.
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (!Connected()) {
return;
}
@ -692,7 +692,7 @@ RPCChannel::SpinInternalEventLoop()
bool
SyncChannel::WaitForNotify()
{
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
// Initialize global objects used in deferred messaging.
Init();
@ -700,7 +700,7 @@ SyncChannel::WaitForNotify()
NS_ASSERTION(mTopFrame && !mTopFrame->mRPC,
"Top frame is not a sync frame!");
MutexAutoUnlock unlock(mMutex);
MonitorAutoUnlock unlock(mMonitor);
bool retval = true;
@ -730,7 +730,7 @@ SyncChannel::WaitForNotify()
MSG msg = { 0 };
// Don't get wrapped up in here if the child connection dies.
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (!Connected()) {
break;
}
@ -814,7 +814,7 @@ SyncChannel::WaitForNotify()
bool
RPCChannel::WaitForNotify()
{
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
if (!StackDepth() && !mBlockedOnParent) {
// There is currently no way to recover from this condition.
@ -827,7 +827,7 @@ RPCChannel::WaitForNotify()
NS_ASSERTION(mTopFrame && mTopFrame->mRPC,
"Top frame is not a sync frame!");
MutexAutoUnlock unlock(mMutex);
MonitorAutoUnlock unlock(mMonitor);
bool retval = true;
@ -890,7 +890,7 @@ RPCChannel::WaitForNotify()
// Don't get wrapped up in here if the child connection dies.
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
if (!Connected()) {
break;
}
@ -954,7 +954,7 @@ RPCChannel::WaitForNotify()
void
SyncChannel::NotifyWorkerThread()
{
mMutex.AssertCurrentThreadOwns();
mMonitor.AssertCurrentThreadOwns();
NS_ASSERTION(mEvent, "No signal event to set, this is really bad!");
if (!SetEvent(mEvent)) {
NS_WARNING("Failed to set NotifyWorkerThread event!");