LCOV - code coverage report
Current view: top level - netwerk/ipc - ChannelEventQueue.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 73 77 94.8 %
Date: 2017-07-14 16:53:18 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * vim: set sw=2 ts=8 et tw=80 :
       3             :  */
       4             : /* This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       7             : 
       8             : #include "ChannelEventQueue.h"
       9             : 
      10             : #include "mozilla/Assertions.h"
      11             : #include "mozilla/Unused.h"
      12             : #include "nsISupports.h"
      13             : #include "nsThreadUtils.h"
      14             : 
      15             : namespace mozilla {
      16             : namespace net {
      17             : 
      18             : ChannelEvent*
      19          16 : ChannelEventQueue::TakeEvent()
      20             : {
      21          16 :   mMutex.AssertCurrentThreadOwns();
      22          16 :   MOZ_ASSERT(mFlushing);
      23             : 
      24          16 :   if (mSuspended || mEventQueue.IsEmpty()) {
      25           4 :     return nullptr;
      26             :   }
      27             : 
      28          24 :   UniquePtr<ChannelEvent> event(Move(mEventQueue[0]));
      29          12 :   mEventQueue.RemoveElementAt(0);
      30             : 
      31          12 :   return event.release();
      32             : }
      33             : 
      34             : void
      35           5 : ChannelEventQueue::FlushQueue()
      36             : {
      37             :   // Events flushed could include destruction of channel (and our own
      38             :   // destructor) unless we make sure its refcount doesn't drop to 0 while this
      39             :   // method is running.
      40          10 :   nsCOMPtr<nsISupports> kungFuDeathGrip(mOwner);
      41             :   mozilla::Unused << kungFuDeathGrip; // Not used in this function
      42             : 
      43             :   // Prevent flushed events from flushing the queue recursively
      44             :   {
      45          10 :     MutexAutoLock lock(mMutex);
      46           5 :     MOZ_ASSERT(!mFlushing);
      47           5 :     mFlushing = true;
      48             :   }
      49             : 
      50           5 :   bool needResumeOnOtherThread = false;
      51             : 
      52             :   while (true) {
      53          27 :     UniquePtr<ChannelEvent> event;
      54             :     {
      55          28 :       MutexAutoLock lock(mMutex);
      56          16 :       event.reset(TakeEvent());
      57          16 :       if (!event) {
      58           4 :         MOZ_ASSERT(mFlushing);
      59           4 :         mFlushing = false;
      60           4 :         MOZ_ASSERT(mEventQueue.IsEmpty() || (mSuspended || !!mForcedCount));
      61           4 :         break;
      62             :       }
      63             :     }
      64             : 
      65          23 :     nsCOMPtr<nsIEventTarget> target = event->GetEventTarget();
      66          12 :     MOZ_ASSERT(target);
      67             : 
      68          12 :     bool isCurrentThread = false;
      69          12 :     nsresult rv = target->IsOnCurrentThread(&isCurrentThread);
      70          12 :     if (NS_WARN_IF(NS_FAILED(rv))) {
      71             :       // Simply run this event on current thread if we are not sure about it
      72             :       // in release channel, or assert in Aurora/Nightly channel.
      73           0 :       MOZ_DIAGNOSTIC_ASSERT(false);
      74             :       isCurrentThread = true;
      75             :     }
      76             : 
      77          12 :     if (!isCurrentThread) {
      78             :       // Next event needs to run on another thread. Put it back to
      79             :       // the front of the queue can try resume on that thread.
      80           1 :       Suspend();
      81           1 :       PrependEvent(event);
      82             : 
      83           1 :       needResumeOnOtherThread = true;
      84             :       {
      85           2 :         MutexAutoLock lock(mMutex);
      86           1 :         MOZ_ASSERT(mFlushing);
      87           1 :         mFlushing = false;
      88           1 :         MOZ_ASSERT(!mEventQueue.IsEmpty());
      89             :       }
      90           1 :       break;
      91             :     }
      92             : 
      93          11 :     event->Run();
      94          11 :   } // end of while(true)
      95             : 
      96             :   // The flush procedure is aborted because next event cannot be run on current
      97             :   // thread. We need to resume the event processing right after flush procedure
      98             :   // is finished.
      99             :   // Note: we cannot call Resume() while "mFlushing == true" because
     100             :   // CompleteResume will not trigger FlushQueue while there is an ongoing flush.
     101           5 :   if (needResumeOnOtherThread) {
     102           1 :     Resume();
     103             :   }
     104           5 : }
     105             : 
     106             : void
     107           1 : ChannelEventQueue::Suspend()
     108             : {
     109           2 :   MutexAutoLock lock(mMutex);
     110           1 :   SuspendInternal();
     111           1 : }
     112             : 
     113             : void
     114           5 : ChannelEventQueue::SuspendInternal()
     115             : {
     116           5 :   mMutex.AssertCurrentThreadOwns();
     117             : 
     118           5 :   mSuspended = true;
     119           5 :   mSuspendCount++;
     120           5 : }
     121             : 
     122           1 : void ChannelEventQueue::Resume()
     123             : {
     124           2 :   MutexAutoLock lock(mMutex);
     125           1 :   ResumeInternal();
     126           1 : }
     127             : 
     128             : void
     129           5 : ChannelEventQueue::ResumeInternal()
     130             : {
     131           5 :   mMutex.AssertCurrentThreadOwns();
     132             : 
     133             :   // Resuming w/o suspend: error in debug mode, ignore in build
     134           5 :   MOZ_ASSERT(mSuspendCount > 0);
     135           5 :   if (mSuspendCount <= 0) {
     136           0 :     return;
     137             :   }
     138             : 
     139           5 :   if (!--mSuspendCount) {
     140           5 :     if (mEventQueue.IsEmpty()) {
     141             :       // Nothing in queue to flush, simply clear the flag.
     142           0 :       mSuspended = false;
     143           0 :       return;
     144             :     }
     145             : 
     146             :     // Hold a strong reference of mOwner to avoid the channel release
     147             :     // before CompleteResume was executed.
     148             :     class CompleteResumeRunnable : public CancelableRunnable
     149             :     {
     150             :     public:
     151           5 :       explicit CompleteResumeRunnable(ChannelEventQueue* aQueue, nsISupports* aOwner)
     152           5 :         : CancelableRunnable("CompleteResumeRunnable")
     153             :         , mQueue(aQueue)
     154           5 :         , mOwner(aOwner)
     155             :       {
     156           5 :       }
     157             : 
     158           5 :       NS_IMETHOD Run() override
     159             :       {
     160           5 :         mQueue->CompleteResume();
     161           5 :         return NS_OK;
     162             :       }
     163             : 
     164             :     private:
     165          15 :       virtual ~CompleteResumeRunnable() {}
     166             : 
     167             :       RefPtr<ChannelEventQueue> mQueue;
     168             :       nsCOMPtr<nsISupports> mOwner;
     169             :     };
     170             : 
     171             :     // Worker thread requires a CancelableRunnable.
     172          10 :     RefPtr<Runnable> event = new CompleteResumeRunnable(this, mOwner);
     173             : 
     174          10 :     nsCOMPtr<nsIEventTarget> target;
     175           5 :       target = mEventQueue[0]->GetEventTarget();
     176           5 :     MOZ_ASSERT(target);
     177             : 
     178           5 :     Unused << NS_WARN_IF(NS_FAILED(target->Dispatch(event.forget(),
     179             :                                                     NS_DISPATCH_NORMAL)));
     180             :   }
     181             : }
     182             : 
     183             : } // namespace net
     184             : } // namespace mozilla

Generated by: LCOV version 1.13