/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */
// This is a non-owning reference. It must live at least until Disconnect is // called to clear it out.
EventQueue* mQueue;
RefPtr<ThreadEventQueue> mOwner;
};
bool ThreadEventQueue::PutEventInternal(already_AddRefed<nsIRunnable>&& aEvent,
EventQueuePriority aPriority,
NestedSink* aSink) { // We want to leak the reference when we fail to dispatch it, so that // we won't release the event in a wrong thread.
LeakRefPtr<nsIRunnable> event(std::move(aEvent));
nsCOMPtr<nsIThreadObserver> obs;
{ // Check if the runnable wants to override the passed-in priority. // Do this outside the lock, so runnables implemented in JS can QI // (and possibly GC) outside of the lock. if (mIsMainThread) { auto* e = event.get(); // can't do_QueryInterface on LeakRefPtr. if (nsCOMPtr<nsIRunnablePriority> runnablePrio = do_QueryInterface(e)) {
uint32_t prio = nsIRunnablePriority::PRIORITY_NORMAL;
runnablePrio->GetPriority(&prio); if (prio == nsIRunnablePriority::PRIORITY_CONTROL) {
aPriority = EventQueuePriority::Control;
} elseif (prio == nsIRunnablePriority::PRIORITY_RENDER_BLOCKING) {
aPriority = EventQueuePriority::RenderBlocking;
} elseif (prio == nsIRunnablePriority::PRIORITY_VSYNC) {
aPriority = EventQueuePriority::Vsync;
} elseif (prio == nsIRunnablePriority::PRIORITY_INPUT_HIGH) {
aPriority = EventQueuePriority::InputHigh;
} elseif (prio == nsIRunnablePriority::PRIORITY_MEDIUMHIGH) {
aPriority = EventQueuePriority::MediumHigh;
} elseif (prio == nsIRunnablePriority::PRIORITY_DEFERRED_TIMERS) {
aPriority = EventQueuePriority::DeferredTimers;
} elseif (prio == nsIRunnablePriority::PRIORITY_IDLE) {
aPriority = EventQueuePriority::Idle;
} elseif (prio == nsIRunnablePriority::PRIORITY_LOW) {
aPriority = EventQueuePriority::Low;
}
}
}
// Make sure to grab the observer before dropping the lock, otherwise the // event that we just placed into the queue could run and eventually delete // this nsThread before the calling thread is scheduled again. We would then // crash while trying to access a dead nsThread.
obs = mObserver;
}
if (obs) {
obs->OnDispatchedEvent();
}
returntrue;
}
already_AddRefed<nsIRunnable> ThreadEventQueue::GetEvent( bool aMayWait, mozilla::TimeDuration* aLastEventDelay) {
nsCOMPtr<nsIRunnable> event;
{ // Scope for lock. When we are about to return, we will exit this // scope so we can do some work after releasing the lock but // before returning.
MutexAutoLock lock(mLock);
for (;;) { constbool noNestedQueue = mNestedQueues.IsEmpty(); if (noNestedQueue) {
event = mBaseQueue->GetEvent(lock, aLastEventDelay);
} else { // We always get events from the topmost queue when there are nested // queues.
event =
mNestedQueues.LastElement().mQueue->GetEvent(lock, aLastEventDelay);
}
if (event) { break;
}
// No runnable available. Sleep waiting for one if if we're supposed to. // Otherwise just go ahead and return null. if (!aMayWait) { break;
}
// We always get events from the topmost queue when there are nested queues. if (mNestedQueues.IsEmpty()) { return mBaseQueue->HasReadyEvent(lock);
} else { return mNestedQueues.LastElement().mQueue->HasReadyEvent(lock);
}
}
// Move events from the old queue to the new one.
nsCOMPtr<nsIRunnable> event;
TimeDuration delay; while ((event = item.mQueue->GetEvent(lock, &delay))) { // preserve the event delay so far
prevQueue->PutEvent(event.forget(), EventQueuePriority::Normal, lock,
&delay);
}
mNestedQueues.RemoveLastElement();
}
size_t ThreadEventQueue::SizeOfExcludingThis(
mozilla::MallocSizeOf aMallocSizeOf) {
size_t n = 0;
{
MutexAutoLock lock(mLock);
n += mBaseQueue->SizeOfIncludingThis(aMallocSizeOf);
n += mNestedQueues.ShallowSizeOfExcludingThis(aMallocSizeOf); for (auto& queue : mNestedQueues) {
n += queue.mEventTarget->SizeOfIncludingThis(aMallocSizeOf);
}
}
already_AddRefed<nsIThreadObserver> ThreadEventQueue::GetObserverOnThread()
MOZ_NO_THREAD_SAFETY_ANALYSIS { // only written on this thread return do_AddRef(mObserver);
}
void ThreadEventQueue::SetObserver(nsIThreadObserver* aObserver) { // Always called from the thread - single writer.
nsCOMPtr<nsIThreadObserver> observer = aObserver;
{
MutexAutoLock lock(mLock);
mObserver.swap(observer);
} if (NS_IsMainThread()) {
TaskController::Get()->SetThreadObserver(aObserver);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.