LCOV - code coverage report
Current view: top level - xpcom/threads - nsEventQueue.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 69 76 90.8 %
Date: 2017-07-14 16:53:18 Functions: 6 7 85.7 %
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 ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsEventQueue.h"
       8             : #include "nsAutoPtr.h"
       9             : #include "mozilla/Logging.h"
      10             : #include "nsThreadUtils.h"
      11             : #include "prthread.h"
      12             : #include "mozilla/ChaosMode.h"
      13             : 
      14             : using namespace mozilla;
      15             : 
      16             : static LazyLogModule sEventQueueLog("nsEventQueue");
      17             : #ifdef LOG
      18             : #undef LOG
      19             : #endif
      20             : #define LOG(args) MOZ_LOG(sEventQueueLog, mozilla::LogLevel::Debug, args)
      21             : 
      22         243 : nsEventQueue::nsEventQueue(mozilla::CondVar& aCondVar, EventQueueType aType)
      23             :   : mHead(nullptr)
      24             :   , mTail(nullptr)
      25             :   , mOffsetHead(0)
      26             :   , mOffsetTail(0)
      27             :   , mEventsAvailable(aCondVar)
      28         243 :   , mType(aType)
      29             : {
      30         243 : }
      31             : 
      32          58 : nsEventQueue::~nsEventQueue()
      33             : {
      34             :   // It'd be nice to be able to assert that no one else is holding the lock,
      35             :   // but NSPR doesn't really expose APIs for it.
      36          29 :   NS_ASSERTION(IsEmpty(),
      37             :                "Non-empty event queue being destroyed; events being leaked.");
      38             : 
      39          29 :   if (mHead) {
      40          14 :     FreePage(mHead);
      41             :   }
      42          29 : }
      43             : 
      44             : bool
      45          14 : nsEventQueue::PeekEvent(nsIRunnable** aEvent, MutexAutoLock& aProofOfLock)
      46             : {
      47          14 :   MOZ_ASSERT(aEvent);
      48          14 :   *aEvent = nullptr;
      49             : 
      50          14 :   if (IsEmpty()) {
      51           0 :     return false;
      52             :   }
      53             : 
      54          14 :   MOZ_ASSERT(mOffsetHead < EVENTS_PER_PAGE);
      55          14 :   MOZ_ASSERT_IF(mHead == mTail, mOffsetHead <= mOffsetTail);
      56          14 :   NS_ADDREF(*aEvent = mHead->mEvents[mOffsetHead]);
      57             : 
      58          14 :   MOZ_ASSERT(*aEvent);
      59             : 
      60          14 :   return true;
      61             : }
      62             : 
      63             : bool
      64        7036 : nsEventQueue::GetEvent(bool aMayWait, nsIRunnable** aResult,
      65             :                        MutexAutoLock& aProofOfLock)
      66             : {
      67        7036 :   if (aResult) {
      68        2211 :     *aResult = nullptr;
      69             :   }
      70             : 
      71        7036 :   while (IsEmpty()) {
      72        3919 :     if (!aMayWait) {
      73        3767 :       return false;
      74             :     }
      75         152 :     LOG(("EVENTQ(%p): wait begin\n", this));
      76         152 :     mEventsAvailable.Wait();
      77         126 :     LOG(("EVENTQ(%p): wait end\n", this));
      78             : 
      79         126 :     if (mType == eSharedCondVarQueue) {
      80         126 :       if (IsEmpty()) {
      81           0 :         return false;
      82             :       }
      83         126 :       break;
      84             :     }
      85             :   }
      86             : 
      87        3243 :   if (aResult) {
      88        1673 :     MOZ_ASSERT(mOffsetHead < EVENTS_PER_PAGE);
      89        1673 :     MOZ_ASSERT_IF(mHead == mTail, mOffsetHead <= mOffsetTail);
      90        1673 :     *aResult = mHead->mEvents[mOffsetHead++];
      91             : 
      92        1673 :     MOZ_ASSERT(*aResult);
      93        1673 :     MOZ_ASSERT(mOffsetHead <= EVENTS_PER_PAGE);
      94             : 
      95             :     // Check if mHead points to empty Page
      96        1673 :     if (mOffsetHead == EVENTS_PER_PAGE) {
      97           3 :       Page* dead = mHead;
      98           3 :       mHead = mHead->mNext;
      99           3 :       FreePage(dead);
     100           3 :       mOffsetHead = 0;
     101             :     }
     102             :   }
     103             : 
     104        3243 :   return true;
     105             : }
     106             : 
     107             : void
     108        1724 : nsEventQueue::PutEvent(already_AddRefed<nsIRunnable>&& aRunnable,
     109             :                        MutexAutoLock& aProofOfLock)
     110             : {
     111        1724 :   if (!mHead) {
     112          84 :     mHead = NewPage();
     113          84 :     MOZ_ASSERT(mHead);
     114             : 
     115          84 :     mTail = mHead;
     116          84 :     mOffsetHead = 0;
     117          84 :     mOffsetTail = 0;
     118        1640 :   } else if (mOffsetTail == EVENTS_PER_PAGE) {
     119           3 :     Page* page = NewPage();
     120           3 :     MOZ_ASSERT(page);
     121             : 
     122           3 :     mTail->mNext = page;
     123           3 :     mTail = page;
     124           3 :     mOffsetTail = 0;
     125             :   }
     126             : 
     127        1724 :   nsIRunnable*& queueLocation = mTail->mEvents[mOffsetTail];
     128        1724 :   MOZ_ASSERT(!queueLocation);
     129        1724 :   queueLocation = aRunnable.take();
     130        1724 :   ++mOffsetTail;
     131        1724 :   LOG(("EVENTQ(%p): notify\n", this));
     132        1724 :   mEventsAvailable.Notify();
     133        1724 : }
     134             : 
     135             : void
     136           0 : nsEventQueue::PutEvent(nsIRunnable* aRunnable, MutexAutoLock& aProofOfLock)
     137             : {
     138           0 :   nsCOMPtr<nsIRunnable> event(aRunnable);
     139           0 :   PutEvent(event.forget(), aProofOfLock);
     140           0 : }
     141             : 
     142             : size_t
     143          73 : nsEventQueue::Count(MutexAutoLock& aProofOfLock) const
     144             : {
     145             :   // It is obvious count is 0 when the queue is empty.
     146          73 :   if (!mHead) {
     147           2 :     return 0;
     148             :   }
     149             : 
     150             :   /* How we count the number of events in the queue:
     151             :    * 1. Let pageCount(x, y) denote the number of pages excluding the tail page
     152             :    *    where x is the index of head page and y is the index of the tail page.
     153             :    * 2. Then we have pageCount(x, y) = y - x.
     154             :    *
     155             :    * Ex: pageCount(0, 0) = 0 where both head and tail pages point to page 0.
     156             :    *     pageCount(0, 1) = 1 where head points to page 0 and tail points page 1.
     157             :    *
     158             :    * 3. number of events = (EVENTS_PER_PAGE * pageCount(x, y))
     159             :    *      - (empty slots in head page) + (non-empty slots in tail page)
     160             :    *      = (EVENTS_PER_PAGE * pageCount(x, y)) - mOffsetHead + mOffsetTail
     161             :    */
     162             : 
     163          71 :   int count = -mOffsetHead;
     164             : 
     165             :   // Compute (EVENTS_PER_PAGE * pageCount(x, y))
     166          71 :   for (Page* page = mHead; page != mTail; page = page->mNext) {
     167           0 :     count += EVENTS_PER_PAGE;
     168             :   }
     169             : 
     170          71 :   count += mOffsetTail;
     171          71 :   MOZ_ASSERT(count >= 0);
     172             : 
     173          71 :   return count;
     174             : }

Generated by: LCOV version 1.13