/* -*- 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/. */
class DoWorkRunnable final : public CancelableRunnable, public nsITimerCallback { public: explicit DoWorkRunnable(MessagePump* aPump)
: CancelableRunnable("ipc::DoWorkRunnable"), mPump(aPump) {
MOZ_ASSERT(aPump);
}
// NB: it is crucial *not* to directly call |aDelegate->DoWork()| // here. To ensure that MessageLoop tasks and XPCOM events have // equal priority, we sensitively rely on processing exactly one // Task per DoWorkRunnable XPCOM event.
if (did_work && delayed_work_time_.is_null()) mDelayedWorkTimer->Cancel();
if (!keep_running_) break;
if (did_work) continue;
did_work = aDelegate->DoIdleWork(); if (!keep_running_) break;
if (did_work) continue;
// This will either sleep or process an event.
NS_ProcessNextEvent(thisThread, true);
}
mDelayedWorkTimer->Cancel();
keep_running_ = true;
}
void MessagePump::ScheduleWork() { // Make sure the event loop wakes up. if (mEventTarget) {
mEventTarget->Dispatch(mDoWorkEvent, NS_DISPATCH_NORMAL);
} else { // Some things (like xpcshell) don't use the app shell and so Run hasn't // been called. We still need to wake up the main thread.
NS_DispatchToMainThread(mDoWorkEvent);
}
event_.Signal();
}
void MessagePump::ScheduleWorkForNestedLoop() { // This method is called when our MessageLoop has just allowed // nested tasks. In our setup, whenever that happens we know that // DoWork() will be called "soon", so there's no need to pay the // cost of what will be a no-op nsThread::Dispatch(mDoWorkEvent).
}
void MessagePump::ScheduleDelayedWork(const base::TimeTicks& aDelayedTime) { // To avoid racing on mDelayedWorkTimer, we need to be on the same thread as // ::Run().
MOZ_RELEASE_ASSERT((!mEventTarget && NS_IsMainThread()) ||
mEventTarget->IsOnCurrentThread());
if (!mDelayedWorkTimer) {
mDelayedWorkTimer = NS_NewTimer(); if (!mDelayedWorkTimer) { // Called before XPCOM has started up? We can't do this correctly.
NS_WARNING("Delayed task might not run!");
delayed_work_time_ = aDelayedTime; return;
}
}
if (!delayed_work_time_.is_null()) {
mDelayedWorkTimer->Cancel();
}
delayed_work_time_ = aDelayedTime;
// TimeDelta's constructor initializes to 0
base::TimeDelta delay; if (aDelayedTime > base::TimeTicks::Now())
delay = aDelayedTime - base::TimeTicks::Now();
// MessageLoop::RunTask() disallows nesting, but our Frankenventloop will // always dispatch DoWork() below from what looks to MessageLoop like a nested // context. So we unconditionally allow nesting here.
loop->SetNestableTasksAllowed(true);
loop->DoWork();
loop->SetNestableTasksAllowed(nestableTasksAllowed);
nsresult DoWorkRunnable::Cancel() { // Workers require cancelable runnables, but we can't really cancel cleanly // here. If we don't process this runnable then we will leave something // unprocessed in the message_loop. Therefore, eagerly complete our work // instead by immediately calling Run(). Run() should be called separately // after this. Unfortunately we cannot use flags to verify this because // DoWorkRunnable is a stateless singleton that can be in the event queue // multiple times simultaneously.
MOZ_ALWAYS_SUCCEEDS(Run()); return NS_OK;
}
// We can get to this point in startup with Tasks in our loop's // incoming_queue_ or pending_queue_, but without a matching // DoWorkRunnable(). In MessagePump::Run() above, we sensitively // depend on *not* directly calling delegate->DoWork(), because that // prioritizes Tasks above XPCOM events. However, from this point // forward, any Task posted to our loop is guaranteed to have a // DoWorkRunnable enqueued for it. // // So we just flush the pending work here and move on.
MessageLoop* loop = MessageLoop::current(); bool nestableTasksAllowed = loop->NestableTasksAllowed();
loop->SetNestableTasksAllowed(true);
// Chromium event notifications to be processed will be received by this // event loop as a DoWorkRunnables via ScheduleWork. Chromium events that // were received before our thread is valid, however, will not generate // runnable wrappers. We must process any of these before we enter this // loop, or we will forever have unprocessed chromium messages in our queue. // // Note we would like to request a flush of the chromium event queue // using a runnable on the xpcom side, but some thread implementations // (dom workers) get cranky if we call ScheduleWork here (ScheduleWork // calls dispatch on mEventTarget) before the thread processes an event. As // such, clear the queue manually. while (aDelegate->DoWork()) {
}
base::ScopedNSAutoreleasePool autoReleasePool; for (;;) {
autoReleasePool.Recycle();
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.