зеркало из https://github.com/mozilla/gecko-dev.git
Bug 828114: Set a timer to ensure content processes are killed if their tabs take a long time to shut down. r=jlebar a=blocking-basecamp
This commit is contained in:
Родитель
d555a604bd
Коммит
dc502af4df
|
@ -646,6 +646,11 @@ struct DelayedDeleteContentParentTask : public nsRunnable
|
|||
void
|
||||
ContentParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (mForceKillTask) {
|
||||
mForceKillTask->Cancel();
|
||||
mForceKillTask = nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
|
||||
if (ppm) {
|
||||
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
|
||||
|
@ -751,9 +756,35 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
|||
NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
|
||||
{
|
||||
// There can be more than one PBrowser for a given app process
|
||||
// because of popup windows. PBrowsers can also destroy
|
||||
// concurrently. When all the PBrowsers are destroying, kick off
|
||||
// another task to ensure the child process *really* shuts down,
|
||||
// even if the PBrowsers themselves never finish destroying.
|
||||
int32_t numLiveTabs = ManagedPBrowserParent().Length();
|
||||
++mNumDestroyingTabs;
|
||||
if (mNumDestroyingTabs != numLiveTabs) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mForceKillTask);
|
||||
int32_t timeoutSecs =
|
||||
Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5);
|
||||
if (timeoutSecs > 0) {
|
||||
MessageLoop::current()->PostDelayedTask(
|
||||
FROM_HERE,
|
||||
mForceKillTask = NewRunnableMethod(this, &ContentParent::KillHard),
|
||||
timeoutSecs * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::NotifyTabDestroyed(PBrowserParent* aTab)
|
||||
{
|
||||
--mNumDestroyingTabs;
|
||||
// There can be more than one PBrowser for a given app process
|
||||
// because of popup windows. When the last one closes, shut
|
||||
// us down.
|
||||
|
@ -797,6 +828,8 @@ ContentParent::ContentParent(const nsAString& aAppManifestURL,
|
|||
, mRunToCompletionDepth(0)
|
||||
, mShouldCallUnblockChild(false)
|
||||
, mAppManifestURL(aAppManifestURL)
|
||||
, mForceKillTask(nullptr)
|
||||
, mNumDestroyingTabs(0)
|
||||
, mIsAlive(true)
|
||||
, mIsDestroyed(false)
|
||||
, mSendPermissionUpdates(false)
|
||||
|
@ -855,6 +888,10 @@ ContentParent::ContentParent(const nsAString& aAppManifestURL,
|
|||
|
||||
ContentParent::~ContentParent()
|
||||
{
|
||||
if (mForceKillTask) {
|
||||
mForceKillTask->Cancel();
|
||||
}
|
||||
|
||||
if (OtherProcess())
|
||||
base::CloseProcessHandle(OtherProcess());
|
||||
|
||||
|
@ -1442,6 +1479,7 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
|||
void
|
||||
ContentParent::KillHard()
|
||||
{
|
||||
mForceKillTask = nullptr;
|
||||
// This ensures the process is eventually killed, but doesn't
|
||||
// immediately KILLITWITHFIRE because we want to get a minidump if
|
||||
// possible. After a timeout though, the process is forceably
|
||||
|
|
|
@ -104,6 +104,8 @@ public:
|
|||
virtual bool CheckPermission(const nsAString& aPermission);
|
||||
virtual bool CheckManifestURL(const nsAString& aManifestURL);
|
||||
|
||||
/** Notify that a tab is beginning its destruction sequence. */
|
||||
void NotifyTabDestroying(PBrowserParent* aTab);
|
||||
/** Notify that a tab was destroyed during normal operation. */
|
||||
void NotifyTabDestroyed(PBrowserParent* aTab);
|
||||
|
||||
|
@ -353,6 +355,15 @@ private:
|
|||
const nsString mAppManifestURL;
|
||||
nsRefPtr<nsFrameMessageManager> mMessageManager;
|
||||
|
||||
// After we initiate shutdown, we also start a timer to ensure
|
||||
// that even content processes that are 100% blocked (say from
|
||||
// SIGSTOP), are still killed eventually. This task enforces that
|
||||
// timer.
|
||||
CancelableTask* mForceKillTask;
|
||||
// How many tabs we're waiting to finish their destruction
|
||||
// sequence. Precisely, how many TabParents have called
|
||||
// NotifyTabDestroying() but not called NotifyTabDestroyed().
|
||||
int32_t mNumDestroyingTabs;
|
||||
// True only while this is ready to be used to host remote tabs.
|
||||
// This must not be used for new purposes after mIsAlive goes to
|
||||
// false, but some previously scheduled IPC traffic may still pass
|
||||
|
|
|
@ -124,6 +124,9 @@ TabParent::Destroy()
|
|||
frame->Destroy();
|
||||
}
|
||||
mIsDestroyed = true;
|
||||
|
||||
ContentParent* cp = static_cast<ContentParent*>(Manager());
|
||||
cp->NotifyTabDestroying(this);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -1762,6 +1762,10 @@ pref("dom.ipc.plugins.hangUITimeoutSecs", 5);
|
|||
// Minimum time that the plugin hang UI will be displayed
|
||||
pref("dom.ipc.plugins.hangUIMinDisplaySecs", 10);
|
||||
#endif
|
||||
// How long a content process can take before closing its IPC channel
|
||||
// after shutdown is initiated. If the process exceeds the timeout,
|
||||
// we fear the worst and kill it.
|
||||
pref("dom.ipc.tabs.shutdownTimeoutSecs", 5);
|
||||
#else
|
||||
// No timeout in DEBUG builds
|
||||
pref("dom.ipc.plugins.timeoutSecs", 0);
|
||||
|
@ -1771,6 +1775,7 @@ pref("dom.ipc.plugins.parentTimeoutSecs", 0);
|
|||
pref("dom.ipc.plugins.hangUITimeoutSecs", 0);
|
||||
pref("dom.ipc.plugins.hangUIMinDisplaySecs", 0);
|
||||
#endif
|
||||
pref("dom.ipc.tabs.shutdownTimeoutSecs", 0);
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
|
Загрузка…
Ссылка в новой задаче