netwerk/cache2/CacheIOThread.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "CacheIOThread.h"
     6 #include "CacheFileIOManager.h"
     8 #include "nsIRunnable.h"
     9 #include "nsISupportsImpl.h"
    10 #include "nsPrintfCString.h"
    11 #include "nsThreadUtils.h"
    12 #include "mozilla/IOInterposer.h"
    13 #include "mozilla/VisualEventTracer.h"
    15 namespace mozilla {
    16 namespace net {
    18 CacheIOThread* CacheIOThread::sSelf = nullptr;
    20 NS_IMPL_ISUPPORTS(CacheIOThread, nsIThreadObserver)
    22 CacheIOThread::CacheIOThread()
    23 : mMonitor("CacheIOThread")
    24 , mThread(nullptr)
    25 , mLowestLevelWaiting(LAST_LEVEL)
    26 , mCurrentlyExecutingLevel(0)
    27 , mHasXPCOMEvents(false)
    28 , mRerunCurrentEvent(false)
    29 , mShutdown(false)
    30 {
    31   sSelf = this;
    32 }
    34 CacheIOThread::~CacheIOThread()
    35 {
    36   sSelf = nullptr;
    37 #ifdef DEBUG
    38   for (uint32_t level = 0; level < LAST_LEVEL; ++level) {
    39     MOZ_ASSERT(!mEventQueue[level].Length());
    40   }
    41 #endif
    42 }
    44 nsresult CacheIOThread::Init()
    45 {
    46   mThread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, this,
    47                             PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
    48                             PR_JOINABLE_THREAD, 128 * 1024);
    49   if (!mThread)
    50     return NS_ERROR_FAILURE;
    52   return NS_OK;
    53 }
    55 nsresult CacheIOThread::Dispatch(nsIRunnable* aRunnable, uint32_t aLevel)
    56 {
    57   NS_ENSURE_ARG(aLevel < LAST_LEVEL);
    59   MonitorAutoLock lock(mMonitor);
    61   if (mShutdown && (PR_GetCurrentThread() != mThread))
    62     return NS_ERROR_UNEXPECTED;
    64   return DispatchInternal(aRunnable, aLevel);
    65 }
    67 nsresult CacheIOThread::DispatchAfterPendingOpens(nsIRunnable* aRunnable)
    68 {
    69   MonitorAutoLock lock(mMonitor);
    71   if (mShutdown && (PR_GetCurrentThread() != mThread))
    72     return NS_ERROR_UNEXPECTED;
    74   // Move everything from later executed OPEN level to the OPEN_PRIORITY level
    75   // where we post the (eviction) runnable.
    76   mEventQueue[OPEN_PRIORITY].AppendElements(mEventQueue[OPEN]);
    77   mEventQueue[OPEN].Clear();
    79   return DispatchInternal(aRunnable, OPEN_PRIORITY);
    80 }
    82 nsresult CacheIOThread::DispatchInternal(nsIRunnable* aRunnable, uint32_t aLevel)
    83 {
    84   mMonitor.AssertCurrentThreadOwns();
    86   mEventQueue[aLevel].AppendElement(aRunnable);
    87   if (mLowestLevelWaiting > aLevel)
    88     mLowestLevelWaiting = aLevel;
    90   mMonitor.NotifyAll();
    92   return NS_OK;
    93 }
    95 bool CacheIOThread::IsCurrentThread()
    96 {
    97   return mThread == PR_GetCurrentThread();
    98 }
   100 bool CacheIOThread::YieldInternal()
   101 {
   102   if (!IsCurrentThread()) {
   103     NS_WARNING("Trying to yield to priority events on non-cache2 I/O thread? "
   104                "You probably do something wrong.");
   105     return false;
   106   }
   108   if (mCurrentlyExecutingLevel == XPCOM_LEVEL) {
   109     // Doesn't make any sense, since this handler is the one
   110     // that would be executed as the next one.
   111     return false;
   112   }
   114   if (!EventsPending(mCurrentlyExecutingLevel))
   115     return false;
   117   mRerunCurrentEvent = true;
   118   return true;
   119 }
   121 nsresult CacheIOThread::Shutdown()
   122 {
   123   {
   124     MonitorAutoLock lock(mMonitor);
   125     mShutdown = true;
   126     mMonitor.NotifyAll();
   127   }
   129   PR_JoinThread(mThread);
   130   mThread = nullptr;
   132   return NS_OK;
   133 }
   135 already_AddRefed<nsIEventTarget> CacheIOThread::Target()
   136 {
   137   nsCOMPtr<nsIEventTarget> target;
   139   target = mXPCOMThread;
   140   if (!target && mThread)
   141   {
   142     MonitorAutoLock lock(mMonitor);
   143     if (!mXPCOMThread)
   144       lock.Wait();
   146     target = mXPCOMThread;
   147   }
   149   return target.forget();
   150 }
   152 // static
   153 void CacheIOThread::ThreadFunc(void* aClosure)
   154 {
   155   PR_SetCurrentThreadName("Cache2 I/O");
   156   mozilla::IOInterposer::RegisterCurrentThread();
   157   CacheIOThread* thread = static_cast<CacheIOThread*>(aClosure);
   158   thread->ThreadFunc();
   159   mozilla::IOInterposer::UnregisterCurrentThread();
   160 }
   162 void CacheIOThread::ThreadFunc()
   163 {
   164   nsCOMPtr<nsIThreadInternal> threadInternal;
   166   {
   167     MonitorAutoLock lock(mMonitor);
   169     // This creates nsThread for this PRThread
   170     nsCOMPtr<nsIThread> xpcomThread = NS_GetCurrentThread();
   172     threadInternal = do_QueryInterface(xpcomThread);
   173     if (threadInternal)
   174       threadInternal->SetObserver(this);
   176     mXPCOMThread.swap(xpcomThread);
   178     lock.NotifyAll();
   180     do {
   181 loopStart:
   182       // Reset the lowest level now, so that we can detect a new event on
   183       // a lower level (i.e. higher priority) has been scheduled while
   184       // executing any previously scheduled event.
   185       mLowestLevelWaiting = LAST_LEVEL;
   187       // Process xpcom events first
   188       while (mHasXPCOMEvents) {
   189         eventtracer::AutoEventTracer tracer(this, eventtracer::eExec, eventtracer::eDone,
   190           "net::cache::io::level(xpcom)");
   192         mHasXPCOMEvents = false;
   193         mCurrentlyExecutingLevel = XPCOM_LEVEL;
   195         MonitorAutoUnlock unlock(mMonitor);
   197         bool processedEvent;
   198         nsresult rv;
   199         do {
   200           rv = mXPCOMThread->ProcessNextEvent(false, &processedEvent);
   201         } while (NS_SUCCEEDED(rv) && processedEvent);
   202       }
   204       uint32_t level;
   205       for (level = 0; level < LAST_LEVEL; ++level) {
   206         if (!mEventQueue[level].Length()) {
   207           // no events on this level, go to the next level
   208           continue;
   209         }
   211         LoopOneLevel(level);
   213         // Go to the first (lowest) level again
   214         goto loopStart;
   215       }
   217       if (EventsPending())
   218         continue;
   220       if (mShutdown)
   221         break;
   223       lock.Wait(PR_INTERVAL_NO_TIMEOUT);
   225       if (EventsPending())
   226         continue;
   228     } while (true);
   230     MOZ_ASSERT(!EventsPending());
   231   } // lock
   233   if (threadInternal)
   234     threadInternal->SetObserver(nullptr);
   235 }
   237 static const char* const sLevelTraceName[] = {
   238   "net::cache::io::level(0)",
   239   "net::cache::io::level(1)",
   240   "net::cache::io::level(2)",
   241   "net::cache::io::level(3)",
   242   "net::cache::io::level(4)",
   243   "net::cache::io::level(5)",
   244   "net::cache::io::level(6)",
   245   "net::cache::io::level(7)",
   246   "net::cache::io::level(8)",
   247   "net::cache::io::level(9)",
   248   "net::cache::io::level(10)",
   249   "net::cache::io::level(11)",
   250   "net::cache::io::level(12)"
   251 };
   253 void CacheIOThread::LoopOneLevel(uint32_t aLevel)
   254 {
   255   eventtracer::AutoEventTracer tracer(this, eventtracer::eExec, eventtracer::eDone,
   256     sLevelTraceName[aLevel]);
   258   nsTArray<nsRefPtr<nsIRunnable> > events;
   259   events.SwapElements(mEventQueue[aLevel]);
   260   uint32_t length = events.Length();
   262   mCurrentlyExecutingLevel = aLevel;
   264   bool returnEvents = false;
   265   uint32_t index;
   266   {
   267     MonitorAutoUnlock unlock(mMonitor);
   269     for (index = 0; index < length; ++index) {
   270       if (EventsPending(aLevel)) {
   271         // Somebody scheduled a new event on a lower level, break and harry
   272         // to execute it!  Don't forget to return what we haven't exec.
   273         returnEvents = true;
   274         break;
   275       }
   277       // Drop any previous flagging, only an event on the current level may set
   278       // this flag.
   279       mRerunCurrentEvent = false;
   281       events[index]->Run();
   283       if (mRerunCurrentEvent) {
   284         // The event handler yields to higher priority events and wants to rerun.
   285         returnEvents = true;
   286         break;
   287       }
   289       // Release outside the lock.
   290       events[index] = nullptr;
   291     }
   292   }
   294   if (returnEvents)
   295     mEventQueue[aLevel].InsertElementsAt(0, events.Elements() + index, length - index);
   296 }
   298 bool CacheIOThread::EventsPending(uint32_t aLastLevel)
   299 {
   300   return mLowestLevelWaiting < aLastLevel || mHasXPCOMEvents;
   301 }
   303 NS_IMETHODIMP CacheIOThread::OnDispatchedEvent(nsIThreadInternal *thread)
   304 {
   305   MonitorAutoLock lock(mMonitor);
   306   mHasXPCOMEvents = true;
   307   MOZ_ASSERT(!mShutdown || (PR_GetCurrentThread() == mThread));
   308   lock.Notify();
   309   return NS_OK;
   310 }
   312 NS_IMETHODIMP CacheIOThread::OnProcessNextEvent(nsIThreadInternal *thread, bool mayWait, uint32_t recursionDepth)
   313 {
   314   return NS_OK;
   315 }
   317 NS_IMETHODIMP CacheIOThread::AfterProcessNextEvent(nsIThreadInternal *thread, uint32_t recursionDepth,
   318                                                    bool eventWasProcessed)
   319 {
   320   return NS_OK;
   321 }
   323 // Memory reporting
   325 size_t CacheIOThread::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
   326 {
   327   MonitorAutoLock lock(const_cast<CacheIOThread*>(this)->mMonitor);
   329   size_t n = 0;
   330   n += mallocSizeOf(mThread);
   331   for (uint32_t level = 0; level < LAST_LEVEL; ++level) {
   332     n += mEventQueue[level].SizeOfExcludingThis(mallocSizeOf);
   333     // Events referenced by the queues are arbitrary objects we cannot be sure
   334     // are reported elsewhere as well as probably not implementing nsISizeOf
   335     // interface.  Deliberatly omitting them from reporting here.
   336   }
   338   return n;
   339 }
   341 size_t CacheIOThread::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
   342 {
   343   return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
   344 }
   346 } // net
   347 } // mozilla

mercurial