From 1a706a942e6f42b35083a251744795995810269c Mon Sep 17 00:00:00 2001 From: Jens Stutte Date: Mon, 12 Dec 2022 15:21:26 +0000 Subject: [PATCH] Bug 1709184 - Part 1: Process pending MT events before advancing the shutdown phase. r=xpcom-reviewers,nika,kmag Differential Revision: https://phabricator.services.mozilla.com/D160176 --- xpcom/base/AppShutdown.cpp | 21 +++++++++++++++++++++ xpcom/build/XPCOMInit.cpp | 7 ++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/xpcom/base/AppShutdown.cpp b/xpcom/base/AppShutdown.cpp index 680739b73c12..5844551095cb 100644 --- a/xpcom/base/AppShutdown.cpp +++ b/xpcom/base/AppShutdown.cpp @@ -340,6 +340,23 @@ void AppShutdown::AdvanceShutdownPhaseInternal( if (sCurrentShutdownPhase >= aPhase) { return; } + + nsCOMPtr thread = do_GetCurrentThread(); + if (sCurrentShutdownPhase >= ShutdownPhase::AppShutdownConfirmed) { + // Give runnables dispatched so far as part of the ongoing phase a chance + // to run before actually advancing the phase. We can do this only after + // we passed the point of no return and thus can expect a linear flow + // through our shutdown phases. This way the processing is also covered + // by the terminator's timer. + // Note that this happens only for main thread runnables, such that the + // correct way of ensuring shutdown processing remains to have an async + // shutdown blocker. + if (thread) { + NS_ProcessPendingEvents(thread); + } + } + + // From now on any IsInOrBeyond checks will find the new phase set. sCurrentShutdownPhase = aPhase; // TODO: Bug 1768581 @@ -371,6 +388,10 @@ void AppShutdown::AdvanceShutdownPhaseInternal( #endif obsService->NotifyObservers(aNotificationSubject, aTopic, aNotificationData); + // Empty our MT event queue again after the notification has finished + if (thread) { + NS_ProcessPendingEvents(thread); + } } } } diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp index 7ef9a98abd91..ae2ff7027c22 100644 --- a/xpcom/build/XPCOMInit.cpp +++ b/xpcom/build/XPCOMInit.cpp @@ -585,7 +585,6 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) { // This must happen after the shutdown of media and widgets, which // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification. - NS_ProcessPendingEvents(thread); gfxPlatform::ShutdownLayersIPC(); mozilla::AppShutdown::AdvanceShutdownPhase( @@ -595,11 +594,11 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) { // dispatches to non main-thread threads. ThreadEventTarget::XPCOMShutdownThreadsNotificationFinished(); #endif - NS_ProcessPendingEvents(thread); // Shutdown the timer thread and all timers that might still be alive nsTimerImpl::Shutdown(); + // Have an extra round of processing after the timers went away. NS_ProcessPendingEvents(thread); // Shutdown all remaining threads. This method does not return until @@ -617,11 +616,9 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) { // XPCOMShutdownFinal is the default phase for ClearOnShutdown. // This AdvanceShutdownPhase will thus free most ClearOnShutdown()'ed // smart pointers. Some destructors may fire extra main thread runnables - // that will be processed below. + // that will be processed inside AdvanceShutdownPhase. AppShutdown::AdvanceShutdownPhase(ShutdownPhase::XPCOMShutdownFinal); - NS_ProcessPendingEvents(thread); - // Shutdown the main thread, processing our last round of events, and then // mark that we've finished main thread event processing. nsThreadManager::get().ShutdownMainThread();