/* -*- 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/. */
#include"mozilla/AbstractThread.h"
#include"mozilla/ClearOnShutdown.h" #include"mozilla/DelayedRunnable.h" #include"mozilla/Maybe.h" #include"mozilla/MozPromise.h"// We initialize the MozPromise logging in this file. #include"mozilla/ProfilerRunnable.h" #include"mozilla/StateWatching.h"// We initialize the StateWatching logging in this file. #include"mozilla/StaticPtr.h" #include"mozilla/TaskDispatcher.h" #include"mozilla/TaskQueue.h" #include"mozilla/Unused.h" #include"nsContentUtils.h" #include"nsIDirectTaskDispatcher.h" #include"nsIThreadInternal.h" #include"nsServiceManagerUtils.h" #include"nsThreadManager.h" #include"nsThreadUtils.h" #include <memory>
class XPCOMThreadWrapper final : public AbstractThread, public nsIThreadObserver, public nsIDirectTaskDispatcher { public:
XPCOMThreadWrapper(nsIThreadInternal* aThread, bool aRequireTailDispatch, bool aOnThread)
: AbstractThread(aRequireTailDispatch),
mThread(aThread),
mDirectTaskDispatcher(do_QueryInterface(aThread)),
mOnThread(aOnThread) {
MOZ_DIAGNOSTIC_ASSERT(mThread && mDirectTaskDispatcher);
MOZ_DIAGNOSTIC_ASSERT(!aOnThread || IsCurrentThreadIn()); if (aOnThread) {
MOZ_ASSERT(!sCurrentThreadTLS.get(), "There can only be a single XPCOMThreadWrapper available on a " "thread"); // Set the default current thread so that GetCurrent() never returns // nullptr.
sCurrentThreadTLS.set(this);
}
}
// At a certain point during shutdown, we stop processing events from the // main thread event queue (this happens long after all _other_ XPCOM // threads have been shut down). However, various bits of subsequent // teardown logic (the media shutdown blocker and the final shutdown cycle // collection) can trigger state watching and state mirroring notifications // that result in dispatch to the main thread. This causes shutdown leaks, // because the |Runner| wrapper below creates a guaranteed cycle // (Thread->EventQueue->Runnable->Thread) until the event is processed. So // if we put the event into a queue that will never be processed, we'll wind // up with a leak. // // We opt to just release the runnable in that case. Ordinarily, this // approach could cause problems for runnables that are only safe to be // released on the target thread (and not the dispatching thread). This is // why XPCOM thread dispatch explicitly leaks the runnable when dispatch // fails, rather than releasing it. But given that this condition only // applies very late in shutdown when only one thread remains operational, // that concern is unlikely to apply. if (gXPCOMMainThreadEventsAreDoomed) { return NS_ERROR_FAILURE;
}
RefPtr<nsIRunnable> runner = new Runner(this, r.forget()); return mThread->Dispatch(runner.forget(), NS_DISPATCH_NORMAL);
}
// Prevent a GCC warning about the other overload of Dispatch being hidden. using AbstractThread::Dispatch;
NS_IMETHOD AfterProcessNextEvent(nsIThreadInternal* thread, bool eventWasProcessed) override { // This is the primary case.
MaybeFireTailDispatcher(); return NS_OK;
}
NS_IMETHOD OnProcessNextEvent(nsIThreadInternal* thread, bool mayWait) override { // In general, the tail dispatcher is handled at the end of the current in // AfterProcessNextEvent() above. However, if start spinning a nested event // loop, it's generally better to fire the tail dispatcher before the first // nested event, rather than after it. This check handles that case.
MaybeFireTailDispatcher(); return NS_OK;
}
//----------------------------------------------------------------------------- // nsIDirectTaskDispatcher //----------------------------------------------------------------------------- // Forward calls to nsIDirectTaskDispatcher to the underlying nsThread object. // We can't use the generated NS_FORWARD_NSIDIRECTTASKDISPATCHER macro // as already_AddRefed type must be moved.
NS_IMETHOD DispatchDirectTask(already_AddRefed<nsIRunnable> aEvent) override { return mDirectTaskDispatcher->DispatchDirectTask(std::move(aEvent));
}
NS_IMETHOD DrainDirectTasks() override { return mDirectTaskDispatcher->DrainDirectTasks();
}
NS_IMETHOD HaveDirectTasks(bool* aResult) override { return mDirectTaskDispatcher->HaveDirectTasks(aResult);
}
~XPCOMThreadWrapper() { if (mOnThread) {
MOZ_DIAGNOSTIC_ASSERT(IsCurrentThreadIn(), "Must be destroyed on the thread it was created");
sCurrentThreadTLS.set(nullptr);
}
}
bool AbstractThread::RequiresTailDispatch(AbstractThread* aThread) const {
MOZ_ASSERT(aThread); // We require tail dispatch if both the source and destination // threads support it. return SupportsTailDispatch() && aThread->SupportsTailDispatch();
}
bool AbstractThread::RequiresTailDispatchFromCurrentThread() const {
AbstractThread* current = GetCurrent(); return current && RequiresTailDispatch(current);
}
void AbstractThread::DispatchStateChange(
already_AddRefed<nsIRunnable> aRunnable) {
AbstractThread* currentThread = GetCurrent();
MOZ_DIAGNOSTIC_ASSERT(currentThread, "An AbstractThread must exist"); if (currentThread->IsTailDispatcherAvailable()) {
currentThread->TailDispatcher().AddStateChangeTask(this,
std::move(aRunnable));
} else { // If the tail dispatcher isn't available, we just avoid sending state // updates. // // This happens, specifically (1) During async shutdown (via the media // shutdown blocker), and (2) During the final shutdown cycle collection. // Both of these trigger changes to various watched and mirrored state.
nsCOMPtr<nsIRunnable> neverDispatched = aRunnable;
}
}
/* static */ void AbstractThread::DispatchDirectTask(
already_AddRefed<nsIRunnable> aRunnable) {
AbstractThread* currentThread = GetCurrent();
MOZ_DIAGNOSTIC_ASSERT(currentThread, "An AbstractThread must exist"); if (currentThread->IsTailDispatcherAvailable()) {
currentThread->TailDispatcher().AddDirectTask(std::move(aRunnable));
} else { // If the tail dispatcher isn't available, we post as a regular task.
currentThread->Dispatch(std::move(aRunnable));
}
}
} // namespace mozilla
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
¤
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.