Bug 552294: *Channel::OnError must run atomically. r=bent
--- a/ipc/glue/AsyncChannel.cpp
+++ b/ipc/glue/AsyncChannel.cpp
@@ -439,21 +439,28 @@ AsyncChannel::OnChannelConnected(int32 p
void
AsyncChannel::OnChannelError()
{
AssertIOThread();
MutexAutoLock lock(mMutex);
- // NB: this can race with the `Goodbye' event being processed by
- // the worker thread
if (ChannelClosing != mChannelState)
mChannelState = ChannelError;
+ PostErrorNotifyTask();
+}
+
+void
+AsyncChannel::PostErrorNotifyTask()
+{
+ AssertIOThread();
+ mMutex.AssertCurrentThreadOwns();
+
NS_ASSERTION(!mChannelErrorTask, "OnChannelError called twice?");
// This must be the last code that runs on this thread!
mChannelErrorTask =
NewRunnableMethod(this, &AsyncChannel::OnNotifyMaybeChannelError);
mWorkerLoop->PostTask(FROM_HERE, mChannelErrorTask);
}
--- a/ipc/glue/AsyncChannel.h
+++ b/ipc/glue/AsyncChannel.h
@@ -170,16 +170,17 @@ protected:
virtual void Clear();
// Run on the IO thread
void OnChannelOpened();
void OnSend(Message* aMsg);
void OnCloseChannel();
+ void PostErrorNotifyTask();
// Return true if |msg| is a special message targeted at the IO
// thread, in which case it shouldn't be delivered to the worker.
bool MaybeInterceptSpecialIOMessage(const Message& msg);
void ProcessGoodbyeMessage();
Transport* mTransport;
AsyncListener* mListener;
--- a/ipc/glue/RPCChannel.cpp
+++ b/ipc/glue/RPCChannel.cpp
@@ -649,27 +649,23 @@ RPCChannel::OnMessageReceived(const Mess
}
void
RPCChannel::OnChannelError()
{
AssertIOThread();
- {
- MutexAutoLock lock(mMutex);
+ MutexAutoLock lock(mMutex);
+
+ if (ChannelClosing != mChannelState)
+ mChannelState = ChannelError;
- // NB: this can race with the `Goodbye' event being processed by
- // the worker thread
- if (ChannelClosing != mChannelState)
- mChannelState = ChannelError;
+ // skip SyncChannel::OnError(); we subsume its duties
+ if (AwaitingSyncReply() || 0 < StackDepth())
+ NotifyWorkerThread();
- // skip SyncChannel::OnError(); we subsume its duties
- if (AwaitingSyncReply() || 0 < StackDepth())
- NotifyWorkerThread();
- }
-
- AsyncChannel::OnChannelError();
+ PostErrorNotifyTask();
}
} // namespace ipc
} // namespace mozilla
--- a/ipc/glue/SyncChannel.cpp
+++ b/ipc/glue/SyncChannel.cpp
@@ -208,29 +208,25 @@ SyncChannel::OnMessageReceived(const Mes
}
}
void
SyncChannel::OnChannelError()
{
AssertIOThread();
- {
- MutexAutoLock lock(mMutex);
+ MutexAutoLock lock(mMutex);
+
+ if (ChannelClosing != mChannelState)
+ mChannelState = ChannelError;
- // NB: this can race with the `Goodbye' event being processed by
- // the worker thread
- if (ChannelClosing != mChannelState)
- mChannelState = ChannelError;
+ if (AwaitingSyncReply())
+ NotifyWorkerThread();
- if (AwaitingSyncReply())
- NotifyWorkerThread();
- }
-
- AsyncChannel::OnChannelError();
+ PostErrorNotifyTask();
}
//
// Synchronization between worker and IO threads
//
namespace {