Files
palemoon27/netwerk/cache2/CacheIOThread.cpp
T
roytam1 06d40aca85 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1236277 - Retry all connections not just the reused one. r=mcmanus (ed4f2e0b53)
- Bug 366023 - Allow h/1.0 chunked encodings r=bagder (46916cf57d)
- Bug 1234757 - test_protocolproxyservice does not need 2nd arg to asyncopen r=ckerschb (b5be356b2f)
- Bug 1234757 - Use channel.asyncOpen2 within netwerk/test/unit/test_protocolproxyservice.js (r=mcmanus) (ff5fed346c)
- Bug 1213953. Remove pref "layout.imagevisibility.enabled_for_browser_elements_only", it is unused and obsolete. r=seth (b3263ece72)
- Bug 1218506 - Uninitialised value use in nsHttpTransaction::OnTransportStatus. r=mcmanus. (860ebc7b21)
- Bug 1211168 - Fix resource timing domainLookupStart by setting the timestamp only once. r=mcmanus (d29ce1c707)
- Bug 1242172. Invalidate intrinsic ISizes that depend on viewport BSize when the viewport is resized. r=dbaron (9f01b86d3d)
- Bug 1154277: Part 1 - allow to swap docShells on remote browsers that are not a child of a BrowserDOMWindow. r=smaug (ec889b29de)
- Bug 1230918 - remove useless null-pointer check on aChild that only caused a Coverity - Dereference before null check. r=dbaron (73e4595582)
- Bug 1149260 - Guard against trying to draw a drag image with zero length. r=enndeakin (212553ba76)
- Bug 1209780. Check DrawResult return value in nsBaseDragService. r=seth (8ed14eae88)
- Bug 1242690 - Make sure that synthetic mouse events have a reasonable guid so that the callback transform can get unapplied properly. r=botond (b612388818)
- Bug 1251140 - Baldr: Implement CtzI. r=jandem (ef6c59485b)
- Bug 1250198: Workaround unaligned memory accesses by masking the low bits; r=sunfish (5e8857f269)
- Bug 1246116: Translate AsmJS loops into wasm opcodes and implement Wasm loops; r=luke (45297bf96e)
- Bug 1251995 part 5 - Unify units of dirty rect used for painting text frame. r=jfkthame (4952922181)
- Bug 1227148 - Add SameObject and NewObject annotations to some ServiceWorkerContainer members; r=bzbarsky (53720dde2f)
- Bug 1238206 - Make ServiceWorkerContainer.getRegistration() return Promise<any>; r=baku (94425218b2)
- Bug 1218139 - Remove ServiceWorkerContainer.onreloadpage; r=bzbarsky (3fe7677476)
- Bug 1251519 Part 1 - Remove nsTextFrameBase as an nsFrame alias. r=mats (956adccf62)
- Bug 1253094, part 6 - Stop using DebugOnly for class/struct members in netwerk/. r=mayhemer (b517f06795)
- reinstantiate accidentally removed w (32fa5b8337)
- Bug 1246775 - fix Canvas2D drawWindow to reacquire its DT after rendering. r=bas (24131c73f7)
- Bug 1256515 - bail out in CanvasRenderingContext2D::DrawWindow if snapshotting draw target fails. r=bas.schouten (75b4d52542)
- Bug 1255172. Fix unsafe reference gc hazards people snuck into DOM code. r=bkelly (6cb8348aa5)
- Bug 1235677 - Wait for helper threads before resetting OOM simulation r=terrence (680b607812)
- Bug 1256672 - Make OOM alloc counters 64 bit. r=terrence (1e4dbbe201)
- Bug 1238207 - make ServiceWorkerGlobalScope.skipWaiting() return Promise<void>; r=baku (6577777f97)
- Bug 1251875 - Part 1: Remove the dom.serviceWorkers.interception.enabled pref; r=bkelly (6bae86b488)
- Bug 1251875 - Part 2: Remove the dom.serviceWorkers.interception.opaque.enabled pref; r=bkelly (9b2946325a)
- Bug 1253094, part 7 - Stop using DebugOnly for class/struct members in storage/. r=mak (9422188881)
2024-02-08 12:08:19 +08:00

365 lines
8.7 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CacheIOThread.h"
#include "CacheFileIOManager.h"
#include "nsIRunnable.h"
#include "nsISupportsImpl.h"
#include "nsPrintfCString.h"
#include "nsThreadUtils.h"
#include "mozilla/IOInterposer.h"
namespace mozilla {
namespace net {
CacheIOThread* CacheIOThread::sSelf = nullptr;
NS_IMPL_ISUPPORTS(CacheIOThread, nsIThreadObserver)
CacheIOThread::CacheIOThread()
: mMonitor("CacheIOThread")
, mThread(nullptr)
, mXPCOMThread(nullptr)
, mLowestLevelWaiting(LAST_LEVEL)
, mCurrentlyExecutingLevel(0)
, mHasXPCOMEvents(false)
, mRerunCurrentEvent(false)
, mShutdown(false)
#ifdef DEBUG
, mInsideLoop(true)
#endif
{
sSelf = this;
}
CacheIOThread::~CacheIOThread()
{
if (mXPCOMThread) {
nsIThread *thread = mXPCOMThread;
thread->Release();
}
sSelf = nullptr;
#ifdef DEBUG
for (uint32_t level = 0; level < LAST_LEVEL; ++level) {
MOZ_ASSERT(!mEventQueue[level].Length());
}
#endif
}
nsresult CacheIOThread::Init()
{
mThread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, this,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, 128 * 1024);
if (!mThread)
return NS_ERROR_FAILURE;
return NS_OK;
}
nsresult CacheIOThread::Dispatch(nsIRunnable* aRunnable, uint32_t aLevel)
{
NS_ENSURE_ARG(aLevel < LAST_LEVEL);
// Runnable is always expected to be non-null, hard null-check bellow.
MOZ_ASSERT(aRunnable);
MonitorAutoLock lock(mMonitor);
if (mShutdown && (PR_GetCurrentThread() != mThread))
return NS_ERROR_UNEXPECTED;
return DispatchInternal(aRunnable, aLevel);
}
nsresult CacheIOThread::DispatchAfterPendingOpens(nsIRunnable* aRunnable)
{
// Runnable is always expected to be non-null, hard null-check bellow.
MOZ_ASSERT(aRunnable);
MonitorAutoLock lock(mMonitor);
if (mShutdown && (PR_GetCurrentThread() != mThread))
return NS_ERROR_UNEXPECTED;
// Move everything from later executed OPEN level to the OPEN_PRIORITY level
// where we post the (eviction) runnable.
mEventQueue[OPEN_PRIORITY].AppendElements(mEventQueue[OPEN]);
mEventQueue[OPEN].Clear();
return DispatchInternal(aRunnable, OPEN_PRIORITY);
}
nsresult CacheIOThread::DispatchInternal(nsIRunnable* aRunnable, uint32_t aLevel)
{
if (NS_WARN_IF(!aRunnable))
return NS_ERROR_NULL_POINTER;
mMonitor.AssertCurrentThreadOwns();
mEventQueue[aLevel].AppendElement(aRunnable);
if (mLowestLevelWaiting > aLevel)
mLowestLevelWaiting = aLevel;
mMonitor.NotifyAll();
return NS_OK;
}
bool CacheIOThread::IsCurrentThread()
{
return mThread == PR_GetCurrentThread();
}
bool CacheIOThread::YieldInternal()
{
if (!IsCurrentThread()) {
NS_WARNING("Trying to yield to priority events on non-cache2 I/O thread? "
"You probably do something wrong.");
return false;
}
if (mCurrentlyExecutingLevel == XPCOM_LEVEL) {
// Doesn't make any sense, since this handler is the one
// that would be executed as the next one.
return false;
}
if (!EventsPending(mCurrentlyExecutingLevel))
return false;
mRerunCurrentEvent = true;
return true;
}
nsresult CacheIOThread::Shutdown()
{
{
MonitorAutoLock lock(mMonitor);
mShutdown = true;
mMonitor.NotifyAll();
}
PR_JoinThread(mThread);
mThread = nullptr;
return NS_OK;
}
already_AddRefed<nsIEventTarget> CacheIOThread::Target()
{
nsCOMPtr<nsIEventTarget> target;
target = mXPCOMThread;
if (!target && mThread)
{
MonitorAutoLock lock(mMonitor);
if (!mXPCOMThread)
lock.Wait();
target = mXPCOMThread;
}
return target.forget();
}
// static
void CacheIOThread::ThreadFunc(void* aClosure)
{
PR_SetCurrentThreadName("Cache2 I/O");
mozilla::IOInterposer::RegisterCurrentThread();
CacheIOThread* thread = static_cast<CacheIOThread*>(aClosure);
thread->ThreadFunc();
mozilla::IOInterposer::UnregisterCurrentThread();
}
void CacheIOThread::ThreadFunc()
{
nsCOMPtr<nsIThreadInternal> threadInternal;
{
MonitorAutoLock lock(mMonitor);
// This creates nsThread for this PRThread
nsCOMPtr<nsIThread> xpcomThread = NS_GetCurrentThread();
threadInternal = do_QueryInterface(xpcomThread);
if (threadInternal)
threadInternal->SetObserver(this);
mXPCOMThread = xpcomThread.forget().take();
lock.NotifyAll();
do {
loopStart:
// Reset the lowest level now, so that we can detect a new event on
// a lower level (i.e. higher priority) has been scheduled while
// executing any previously scheduled event.
mLowestLevelWaiting = LAST_LEVEL;
// Process xpcom events first
while (mHasXPCOMEvents) {
mHasXPCOMEvents = false;
mCurrentlyExecutingLevel = XPCOM_LEVEL;
MonitorAutoUnlock unlock(mMonitor);
bool processedEvent;
nsresult rv;
do {
nsIThread *thread = mXPCOMThread;
rv = thread->ProcessNextEvent(false, &processedEvent);
} while (NS_SUCCEEDED(rv) && processedEvent);
}
uint32_t level;
for (level = 0; level < LAST_LEVEL; ++level) {
if (!mEventQueue[level].Length()) {
// no events on this level, go to the next level
continue;
}
LoopOneLevel(level);
// Go to the first (lowest) level again
goto loopStart;
}
if (EventsPending())
continue;
if (mShutdown)
break;
lock.Wait(PR_INTERVAL_NO_TIMEOUT);
if (EventsPending())
continue;
} while (true);
MOZ_ASSERT(!EventsPending());
#ifdef DEBUG
// This is for correct assertion on XPCOM events dispatch.
mInsideLoop = false;
#endif
} // lock
if (threadInternal)
threadInternal->SetObserver(nullptr);
}
static const char* const sLevelTraceName[] = {
"net::cache::io::level(0)",
"net::cache::io::level(1)",
"net::cache::io::level(2)",
"net::cache::io::level(3)",
"net::cache::io::level(4)",
"net::cache::io::level(5)",
"net::cache::io::level(6)",
"net::cache::io::level(7)",
"net::cache::io::level(8)",
"net::cache::io::level(9)",
"net::cache::io::level(10)",
"net::cache::io::level(11)",
"net::cache::io::level(12)"
};
void CacheIOThread::LoopOneLevel(uint32_t aLevel)
{
nsTArray<nsCOMPtr<nsIRunnable> > events;
events.SwapElements(mEventQueue[aLevel]);
uint32_t length = events.Length();
mCurrentlyExecutingLevel = aLevel;
bool returnEvents = false;
uint32_t index;
{
MonitorAutoUnlock unlock(mMonitor);
for (index = 0; index < length; ++index) {
if (EventsPending(aLevel)) {
// Somebody scheduled a new event on a lower level, break and harry
// to execute it! Don't forget to return what we haven't exec.
returnEvents = true;
break;
}
// Drop any previous flagging, only an event on the current level may set
// this flag.
mRerunCurrentEvent = false;
events[index]->Run();
if (mRerunCurrentEvent) {
// The event handler yields to higher priority events and wants to rerun.
returnEvents = true;
break;
}
// Release outside the lock.
events[index] = nullptr;
}
}
if (returnEvents)
mEventQueue[aLevel].InsertElementsAt(0, events.Elements() + index, length - index);
}
bool CacheIOThread::EventsPending(uint32_t aLastLevel)
{
return mLowestLevelWaiting < aLastLevel || mHasXPCOMEvents;
}
NS_IMETHODIMP CacheIOThread::OnDispatchedEvent(nsIThreadInternal *thread)
{
MonitorAutoLock lock(mMonitor);
mHasXPCOMEvents = true;
MOZ_ASSERT(mInsideLoop);
lock.Notify();
return NS_OK;
}
NS_IMETHODIMP CacheIOThread::OnProcessNextEvent(nsIThreadInternal *thread, bool mayWait)
{
return NS_OK;
}
NS_IMETHODIMP CacheIOThread::AfterProcessNextEvent(nsIThreadInternal *thread,
bool eventWasProcessed)
{
return NS_OK;
}
// Memory reporting
size_t CacheIOThread::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
MonitorAutoLock lock(const_cast<CacheIOThread*>(this)->mMonitor);
size_t n = 0;
n += mallocSizeOf(mThread);
for (uint32_t level = 0; level < LAST_LEVEL; ++level) {
n += mEventQueue[level].ShallowSizeOfExcludingThis(mallocSizeOf);
// Events referenced by the queues are arbitrary objects we cannot be sure
// are reported elsewhere as well as probably not implementing nsISizeOf
// interface. Deliberatly omitting them from reporting here.
}
return n;
}
size_t CacheIOThread::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
}
} // namespace net
} // namespace mozilla