Bug 540886, part 1: Refactor "special message" dispatch in AsyncChannel. r=bent
authorChris Jones <jones.chris.g@gmail.com>
Wed, 27 Jan 2010 00:41:31 -0600
changeset 38099 07ed72e5400b3bc715ec6d48e9d39ef14e3fcdb0
parent 38098 26ee15150bf703b614cec5aa00a83a5f69382140
child 38100 b89339a2523d8ace64c6ce60fa38fc8eb2067c27
push id11617
push usercjones@mozilla.com
push dateFri, 12 Feb 2010 05:46:47 +0000
treeherdermozilla-central@c5ca3076da1b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs540886
milestone1.9.3a2pre
Bug 540886, part 1: Refactor "special message" dispatch in AsyncChannel. r=bent
ipc/glue/AsyncChannel.cpp
ipc/glue/AsyncChannel.h
--- a/ipc/glue/AsyncChannel.cpp
+++ b/ipc/glue/AsyncChannel.cpp
@@ -49,16 +49,42 @@ using mozilla::MutexAutoLock;
 
 template<>
 struct RunnableMethodTraits<mozilla::ipc::AsyncChannel>
 {
     static void RetainCallee(mozilla::ipc::AsyncChannel* obj) { }
     static void ReleaseCallee(mozilla::ipc::AsyncChannel* obj) { }
 };
 
+namespace {
+
+// This is an async message
+class GoodbyeMessage : public IPC::Message
+{
+public:
+    enum { ID = GOODBYE_MESSAGE_TYPE };
+    GoodbyeMessage() :
+        IPC::Message(MSG_ROUTING_NONE, ID, PRIORITY_NORMAL)
+    {
+    }
+    // XXX not much point in implementing this; maybe could help with
+    // debugging?
+    static bool Read(const Message* msg)
+    {
+        return true;
+    }
+    void Log(const std::string& aPrefix,
+             FILE* aOutf) const
+    {
+        fputs("(special `Goodbye' message)", aOutf);
+    }
+};
+
+} // namespace <anon>
+
 namespace mozilla {
 namespace ipc {
 
 AsyncChannel::AsyncChannel(AsyncListener* aListener)
   : mTransport(0),
     mListener(aListener),
     mChannelState(ChannelClosed),
     mMutex("mozilla.ipc.AsyncChannel.mMutex"),
@@ -145,17 +171,17 @@ AsyncChannel::Close()
         if (ChannelConnected != mChannelState)
             // XXX be strict about this until there's a compelling reason
             // to relax
             NS_RUNTIMEABORT("Close() called on closed channel!");
 
         AssertWorkerThread();
 
         // notify the other side that we're about to close our socket
-        SendGoodbye();
+        SendSpecialMessage(new GoodbyeMessage());
 
         mChannelState = ChannelClosing;
 
         // and post the task will do the actual close
         mIOLoop->PostTask(
             FROM_HERE, NewRunnableMethod(this, &AsyncChannel::OnCloseChannel));
 
         while (ChannelClosing == mChannelState)
@@ -193,70 +219,54 @@ AsyncChannel::Send(Message* msg)
 
 void
 AsyncChannel::OnDispatchMessage(const Message& msg)
 {
     AssertWorkerThread();
     NS_ASSERTION(!msg.is_reply(), "can't process replies here");
     NS_ASSERTION(!(msg.is_sync() || msg.is_rpc()), "async dispatch only");
 
-    if (MaybeInterceptGoodbye(msg))
-        // there's a NotifyMaybeChannelError event waiting for us, or
-        // will be soon
+    if (MSG_ROUTING_NONE == msg.routing_id()) {
+        if (!OnSpecialMessage(msg.type(), msg))
+            // XXX real error handling
+            NS_RUNTIMEABORT("unhandled special message!");
         return;
+    }
 
     // it's OK to dispatch messages if the channel is closed/error'd,
     // since we don't have a reply to send back
 
     (void)MaybeHandleError(mListener->OnMessageReceived(msg), "AsyncChannel");
 }
 
-// This is an async message
-class GoodbyeMessage : public IPC::Message
+bool
+AsyncChannel::OnSpecialMessage(uint16 id, const Message& msg)
 {
-public:
-    enum { ID = GOODBYE_MESSAGE_TYPE };
-    GoodbyeMessage() :
-        IPC::Message(MSG_ROUTING_NONE, ID, PRIORITY_NORMAL)
-    {
+    switch (id) {
+    case GOODBYE_MESSAGE_TYPE:
+        return ProcessGoodbyeMessage();
+
+    default:
+        return false;
     }
-    // XXX not much point in implementing this; maybe could help with
-    // debugging?
-    static bool Read(const Message* msg)
-    {
-        return true;
-    }
-    void Log(const std::string& aPrefix,
-             FILE* aOutf) const
-    {
-        fputs("(special `Goodbye' message)", aOutf);
-    }
-};
+}
 
 void
-AsyncChannel::SendGoodbye()
+AsyncChannel::SendSpecialMessage(Message* msg)
 {
     AssertWorkerThread();
 
     mIOLoop->PostTask(
         FROM_HERE,
-        NewRunnableMethod(this, &AsyncChannel::OnSend, new GoodbyeMessage()));
+        NewRunnableMethod(this, &AsyncChannel::OnSend, msg));
 }
 
 bool
-AsyncChannel::MaybeInterceptGoodbye(const Message& msg)
+AsyncChannel::ProcessGoodbyeMessage()
 {
-    // IPDL code isn't allowed to send MSG_ROUTING_NONE messages, so
-    // there's no chance of confusion here
-    if (MSG_ROUTING_NONE != msg.routing_id())
-        return false;
-
-    if (msg.is_sync() || msg.is_rpc() || GOODBYE_MESSAGE_TYPE != msg.type())
-        NS_RUNTIMEABORT("received unknown MSG_ROUTING_NONE message when expecting `Goodbye'");
-
     MutexAutoLock lock(mMutex);
     // TODO sort out Close() on this side racing with Close() on the
     // other side
     mChannelState = ChannelClosing;
 
     printf("NOTE: %s process received `Goodbye', closing down\n",
            mChild ? "child" : "parent");
 
--- a/ipc/glue/AsyncChannel.h
+++ b/ipc/glue/AsyncChannel.h
@@ -138,29 +138,31 @@ protected:
 
     bool Connected() {
         mMutex.AssertCurrentThreadOwns();
         return ChannelConnected == mChannelState;
     }
 
     // Run on the worker thread
     void OnDispatchMessage(const Message& aMsg);
+    virtual bool OnSpecialMessage(uint16 id, const Message& msg);
+    void SendSpecialMessage(Message* msg);
+
     bool MaybeHandleError(Result code, const char* channelName);
     void ReportConnectionError(const char* channelName);
 
     void PrintErrorMessage(const char* channelName, const char* msg)
     {
         fprintf(stderr, "\n###!!! [%s][%s] Error: %s\n\n",
                 mChild ? "Child" : "Parent", channelName, msg);
     }
 
     // Run on the worker thread
 
-    void SendGoodbye();
-    bool MaybeInterceptGoodbye(const Message& msg);
+    bool ProcessGoodbyeMessage();
 
     void NotifyChannelClosed();
     void NotifyMaybeChannelError();
 
     void Clear();
 
     // Run on the IO thread