зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 2 changesets (bug 1777198) for causing build bustage in dom/ipc/ProcessHangMonitor.cpp CLOSED TREE
Backed out changeset 472fe2d7af01 (bug 1777198) Backed out changeset 0b9cb5b44360 (bug 1777198)
This commit is contained in:
Родитель
8ec529562a
Коммит
646227cd7d
|
@ -1652,7 +1652,6 @@ const nsACString& ContentParent::GetRemoteType() const { return mRemoteType; }
|
|||
|
||||
static StaticRefPtr<nsIAsyncShutdownClient> sXPCOMShutdownClient;
|
||||
static StaticRefPtr<nsIAsyncShutdownClient> sProfileBeforeChangeClient;
|
||||
static StaticRefPtr<nsIAsyncShutdownClient> sQuitApplicationGrantedClient;
|
||||
|
||||
void ContentParent::Init() {
|
||||
MOZ_ASSERT(sXPCOMShutdownClient);
|
||||
|
@ -1723,7 +1722,6 @@ void ContentParent::MaybeBeginShutDown(uint32_t aExpectedBrowserCount,
|
|||
|
||||
// We're dying now, prevent anything from re-using this process.
|
||||
MarkAsDead();
|
||||
SignalImpendingShutdownToContentJS();
|
||||
StartForceKillTimer();
|
||||
|
||||
if (aSendShutDown) {
|
||||
|
@ -1801,12 +1799,7 @@ void ContentParent::ShutDownProcess(ShutDownMethod aMethod) {
|
|||
__LINE__);
|
||||
mShutdownPending = true;
|
||||
// Start the force-kill timer if we haven't already.
|
||||
// This can happen if we shutdown a process while launching or
|
||||
// because it is removed from the cached processes pool.
|
||||
if (!mForceKillTimer) {
|
||||
SignalImpendingShutdownToContentJS();
|
||||
StartForceKillTimer();
|
||||
}
|
||||
StartForceKillTimer();
|
||||
} else {
|
||||
MaybeLogBlockShutdownDiagnostics(
|
||||
this, "ShutDownProcess: !!! Send shutdown message failed! !!!",
|
||||
|
@ -2374,6 +2367,8 @@ void ContentParent::StartForceKillTimer() {
|
|||
return;
|
||||
}
|
||||
|
||||
NotifyImpendingShutdown();
|
||||
|
||||
int32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
|
||||
if (timeoutSecs > 0) {
|
||||
NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer),
|
||||
|
@ -3583,71 +3578,14 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent)
|
|||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMProcessParent)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
class RequestContentJSInterruptRunnable final : public Runnable {
|
||||
public:
|
||||
explicit RequestContentJSInterruptRunnable(PProcessHangMonitorParent* aActor)
|
||||
: Runnable("dom::RequestContentJSInterruptRunnable"),
|
||||
mHangMonitorActor(aActor) {}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
MOZ_ASSERT(mHangMonitorActor);
|
||||
Unused << mHangMonitorActor->SendRequestContentJSInterrupt();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
// The end-of-life of ContentParent::mHangMonitorActor is bound to
|
||||
// ContentParent::ActorDestroy and then HangMonitorParent::Shutdown
|
||||
// dispatches a shutdown runnable to this queue and waits for it to be
|
||||
// executed. So the runnable needs not to care about keeping it alive,
|
||||
// as it is surely dispatched earlier than the
|
||||
// HangMonitorParent::ShutdownOnThread.
|
||||
PProcessHangMonitorParent* mHangMonitorActor;
|
||||
};
|
||||
|
||||
void ContentParent::SignalImpendingShutdownToContentJS() {
|
||||
if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
|
||||
MaybeLogBlockShutdownDiagnostics(
|
||||
this, "BlockShutdown: NotifyImpendingShutdown.", __FILE__, __LINE__);
|
||||
NotifyImpendingShutdown();
|
||||
if (mHangMonitorActor &&
|
||||
StaticPrefs::dom_abort_script_on_child_shutdown()) {
|
||||
MaybeLogBlockShutdownDiagnostics(
|
||||
this, "BlockShutdown: RequestContentJSInterrupt.", __FILE__,
|
||||
__LINE__);
|
||||
RefPtr<RequestContentJSInterruptRunnable> r =
|
||||
new RequestContentJSInterruptRunnable(mHangMonitorActor);
|
||||
ProcessHangMonitor::Get()->Dispatch(r.forget());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Async shutdown blocker
|
||||
NS_IMETHODIMP
|
||||
ContentParent::BlockShutdown(nsIAsyncShutdownClient* aClient) {
|
||||
if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
mBlockShutdownCalled = true;
|
||||
#endif
|
||||
// Our real shutdown has not yet started. Just notify the
|
||||
// impending shutdown and eventually cancel content JS.
|
||||
SignalImpendingShutdownToContentJS();
|
||||
if (sQuitApplicationGrantedClient) {
|
||||
Unused << sQuitApplicationGrantedClient->RemoveBlocker(this);
|
||||
}
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
mBlockShutdownCalled = false;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
// We register two final shutdown blockers and both would call us, but if
|
||||
// things go well we will unregister both as (delayed) reaction to the first
|
||||
// call we get and thus never receive a second call. Thus we believe that we
|
||||
// will get called only once except for quit-application-granted, which is
|
||||
// handled above.
|
||||
// We register two shutdown blockers and both would call us, but
|
||||
// if things go well we will unregister both as (delayed) reaction
|
||||
// to the first call we get and thus never receive a second call.
|
||||
// Thus we believe that we will get called only once.
|
||||
MOZ_ASSERT(!mBlockShutdownCalled);
|
||||
mBlockShutdownCalled = true;
|
||||
#endif
|
||||
|
@ -3733,15 +3671,6 @@ static void InitShutdownClients() {
|
|||
ClearOnShutdown(&sProfileBeforeChangeClient);
|
||||
}
|
||||
}
|
||||
// TODO: ShutdownPhase::AppShutdownConfirmed is not mapping to
|
||||
// QuitApplicationGranted, see bug 1762840 comment 4.
|
||||
if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
|
||||
rv = svc->GetQuitApplicationGranted(getter_AddRefs(client));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
sQuitApplicationGrantedClient = client.forget();
|
||||
ClearOnShutdown(&sQuitApplicationGrantedClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3758,10 +3687,6 @@ void ContentParent::AddShutdownBlockers() {
|
|||
sProfileBeforeChangeClient->AddBlocker(
|
||||
this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
|
||||
}
|
||||
if (sQuitApplicationGrantedClient) {
|
||||
sQuitApplicationGrantedClient->AddBlocker(
|
||||
this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
|
||||
}
|
||||
}
|
||||
|
||||
void ContentParent::RemoveShutdownBlockers() {
|
||||
|
@ -3780,9 +3705,6 @@ void ContentParent::RemoveShutdownBlockers() {
|
|||
if (sProfileBeforeChangeClient) {
|
||||
Unused << sProfileBeforeChangeClient->RemoveBlocker(this);
|
||||
}
|
||||
if (sQuitApplicationGrantedClient) {
|
||||
Unused << sQuitApplicationGrantedClient->RemoveBlocker(this);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -817,13 +817,6 @@ class ContentParent final : public PContentParent,
|
|||
*/
|
||||
void MarkAsDead();
|
||||
|
||||
/**
|
||||
* Let the process know we are about to send a shutdown through a
|
||||
* non-mainthread side channel in order to bypass mainthread congestion.
|
||||
* This potentially cancels mainthread content JS execution.
|
||||
*/
|
||||
void SignalImpendingShutdownToContentJS();
|
||||
|
||||
/**
|
||||
* Check if this process is ready to be shut down, and if it is, begin the
|
||||
* shutdown process. Should be called whenever a change occurs which could
|
||||
|
|
|
@ -32,7 +32,6 @@ parent:
|
|||
|
||||
child:
|
||||
async TerminateScript();
|
||||
async RequestContentJSInterrupt();
|
||||
|
||||
async BeginStartingDebugger();
|
||||
async EndStartingDebugger();
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/ipc/Endpoint.h"
|
||||
#include "mozilla/ipc/ProcessChild.h"
|
||||
#include "mozilla/ipc/TaskFactory.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
@ -111,7 +110,6 @@ class HangMonitorChild : public PProcessHangMonitorChild,
|
|||
void MaybeStartPaintWhileInterruptingJS();
|
||||
|
||||
mozilla::ipc::IPCResult RecvTerminateScript() override;
|
||||
mozilla::ipc::IPCResult RecvRequestContentJSInterrupt() override;
|
||||
mozilla::ipc::IPCResult RecvBeginStartingDebugger() override;
|
||||
mozilla::ipc::IPCResult RecvEndStartingDebugger() override;
|
||||
|
||||
|
@ -260,7 +258,6 @@ class HangMonitorParent : public PProcessHangMonitorParent,
|
|||
const dom::CancelContentJSOptions& aCancelContentJSOptions);
|
||||
|
||||
void TerminateScript();
|
||||
void RequestContentJSInterrupt();
|
||||
void BeginStartingDebugger();
|
||||
void EndStartingDebugger();
|
||||
|
||||
|
@ -347,18 +344,6 @@ HangMonitorChild::~HangMonitorChild() {
|
|||
bool HangMonitorChild::InterruptCallback() {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (StaticPrefs::dom_abort_script_on_child_shutdown() &&
|
||||
mozilla::ipc::ProcessChild::ExpectingShutdown()) {
|
||||
// We preserve chrome JS from cancel, but not extension content JS.
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
NS_WARNING(
|
||||
"HangMonitorChild::InterruptCallback: ExpectingShutdown, "
|
||||
"canceling content JS execution.\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't start painting if we're not in a good place to run script. We run
|
||||
// chrome script during layout and such, and it wouldn't be good to interrupt
|
||||
// painting code from there.
|
||||
|
@ -510,18 +495,6 @@ mozilla::ipc::IPCResult HangMonitorChild::RecvTerminateScript() {
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult HangMonitorChild::RecvRequestContentJSInterrupt() {
|
||||
MOZ_RELEASE_ASSERT(IsOnThread());
|
||||
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::IPCShutdownState,
|
||||
"HangMonitorChild::RecvRequestContentJSInterrupt"_ns);
|
||||
// In order to cancel JS execution on shutdown, we expect that
|
||||
// ProcessChild::NotifiedImpendingShutdown has been called before.
|
||||
JS_RequestInterruptCallback(mContext);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult HangMonitorChild::RecvBeginStartingDebugger() {
|
||||
MOZ_RELEASE_ASSERT(IsOnThread());
|
||||
|
||||
|
@ -904,14 +877,6 @@ void HangMonitorParent::TerminateScript() {
|
|||
}
|
||||
}
|
||||
|
||||
void HangMonitorParent::RequestContentJSInterrupt() {
|
||||
MOZ_RELEASE_ASSERT(IsOnThread());
|
||||
|
||||
if (mIPCOpen) {
|
||||
Unused << SendRequestContentJSInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
void HangMonitorParent::BeginStartingDebugger() {
|
||||
MOZ_RELEASE_ASSERT(IsOnThread());
|
||||
|
||||
|
|
|
@ -63,7 +63,3 @@ support-files =
|
|||
browser_wpi_base.js
|
||||
[browser_pbrowser_creation_failure.js]
|
||||
skip-if = !fission
|
||||
[browser_content_shutdown_with_endless_js.js]
|
||||
support-files =
|
||||
file_endless_js.html
|
||||
file_dummy.html
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const EMPTY_PAGE =
|
||||
"http://mochi.test:8888/browser/dom/ipc/tests/file_dummy.html";
|
||||
|
||||
const HANG_PAGE =
|
||||
"http://mochi.test:8888/browser/dom/ipc/tests/file_endless_js.html";
|
||||
|
||||
function pushPref(name, val) {
|
||||
return SpecialPowers.pushPrefEnv({ set: [[name, val]] });
|
||||
}
|
||||
|
||||
async function createAndShutdownContentProcess(url) {
|
||||
info("Create and shutdown a content process for " + url);
|
||||
|
||||
let oldChildCount = Services.ppmm.childCount;
|
||||
info("Old process count: " + oldChildCount);
|
||||
|
||||
let tabpromise = BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
opening: url,
|
||||
waitForLoad: true,
|
||||
forceNewProcess: true,
|
||||
});
|
||||
|
||||
let tab = await tabpromise;
|
||||
|
||||
// It seems that the ppmm counter is racy wrt tabpromise.
|
||||
Services.tm.spinEventLoopUntil(
|
||||
"browser_content_shutdown_with_endless_js",
|
||||
() => Services.ppmm.childCount > oldChildCount
|
||||
);
|
||||
|
||||
let newChildCount = Services.ppmm.childCount;
|
||||
info("New process count: " + newChildCount);
|
||||
|
||||
ok(newChildCount == oldChildCount + 1, "Process created.");
|
||||
|
||||
// Start the shutdown of the child process
|
||||
let tabClosed = BrowserTestUtils.waitForTabClosing(tab);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
ok(true, "removeTab");
|
||||
|
||||
Services.tm.spinEventLoopUntil(
|
||||
"browser_content_shutdown_with_endless_js",
|
||||
() => Services.ppmm.childCount < newChildCount
|
||||
);
|
||||
|
||||
info("New count: " + Services.ppmm.childCount);
|
||||
await tabClosed;
|
||||
|
||||
ok(
|
||||
Services.ppmm.childCount == oldChildCount,
|
||||
"Shutdown of content process complete."
|
||||
);
|
||||
}
|
||||
|
||||
add_task(async () => {
|
||||
// This test is only relevant in e10s.
|
||||
if (!gMultiProcessBrowser) {
|
||||
ok(true, "We are not in multiprocess mode, skipping test.");
|
||||
return;
|
||||
}
|
||||
|
||||
await pushPref("dom.abort_script_on_child_shutdown", true);
|
||||
|
||||
// Ensure the process cache cannot interfere.
|
||||
pushPref("dom.ipc.processPreload.enabled", false);
|
||||
// Ensure we have no cached processes from previous tests.
|
||||
Services.ppmm.releaseCachedProcesses();
|
||||
|
||||
// First let's do a dry run that should always succeed.
|
||||
await createAndShutdownContentProcess(EMPTY_PAGE);
|
||||
|
||||
// Now we will start a shutdown of our content process while our content
|
||||
// script is running an endless loop.
|
||||
//
|
||||
// If the JS does not get interrupted on shutdown, it will cause this test
|
||||
// to hang.
|
||||
await createAndShutdownContentProcess(HANG_PAGE);
|
||||
});
|
|
@ -1,15 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head><meta charset="utf-8"></head>
|
||||
<script>
|
||||
function hang() {
|
||||
let i = 1;
|
||||
while (i > 0) {
|
||||
i = Date.now();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<body onload="hang()">
|
||||
<h1>This is an endless JS loop</h1>
|
||||
</body>
|
||||
</html>
|
|
@ -74,7 +74,7 @@ void ProcessChild::NotifiedImpendingShutdown() {
|
|||
sExpectingShutdown = true;
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::IPCShutdownState,
|
||||
"NotifiedImpendingShutdown"_ns);
|
||||
"NotifyImpendingShutdown received."_ns);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
|
@ -4514,12 +4514,6 @@
|
|||
#endif
|
||||
mirror: always
|
||||
|
||||
# Controls if a content script will be aborted on child process shutdown.
|
||||
- name: dom.abort_script_on_child_shutdown
|
||||
type: bool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
- name: dom.max_chrome_script_run_time
|
||||
type: int32_t
|
||||
value: 0
|
||||
|
|
Загрузка…
Ссылка в новой задаче