NS_IMETHODIMP DoWorkRunnable::Notify(nsITimer* aTimer) { MessageLoop* loop = MessageLoop::current(); MOZ_ASSERT(loop); bool nestableTasksAllowed = loop->NestableTasksAllowed(); loop->SetNestableTasksAllowed(true); mPump->DoDelayedWork(loop); loop->SetNestableTasksAllowed(nestableTasksAllowed); return NS_OK; }
nsresult XRE_RunAppShell() { nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE); #if defined(XP_MACOSX) { // In content processes that want XPCOM (and hence want // AppShell), we usually run our hybrid event loop through // MessagePump::Run(), by way of nsBaseAppShell::Run(). The // Cocoa nsAppShell impl, however, implements its own Run() // that's unaware of MessagePump. That's all rather suboptimal, // but oddly enough not a problem... usually. // // The problem with this setup comes during startup. // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref // service, so we have to init IPC first. But, IPC also // indirectly kinda-depends on XPCOM, because MessagePump // schedules work from off-main threads (e.g. IO thread) by // using NS_DispatchToMainThread(). If the IO thread receives a // Message from the parent before nsThreadManager is // initialized, then DispatchToMainThread() will fail, although // MessagePump will remember the task. This race condition // isn't a problem when appShell->Run() ends up in // MessagePump::Run(), because MessagePump will immediate see it // has work to do. It *is* a problem when we end up in [NSApp // run], because it's not aware that MessagePump has work that // needs to be processed; that was supposed to be signaled by // nsIRunnable(s). // // So instead of hacking Cocoa nsAppShell or rewriting the // event-loop system, we compromise here by processing any tasks // that might have been enqueued on MessagePump, *before* // MessagePump::ScheduleWork was able to successfully // DispatchToMainThread(). MessageLoop* loop = MessageLoop::current(); bool couldNest = loop->NestableTasksAllowed(); loop->SetNestableTasksAllowed(true); RefPtr<Runnable> task = new MessageLoop::QuitTask(); loop->PostTask(task.forget()); loop->Run(); loop->SetNestableTasksAllowed(couldNest); } #endif // XP_MACOSX return appShell->Run(); }
NS_IMETHODIMP DoWorkRunnable::Run() { MessageLoop* loop = MessageLoop::current(); MOZ_ASSERT(loop); bool nestableTasksAllowed = loop->NestableTasksAllowed(); // 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); return NS_OK; }
NS_IMETHODIMP DoWorkRunnable::Run() { MessageLoop* loop = MessageLoop::current(); NS_ASSERTION(loop, "Shouldn't be null!"); if (loop) { bool nestableTasksAllowed = loop->NestableTasksAllowed(); // 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); } return NS_OK; }
void MessagePumpForChildProcess::Run(MessagePump::Delegate* aDelegate) { if (mFirstRun) { #ifdef DEBUG NS_ASSERTION(aDelegate && gFirstDelegate == nullptr, "Huh?!"); gFirstDelegate = aDelegate; #endif mFirstRun = false; if (NS_FAILED(XRE_RunAppShell())) { NS_WARNING("Failed to run app shell?!"); } #ifdef DEBUG NS_ASSERTION(aDelegate && aDelegate == gFirstDelegate, "Huh?!"); gFirstDelegate = nullptr; #endif return; } #ifdef DEBUG NS_ASSERTION(aDelegate && aDelegate == gFirstDelegate, "Huh?!"); #endif // 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); while (aDelegate->DoWork()); loop->SetNestableTasksAllowed(nestableTasksAllowed); // Really run. mozilla::ipc::MessagePump::Run(aDelegate); }