diff --git a/accessible/ipc/win/DocAccessibleChild.cpp b/accessible/ipc/win/DocAccessibleChild.cpp index cec4ca305339..1fbbdcc243ca 100644 --- a/accessible/ipc/win/DocAccessibleChild.cpp +++ b/accessible/ipc/win/DocAccessibleChild.cpp @@ -22,7 +22,7 @@ DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager) MOZ_COUNT_CTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase); if (!sPlatformChild) { sPlatformChild = new PlatformChild(); - ClearOnShutdown(&sPlatformChild, ShutdownPhase::XPCOMShutdown); + ClearOnShutdown(&sPlatformChild, ShutdownPhase::Shutdown); } SetManager(aManager); diff --git a/browser/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js b/browser/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js index d6727721351b..413a4eafcf51 100644 --- a/browser/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js +++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_cookie_settings.js @@ -28,7 +28,7 @@ async function fake_profile_change() { }, "cookie-db-closed"); Services.cookies .QueryInterface(Ci.nsIObserver) - .observe(null, "profile-before-change", null); + .observe(null, "profile-before-change", "shutdown-persist"); }); await new Promise(resolve => { Services.obs.addObserver(function waitForDBOpen() { diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 4614888394de..a863a189594a 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -575,7 +575,7 @@ ContentChild::ContentChild() // happens without requiring the observer service at this time. if (!sShutdownCanary) { sShutdownCanary = new ShutdownCanary(); - ClearOnShutdown(&sShutdownCanary, ShutdownPhase::XPCOMShutdown); + ClearOnShutdown(&sShutdownCanary, ShutdownPhase::Shutdown); } } diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index e22659209254..343b35573abb 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -2839,7 +2839,7 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) { // can't init the process without it, and since we're going to be canceling // whatever load attempt that initiated this process creation anyway, just // bail out now if shutdown has already started. - if (PastShutdownPhase(ShutdownPhase::XPCOMShutdown)) { + if (PastShutdownPhase(ShutdownPhase::Shutdown)) { return false; } diff --git a/dom/media/MediaCache.cpp b/dom/media/MediaCache.cpp index ec9122e9edd2..9f913ce642ad 100644 --- a/dom/media/MediaCache.cpp +++ b/dom/media/MediaCache.cpp @@ -773,7 +773,7 @@ RefPtr MediaCache::GetMediaCache(int64_t aContentLength, thread->Shutdown(); } } sClearThread; - ClearOnShutdown(&sClearThread, ShutdownPhase::XPCOMShutdownThreads); + ClearOnShutdown(&sClearThread, ShutdownPhase::ShutdownThreads); } if (!sThread) { diff --git a/dom/media/doctor/DecoderDoctorLogger.cpp b/dom/media/doctor/DecoderDoctorLogger.cpp index 927650babc81..d6119778460f 100644 --- a/dom/media/doctor/DecoderDoctorLogger.cpp +++ b/dom/media/doctor/DecoderDoctorLogger.cpp @@ -116,11 +116,9 @@ bool DecoderDoctorLogger::EnsureLogIsEnabled() { TaskCategory::Other, NS_NewRunnableFunction("DDLogger shutdown setup", [] { sDDLogShutdowner = MakeUnique(); - ClearOnShutdown(&sDDLogShutdowner, - ShutdownPhase::XPCOMShutdown); + ClearOnShutdown(&sDDLogShutdowner, ShutdownPhase::Shutdown); sDDLogDeleter = MakeUnique(); - ClearOnShutdown(&sDDLogDeleter, - ShutdownPhase::XPCOMShutdownThreads); + ClearOnShutdown(&sDDLogDeleter, ShutdownPhase::ShutdownThreads); }))); // Nobody else should change the state when *we* are enabling logging. diff --git a/dom/media/mediacapabilities/MediaCapabilities.cpp b/dom/media/mediacapabilities/MediaCapabilities.cpp index 6fcfc9c9b9a5..e110e3dcdcf4 100644 --- a/dom/media/mediacapabilities/MediaCapabilities.cpp +++ b/dom/media/mediacapabilities/MediaCapabilities.cpp @@ -257,7 +257,7 @@ already_AddRefed MediaCapabilities::DecodingInfo( NS_NewRunnableFunction( "MediaCapabilities::AllocPolicy:Video", []() { ClearOnShutdown(&sVideoAllocPolicy, - ShutdownPhase::XPCOMShutdownThreads); + ShutdownPhase::ShutdownThreads); })); return new SingleAllocPolicy(TrackInfo::TrackType::kVideoTrack, taskQueue); diff --git a/dom/media/platforms/AllocationPolicy.cpp b/dom/media/platforms/AllocationPolicy.cpp index a56bf1d3a1dd..bb568c325ad8 100644 --- a/dom/media/platforms/AllocationPolicy.cpp +++ b/dom/media/platforms/AllocationPolicy.cpp @@ -97,8 +97,7 @@ NotNull GlobalAllocPolicy::Instance(TrackType aTrack) { TaskCategory::Other, NS_NewRunnableFunction( "GlobalAllocPolicy::GlobalAllocPolicy:Audio", []() { - ClearOnShutdown(&sAudioPolicy, - ShutdownPhase::XPCOMShutdownThreads); + ClearOnShutdown(&sAudioPolicy, ShutdownPhase::ShutdownThreads); })); return new AllocPolicyImpl(MediaDecoderLimitDefault()); }(); @@ -109,8 +108,7 @@ NotNull GlobalAllocPolicy::Instance(TrackType aTrack) { TaskCategory::Other, NS_NewRunnableFunction( "GlobalAllocPolicy::GlobalAllocPolicy:Audio", []() { - ClearOnShutdown(&sVideoPolicy, - ShutdownPhase::XPCOMShutdownThreads); + ClearOnShutdown(&sVideoPolicy, ShutdownPhase::ShutdownThreads); })); return new AllocPolicyImpl(MediaDecoderLimitDefault()); }(); diff --git a/dom/media/webrtc/CubebDeviceEnumerator.cpp b/dom/media/webrtc/CubebDeviceEnumerator.cpp index e34c994f20fb..f7f8ec46d86d 100644 --- a/dom/media/webrtc/CubebDeviceEnumerator.cpp +++ b/dom/media/webrtc/CubebDeviceEnumerator.cpp @@ -30,7 +30,7 @@ CubebDeviceEnumerator* CubebDeviceEnumerator::GetInstance() { sInstance = new CubebDeviceEnumerator(); static bool clearOnShutdownSetup = []() -> bool { auto setClearOnShutdown = []() -> void { - ClearOnShutdown(&sInstance, ShutdownPhase::XPCOMShutdownThreads); + ClearOnShutdown(&sInstance, ShutdownPhase::ShutdownThreads); }; if (NS_IsMainThread()) { setClearOnShutdown(); diff --git a/dom/media/webrtc/transport/nr_socket_prsock.cpp b/dom/media/webrtc/transport/nr_socket_prsock.cpp index 4b18c115246b..6088581be9e7 100644 --- a/dom/media/webrtc/transport/nr_socket_prsock.cpp +++ b/dom/media/webrtc/transport/nr_socket_prsock.cpp @@ -241,7 +241,7 @@ class SingletonThreadHolder final { static StaticRefPtr sThread; static void ClearSingletonOnShutdown() { - ClearOnShutdown(&sThread, ShutdownPhase::XPCOMShutdownLoaders); + ClearOnShutdown(&sThread, ShutdownPhase::ShutdownLoaders); } #endif diff --git a/dom/plugins/ipc/PluginProcessChild.cpp b/dom/plugins/ipc/PluginProcessChild.cpp index c411914449cc..986243f93f30 100644 --- a/dom/plugins/ipc/PluginProcessChild.cpp +++ b/dom/plugins/ipc/PluginProcessChild.cpp @@ -176,7 +176,7 @@ void PluginProcessChild::CleanUp() { NS_LogTerm(); #endif - mozilla::KillClearOnShutdown(ShutdownPhase::XPCOMShutdownFinal); + mozilla::KillClearOnShutdown(ShutdownPhase::ShutdownFinal); AbstractThread::ShutdownMainThread(); diff --git a/dom/storage/SessionStorageManager.cpp b/dom/storage/SessionStorageManager.cpp index 547eb85bcfe2..03084ba31d2b 100644 --- a/dom/storage/SessionStorageManager.cpp +++ b/dom/storage/SessionStorageManager.cpp @@ -625,7 +625,7 @@ BackgroundSessionStorageManager* BackgroundSessionStorageManager::GetOrCreate( return; } }, - ShutdownPhase::XPCOMShutdown); + ShutdownPhase::Shutdown); })); } diff --git a/dom/webauthn/U2FTokenManager.cpp b/dom/webauthn/U2FTokenManager.cpp index cffce323c563..bacf0b3869fb 100644 --- a/dom/webauthn/U2FTokenManager.cpp +++ b/dom/webauthn/U2FTokenManager.cpp @@ -89,7 +89,7 @@ class U2FPrefManager final : public nsIObserver { PREF_WEBAUTHN_ANDROID_FIDO2_ENABLED); Preferences::AddStrongObserver(gPrefManager, PREF_WEBAUTHN_ALLOW_DIRECT_ATTESTATION); - ClearOnShutdown(&gPrefManager, ShutdownPhase::XPCOMShutdownThreads); + ClearOnShutdown(&gPrefManager, ShutdownPhase::ShutdownThreads); } return gPrefManager; } diff --git a/gfx/vr/VRManager.cpp b/gfx/vr/VRManager.cpp index b08880db5705..72bc02b674e2 100644 --- a/gfx/vr/VRManager.cpp +++ b/gfx/vr/VRManager.cpp @@ -161,7 +161,7 @@ VRManager::VRManager() VRServiceHost::Init(mVRProcessEnabled); mServiceHost = VRServiceHost::Get(); // We must shutdown before VRServiceHost, which is cleared - // on ShutdownPhase::XPCOMShutdownFinal, potentially before VRManager. + // on ShutdownPhase::ShutdownFinal, potentially before VRManager. // We hold a reference to VRServiceHost to ensure it stays // alive until we have shut down. #else diff --git a/gfx/vr/VRServiceHost.cpp b/gfx/vr/VRServiceHost.cpp index 933a5467e5d8..7250bfe74d8e 100644 --- a/gfx/vr/VRServiceHost.cpp +++ b/gfx/vr/VRServiceHost.cpp @@ -240,8 +240,7 @@ void VRServiceHost::PuppetReset() { // If we're already into ShutdownFinal, the VRPuppetCommandBuffer instance // will have been cleared, so don't try to access it after that point. if (!mVRProcessEnabled && - !(NS_IsMainThread() && - PastShutdownPhase(ShutdownPhase::XPCOMShutdownFinal))) { + !(NS_IsMainThread() && PastShutdownPhase(ShutdownPhase::ShutdownFinal))) { // Puppet is running in this process, tell it to reset directly. VRPuppetCommandBuffer::Get().Reset(); } diff --git a/intl/locale/LocaleService.cpp b/intl/locale/LocaleService.cpp index d8b629787770..929b235235a3 100644 --- a/intl/locale/LocaleService.cpp +++ b/intl/locale/LocaleService.cpp @@ -152,7 +152,7 @@ LocaleService* LocaleService::GetInstance() { } // DOM might use ICUUtils and LocaleService during UnbindFromTree by // final cycle collection. - ClearOnShutdown(&sInstance, ShutdownPhase::CCPostLastCycleCollection); + ClearOnShutdown(&sInstance, ShutdownPhase::ShutdownPostLastCycleCollection); } return sInstance; } diff --git a/intl/strres/nsStringBundle.cpp b/intl/strres/nsStringBundle.cpp index 070fb0e78de6..2a6c77caf79a 100644 --- a/intl/strres/nsStringBundle.cpp +++ b/intl/strres/nsStringBundle.cpp @@ -472,7 +472,7 @@ nsresult nsStringBundleBase::ParseProperties(nsIPersistentProperties** aProps) { nsresult nsStringBundle::LoadProperties() { // Something such as Necko might use string bundle after ClearOnShutdown is // called. LocaleService etc is already down, so we cannot get bundle data. - if (PastShutdownPhase(ShutdownPhase::XPCOMShutdown)) { + if (PastShutdownPhase(ShutdownPhase::Shutdown)) { return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; } @@ -500,7 +500,7 @@ nsresult SharedStringBundle::LoadProperties() { // our string bundles come from). Since shared string bundles won't be // useful after shutdown has started anyway (and we almost certainly got // here from a pre-load attempt in an idle task), just bail out. - if (PastShutdownPhase(ShutdownPhase::XPCOMShutdown)) { + if (PastShutdownPhase(ShutdownPhase::Shutdown)) { return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; } diff --git a/ipc/mscom/EnsureMTA.cpp b/ipc/mscom/EnsureMTA.cpp index 1f0728211ce4..4950664c6cc2 100644 --- a/ipc/mscom/EnsureMTA.cpp +++ b/ipc/mscom/EnsureMTA.cpp @@ -126,7 +126,7 @@ nsCOMPtr EnsureMTA::GetMTAThread() { BackgroundMTAData* bgData = new BackgroundMTAData(); auto setClearOnShutdown = [ptr = &sMTAData]() -> void { - ClearOnShutdown(ptr, ShutdownPhase::XPCOMShutdownThreads); + ClearOnShutdown(ptr, ShutdownPhase::ShutdownThreads); }; if (NS_IsMainThread()) { diff --git a/ipc/mscom/Registration.cpp b/ipc/mscom/Registration.cpp index e984ad0de4b2..f93df2b3a837 100644 --- a/ipc/mscom/Registration.cpp +++ b/ipc/mscom/Registration.cpp @@ -500,7 +500,7 @@ void RegisterArrayData(const ArrayData* aArrayData, size_t aLength) { if (!sArrayData) { sArrayData = new Vector>(); - ClearOnShutdown(&sArrayData, ShutdownPhase::XPCOMShutdownThreads); + ClearOnShutdown(&sArrayData, ShutdownPhase::ShutdownThreads); } MOZ_ALWAYS_TRUE(sArrayData->emplaceBack(std::make_pair(aArrayData, aLength))); diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index e3f5372ee22d..87857f2bcf85 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -1220,7 +1220,7 @@ nsresult mozJSComponentLoader::Import(JSContext* aCx, !mInProgressImports.Get(info.Key(), &mod)) { // We're trying to import a new JSM, but we're late in shutdown and this // will likely not succeed and might even crash, so fail here. - if (PastShutdownPhase(ShutdownPhase::XPCOMShutdownFinal)) { + if (PastShutdownPhase(ShutdownPhase::ShutdownFinal)) { return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; } diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index 7ae7a0102d74..2fe57572ba3d 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -172,7 +172,8 @@ already_AddRefed nsHttpHandler::GetInstance() { MOZ_ASSERT(NS_SUCCEEDED(rv)); // There is code that may be executed during the final cycle collection // shutdown and still referencing gHttpHandler. - ClearOnShutdown(&gHttpHandler, ShutdownPhase::CCPostLastCycleCollection); + ClearOnShutdown(&gHttpHandler, + ShutdownPhase::ShutdownPostLastCycleCollection); } RefPtr httpHandler = gHttpHandler; return httpHandler.forget(); diff --git a/netwerk/test/unit/head_cookies.js b/netwerk/test/unit/head_cookies.js index faf2af580559..feb6939b4f89 100644 --- a/netwerk/test/unit/head_cookies.js +++ b/netwerk/test/unit/head_cookies.js @@ -100,7 +100,7 @@ function do_close_profile(generator) { // Close the db. let service = Services.cookies.QueryInterface(Ci.nsIObserver); - service.observe(null, "profile-before-change", null); + service.observe(null, "profile-before-change", "shutdown-persist"); } function _promise_observer(topic) { @@ -131,7 +131,7 @@ function promise_close_profile() { // Close the db. let service = Services.cookies.QueryInterface(Ci.nsIObserver); - service.observe(null, "profile-before-change", null); + service.observe(null, "profile-before-change", "shutdown-persist"); return promise; } diff --git a/toolkit/components/extensions/webrequest/ChannelWrapper.cpp b/toolkit/components/extensions/webrequest/ChannelWrapper.cpp index 6dc55356edb9..91f5af6e1da4 100644 --- a/toolkit/components/extensions/webrequest/ChannelWrapper.cpp +++ b/toolkit/components/extensions/webrequest/ChannelWrapper.cpp @@ -100,7 +100,7 @@ static LinkedList& ChannelList() { static UniquePtr sChannelList; if (!sChannelList) { sChannelList.reset(new ChannelListHolder()); - ClearOnShutdown(&sChannelList, ShutdownPhase::XPCOMShutdown); + ClearOnShutdown(&sChannelList, ShutdownPhase::Shutdown); } return *sChannelList; } diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp index 664c8663036b..dd475eb83b3b 100644 --- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp @@ -441,10 +441,11 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { // No chance of the shutdown being cancelled from here on; tell people // we're shutting down for sure while all services are still available. - bool isRestarting = mozilla::AppShutdown::IsRestarting(); - mozilla::AppShutdown::AdvanceShutdownPhase( - mozilla::ShutdownPhase::AppShutdownConfirmed, - isRestarting ? u"restart" : u"shutdown"); + if (obsService) { + bool isRestarting = mozilla::AppShutdown::IsRestarting(); + obsService->NotifyObservers(nullptr, "quit-application", + isRestarting ? u"restart" : u"shutdown"); + } if (!mRunning) { postedExitEvent = true; diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index ec9cb8c0541c..5e87b6c3655a 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -12632,21 +12632,8 @@ "kind": "exponential", "high": 65, "n_buckets": 10, - "bug_numbers": [1689953], - "alert_emails": ["dothayer@mozilla.com, jstutte@mozilla.com"], "description": "Duration of shutdown phase quit-application, as measured by the shutdown terminator, in seconds of activity" }, - "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_NET_TEARDOWN": { - "record_in_processes": ["main", "content"], - "products": ["firefox", "fennec", "thunderbird"], - "expires_in_version": "never", - "kind": "exponential", - "high": 65, - "n_buckets": 10, - "bug_numbers": [1689953], - "alert_emails": ["dothayer@mozilla.com, jstutte@mozilla.com"], - "description": "Duration of shutdown phase profile-change-net-teardown, as measured by the shutdown terminator, in seconds of activity" - }, "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_TEARDOWN": { "record_in_processes": ["main", "content"], "products": ["firefox", "fennec", "thunderbird"], @@ -12654,32 +12641,8 @@ "kind": "exponential", "high": 65, "n_buckets": 10, - "bug_numbers": [1689953], - "alert_emails": ["dothayer@mozilla.com, jstutte@mozilla.com"], "description": "Duration of shutdown phase profile-change-teardown, as measured by the shutdown terminator, in seconds of activity" }, - "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE": { - "record_in_processes": ["main", "content"], - "products": ["firefox", "fennec", "thunderbird"], - "expires_in_version": "never", - "kind": "exponential", - "high": 65, - "n_buckets": 10, - "bug_numbers": [1689953], - "alert_emails": ["dothayer@mozilla.com, jstutte@mozilla.com"], - "description": "Duration of shutdown phase profile-before-change, as measured by the shutdown terminator, in seconds of activity" - }, - "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE_QM": { - "record_in_processes": ["main", "content"], - "products": ["firefox", "fennec", "thunderbird"], - "expires_in_version": "never", - "kind": "exponential", - "high": 65, - "n_buckets": 10, - "bug_numbers": [1689953], - "alert_emails": ["dothayer@mozilla.com, jstutte@mozilla.com"], - "description": "Duration of shutdown phase profile-before-change-qm, as measured by the shutdown terminator, in seconds of activity" - }, "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_WILL_SHUTDOWN": { "record_in_processes": ["main", "content"], "products": ["firefox", "fennec", "thunderbird"], @@ -12687,20 +12650,16 @@ "kind": "exponential", "high": 65, "n_buckets": 10, - "bug_numbers": [1689953], - "alert_emails": ["dothayer@mozilla.com, jstutte@mozilla.com"], "description": "Duration of shutdown phase xpcom-will-shutdown, as measured by the shutdown terminator, in seconds of activity" }, - "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_SHUTDOWN": { + "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE": { "record_in_processes": ["main", "content"], "products": ["firefox", "fennec", "thunderbird"], "expires_in_version": "never", "kind": "exponential", "high": 65, "n_buckets": 10, - "bug_numbers": [1689953], - "alert_emails": ["dothayer@mozilla.com, jstutte@mozilla.com"], - "description": "Duration of shutdown phase xpcom-shutdown, as measured by the shutdown terminator, in seconds of activity" + "description": "Duration of shutdown phase profile-before-change, as measured by the shutdown terminator, in seconds of activity" }, "TAP_TO_LOAD_ENABLED": { "record_in_processes": ["main", "content"], diff --git a/toolkit/components/telemetry/histogram-allowlists.json b/toolkit/components/telemetry/histogram-allowlists.json index b986919ee965..2fe7b7df6dfd 100644 --- a/toolkit/components/telemetry/histogram-allowlists.json +++ b/toolkit/components/telemetry/histogram-allowlists.json @@ -316,6 +316,10 @@ "SERVICE_WORKER_WAS_SPAWNED", "SHOULD_AUTO_DETECT_LANGUAGE", "SHOULD_TRANSLATION_UI_APPEAR", + "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE", + "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_TEARDOWN", + "SHUTDOWN_PHASE_DURATION_TICKS_QUIT_APPLICATION", + "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_WILL_SHUTDOWN", "SLOW_ADDON_WARNING_RESPONSE_TIME", "SLOW_ADDON_WARNING_STATES", "STARTUP_CRASH_DETECTED", @@ -788,6 +792,10 @@ "SERVICE_WORKER_WAS_SPAWNED", "SHOULD_AUTO_DETECT_LANGUAGE", "SHOULD_TRANSLATION_UI_APPEAR", + "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE", + "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_TEARDOWN", + "SHUTDOWN_PHASE_DURATION_TICKS_QUIT_APPLICATION", + "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_WILL_SHUTDOWN", "SLOW_ADDON_WARNING_RESPONSE_TIME", "SLOW_ADDON_WARNING_STATES", "SLOW_SCRIPT_NOTICE_COUNT", diff --git a/toolkit/components/terminator/TerminatorTelemetry.jsm b/toolkit/components/terminator/TerminatorTelemetry.jsm index 42e91878122f..36f0e947cc0c 100644 --- a/toolkit/components/terminator/TerminatorTelemetry.jsm +++ b/toolkit/components/terminator/TerminatorTelemetry.jsm @@ -31,16 +31,11 @@ function nsTerminatorTelemetry() {} var HISTOGRAMS = { "quit-application": "SHUTDOWN_PHASE_DURATION_TICKS_QUIT_APPLICATION", - "profile-change-net-teardown": - "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_NET_TEARDOWN", "profile-change-teardown": "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_TEARDOWN", "profile-before-change": "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE", - "profile-before-change-qm": - "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE_QM", "xpcom-will-shutdown": "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_WILL_SHUTDOWN", - "xpcom-shutdown": "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_SHUTDOWN", }; nsTerminatorTelemetry.prototype = { diff --git a/toolkit/components/terminator/nsTerminator.cpp b/toolkit/components/terminator/nsTerminator.cpp index f0d2a08c29a3..6a1a17c05722 100644 --- a/toolkit/components/terminator/nsTerminator.cpp +++ b/toolkit/components/terminator/nsTerminator.cpp @@ -15,7 +15,6 @@ * process as fast as possible, without any cleanup. */ -#include "mozilla/ShutdownPhase.h" #include "nsTerminator.h" #include "prthread.h" @@ -40,7 +39,6 @@ # include #endif -#include "mozilla/AppShutdown.h" #include "mozilla/ArrayUtils.h" #include "mozilla/Atomics.h" #include "mozilla/Attributes.h" @@ -66,8 +64,6 @@ // forcefully. #define ADDITIONAL_WAIT_BEFORE_CRASH_MS 3000 -#define HEARTBEAT_INTERVAL_MS 100 - namespace mozilla { namespace { @@ -80,34 +76,25 @@ namespace { * ticks between the time we receive a notification and the next one. */ struct ShutdownStep { - mozilla::ShutdownPhase mPhase; + char const* const mTopic; int mTicks; - constexpr explicit ShutdownStep(mozilla::ShutdownPhase aPhase) - : mPhase(aPhase), mTicks(-1) {} + constexpr explicit ShutdownStep(const char* const topic) + : mTopic(topic), mTicks(-1) {} }; static ShutdownStep sShutdownSteps[] = { - ShutdownStep(mozilla::ShutdownPhase::AppShutdownConfirmed), - ShutdownStep(mozilla::ShutdownPhase::AppShutdownNetTeardown), - ShutdownStep(mozilla::ShutdownPhase::AppShutdownTeardown), - ShutdownStep(mozilla::ShutdownPhase::AppShutdown), - ShutdownStep(mozilla::ShutdownPhase::AppShutdownQM), - ShutdownStep(mozilla::ShutdownPhase::XPCOMWillShutdown), - ShutdownStep(mozilla::ShutdownPhase::XPCOMShutdown), + ShutdownStep("quit-application"), + ShutdownStep("profile-change-net-teardown"), + ShutdownStep("profile-change-teardown"), + ShutdownStep("profile-before-change"), + ShutdownStep("profile-before-change-qm"), + ShutdownStep("xpcom-will-shutdown"), + ShutdownStep("xpcom-shutdown"), }; Atomic sShutdownNotified; -int GetStepForPhase(mozilla::ShutdownPhase aPhase) { - for (size_t i = 0; i < std::size(sShutdownSteps); i++) { - if (sShutdownSteps[i].mPhase >= aPhase) { - return (int)i; - } - } - return -1; -} - // Utility function: create a thread that is non-joinable, // does not prevent the process from terminating, is never // cooperatively scheduled, and uses a default stack size. @@ -185,9 +172,9 @@ void RunWatchdog(void* arg) { // more reasonable. // #if defined(XP_WIN) - Sleep(HEARTBEAT_INTERVAL_MS /* ms */); + Sleep(1000 /* ms */); #else - usleep(HEARTBEAT_INTERVAL_MS * 1000 /* usec */); + usleep(1000000 /* usec */); #endif if (gHeartbeat++ < timeToLive) { @@ -198,24 +185,24 @@ void RunWatchdog(void* arg) { // The shutdown steps are not completed yet. Let's report the last one. if (!sShutdownNotified) { - mozilla::ShutdownPhase lastStep = mozilla::ShutdownPhase::NotInShutdown; + const char* lastStep = nullptr; // Looping inverse here to make the search more robust in case // the observer that triggers UpdateHeartbeat was not called // at all or in the expected order on some step. This should // give us always the last known ShutdownStep. for (int i = ArrayLength(sShutdownSteps) - 1; i >= 0; --i) { if (sShutdownSteps[i].mTicks > -1) { - lastStep = sShutdownSteps[i].mPhase; + lastStep = sShutdownSteps[i].mTopic; break; } } - if (lastStep != mozilla::ShutdownPhase::NotInShutdown) { + if (lastStep) { nsCString msg; msg.AppendPrintf( "Shutdown hanging at step %s. " "Something is blocking the main-thread.", - mozilla::AppShutdown::GetObserverKey(lastStep)); + lastStep); // This string will be leaked. MOZ_CRASH_UNSAFE(strdup(msg.BeginReading())); } @@ -362,7 +349,6 @@ void RunWriter(void* arg) { // will be written correctly, but, again, we don't care enough // about the data to make more efforts. // - Unused << PR_Delete(destinationPath.get()); if (PR_Rename(tmpFilePath.get(), destinationPath.get()) != PR_SUCCESS) { break; } @@ -375,11 +361,25 @@ NS_IMPL_ISUPPORTS(nsTerminator, nsIObserver) nsTerminator::nsTerminator() : mInitialized(false), mCurrentStep(-1) {} +// During startup, register as an observer for all interesting topics. +nsresult nsTerminator::SelfInit() { + nsCOMPtr os = mozilla::services::GetObserverService(); + if (!os) { + return NS_ERROR_UNEXPECTED; + } + + for (auto& shutdownStep : sShutdownSteps) { + DebugOnly rv = os->AddObserver(this, shutdownStep.mTopic, false); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddObserver failed"); + } + + return NS_OK; +} + // Actually launch these threads. This takes place at the first sign of // shutdown. void nsTerminator::Start() { MOZ_ASSERT(!mInitialized); - sShutdownNotified = false; StartWatchdog(); #if !defined(NS_FREE_PERMANENT_DATA) // Only allow nsTerminator to write on non-leak-checked builds so we don't @@ -388,33 +388,7 @@ void nsTerminator::Start() { StartWriter(); #endif // !defined(NS_FREE_PERMANENT_DATA) mInitialized = true; -} - -NS_IMETHODIMP -nsTerminator::Observe(nsISupports*, const char* aTopic, const char16_t*) { - // This Observe is now only used for testing purposes. - // XXX: Check if we should change our testing strategy. - if (strcmp(aTopic, "terminator-test-quit-application") == 0) { - AdvancePhase(mozilla::ShutdownPhase::AppShutdownConfirmed); - } else if (strcmp(aTopic, "terminator-test-profile-change-net-teardown") == - 0) { - AdvancePhase(mozilla::ShutdownPhase::AppShutdownNetTeardown); - } else if (strcmp(aTopic, "terminator-test-profile-change-teardown") == 0) { - AdvancePhase(mozilla::ShutdownPhase::AppShutdownTeardown); - } else if (strcmp(aTopic, "terminator-test-profile-before-change") == 0) { - AdvancePhase(mozilla::ShutdownPhase::AppShutdown); - } else if (strcmp(aTopic, "terminator-test-profile-before-change-qm") == 0) { - AdvancePhase(mozilla::ShutdownPhase::AppShutdownQM); - } else if (strcmp(aTopic, - "terminator-test-profile-before-change-telemetry") == 0) { - AdvancePhase(mozilla::ShutdownPhase::AppShutdownTelemetry); - } else if (strcmp(aTopic, "terminator-test-xpcom-will-shutdown") == 0) { - AdvancePhase(mozilla::ShutdownPhase::XPCOMWillShutdown); - } else if (strcmp(aTopic, "terminator-test-xpcom-shutdown") == 0) { - AdvancePhase(mozilla::ShutdownPhase::XPCOMShutdown); - } - - return NS_OK; + sShutdownNotified = false; } // Prepare, allocate and start the watchdog thread. @@ -457,12 +431,11 @@ void nsTerminator::StartWatchdog() { #endif UniquePtr options(new Options()); - const PRIntervalTime ticksDuration = - PR_MillisecondsToInterval(HEARTBEAT_INTERVAL_MS); + const PRIntervalTime ticksDuration = PR_MillisecondsToInterval(1000); options->crashAfterTicks = crashAfterMS / ticksDuration; // Handle systems where ticksDuration is greater than crashAfterMS. if (options->crashAfterTicks == 0) { - options->crashAfterTicks = crashAfterMS / HEARTBEAT_INTERVAL_MS; + options->crashAfterTicks = crashAfterMS / 1000; } DebugOnly watchdogThread = @@ -505,11 +478,14 @@ void nsTerminator::StartWriter() { } } -void nsTerminator::AdvancePhase(mozilla::ShutdownPhase aPhase) { - // If we are done, do nothing - if (sShutdownNotified) { - return; +NS_IMETHODIMP +nsTerminator::Observe(nsISupports*, const char* aTopic, const char16_t*) { + if (strcmp(aTopic, "profile-after-change") == 0) { + return SelfInit(); } + + // Other notifications are shutdown-related. + // As we have seen examples in the wild of shutdown notifications // not being sent (or not being sent in the expected order), we do // not assume a specific order. @@ -517,29 +493,41 @@ void nsTerminator::AdvancePhase(mozilla::ShutdownPhase aPhase) { Start(); } - UpdateHeartbeat(GetStepForPhase(aPhase)); + UpdateHeartbeat(aTopic); #if !defined(NS_FREE_PERMANENT_DATA) // Only allow nsTerminator to write on non-leak checked builds so we don't get // leak warnings on shutdown for intentional leaks (see bug 1242084). This // will be enabled again by bug 1255484 when 1255478 lands. UpdateTelemetry(); #endif // !defined(NS_FREE_PERMANENT_DATA) - UpdateCrashReport(mozilla::AppShutdown::GetObserverKey(aPhase)); + UpdateCrashReport(aTopic); + + // Perform a little cleanup + nsCOMPtr os = mozilla::services::GetObserverService(); + MOZ_RELEASE_ASSERT(os); + (void)os->RemoveObserver(this, aTopic); + + return NS_OK; } -void nsTerminator::UpdateHeartbeat(int32_t aStep) { - MOZ_ASSERT(aStep >= mCurrentStep); - - if (aStep > mCurrentStep) { - // Reset the clock, find out how long the current phase has lasted. - uint32_t ticks = gHeartbeat.exchange(0); - if (mCurrentStep >= 0) { - sShutdownSteps[mCurrentStep].mTicks = ticks; - } - sShutdownSteps[aStep].mTicks = 0; - - mCurrentStep = aStep; +void nsTerminator::UpdateHeartbeat(const char* aTopic) { + // Reset the clock, find out how long the current phase has lasted. + uint32_t ticks = gHeartbeat.exchange(0); + if (mCurrentStep >= 0) { + sShutdownSteps[mCurrentStep].mTicks = ticks; } + + // Find out where we now are in the current shutdown. + // Don't assume that shutdown takes place in the expected order. + int nextStep = -1; + for (size_t i = 0; i < ArrayLength(sShutdownSteps); ++i) { + if (strcmp(sShutdownSteps[i].mTopic, aTopic) == 0) { + nextStep = i; + break; + } + } + MOZ_ASSERT(nextStep != -1); + mCurrentStep = nextStep; } void nsTerminator::UpdateTelemetry() { @@ -568,8 +556,7 @@ void nsTerminator::UpdateTelemetry() { telemetryData->AppendLiteral(", "); } telemetryData->AppendLiteral(R"(")"); - telemetryData->Append( - mozilla::AppShutdown::GetObserverKey(shutdownStep.mPhase)); + telemetryData->Append(shutdownStep.mTopic); telemetryData->AppendLiteral(R"(": )"); telemetryData->AppendInt(shutdownStep.mTicks); } diff --git a/toolkit/components/terminator/nsTerminator.h b/toolkit/components/terminator/nsTerminator.h index 6e03a70cac31..d01832ae2174 100644 --- a/toolkit/components/terminator/nsTerminator.h +++ b/toolkit/components/terminator/nsTerminator.h @@ -18,21 +18,21 @@ class nsTerminator final : public nsIObserver { NS_DECL_NSIOBSERVER nsTerminator(); - void AdvancePhase(mozilla::ShutdownPhase aPhase); private: + nsresult SelfInit(); void Start(); void StartWatchdog(); void StartWriter(); - void UpdateHeartbeat(int aStep); + void UpdateHeartbeat(const char* aTopic); void UpdateTelemetry(); void UpdateCrashReport(const char* aTopic); ~nsTerminator() = default; bool mInitialized; - int mCurrentStep; + int32_t mCurrentStep; }; // This is called by XPCOMInit when the shutdown is completed. diff --git a/toolkit/components/terminator/tests/xpcshell/test_terminator_record.js b/toolkit/components/terminator/tests/xpcshell/test_terminator_record.js index 22f24cc5b5af..e6f8b8671a8e 100644 --- a/toolkit/components/terminator/tests/xpcshell/test_terminator_record.js +++ b/toolkit/components/terminator/tests/xpcshell/test_terminator_record.js @@ -16,17 +16,6 @@ var PATH; var PATH_TMP; var terminator; -let KEYS = [ - "quit-application", - "profile-change-net-teardown", - "profile-change-teardown", - "profile-before-change", - "profile-before-change-qm", - "profile-before-change-telemetry", - "xpcom-will-shutdown", - "xpcom-shutdown", -]; - add_task(async function init() { do_get_profile(); PATH = Path.join(Constants.Path.localProfileDir, "ShutdownDuration.json"); @@ -39,6 +28,7 @@ add_task(async function init() { terminator = Cc["@mozilla.org/toolkit/shutdown-terminator;1"].createInstance( Ci.nsIObserver ); + terminator.observe(null, "profile-after-change", null); }); var promiseShutdownDurationData = async function() { @@ -61,22 +51,23 @@ var promiseShutdownDurationData = async function() { }; add_task(async function test_record() { + let PHASE0 = "profile-change-teardown"; + let PHASE1 = "profile-before-change"; + let PHASE2 = "xpcom-will-shutdown"; let t0 = Date.now(); info("Starting shutdown"); - terminator.observe(null, "terminator-test-" + KEYS[2], null); - await new Promise(resolve => setTimeout(resolve, 200)); + terminator.observe(null, "profile-change-teardown", null); info("Moving to next phase"); - terminator.observe(null, "terminator-test-" + KEYS[3], null); - await new Promise(resolve => setTimeout(resolve, 100)); + terminator.observe(null, PHASE1, null); let data = await promiseShutdownDurationData(); let t1 = Date.now(); - Assert.ok(KEYS[2] in data, "The file contains the expected key"); - let duration = data[KEYS[2]]; + Assert.ok(PHASE0 in data, "The file contains the expected key"); + let duration = data[PHASE0]; Assert.equal(typeof duration, "number"); Assert.ok(duration >= 0, "Duration is a non-negative number"); Assert.ok( @@ -86,7 +77,7 @@ add_task(async function test_record() { Assert.equal( Object.keys(data).length, - 2, + 1, "Data does not contain other durations" ); @@ -98,7 +89,7 @@ add_task(async function test_record() { let WAIT_MS = 2000; await new Promise(resolve => setTimeout(resolve, WAIT_MS)); - terminator.observe(null, "terminator-test-" + KEYS[4], null); + terminator.observe(null, PHASE2, null); data = await promiseShutdownDurationData(); let t2 = Date.now(); @@ -107,18 +98,18 @@ add_task(async function test_record() { Object.keys(data) .sort() .join(", "), - [KEYS[2], KEYS[3], KEYS[4]].sort().join(", "), + [PHASE0, PHASE1].sort().join(", "), "The file contains the expected keys" ); - Assert.equal(data[KEYS[2]], duration, "Duration of phase 0 hasn't changed"); - let duration2 = data[KEYS[3]]; + Assert.equal(data[PHASE0], duration, "Duration of phase 0 hasn't changed"); + let duration2 = data[PHASE1]; Assert.equal(typeof duration2, "number"); Assert.ok( - duration2 >= WAIT_MS / 100, - "We have waited at least " + WAIT_MS / 100 + " ticks" + duration2 >= WAIT_MS / 2000, + "We have waited at least " + WAIT_MS / 2000 + " ticks" ); Assert.ok( - duration2 <= Math.ceil((t2 - t1) / 100) + 1, + duration2 <= Math.ceil((t2 - t1) / 1000) + 1, "Duration is reasonable" ); }); diff --git a/toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js b/toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js index 6ee9b55e6b53..e5c76ae03ffe 100644 --- a/toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js +++ b/toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js @@ -15,16 +15,11 @@ var PATH; var HISTOGRAMS = { "quit-application": "SHUTDOWN_PHASE_DURATION_TICKS_QUIT_APPLICATION", - "profile-change-net-teardown": - "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_NET_TEARDOWN", "profile-change-teardown": "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_TEARDOWN", "profile-before-change": "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE", - "profile-before-change-qm": - "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE_QM", "xpcom-will-shutdown": "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_WILL_SHUTDOWN", - "xpcom-shutdown": "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_SHUTDOWN", }; add_task(async function init() { diff --git a/toolkit/crashreporter/test/unit/test_crash_terminator.js b/toolkit/crashreporter/test/unit/test_crash_terminator.js index e0083cd44a59..908df581ef3b 100644 --- a/toolkit/crashreporter/test/unit/test_crash_terminator.js +++ b/toolkit/crashreporter/test/unit/test_crash_terminator.js @@ -11,7 +11,7 @@ function setup_crash() { ); Services.prefs.setBoolPref("toolkit.terminator.testing", true); - Services.prefs.setIntPref("toolkit.asyncshutdown.crash_timeout", 150); + Services.prefs.setIntPref("toolkit.asyncshutdown.crash_timeout", 10); // Initialize the terminator // (normally, this is done through the manifest file, but xpcshell @@ -19,12 +19,12 @@ function setup_crash() { let terminator = Cc[ "@mozilla.org/toolkit/shutdown-terminator;1" ].createInstance(Ci.nsIObserver); - terminator.observe(null, "terminator-test-profile-after-change", null); + terminator.observe(null, "profile-after-change", null); // Inform the terminator that shutdown has started // Pick an arbitrary notification - terminator.observe(null, "terminator-test-profile-before-change", null); - terminator.observe(null, "terminator-test-xpcom-will-shutdown", null); + terminator.observe(null, "xpcom-will-shutdown", null); + terminator.observe(null, "profile-before-change", null); dump("Waiting (actively) for the crash\n"); Services.tm.spinEventLoopUntil(() => false); @@ -32,7 +32,7 @@ function setup_crash() { function after_crash(mdump, extra) { info("Crash signature: " + JSON.stringify(extra, null, "\t")); - Assert.equal(extra.ShutdownProgress, "xpcom-will-shutdown"); + Assert.equal(extra.ShutdownProgress, "profile-before-change"); } add_task(async function run_test() { diff --git a/toolkit/profile/notifications.txt b/toolkit/profile/notifications.txt index e6703b274c42..eab1e2c347ae 100644 --- a/toolkit/profile/notifications.txt +++ b/toolkit/profile/notifications.txt @@ -44,6 +44,15 @@ observer's Observe() method. profile-do-change profile-after-change +"shutdown-persist" + The user is logging out and whatever data the observer stores + for the current profile should be released from memory and + saved to disk. + The following topics happen in this context: + profile-change-net-teardown + profile-change-teardown + profile-before-change + See https://wiki.mozilla.org/XPCOM_Shutdown for more details about the shutdown process. diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp index 064096fe0fce..c83f1b7de17d 100644 --- a/toolkit/xre/nsXREDirProvider.cpp +++ b/toolkit/xre/nsXREDirProvider.cpp @@ -37,7 +37,6 @@ #include "mozilla/dom/ScriptSettings.h" -#include "mozilla/AppShutdown.h" #include "mozilla/AutoRestore.h" #ifdef MOZ_BACKGROUNDTASKS # include "mozilla/BackgroundTasks.h" @@ -1057,24 +1056,30 @@ void nsXREDirProvider::DoShutdown() { AUTO_PROFILER_LABEL("nsXREDirProvider::DoShutdown", OTHER); if (mProfileNotified) { - mozilla::AppShutdown::AdvanceShutdownPhase( - mozilla::ShutdownPhase::AppShutdownNetTeardown, nullptr); - mozilla::AppShutdown::AdvanceShutdownPhase( - mozilla::ShutdownPhase::AppShutdownTeardown, nullptr); + nsCOMPtr obsSvc = + mozilla::services::GetObserverService(); + NS_ASSERTION(obsSvc, "No observer service?"); + if (obsSvc) { + static const char16_t kShutdownPersist[] = u"shutdown-persist"; + obsSvc->NotifyObservers(nullptr, "profile-change-net-teardown", + kShutdownPersist); + obsSvc->NotifyObservers(nullptr, "profile-change-teardown", + kShutdownPersist); #ifdef DEBUG - // Not having this causes large intermittent leaks. See bug 1340425. - if (JSContext* cx = mozilla::dom::danger::GetJSContext()) { - JS_GC(cx); - } + // Not having this causes large intermittent leaks. See bug 1340425. + if (JSContext* cx = mozilla::dom::danger::GetJSContext()) { + JS_GC(cx); + } #endif - mozilla::AppShutdown::AdvanceShutdownPhase( - mozilla::ShutdownPhase::AppShutdown, nullptr); - mozilla::AppShutdown::AdvanceShutdownPhase( - mozilla::ShutdownPhase::AppShutdownQM, nullptr); - mozilla::AppShutdown::AdvanceShutdownPhase( - mozilla::ShutdownPhase::AppShutdownTelemetry, nullptr); + obsSvc->NotifyObservers(nullptr, "profile-before-change", + kShutdownPersist); + obsSvc->NotifyObservers(nullptr, "profile-before-change-qm", + kShutdownPersist); + obsSvc->NotifyObservers(nullptr, "profile-before-change-telemetry", + kShutdownPersist); + } mProfileNotified = false; } diff --git a/tools/profiler/gecko/ProfilerParent.cpp b/tools/profiler/gecko/ProfilerParent.cpp index 5846b1cda046..e5cc324a91e0 100644 --- a/tools/profiler/gecko/ProfilerParent.cpp +++ b/tools/profiler/gecko/ProfilerParent.cpp @@ -400,7 +400,7 @@ void ProfilerParentTracker::EnsureInstance() { // The tracker should get destroyed before threads are shutdown, because its // destruction closes extant channels, which could trigger promise rejections // that need to be dispatched to other threads. - ClearOnShutdown(&sInstance, ShutdownPhase::XPCOMShutdownThreads); + ClearOnShutdown(&sInstance, ShutdownPhase::ShutdownThreads); } /* static */ diff --git a/widget/windows/WinUtils.cpp b/widget/windows/WinUtils.cpp index af4ae6840f3c..3374dc4f481c 100644 --- a/widget/windows/WinUtils.cpp +++ b/widget/windows/WinUtils.cpp @@ -2137,7 +2137,7 @@ const WinUtils::WhitelistVec& WinUtils::GetWhitelistedPaths() { static WhitelistVec sWhitelist([]() -> WhitelistVec { auto setClearFn = [ptr = &sWhitelist]() -> void { RunOnShutdown([ptr]() -> void { ptr->clear(); }, - ShutdownPhase::XPCOMShutdownFinal); + ShutdownPhase::ShutdownFinal); }; if (NS_IsMainThread()) { diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 65e3f70a2fce..6ba99fe813fd 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -5197,30 +5197,22 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam, // Windows won't let us do that. Bug 212316. nsCOMPtr obsServ = mozilla::services::GetObserverService(); + const char16_t* context = u"shutdown-persist"; const char16_t* syncShutdown = u"syncShutdown"; const char16_t* quitType = GetQuitType(); - AppShutdown::Init(AppShutdownMode::Normal, 0); - obsServ->NotifyObservers(nullptr, "quit-application-granted", syncShutdown); obsServ->NotifyObservers(nullptr, "quit-application-forced", nullptr); - - AppShutdown::OnShutdownConfirmed(); - - AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownConfirmed, - quitType); - AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownNetTeardown, - nullptr); - AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownTeardown, - nullptr); - AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdown, nullptr); - AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownQM, - nullptr); - AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownTelemetry, - nullptr); - - AppShutdown::DoImmediateExit(); + obsServ->NotifyObservers(nullptr, "quit-application", quitType); + obsServ->NotifyObservers(nullptr, "profile-change-net-teardown", + context); + obsServ->NotifyObservers(nullptr, "profile-change-teardown", context); + obsServ->NotifyObservers(nullptr, "profile-before-change", context); + obsServ->NotifyObservers(nullptr, "profile-before-change-qm", context); + obsServ->NotifyObservers(nullptr, "profile-before-change-telemetry", + context); + mozilla::AppShutdown::DoImmediateExit(); } sCanQuit = TRI_UNKNOWN; result = true; diff --git a/xpcom/base/AppShutdown.cpp b/xpcom/base/AppShutdown.cpp index 8cc41eefbd64..bf47f0c76c1c 100644 --- a/xpcom/base/AppShutdown.cpp +++ b/xpcom/base/AppShutdown.cpp @@ -4,6 +4,8 @@ * 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 "AppShutdown.h" + #ifdef XP_WIN # include #else @@ -11,7 +13,6 @@ #endif #include "GeckoProfiler.h" -#include "mozilla/ClearOnShutdown.h" #include "mozilla/CmdLineAndEnvUtils.h" #include "mozilla/PoisonIOInterposer.h" #include "mozilla/Printf.h" @@ -20,19 +21,11 @@ #include "mozilla/StartupTimeline.h" #include "mozilla/StaticPrefs_toolkit.h" #include "mozilla/LateWriteChecks.h" -#include "mozilla/Services.h" #include "nsAppDirectoryServiceDefs.h" #include "nsAppRunner.h" #include "nsDirectoryServiceUtils.h" #include "nsICertStorage.h" #include "nsThreadUtils.h" - -#include "AppShutdown.h" - -// TODO: understand why on Android we cannot include this and if we should -#ifndef ANDROID -# include "nsTerminator.h" -#endif #include "prenv.h" #ifdef MOZ_NEW_XULSTORE @@ -41,29 +34,6 @@ namespace mozilla { -const char* sPhaseObserverKeys[] = { - nullptr, // NotInShutdown - "quit-application", // AppShutdownConfirmed - "profile-change-net-teardown", // AppShutdownNetTeardown - "profile-change-teardown", // AppShutdownTeardown - "profile-before-change", // AppShutdown - "profile-before-change-qm", // AppShutdownQM - "profile-before-change-telemetry", // AppShutdownTelemetry - "xpcom-will-shutdown", // XPCOMWillShutdown - "xpcom-shutdown", // XPCOMShutdown - "xpcom-shutdown-threads", // XPCOMShutdownThreads - nullptr, // XPCOMShutdownLoaders - nullptr, // XPCOMShutdownFinal - nullptr // CCPostLastCycleCollection -}; - -static_assert(sizeof(sPhaseObserverKeys) / sizeof(sPhaseObserverKeys[0]) == - (size_t)ShutdownPhase::ShutdownPhase_Length); - -#ifndef ANDROID -static nsTerminator* sTerminator = nullptr; -#endif - static ShutdownPhase sFastShutdownPhase = ShutdownPhase::NotInShutdown; static ShutdownPhase sLateWriteChecksPhase = ShutdownPhase::NotInShutdown; static AppShutdownMode sShutdownMode = AppShutdownMode::Normal; @@ -84,11 +54,11 @@ static char* sSavedProfLDEnvVar = nullptr; ShutdownPhase GetShutdownPhaseFromPrefValue(int32_t aPrefValue) { switch (aPrefValue) { case 1: - return ShutdownPhase::CCPostLastCycleCollection; + return ShutdownPhase::ShutdownPostLastCycleCollection; case 2: - return ShutdownPhase::XPCOMShutdownThreads; + return ShutdownPhase::ShutdownThreads; case 3: - return ShutdownPhase::XPCOMShutdown; + return ShutdownPhase::Shutdown; // NOTE: the remaining values from the ShutdownPhase enum will be added // when we're at least reasonably confident that the world won't come // crashing down if we do a fast shutdown at that point. @@ -108,11 +78,6 @@ void AppShutdown::SaveEnvVarsForPotentialRestart() { } } -const char* AppShutdown::GetObserverKey(ShutdownPhase aPhase) { - return sPhaseObserverKeys[static_cast>( - aPhase)]; -} - void AppShutdown::MaybeDoRestart() { if (sShutdownMode == AppShutdownMode::Restart) { StopLateWriteChecks(); @@ -170,10 +135,6 @@ void AppShutdown::Init(AppShutdownMode aMode, int aExitCode) { sExitCode = aExitCode; -#ifndef ANDROID - sTerminator = new nsTerminator(); -#endif - // Late-write checks needs to find the profile directory, so it has to // be initialized before services::Shutdown or (because of // xpcshell tests replacing the service) modules being unloaded. @@ -282,28 +243,4 @@ bool AppShutdown::IsRestarting() { return sShutdownMode == AppShutdownMode::Restart; } -void AppShutdown::AdvanceShutdownPhase( - ShutdownPhase aPhase, const char16_t* aNotificationData, - nsCOMPtr aNotificationSubject) { -#ifndef ANDROID - if (sTerminator) { - sTerminator->AdvancePhase(aPhase); - } -#endif - - mozilla::KillClearOnShutdown(aPhase); - - MaybeFastShutdown(aPhase); - - const char* aTopic = AppShutdown::GetObserverKey(aPhase); - if (aTopic) { - nsCOMPtr obsService = - mozilla::services::GetObserverService(); - if (obsService) { - obsService->NotifyObservers(aNotificationSubject, aTopic, - aNotificationData); - } - } -} - } // namespace mozilla diff --git a/xpcom/base/AppShutdown.h b/xpcom/base/AppShutdown.h index b1fd4f5c1963..4a480b632376 100644 --- a/xpcom/base/AppShutdown.h +++ b/xpcom/base/AppShutdown.h @@ -7,7 +7,6 @@ #ifndef AppShutdown_h #define AppShutdown_h -#include #include "ShutdownPhase.h" namespace mozilla { @@ -20,6 +19,7 @@ enum class AppShutdownMode { class AppShutdown { public: static bool IsShuttingDown(); + /** * Returns the current exit code that the process will be terminated with. */ @@ -47,6 +47,12 @@ class AppShutdown { */ static void MaybeDoRestart(); + /** + * This will perform a fast shutdown via _exit(0) or similar if the user's + * prefs are configured to do so at this phase. + */ + static void MaybeFastShutdown(ShutdownPhase aPhase); + /** * The _exit() call is not a safe way to terminate your own process on * Windows, because _exit runs DLL detach callbacks which run static @@ -63,25 +69,6 @@ class AppShutdown { * restart. */ static bool IsRestarting(); - - /** - * Wrapper for shutdown notifications that inform the terminator before - * we notify other observers. Calls MaybeFastShutdown. - */ - static void AdvanceShutdownPhase( - ShutdownPhase aPhase, const char16_t* aNotificationData = nullptr, - nsCOMPtr aNotificationSubject = nullptr); - - /** - * This will perform a fast shutdown via _exit(0) or similar if the user's - * prefs are configured to do so at this phase. - */ - static void MaybeFastShutdown(ShutdownPhase aPhase); - - /** - * Map shutdown phases to observer keys - */ - static const char* GetObserverKey(ShutdownPhase aPhase); }; } // namespace mozilla diff --git a/xpcom/base/ClearOnShutdown.h b/xpcom/base/ClearOnShutdown.h index 7fed03c9904b..522428736c05 100644 --- a/xpcom/base/ClearOnShutdown.h +++ b/xpcom/base/ClearOnShutdown.h @@ -19,8 +19,7 @@ * This header exports two public methods in the mozilla namespace: * * template - * void ClearOnShutdown(SmartPtr *aPtr, - * aPhase=ShutdownPhase::XPCOMShutdownFinal) + * void ClearOnShutdown(SmartPtr *aPtr, aPhase=ShutdownPhase::ShutdownFinal) * * This function takes a pointer to a smart pointer and nulls the smart pointer * on shutdown (and a particular phase of shutdown as needed). If a phase @@ -41,7 +40,7 @@ * * template * void RunOnShutdown(CallableT&& aCallable, - * aPhase = ShutdownPhase::XPCOMShutdownFinal) + * aPhase = ShutdownPhase::ShutdownFinal) * * This function takes a callable and executes it upon shutdown at the start of * the specified phase. If the phase has already occurred when RunOnShutdown() @@ -109,7 +108,7 @@ extern ShutdownPhase sCurrentShutdownPhase; template inline void ClearOnShutdown( - SmartPtr* aPtr, ShutdownPhase aPhase = ShutdownPhase::XPCOMShutdownFinal) { + SmartPtr* aPtr, ShutdownPhase aPhase = ShutdownPhase::ShutdownFinal) { using namespace ClearOnShutdown_Internal; MOZ_ASSERT(NS_IsMainThread()); @@ -119,9 +118,8 @@ inline void ClearOnShutdown( } template -inline void RunOnShutdown( - CallableT&& aCallable, - ShutdownPhase aPhase = ShutdownPhase::XPCOMShutdownFinal) { +inline void RunOnShutdown(CallableT&& aCallable, + ShutdownPhase aPhase = ShutdownPhase::ShutdownFinal) { using namespace ClearOnShutdown_Internal; MOZ_ASSERT(NS_IsMainThread()); diff --git a/xpcom/base/ShutdownPhase.h b/xpcom/base/ShutdownPhase.h index 47c267748109..04b891e13d88 100644 --- a/xpcom/base/ShutdownPhase.h +++ b/xpcom/base/ShutdownPhase.h @@ -12,21 +12,15 @@ namespace mozilla { // Must be contiguous starting at 0 enum class ShutdownPhase { NotInShutdown = 0, - AppShutdownConfirmed, - AppShutdownNetTeardown, - AppShutdownTeardown, - AppShutdown, - AppShutdownQM, - AppShutdownTelemetry, - XPCOMWillShutdown, - XPCOMShutdown, - XPCOMShutdownThreads, - XPCOMShutdownLoaders, - XPCOMShutdownFinal, - CCPostLastCycleCollection, - ShutdownPhase_Length, // never pass this value - First = AppShutdownConfirmed, // for iteration - Last = XPCOMShutdownFinal + WillShutdown, + Shutdown, + ShutdownThreads, + ShutdownLoaders, + ShutdownFinal, + ShutdownPostLastCycleCollection, + ShutdownPhase_Length, // never pass this value + First = WillShutdown, // for iteration + Last = ShutdownFinal }; } // namespace mozilla diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp index b305d4200b06..fbee0bef7434 100644 --- a/xpcom/build/XPCOMInit.cpp +++ b/xpcom/build/XPCOMInit.cpp @@ -598,29 +598,45 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) { return NS_ERROR_UNEXPECTED; } - mozilla::AppShutdown::AdvanceShutdownPhase( - mozilla::ShutdownPhase::XPCOMWillShutdown); + RefPtr observerService; + CallGetService("@mozilla.org/observer-service;1", + (nsObserverService**)getter_AddRefs(observerService)); - nsCOMPtr mgr; - rv = NS_GetServiceManager(getter_AddRefs(mgr)); - if (NS_SUCCEEDED(rv)) { - // We want the service manager to be the subject of notifications - mozilla::AppShutdown::AdvanceShutdownPhase( - mozilla::ShutdownPhase::XPCOMShutdown, nullptr, - do_QueryInterface(mgr)); - } + if (observerService) { + mozilla::KillClearOnShutdown(ShutdownPhase::WillShutdown); + mozilla::AppShutdown::MaybeFastShutdown( + mozilla::ShutdownPhase::WillShutdown); + observerService->NotifyObservers( + nullptr, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, nullptr); + + nsCOMPtr mgr; + rv = NS_GetServiceManager(getter_AddRefs(mgr)); + if (NS_SUCCEEDED(rv)) { + mozilla::KillClearOnShutdown(ShutdownPhase::Shutdown); + mozilla::AppShutdown::MaybeFastShutdown( + mozilla::ShutdownPhase::Shutdown); + observerService->NotifyObservers(mgr, NS_XPCOM_SHUTDOWN_OBSERVER_ID, + nullptr); + } #ifndef ANDROID - mozilla::XPCOMShutdownNotified(); + mozilla::XPCOMShutdownNotified(); #endif + } // 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( - mozilla::ShutdownPhase::XPCOMShutdownThreads); + if (observerService) { + mozilla::KillClearOnShutdown(ShutdownPhase::ShutdownThreads); + mozilla::AppShutdown::MaybeFastShutdown( + mozilla::ShutdownPhase::ShutdownThreads); + observerService->NotifyObservers( + nullptr, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, nullptr); + } + gXPCOMThreadsShutDown = true; NS_ProcessPendingEvents(thread); @@ -630,13 +646,8 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) { NS_ProcessPendingEvents(thread); - mozilla::KillClearOnShutdown(ShutdownPhase::XPCOMShutdownLoaders); - // XXX: Why don't we try a MaybeFastShutdown for XPCOMShutdownLoaders ? - - RefPtr observerService; - CallGetService("@mozilla.org/observer-service;1", - (nsObserverService**)getter_AddRefs(observerService)); if (observerService) { + mozilla::KillClearOnShutdown(ShutdownPhase::ShutdownLoaders); observerService->Shutdown(); } @@ -644,7 +655,7 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) { // we've finished notifying observers of XPCOM shutdown, because shutdown // observers themselves might call ClearOnShutdown(). // Some destructors may fire extra runnables that will be processed below. - mozilla::KillClearOnShutdown(ShutdownPhase::XPCOMShutdownFinal); + mozilla::KillClearOnShutdown(ShutdownPhase::ShutdownFinal); // Shutdown all remaining threads. This method does not return until // all threads created using the thread manager (with the exception of @@ -664,7 +675,7 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) { AbstractThread::ShutdownMainThread(); mozilla::AppShutdown::MaybeFastShutdown( - mozilla::ShutdownPhase::XPCOMShutdownFinal); + mozilla::ShutdownPhase::ShutdownFinal); // XPCOM is officially in shutdown mode NOW // Set this only after the observers have been notified as this @@ -707,9 +718,9 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) { // There can be code trying to refer to global objects during the final cc // shutdown. This is the phase for such global objects to correctly release. - mozilla::KillClearOnShutdown(ShutdownPhase::CCPostLastCycleCollection); + mozilla::KillClearOnShutdown(ShutdownPhase::ShutdownPostLastCycleCollection); mozilla::AppShutdown::MaybeFastShutdown( - mozilla::ShutdownPhase::CCPostLastCycleCollection); + mozilla::ShutdownPhase::ShutdownPostLastCycleCollection); mozilla::scache::StartupCache::DeleteSingleton();