LCOV - app.info - ipc/glue/RPCChannel.cpp

LCOV - code coverage report
| Current view: | directory - ipc/glue - RPCChannel.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 326 | 7 | 2.1 %
| Date: | 2012-04-21 | Functions: | 34 | 3 | 8.8 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: sw=4 ts=4 et :
           3                 :  */
           4                 : /* ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla Plugin App.
          18                 :  *
          19                 :  * The Initial Developer of the Original Code is
          20                 :  *   Chris Jones <jones.chris.g@gmail.com>
          21                 :  * Portions created by the Initial Developer are Copyright (C) 2009
          22                 :  * the Initial Developer. All Rights Reserved.
          23                 :  *
          24                 :  * Contributor(s):
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : #include "mozilla/ipc/RPCChannel.h"
          41                 : #include "mozilla/ipc/ProtocolUtils.h"
          42                 :
          43                 : #include "nsDebug.h"
          44                 : #include "nsTraceRefcnt.h"
          45                 :
          46                 : #define RPC_ASSERT(_cond, ...)                                      \
          47                 :     do {                                                            \
          48                 :         if (!(_cond))                                               \
          49                 :             DebugAbort(__FILE__, __LINE__, #_cond,## __VA_ARGS__);  \
          50                 :     } while (0)
          51                 :
          52                 : using mozilla::MonitorAutoLock;
          53                 : using mozilla::MonitorAutoUnlock;
          54                 :
          55                 : template<>
          56                 : struct RunnableMethodTraits<mozilla::ipc::RPCChannel>
          57               1 : {
          58               1 :     static void RetainCallee(mozilla::ipc::RPCChannel* obj) { }
          59               0 :     static void ReleaseCallee(mozilla::ipc::RPCChannel* obj) { }
          60                 : };
          61                 :
          62                 :
          63                 : namespace
          64                 : {
          65                 :
          66                 : // Async (from the sending side's perspective)
          67                 : class BlockChildMessage : public IPC::Message
          68               0 : {
          69                 : public:
          70                 :     enum { ID = BLOCK_CHILD_MESSAGE_TYPE };
          71               0 :     BlockChildMessage() :
          72               0 :         Message(MSG_ROUTING_NONE, ID, IPC::Message::PRIORITY_NORMAL)
          73               0 :     { }
          74                 : };
          75                 :
          76                 : // Async
          77                 : class UnblockChildMessage : public IPC::Message
          78               0 : {
          79                 : public:
          80                 :     enum { ID = UNBLOCK_CHILD_MESSAGE_TYPE };
          81               0 :     UnblockChildMessage() :
          82               0 :         Message(MSG_ROUTING_NONE, ID, IPC::Message::PRIORITY_NORMAL)
          83               0 :     { }
          84                 : };
          85                 :
          86                 : } // namespace <anon>
          87                 :
          88                 :
          89                 : namespace mozilla {
          90                 : namespace ipc {
          91                 :
          92               1 : RPCChannel::RPCChannel(RPCListener* aListener)
          93                 :   : SyncChannel(aListener),
          94                 :     mPending(),
          95                 :     mStack(),
          96                 :     mOutOfTurnReplies(),
          97                 :     mDeferred(),
          98                 :     mRemoteStackDepthGuess(0),
          99                 :     mBlockedOnParent(false),
         100               1 :     mSawRPCOutMsg(false)
         101                 : {
         102               1 :     MOZ_COUNT_CTOR(RPCChannel);
         103                 :
         104                 :     mDequeueOneTask = new RefCountedTask(NewRunnableMethod(
         105                 :                                                  this,
         106               2 :                                                  &RPCChannel::OnMaybeDequeueOne));
         107               1 : }
         108                 :
         109               0 : RPCChannel::~RPCChannel()
         110                 : {
         111               0 :     MOZ_COUNT_DTOR(RPCChannel);
         112               0 :     RPC_ASSERT(mCxxStackFrames.empty(), "mismatched CxxStackFrame ctor/dtors");
         113               0 : }
         114                 :
         115                 : void
         116               0 : RPCChannel::Clear()
         117                 : {
         118               0 :     mDequeueOneTask->Cancel();
         119                 :
         120               0 :     AsyncChannel::Clear();
         121               0 : }
         122                 :
         123                 : bool
         124               0 : RPCChannel::EventOccurred() const
         125                 : {
         126               0 :     AssertWorkerThread();
         127               0 :     mMonitor->AssertCurrentThreadOwns();
         128               0 :     RPC_ASSERT(StackDepth() > 0, "not in wait loop");
         129                 :
         130               0 :     return (!Connected() ||
         131               0 :             !mPending.empty() ||
         132               0 :             (!mOutOfTurnReplies.empty() &&
         133               0 :              mOutOfTurnReplies.find(mStack.top().seqno())
         134               0 :              != mOutOfTurnReplies.end()));
         135                 : }
         136                 :
         137                 : bool
         138               0 : RPCChannel::Send(Message* msg)
         139                 : {
         140               0 :     Message copy = *msg;
         141               0 :     CxxStackFrame f(*this, OUT_MESSAGE, &copy);
         142               0 :     return AsyncChannel::Send(msg);
         143                 : }
         144                 :
         145                 : bool
         146               0 : RPCChannel::Send(Message* msg, Message* reply)
         147                 : {
         148               0 :     Message copy = *msg;
         149               0 :     CxxStackFrame f(*this, OUT_MESSAGE, &copy);
         150               0 :     return SyncChannel::Send(msg, reply);
         151                 : }
         152                 :
         153                 : bool
         154               0 : RPCChannel::Call(Message* _msg, Message* reply)
         155                 : {
         156               0 :     nsAutoPtr<Message> msg(_msg);
         157               0 :     AssertWorkerThread();
         158               0 :     mMonitor->AssertNotCurrentThreadOwns();
         159               0 :     RPC_ASSERT(!ProcessingSyncMessage(),
         160                 :                "violation of sync handler invariant");
         161               0 :     RPC_ASSERT(msg->is_rpc(), "can only Call() RPC messages here");
         162                 :
         163                 : #ifdef OS_WIN
         164                 :     SyncStackFrame frame(this, true);
         165                 : #endif
         166                 :
         167               0 :     Message copy = *msg;
         168               0 :     CxxStackFrame f(*this, OUT_MESSAGE, &copy);
         169                 :
         170               0 :     MonitorAutoLock lock(*mMonitor);
         171                 :
         172               0 :     if (!Connected()) {
         173               0 :         ReportConnectionError("RPCChannel");
         174               0 :         return false;
         175                 :     }
         176                 :
         177               0 :     msg->set_seqno(NextSeqno());
         178               0 :     msg->set_rpc_remote_stack_depth_guess(mRemoteStackDepthGuess);
         179               0 :     msg->set_rpc_local_stack_depth(1 + StackDepth());
         180               0 :     mStack.push(*msg);
         181                 :
         182               0 :     mLink->SendMessage(msg.forget());
         183                 :
         184               0 :     while (1) {
         185                 :         // if a handler invoked by *Dispatch*() spun a nested event
         186                 :         // loop, and the connection was broken during that loop, we
         187                 :         // might have already processed the OnError event. if so,
         188                 :         // trying another loop iteration will be futile because
         189                 :         // channel state will have been cleared
         190               0 :         if (!Connected()) {
         191               0 :             ReportConnectionError("RPCChannel");
         192               0 :             return false;
         193                 :         }
         194                 :
         195                 :         // now might be the time to process a message deferred because
         196                 :         // of race resolution
         197               0 :         MaybeUndeferIncall();
         198                 :
         199                 :         // here we're waiting for something to happen. see long
         200                 :         // comment about the queue in RPCChannel.h
         201               0 :         while (!EventOccurred()) {
         202               0 :             bool maybeTimedOut = !RPCChannel::WaitForNotify();
         203                 :
         204               0 :             if (EventOccurred() ||
         205                 :                 // we might have received a "subtly deferred" message
         206                 :                 // in a nested loop that it's now time to process
         207               0 :                 (!maybeTimedOut &&
         208               0 :                  (!mDeferred.empty() || !mOutOfTurnReplies.empty())))
         209               0 :                 break;
         210                 :
         211               0 :             if (maybeTimedOut && !ShouldContinueFromTimeout())
         212               0 :                 return false;
         213                 :         }
         214                 :
         215               0 :         if (!Connected()) {
         216               0 :             ReportConnectionError("RPCChannel");
         217               0 :             return false;
         218                 :         }
         219                 :
         220               0 :         Message recvd;
         221               0 :         MessageMap::iterator it;
         222               0 :         if (!mOutOfTurnReplies.empty() &&
         223               0 :             ((it = mOutOfTurnReplies.find(mStack.top().seqno())) !=
         224               0 :             mOutOfTurnReplies.end())) {
         225               0 :             recvd = it->second;
         226               0 :             mOutOfTurnReplies.erase(it);
         227                 :         }
         228               0 :         else if (!mPending.empty()) {
         229               0 :             recvd = mPending.front();
         230               0 :             mPending.pop();
         231                 :         }
         232                 :         else {
         233                 :             // because of subtleties with nested event loops, it's
         234                 :             // possible that we got here and nothing happened.  or, we
         235                 :             // might have a deferred in-call that needs to be
         236                 :             // processed.  either way, we won't break the inner while
         237                 :             // loop again until something new happens.
         238               0 :             continue;
         239                 :         }
         240                 :
         241               0 :         if (!recvd.is_sync() && !recvd.is_rpc()) {
         242               0 :             MonitorAutoUnlock unlock(*mMonitor);
         243                 :
         244               0 :             CxxStackFrame f(*this, IN_MESSAGE, &recvd);
         245               0 :             AsyncChannel::OnDispatchMessage(recvd);
         246                 :
         247               0 :             continue;
         248                 :         }
         249                 :
         250               0 :         if (recvd.is_sync()) {
         251               0 :             RPC_ASSERT(mPending.empty(),
         252                 :                        "other side should have been blocked");
         253               0 :             MonitorAutoUnlock unlock(*mMonitor);
         254                 :
         255               0 :             CxxStackFrame f(*this, IN_MESSAGE, &recvd);
         256               0 :             SyncChannel::OnDispatchMessage(recvd);
         257                 :
         258               0 :             continue;
         259                 :         }
         260                 :
         261               0 :         RPC_ASSERT(recvd.is_rpc(), "wtf???");
         262                 :
         263               0 :         if (recvd.is_reply()) {
         264               0 :             RPC_ASSERT(0 < mStack.size(), "invalid RPC stack");
         265                 :
         266               0 :             const Message& outcall = mStack.top();
         267                 :
         268                 :             // in the parent, seqno's increase from 0, and in the
         269                 :             // child, they decrease from 0
         270               0 :             if ((!mChild && recvd.seqno() < outcall.seqno()) ||
         271               0 :                 (mChild && recvd.seqno() > outcall.seqno())) {
         272               0 :                 mOutOfTurnReplies[recvd.seqno()] = recvd;
         273               0 :                 continue;
         274                 :             }
         275                 :
         276                 :             // FIXME/cjones: handle error
         277               0 :             RPC_ASSERT(
         278                 :                 recvd.is_reply_error() ||
         279                 :                 (recvd.type() == (outcall.type()+1) &&
         280                 :                  recvd.seqno() == outcall.seqno()),
         281                 :                 "somebody's misbehavin'", "rpc", true);
         282                 :
         283                 :             // we received a reply to our most recent outstanding
         284                 :             // call.  pop this frame and return the reply
         285               0 :             mStack.pop();
         286                 :
         287               0 :             bool isError = recvd.is_reply_error();
         288               0 :             if (!isError) {
         289               0 :                 *reply = recvd;
         290                 :             }
         291                 :
         292               0 :             if (0 == StackDepth()) {
         293               0 :                 RPC_ASSERT(
         294                 :                     mOutOfTurnReplies.empty(),
         295                 :                     "still have pending replies with no pending out-calls",
         296                 :                     "rpc", true);
         297                 :             }
         298                 :
         299                 :             // finished with this RPC stack frame
         300               0 :             return !isError;
         301                 :         }
         302                 :
         303                 :         // in-call.  process in a new stack frame.
         304                 :
         305                 :         // "snapshot" the current stack depth while we own the Monitor
         306               0 :         size_t stackDepth = StackDepth();
         307                 :         {
         308               0 :             MonitorAutoUnlock unlock(*mMonitor);
         309                 :             // someone called in to us from the other side.  handle the call
         310               0 :             CxxStackFrame f(*this, IN_MESSAGE, &recvd);
         311               0 :             Incall(recvd, stackDepth);
         312                 :             // FIXME/cjones: error handling
         313                 :         }
         314                 :     }
         315                 :
         316                 :     return true;
         317                 : }
         318                 :
         319                 : void
         320               0 : RPCChannel::MaybeUndeferIncall()
         321                 : {
         322               0 :     AssertWorkerThread();
         323               0 :     mMonitor->AssertCurrentThreadOwns();
         324                 :
         325               0 :     if (mDeferred.empty())
         326               0 :         return;
         327                 :
         328               0 :     size_t stackDepth = StackDepth();
         329                 :
         330                 :     // the other side can only *under*-estimate our actual stack depth
         331               0 :     RPC_ASSERT(mDeferred.top().rpc_remote_stack_depth_guess() <= stackDepth,
         332                 :                "fatal logic error");
         333                 :
         334               0 :     if (mDeferred.top().rpc_remote_stack_depth_guess() < RemoteViewOfStackDepth(stackDepth))
         335               0 :         return;
         336                 :
         337                 :     // maybe time to process this message
         338               0 :     Message call = mDeferred.top();
         339               0 :     mDeferred.pop();
         340                 :
         341                 :     // fix up fudge factor we added to account for race
         342               0 :     RPC_ASSERT(0 < mRemoteStackDepthGuess, "fatal logic error");
         343               0 :     --mRemoteStackDepthGuess;
         344                 :
         345               0 :     mPending.push(call);
         346                 : }
         347                 :
         348                 : void
         349               0 : RPCChannel::EnqueuePendingMessages()
         350                 : {
         351               0 :     AssertWorkerThread();
         352               0 :     mMonitor->AssertCurrentThreadOwns();
         353                 :
         354               0 :     MaybeUndeferIncall();
         355                 :
         356               0 :     for (size_t i = 0; i < mDeferred.size(); ++i)
         357                 :         mWorkerLoop->PostTask(
         358                 :             FROM_HERE,
         359               0 :             new DequeueTask(mDequeueOneTask));
         360                 :
         361                 :     // XXX performance tuning knob: could process all or k pending
         362                 :     // messages here, rather than enqueuing for later processing
         363                 :
         364               0 :     for (size_t i = 0; i < mPending.size(); ++i)
         365                 :         mWorkerLoop->PostTask(
         366                 :             FROM_HERE,
         367               0 :             new DequeueTask(mDequeueOneTask));
         368               0 : }
         369                 :
         370                 : void
         371               0 : RPCChannel::FlushPendingRPCQueue()
         372                 : {
         373               0 :     AssertWorkerThread();
         374               0 :     mMonitor->AssertNotCurrentThreadOwns();
         375                 :
         376                 :     {
         377               0 :         MonitorAutoLock lock(*mMonitor);
         378                 :
         379               0 :         if (mDeferred.empty()) {
         380               0 :             if (mPending.empty())
         381                 :                 return;
         382                 :
         383               0 :             const Message& last = mPending.back();
         384               0 :             if (!last.is_rpc() || last.is_reply())
         385                 :                 return;
         386                 :         }
         387                 :     }
         388                 :
         389               0 :     while (OnMaybeDequeueOne());
         390                 : }
         391                 :
         392                 : bool
         393               0 : RPCChannel::OnMaybeDequeueOne()
         394                 : {
         395                 :     // XXX performance tuning knob: could process all or k pending
         396                 :     // messages here
         397                 :
         398               0 :     AssertWorkerThread();
         399               0 :     mMonitor->AssertNotCurrentThreadOwns();
         400                 :
         401               0 :     Message recvd;
         402                 :     {
         403               0 :         MonitorAutoLock lock(*mMonitor);
         404                 :
         405               0 :         if (!Connected()) {
         406               0 :             ReportConnectionError("RPCChannel");
         407               0 :             return false;
         408                 :         }
         409                 :
         410               0 :         if (!mDeferred.empty())
         411               0 :             MaybeUndeferIncall();
         412                 :
         413               0 :         if (mPending.empty())
         414               0 :             return false;
         415                 :
         416               0 :         recvd = mPending.front();
         417               0 :         mPending.pop();
         418                 :     }
         419                 :
         420               0 :     if (IsOnCxxStack() && recvd.is_rpc() && recvd.is_reply()) {
         421                 :         // We probably just received a reply in a nested loop for an
         422                 :         // RPC call sent before entering that loop.
         423               0 :         mOutOfTurnReplies[recvd.seqno()] = recvd;
         424               0 :         return false;
         425                 :     }
         426                 :
         427               0 :     CxxStackFrame f(*this, IN_MESSAGE, &recvd);
         428                 :
         429               0 :     if (recvd.is_rpc())
         430               0 :         Incall(recvd, 0);
         431               0 :     else if (recvd.is_sync())
         432               0 :         SyncChannel::OnDispatchMessage(recvd);
         433                 :     else
         434               0 :         AsyncChannel::OnDispatchMessage(recvd);
         435                 :
         436               0 :     return true;
         437                 : }
         438                 :
         439                 : size_t
         440               0 : RPCChannel::RemoteViewOfStackDepth(size_t stackDepth) const
         441                 : {
         442               0 :     AssertWorkerThread();
         443               0 :     return stackDepth - mOutOfTurnReplies.size();
         444                 : }
         445                 :
         446                 : void
         447               0 : RPCChannel::Incall(const Message& call, size_t stackDepth)
         448                 : {
         449               0 :     AssertWorkerThread();
         450               0 :     mMonitor->AssertNotCurrentThreadOwns();
         451               0 :     RPC_ASSERT(call.is_rpc() && !call.is_reply(), "wrong message type");
         452                 :
         453                 :     // Race detection: see the long comment near
         454                 :     // mRemoteStackDepthGuess in RPCChannel.h.  "Remote" stack depth
         455                 :     // means our side, and "local" means other side.
         456               0 :     if (call.rpc_remote_stack_depth_guess() != RemoteViewOfStackDepth(stackDepth)) {
         457                 :         // RPC in-calls have raced.
         458                 :         // the "winner", if there is one, gets to defer processing of
         459                 :         // the other side's in-call
         460                 :         bool defer;
         461                 :         const char* winner;
         462               0 :         switch (Listener()->MediateRPCRace(mChild ? call : mStack.top(),
         463               0 :                                            mChild ? mStack.top() : call)) {
         464                 :         case RRPChildWins:
         465               0 :             winner = "child";
         466               0 :             defer = mChild;
         467               0 :             break;
         468                 :         case RRPParentWins:
         469               0 :             winner = "parent";
         470               0 :             defer = !mChild;
         471               0 :             break;
         472                 :         case RRPError:
         473               0 :             NS_RUNTIMEABORT("NYI: 'Error' RPC race policy");
         474               0 :             return;
         475                 :         default:
         476               0 :             NS_RUNTIMEABORT("not reached");
         477               0 :             return;
         478                 :         }
         479                 :
         480               0 :         if (LoggingEnabled()) {
         481                 :             fprintf(stderr, "  (%s: %s won, so we're%sdeferring)\n",
         482               0 :                     mChild ? "child" : "parent", winner, defer ? " " : " not ");
         483                 :         }
         484                 :
         485               0 :         if (defer) {
         486                 :             // we now know the other side's stack has one more frame
         487                 :             // than we thought
         488               0 :             ++mRemoteStackDepthGuess; // decremented in MaybeProcessDeferred()
         489               0 :             mDeferred.push(call);
         490               0 :             return;
         491                 :         }
         492                 :
         493                 :         // we "lost" and need to process the other side's in-call.
         494                 :         // don't need to fix up the mRemoteStackDepthGuess here,
         495                 :         // because we're just about to increment it in DispatchCall(),
         496                 :         // which will make it correct again
         497                 :     }
         498                 :
         499                 : #ifdef OS_WIN
         500                 :     SyncStackFrame frame(this, true);
         501                 : #endif
         502                 :
         503               0 :     DispatchIncall(call);
         504                 : }
         505                 :
         506                 : void
         507               0 : RPCChannel::DispatchIncall(const Message& call)
         508                 : {
         509               0 :     AssertWorkerThread();
         510               0 :     mMonitor->AssertNotCurrentThreadOwns();
         511               0 :     RPC_ASSERT(call.is_rpc() && !call.is_reply(),
         512                 :                "wrong message type");
         513                 :
         514               0 :     Message* reply = nsnull;
         515                 :
         516               0 :     ++mRemoteStackDepthGuess;
         517               0 :     Result rv = Listener()->OnCallReceived(call, reply);
         518               0 :     --mRemoteStackDepthGuess;
         519                 :
         520               0 :     if (!MaybeHandleError(rv, "RPCChannel")) {
         521               0 :         delete reply;
         522               0 :         reply = new Message();
         523               0 :         reply->set_rpc();
         524               0 :         reply->set_reply();
         525               0 :         reply->set_reply_error();
         526                 :     }
         527                 :
         528               0 :     reply->set_seqno(call.seqno());
         529                 :
         530                 :     {
         531               0 :         MonitorAutoLock lock(*mMonitor);
         532               0 :         if (ChannelConnected == mChannelState)
         533               0 :             mLink->SendMessage(reply);
         534                 :     }
         535               0 : }
         536                 :
         537                 : bool
         538               0 : RPCChannel::BlockChild()
         539                 : {
         540               0 :     AssertWorkerThread();
         541                 :
         542               0 :     if (mChild)
         543               0 :         NS_RUNTIMEABORT("child tried to block parent");
         544                 :
         545               0 :     MonitorAutoLock lock(*mMonitor);
         546               0 :     SendSpecialMessage(new BlockChildMessage());
         547               0 :     return true;
         548                 : }
         549                 :
         550                 : bool
         551               0 : RPCChannel::UnblockChild()
         552                 : {
         553               0 :     AssertWorkerThread();
         554                 :
         555               0 :     if (mChild)
         556               0 :         NS_RUNTIMEABORT("child tried to unblock parent");
         557                 :
         558               0 :     MonitorAutoLock lock(*mMonitor);
         559               0 :     SendSpecialMessage(new UnblockChildMessage());
         560               0 :     return true;
         561                 : }
         562                 :
         563                 : bool
         564               0 : RPCChannel::OnSpecialMessage(uint16 id, const Message& msg)
         565                 : {
         566               0 :     AssertWorkerThread();
         567                 :
         568               0 :     switch (id) {
         569                 :     case BLOCK_CHILD_MESSAGE_TYPE:
         570               0 :         BlockOnParent();
         571               0 :         return true;
         572                 :
         573                 :     case UNBLOCK_CHILD_MESSAGE_TYPE:
         574               0 :         UnblockFromParent();
         575               0 :         return true;
         576                 :
         577                 :     default:
         578               0 :         return SyncChannel::OnSpecialMessage(id, msg);
         579                 :     }
         580                 : }
         581                 :
         582                 : void
         583               0 : RPCChannel::BlockOnParent()
         584                 : {
         585               0 :     AssertWorkerThread();
         586                 :
         587               0 :     if (!mChild)
         588               0 :         NS_RUNTIMEABORT("child tried to block parent");
         589                 :
         590               0 :     MonitorAutoLock lock(*mMonitor);
         591                 :
         592               0 :     if (mBlockedOnParent || AwaitingSyncReply() || 0 < StackDepth())
         593               0 :         NS_RUNTIMEABORT("attempt to block child when it's already blocked");
         594                 :
         595               0 :     mBlockedOnParent = true;
         596               0 :     do {
         597                 :         // XXX this dispatch loop shares some similarities with the
         598                 :         // one in Call(), but the logic is simpler and different
         599                 :         // enough IMHO to warrant its own dispatch loop
         600               0 :         while (Connected() && mPending.empty() && mBlockedOnParent) {
         601               0 :             WaitForNotify();
         602                 :         }
         603                 :
         604               0 :         if (!Connected()) {
         605               0 :             mBlockedOnParent = false;
         606               0 :             ReportConnectionError("RPCChannel");
         607               0 :             break;
         608                 :         }
         609                 :
         610               0 :         if (!mPending.empty()) {
         611               0 :             Message recvd = mPending.front();
         612               0 :             mPending.pop();
         613                 :
         614               0 :             MonitorAutoUnlock unlock(*mMonitor);
         615                 :
         616               0 :             CxxStackFrame f(*this, IN_MESSAGE, &recvd);
         617               0 :             if (recvd.is_rpc()) {
         618                 :                 // stack depth must be 0 here
         619               0 :                 Incall(recvd, 0);
         620                 :             }
         621               0 :             else if (recvd.is_sync()) {
         622               0 :                 SyncChannel::OnDispatchMessage(recvd);
         623                 :             }
         624                 :             else {
         625               0 :                 AsyncChannel::OnDispatchMessage(recvd);
         626                 :             }
         627                 :         }
         628                 :     } while (mBlockedOnParent);
         629                 :
         630               0 :     EnqueuePendingMessages();
         631               0 : }
         632                 :
         633                 : void
         634               0 : RPCChannel::UnblockFromParent()
         635                 : {
         636               0 :     AssertWorkerThread();
         637                 :
         638               0 :     if (!mChild)
         639               0 :         NS_RUNTIMEABORT("child tried to block parent");
         640               0 :     MonitorAutoLock lock(*mMonitor);
         641               0 :     mBlockedOnParent = false;
         642               0 : }
         643                 :
         644                 : void
         645               0 : RPCChannel::ExitedCxxStack()
         646                 : {
         647               0 :     Listener()->OnExitedCxxStack();
         648               0 :     if (mSawRPCOutMsg) {
         649               0 :         MonitorAutoLock lock(*mMonitor);
         650                 :         // see long comment in OnMaybeDequeueOne()
         651               0 :         EnqueuePendingMessages();
         652               0 :         mSawRPCOutMsg = false;
         653                 :     }
         654               0 : }
         655                 :
         656                 : void
         657               0 : RPCChannel::DebugAbort(const char* file, int line, const char* cond,
         658                 :                        const char* why,
         659                 :                        const char* type, bool reply) const
         660                 : {
         661                 :     fprintf(stderr,
         662                 :             "###!!! [RPCChannel][%s][%s:%d] "
         663                 :             "Assertion (%s) failed.  %s (triggered by %s%s)\n",
         664                 :             mChild ? "Child" : "Parent",
         665                 :             file, line, cond,
         666                 :             why,
         667               0 :             type, reply ? "reply" : "");
         668                 :     // technically we need the mutex for this, but we're dying anyway
         669               0 :     DumpRPCStack(stderr, "  ");
         670                 :     fprintf(stderr, "  remote RPC stack guess: %lu\n",
         671               0 :             mRemoteStackDepthGuess);
         672                 :     fprintf(stderr, "  deferred stack size: %lu\n",
         673               0 :             mDeferred.size());
         674                 :     fprintf(stderr, "  out-of-turn RPC replies stack size: %lu\n",
         675               0 :             mOutOfTurnReplies.size());
         676                 :     fprintf(stderr, "  Pending queue size: %lu, front to back:\n",
         677               0 :             mPending.size());
         678                 :
         679               0 :     MessageQueue pending = mPending;
         680               0 :     while (!pending.empty()) {
         681                 :         fprintf(stderr, "    [ %s%s ]\n",
         682               0 :                 pending.front().is_rpc() ? "rpc" :
         683               0 :                 (pending.front().is_sync() ? "sync" : "async"),
         684               0 :                 pending.front().is_reply() ? "reply" : "");
         685               0 :         pending.pop();
         686                 :     }
         687                 :
         688               0 :     NS_RUNTIMEABORT(why);
         689               0 : }
         690                 :
         691                 : void
         692               0 : RPCChannel::DumpRPCStack(FILE* outfile, const char* const pfx) const
         693                 : {
         694               0 :     NS_WARN_IF_FALSE(MessageLoop::current() != mWorkerLoop,
         695                 :                      "The worker thread had better be paused in a debugger!");
         696                 :
         697               0 :     if (!outfile)
         698               0 :         outfile = stdout;
         699                 :
         700               0 :     fprintf(outfile, "%sRPCChannel 'backtrace':\n", pfx);
         701                 :
         702                 :     // print a python-style backtrace, first frame to last
         703               0 :     for (PRUint32 i = 0; i < mCxxStackFrames.size(); ++i) {
         704                 :         int32 id;
         705                 :         const char* dir, *sems, *name;
         706               0 :         mCxxStackFrames[i].Describe(&id, &dir, &sems, &name);
         707                 :
         708                 :         fprintf(outfile, "%s[(%u) %s %s %s(actor=%d) ]\n", pfx,
         709               0 :                 i, dir, sems, name, id);
         710                 :     }
         711               0 : }
         712                 :
         713                 : //
         714                 : // The methods below run in the context of the link thread, and can proxy
         715                 : // back to the methods above
         716                 : //
         717                 :
         718                 : void
         719               0 : RPCChannel::OnMessageReceivedFromLink(const Message& msg)
         720                 : {
         721               0 :     AssertLinkThread();
         722               0 :     mMonitor->AssertCurrentThreadOwns();
         723                 :
         724               0 :     if (MaybeInterceptSpecialIOMessage(msg))
         725               0 :         return;
         726                 :
         727                 :     // regardless of the RPC stack, if we're awaiting a sync reply, we
         728                 :     // know that it needs to be immediately handled to unblock us.
         729               0 :     if (AwaitingSyncReply() && msg.is_sync()) {
         730                 :         // wake up worker thread waiting at SyncChannel::Send
         731               0 :         mRecvd = msg;
         732               0 :         NotifyWorkerThread();
         733               0 :         return;
         734                 :     }
         735                 :
         736               0 :     mPending.push(msg);
         737                 :
         738               0 :     if (0 == StackDepth() && !mBlockedOnParent) {
         739                 :         // the worker thread might be idle, make sure it wakes up
         740                 :         mWorkerLoop->PostTask(FROM_HERE,
         741               0 :                                      new DequeueTask(mDequeueOneTask));
         742                 :     }
         743               0 :     else if (!AwaitingSyncReply())
         744               0 :         NotifyWorkerThread();
         745                 : }
         746                 :
         747                 :
         748                 : void
         749               0 : RPCChannel::OnChannelErrorFromLink()
         750                 : {
         751               0 :     AssertLinkThread();
         752               0 :     mMonitor->AssertCurrentThreadOwns();
         753                 :
         754               0 :     if (0 < StackDepth())
         755               0 :         NotifyWorkerThread();
         756                 :
         757               0 :     SyncChannel::OnChannelErrorFromLink();
         758               0 : }
         759                 :
         760                 : } // namespace ipc
         761                 : } // namespace mozilla
         762                 :

Generated by: LCOV version 1.7